mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-15 15:46:30 +03:00
Bound the hand, greek the copy, and treat waiting as supervision
A codex field run dealt six challengers into an eight-sketch batch behind an opaque subagent, and the user stared at a page of shimmer asking whether anything was happening at all. Four fixes from that run. A hand now holds at most three challengers, the rest banked for re-rolls, so fairness within the hand stops multiplying into a queue. Sketches greek everything but the product's real name and one real headline, because an invented spec, price, or ship date in a sketch is a claim PRODUCT.md never made, and comps have solved this for a century. Sketch production follows the user's reading order with the first file doubling as the producer's heartbeat, and the parent's --wait loop checks the sketch directory each pass, reclaiming the batch inline when two minutes pass with nothing landed. And a failed --start now captures the daemon's stderr to a per-key log and names the sandbox as the usual suspect, instead of reporting only that failure occurred. The shimmer counts its elapsed seconds, and gives up at 150 instead of 300. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
149d71a772
commit
0eb443d29b
@@ -222,14 +222,25 @@ if (hasFlag('start')) {
|
||||
const key = arg('key') || Math.random().toString(16).slice(2, 10);
|
||||
// In start mode the agent is alive and owns browser routing; the server
|
||||
// only opens the system browser itself when --open forces it.
|
||||
// The daemon's output lands in a per-key log so a startup failure can say
|
||||
// what actually went wrong instead of only that it did.
|
||||
const logFile = path.join(QUESTION_DIR, `${key}.log`);
|
||||
const logFd = fs.openSync(logFile, 'a');
|
||||
const child = spawn(process.execPath, [
|
||||
fileURLToPath(import.meta.url), '--payload', payloadPath, '--detached-serve', '--key', key,
|
||||
'--timeout', String(timeoutSec), ...(hasFlag('open') ? [] : ['--no-open']),
|
||||
], { detached: true, stdio: 'ignore' });
|
||||
], { detached: true, stdio: ['ignore', logFd, logFd] });
|
||||
child.unref();
|
||||
fs.closeSync(logFd);
|
||||
const deadline = Date.now() + 8000;
|
||||
while (Date.now() < deadline && !fs.existsSync(stateFile(key))) await new Promise((r) => setTimeout(r, 100));
|
||||
if (!fs.existsSync(stateFile(key))) { console.error('serve-question: server failed to start'); process.exit(1); }
|
||||
if (!fs.existsSync(stateFile(key))) {
|
||||
let tail = '';
|
||||
try { tail = fs.readFileSync(logFile, 'utf8').trim().split('\n').slice(-4).join('\n '); } catch { /* log never written */ }
|
||||
console.error(`serve-question: server failed to start${tail ? `\n ${tail}` : ''}`);
|
||||
console.error(`serve-question: log at ${path.relative(process.cwd(), logFile) || logFile}. A sandboxed exec that cannot listen on localhost causes exactly this; rerun this command once through the harness's network-enabled or unsandboxed command tool before falling back.`);
|
||||
process.exit(1);
|
||||
}
|
||||
const state = JSON.parse(fs.readFileSync(stateFile(key), 'utf8'));
|
||||
console.log(`QUESTION URL: ${state.url}`);
|
||||
console.log(`QUESTION KEY: ${key}`);
|
||||
@@ -617,13 +628,16 @@ function page() {
|
||||
document.querySelectorAll('.media.sketching').forEach(m => {
|
||||
const url = m.dataset.sketch;
|
||||
const img = m.querySelector('img.sketch');
|
||||
const note = m.querySelector('.sketch-note');
|
||||
const started = Date.now();
|
||||
const settle = () => { m.classList.remove('sketching'); m.querySelector('.shimmer')?.remove(); };
|
||||
// A live elapsed count is the difference between "working" and "frozen".
|
||||
const tick = setInterval(() => { if (note) note.textContent = 'sketching · ' + Math.round((Date.now() - started) / 1000) + 's'; }, 1000);
|
||||
const settle = () => { clearInterval(tick); m.classList.remove('sketching'); m.querySelector('.shimmer')?.remove(); };
|
||||
const tryLoad = () => {
|
||||
const probe = new Image();
|
||||
probe.onload = () => { img.src = probe.src; img.hidden = false; settle(); };
|
||||
probe.onerror = () => {
|
||||
if (Date.now() - started > 300000) {
|
||||
if (Date.now() - started > 150000) {
|
||||
const pip = m.querySelector('.pip img');
|
||||
if (pip) { img.src = pip.getAttribute('src'); img.hidden = false; }
|
||||
else { m.closest('.face').classList.add('text-only'); m.remove(); }
|
||||
|
||||
Reference in New Issue
Block a user