Add /impeccable generate: agent-initiated live variants (Node-era squash)

Squash of the ten commits reviewed on PR #626, plus the last review
round's connection-aware roll call, before the rebase onto the Rust
engine: the generate command reference and router row, the overlay's
agent-target handling (roll call, leases, replay, rescue), the Node-era
live-server routes and live-generate CLI, the hook stand-down, the pricing
cards e2e fixture, and the unit, contract, e2e, and skill-behavior tests.
The server, CLI, hook, and pin halves are ported to the engine crates in
the commits that follow.

AI-assisted: implemented and tested with Claude Code under maintainer
direction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Abdul Wahab
2026-09-15 05:45:49 +05:00
committed by Abdul Wahab
co-authored by Claude Fable 5
parent 1c043ea7c9
commit fc89b0ed62
27 changed files with 1851 additions and 16 deletions
+147
View File
@@ -810,6 +810,130 @@ for (const { name, fixture } of fixtures) {
});
}
// -----------------------------------------------------------------
// Agent-initiated targeting (the `generate` command). The agent names
// the element over the live-generate CLI; the overlay resolves the
// selector, scrolls to it, enters the picked state, and fires Go with
// no user click. Everything downstream (generate event, variants,
// cycling, accept, carbonize) is the standard pipeline, so the second
// half of this test reuses the core helpers unchanged.
// -----------------------------------------------------------------
if (shouldRunScenario('agent-target') && fixture.runtime.agentTargetScenario) {
it('agent-initiated target scrolls, picks, and generates without a user click', liveE2eTestOptions, async (t) => {
if (!canRunFakeAgentScenario(t)) return;
const scenario = fixture.runtime.agentTargetScenario;
const session = await bootFixtureSession({
name,
fixture,
browser,
agent: createFakeAgent(),
wrapTarget: wrapTargetFromPickedElement,
atomicDelayMs,
log: (m) => t.diagnostic(m),
});
const { page, appRoot, teardown } = session;
try {
await waitForHandshake(page);
// Failure contracts first; none of these may start a session.
const miss = runLiveGenerate(appRoot, { selector: scenario.missSelector, action: scenario.action });
assert.equal(miss.ok, false);
assert.equal(miss.error, 'no_match');
const ambiguous = runLiveGenerate(appRoot, { selector: scenario.ambiguousSelector, action: scenario.action });
assert.equal(ambiguous.ok, false);
assert.equal(ambiguous.error, 'ambiguous');
assert.ok(ambiguous.matchCount >= 2, 'ambiguous reports the match count');
assert.ok(
Array.isArray(ambiguous.candidates) && ambiguous.candidates.length >= 2,
'ambiguous lists candidate descriptors',
);
const dry = runLiveGenerate(appRoot, {
selector: scenario.selector,
action: scenario.action,
'dry-run': true,
});
assert.equal(dry.ok, true, `dry-run resolved: ${JSON.stringify(dry)}`);
assert.equal(dry.dryRun, true);
assert.equal(dry.matchCount, 1);
const noSession = await page.evaluate(() => window.__IMPECCABLE_LIVE_CHROME_CORE__.debugState());
assert.equal(noSession.currentSessionId, null, 'failed and dry-run targets start no session');
assert.equal(await page.evaluate(() => Math.round(window.scrollY)), 0, 'page has not scrolled yet');
// The happy path: resolve, scroll, pick, Go.
t.diagnostic(`Agent-targeting ${scenario.selector} (${scenario.action} x${scenario.count || 3})`);
const res = runLiveGenerate(appRoot, {
selector: scenario.selector,
action: scenario.action,
count: scenario.count || 3,
...(scenario.prompt ? { prompt: scenario.prompt } : {}),
});
assert.equal(res.ok, true, `live-generate succeeded: ${JSON.stringify(res)}`);
assert.match(res.sessionId, /^[0-9a-f]{8}$/, 'a session id came back');
assert.equal(res.action, scenario.action);
const scrolled = await page.evaluate(() => Math.round(window.scrollY));
assert.ok(
scrolled >= (scenario.minScrollY || 100),
`browser scrolled to the target (scrollY=${scrolled})`,
);
const dbg = await page.evaluate(() => window.__IMPECCABLE_LIVE_CHROME_CORE__.debugState());
assert.equal(dbg.currentSessionId, res.sessionId, 'overlay session matches the CLI result');
if (scenario.prompt) {
// The configure bar rebuild once discarded the preset prompt, so
// pin the regression at the wire: the journaled generate event
// must carry the prompt the CLI was given.
const journalPath = join(appRoot, '.impeccable/live/sessions', `${res.sessionId}.jsonl`);
const journaled = readFileSync(journalPath, 'utf-8').trim().split('\n').map((l) => JSON.parse(l));
const generateEvent = journaled.find((entry) => entry.type === 'generate')?.event;
assert.equal(
generateEvent?.freeformPrompt,
scenario.prompt,
'the prompt reached the generate event',
);
}
// A second target while the session is mid-flight must refuse.
const busy = runLiveGenerate(appRoot, { selector: scenario.selector, action: scenario.action });
assert.equal(busy.ok, false);
assert.equal(busy.error, 'busy');
await waitForCyclingRobust(page, 3, { agentMode: 'fake', log: (m) => t.diagnostic(m) });
const sourceFile = await locateSessionFile(appRoot);
assert.ok(sourceFile, 'the variants wrapper landed in a source file');
await cycleToVariant(page, 2, 3);
t.diagnostic('Accepting variant 2');
await clickAccept(page, { expectedVariant: 2 });
await waitForBarHidden(page);
const final = await waitForSourceClean(sourceFile, 20_000, {});
assert.match(
final,
new RegExp(fixture.runtime.acceptedSourcePattern),
'accepted source element survives',
);
for (const needle of fixture.runtime.assertSourceContains || []) {
assert.ok(final.includes(needle), `source still contains ${JSON.stringify(needle)} after accept`);
}
assert.doesNotMatch(final, /data-impeccable-variants="/, 'variants wrapper removed');
assert.doesNotMatch(final, /impeccable-carbonize-start/, 'carbonize block rewritten');
// The overlay is reusable after accept: a fresh dry-run resolves.
const post = runLiveGenerate(appRoot, {
selector: scenario.selector,
action: scenario.action,
'dry-run': true,
});
assert.equal(post.ok, true, 'a new target resolves after accept');
} finally {
await teardownAndResetBrowser(teardown);
}
});
}
// -----------------------------------------------------------------
// Failure injection for component previews.
// -----------------------------------------------------------------
@@ -1363,6 +1487,29 @@ function canRunFakeAgentScenario(t) {
return true;
}
/**
* Run the live-generate verb (agent-initiated targeting) against a staged
* fixture and parse its JSON verdict. The CLI exits 1 for every ok:false
* outcome, so the JSON is read from the thrown error's stdout in that case.
*/
function runLiveGenerate(appRoot, flags) {
const args = [];
for (const [key, value] of Object.entries(flags)) {
if (value === true) args.push(`--${key}`);
else if (value !== undefined && value !== null) args.push(`--${key}`, String(value));
}
let stdout;
try {
stdout = runEngineSync('live-generate', args, { cwd: appRoot });
} catch (err) {
// The verb exits non-zero on every failure verdict but still prints the
// JSON the scenario asserts on.
stdout = err.stdout || '';
if (!stdout.trim()) throw err;
}
return JSON.parse(stdout);
}
/**
* Boot a fixture straight to CYCLING on a component-preview session and hand
* back the handles the scenarios need: the manifest, the route source, and the