@linimin/pi-letscook 0.1.69 → 0.1.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/agents/completion-auditor.md +3 -1
- package/extensions/completion/prompt-surfaces.ts +46 -3
- package/extensions/completion/role-runner.ts +152 -43
- package/package.json +1 -1
- package/scripts/legacy-cleanup-test.sh +1 -1
- package/scripts/role-runner-contract-test.sh +2 -0
- package/scripts/rubric-contract-test.sh +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.71
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- clarified the packaged `completion-auditor` output contract so `Stale or conflicting canonical state` must begin with `yes` or `no`, matching the canonical transcription gate
|
|
8
|
+
- added rubric-contract coverage to keep the stricter auditor yes/no guidance from drifting and to reduce avoidable transcription warnings during audit
|
|
9
|
+
|
|
10
|
+
## 0.1.70
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- added a visible `/cook startup plan` overlay while same-entry primary-agent startup synthesis is running so users no longer wait on a silent UI before Start/Cancel appears
|
|
15
|
+
- reused the same cancellable overlay/heartbeat pattern for `/cook` startup subprocesses so progress updates, elapsed time, and waiting state stay visible during startup-plan synthesis
|
|
16
|
+
|
|
3
17
|
## 0.1.69
|
|
4
18
|
|
|
5
19
|
### Changed
|
|
@@ -52,9 +52,11 @@ Answer only:
|
|
|
52
52
|
- `Tracked and unignored worktree is clean: yes/no`
|
|
53
53
|
- `Worktree blockers: ...`
|
|
54
54
|
- `Next mandatory slice: ...`
|
|
55
|
-
- `Stale or conflicting canonical state: ...`
|
|
55
|
+
- `Stale or conflicting canonical state: yes/no - ...`
|
|
56
56
|
- `Plan truthfully captures remaining slice backlog: yes/no - ...`
|
|
57
57
|
|
|
58
|
+
For every yes/no audit field, start the value with exactly `yes` or `no`. Do not substitute `none`, `clear`, `fresh`, `unknown`, or other synonyms. For example: `Stale or conflicting canonical state: no - canonical state remains aligned with the active slice and backlog.`
|
|
59
|
+
|
|
58
60
|
If the tracked and unignored worktree is dirty after the latest committed slice, report that as a blocker to next-slice progression, do not recommend a new next slice, and point the workflow back to reconciliation of the latest slice.
|
|
59
61
|
|
|
60
62
|
If no remaining gap is evident, say so plainly instead of inventing one.
|
|
@@ -277,14 +277,14 @@ export function buildContextProposalAnalystPrompt(projectName: string, discussio
|
|
|
277
277
|
return lines.join("\n");
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
|
|
280
|
+
function buildCookStartupProgressLines(
|
|
281
281
|
activity: LiveRoleActivity,
|
|
282
282
|
buildInlineRunningLines: (details: {
|
|
283
283
|
role?: string;
|
|
284
284
|
startedAt?: number;
|
|
285
285
|
updatedAt?: number;
|
|
286
286
|
currentAction?: string;
|
|
287
|
-
toolActivity?: string
|
|
287
|
+
toolActivity?: string;
|
|
288
288
|
toolRecentActivity?: string[];
|
|
289
289
|
recentActivity?: string[];
|
|
290
290
|
assistantSummary?: string;
|
|
@@ -294,6 +294,7 @@ export function contextProposalAnalystProgressLines(
|
|
|
294
294
|
verifying?: string;
|
|
295
295
|
stateDeltas?: string[];
|
|
296
296
|
}) => string[],
|
|
297
|
+
footerLine: string,
|
|
297
298
|
): string[] {
|
|
298
299
|
return [
|
|
299
300
|
...buildInlineRunningLines({
|
|
@@ -312,10 +313,52 @@ export function contextProposalAnalystProgressLines(
|
|
|
312
313
|
stateDeltas: activity.stateDeltas,
|
|
313
314
|
}),
|
|
314
315
|
"",
|
|
315
|
-
|
|
316
|
+
footerLine,
|
|
316
317
|
];
|
|
317
318
|
}
|
|
318
319
|
|
|
320
|
+
export function contextProposalAnalystProgressLines(
|
|
321
|
+
activity: LiveRoleActivity,
|
|
322
|
+
buildInlineRunningLines: (details: {
|
|
323
|
+
role?: string;
|
|
324
|
+
startedAt?: number;
|
|
325
|
+
updatedAt?: number;
|
|
326
|
+
currentAction?: string;
|
|
327
|
+
toolActivity?: string;
|
|
328
|
+
toolRecentActivity?: string[];
|
|
329
|
+
recentActivity?: string[];
|
|
330
|
+
assistantSummary?: string;
|
|
331
|
+
progress?: string;
|
|
332
|
+
rationale?: string;
|
|
333
|
+
nextStep?: string;
|
|
334
|
+
verifying?: string;
|
|
335
|
+
stateDeltas?: string[];
|
|
336
|
+
}) => string[],
|
|
337
|
+
): string[] {
|
|
338
|
+
return buildCookStartupProgressLines(activity, buildInlineRunningLines, "This step only prepares a proposal for confirmation.");
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export function primaryAgentHandoffProgressLines(
|
|
342
|
+
activity: LiveRoleActivity,
|
|
343
|
+
buildInlineRunningLines: (details: {
|
|
344
|
+
role?: string;
|
|
345
|
+
startedAt?: number;
|
|
346
|
+
updatedAt?: number;
|
|
347
|
+
currentAction?: string;
|
|
348
|
+
toolActivity?: string;
|
|
349
|
+
toolRecentActivity?: string[];
|
|
350
|
+
recentActivity?: string[];
|
|
351
|
+
assistantSummary?: string;
|
|
352
|
+
progress?: string;
|
|
353
|
+
rationale?: string;
|
|
354
|
+
nextStep?: string;
|
|
355
|
+
verifying?: string;
|
|
356
|
+
stateDeltas?: string[];
|
|
357
|
+
}) => string[],
|
|
358
|
+
): string[] {
|
|
359
|
+
return buildCookStartupProgressLines(activity, buildInlineRunningLines, "This step only synthesizes the startup plan for Start/Cancel confirmation.");
|
|
360
|
+
}
|
|
361
|
+
|
|
319
362
|
export function buildEvaluationRoleContextLines(
|
|
320
363
|
snapshot: CompletionStateSnapshot,
|
|
321
364
|
role: string,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type ContextProposal,
|
|
12
12
|
type RecentDiscussionEntry,
|
|
13
13
|
} from "./proposal";
|
|
14
|
-
import { contextProposalAnalystProgressLines } from "./prompt-surfaces";
|
|
14
|
+
import { contextProposalAnalystProgressLines, primaryAgentHandoffProgressLines } from "./prompt-surfaces";
|
|
15
15
|
import {
|
|
16
16
|
applyLiveRoleEvent,
|
|
17
17
|
buildInlineRunningLines,
|
|
@@ -108,7 +108,12 @@ const PRIMARY_AGENT_HANDOFF_SYSTEM_PROMPT = [
|
|
|
108
108
|
].join(" ");
|
|
109
109
|
const PRIMARY_AGENT_HANDOFF_ROLE = "cook-primary-agent-handoff";
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
type CookStartupOverlayOptions = {
|
|
112
|
+
title: string;
|
|
113
|
+
footer: string;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
class CookStartupOverlay extends Container {
|
|
112
117
|
private readonly border: DynamicBorder;
|
|
113
118
|
private readonly title: Text;
|
|
114
119
|
private readonly body: Text;
|
|
@@ -116,7 +121,10 @@ class StartupAnalystOverlay extends Container {
|
|
|
116
121
|
private lines: string[] = [];
|
|
117
122
|
onAbort?: () => void;
|
|
118
123
|
|
|
119
|
-
constructor(
|
|
124
|
+
constructor(
|
|
125
|
+
private readonly theme: any,
|
|
126
|
+
private readonly options: CookStartupOverlayOptions,
|
|
127
|
+
) {
|
|
120
128
|
super();
|
|
121
129
|
this.border = new DynamicBorder((s: string) => this.theme.fg("accent", s));
|
|
122
130
|
this.title = new Text("", 1, 0);
|
|
@@ -136,9 +144,9 @@ class StartupAnalystOverlay extends Container {
|
|
|
136
144
|
}
|
|
137
145
|
|
|
138
146
|
private updateDisplay(): void {
|
|
139
|
-
this.title.setText(this.theme.fg("accent", this.theme.bold(
|
|
147
|
+
this.title.setText(this.theme.fg("accent", this.theme.bold(this.options.title)));
|
|
140
148
|
this.body.setText(formatInlineRunningText(this.theme, this.lines, { primaryAssistant: true }));
|
|
141
|
-
this.footer.setText(this.theme.fg("muted",
|
|
149
|
+
this.footer.setText(this.theme.fg("muted", this.options.footer));
|
|
142
150
|
}
|
|
143
151
|
|
|
144
152
|
override handleInput(data: string): void {
|
|
@@ -192,12 +200,15 @@ async function runContextProposalAnalystSubprocess(params: AnalyzeContextProposa
|
|
|
192
200
|
const args: string[] = ["--mode", "json", "-p", "--no-session", "--no-extensions", "--append-system-prompt", systemPromptTemp.filePath, "--model", modelArg, prompt];
|
|
193
201
|
const invocation = getPiInvocation(args);
|
|
194
202
|
const liveActivity = createLiveRoleActivity(STARTUP_ANALYST_ROLE);
|
|
203
|
+
liveActivity.toolActivity = undefined;
|
|
204
|
+
liveActivity.toolRecentActivity = [];
|
|
205
|
+
liveActivity.recentActivity = [];
|
|
195
206
|
liveActivity.progress = "Analyzing recent discussion";
|
|
196
207
|
liveActivity.currentAction = "Reading recent discussion and preparing a startup proposal";
|
|
197
208
|
liveActivity.assistantSummary = liveActivity.progress;
|
|
198
209
|
liveActivity.recentActivity = pushRecentActivity(liveActivity.recentActivity, `assistant: ${liveActivity.progress}`);
|
|
199
210
|
const messages: RoleMessage[] = [];
|
|
200
|
-
let overlay:
|
|
211
|
+
let overlay: CookStartupOverlay | undefined;
|
|
201
212
|
let finishOverlay: ((value: string | undefined) => void) | undefined;
|
|
202
213
|
let overlaySettled = false;
|
|
203
214
|
const settleOverlay = (value: string | undefined) => {
|
|
@@ -313,7 +324,10 @@ async function runContextProposalAnalystSubprocess(params: AnalyzeContextProposa
|
|
|
313
324
|
if (ui) {
|
|
314
325
|
return await ui.custom<string | undefined>((_tui, theme, _kb, done) => {
|
|
315
326
|
finishOverlay = done;
|
|
316
|
-
overlay = new
|
|
327
|
+
overlay = new CookStartupOverlay(theme, {
|
|
328
|
+
title: "/cook proposal analyst",
|
|
329
|
+
footer: "Esc/Ctrl+C cancel • This analysis runs before /cook writes canonical workflow state",
|
|
330
|
+
});
|
|
317
331
|
overlay.setLines(contextProposalAnalystProgressLines(liveActivity, buildInlineRunningLines));
|
|
318
332
|
run().then(settleOverlay).catch(() => settleOverlay(undefined));
|
|
319
333
|
return overlay;
|
|
@@ -353,52 +367,147 @@ async function runPrimaryAgentHandoffSubprocess(params: GenerateCookHandoffWithA
|
|
|
353
367
|
if (!modelArg) return undefined;
|
|
354
368
|
const cwd = params.getCtxCwd(ctx);
|
|
355
369
|
const runCwd = findCompletionRoot(cwd) ?? findRepoRoot(cwd) ?? cwd;
|
|
370
|
+
const rootKey = completionRootKey(undefined, cwd);
|
|
356
371
|
const prompt = buildPrimaryAgentHandoffPrompt(projectName, recentEntries, params.workflowContextLines ?? []);
|
|
357
372
|
const systemPromptTemp = await writeTempFile(runCwd, "pi-cook-primary-agent-handoff-", PRIMARY_AGENT_HANDOFF_SYSTEM_PROMPT);
|
|
358
373
|
const args: string[] = ["--mode", "json", "-p", "--no-session", "--no-extensions", "--append-system-prompt", systemPromptTemp.filePath, "--model", modelArg, prompt];
|
|
359
374
|
const invocation = getPiInvocation(args);
|
|
360
375
|
const liveActivity = createLiveRoleActivity(PRIMARY_AGENT_HANDOFF_ROLE);
|
|
361
|
-
liveActivity.
|
|
362
|
-
liveActivity.
|
|
363
|
-
liveActivity.
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
376
|
+
liveActivity.toolActivity = undefined;
|
|
377
|
+
liveActivity.toolRecentActivity = [];
|
|
378
|
+
liveActivity.recentActivity = [];
|
|
379
|
+
liveActivity.currentAction = "Reading current task context";
|
|
380
|
+
liveActivity.rationale = "Loading canonical workflow context";
|
|
381
|
+
liveActivity.nextStep = "Synthesizing startup plan";
|
|
382
|
+
liveActivity.verifying = "Waiting for model response...";
|
|
383
|
+
let overlay: CookStartupOverlay | undefined;
|
|
384
|
+
let finishOverlay: ((value: string | undefined) => void) | undefined;
|
|
385
|
+
let overlaySettled = false;
|
|
386
|
+
const settleOverlay = (value: string | undefined) => {
|
|
387
|
+
if (overlaySettled) return;
|
|
388
|
+
overlaySettled = true;
|
|
389
|
+
finishOverlay?.(value);
|
|
390
|
+
};
|
|
391
|
+
const updateActivity = (fresh = false) => {
|
|
392
|
+
if (fresh) liveActivity.updatedAt = nowMs();
|
|
393
|
+
params.liveRoleActivityByRoot.set(rootKey, cloneLiveRoleActivity(liveActivity, { status: "running" }));
|
|
394
|
+
void refreshCompletionStatus({
|
|
395
|
+
ctx,
|
|
396
|
+
liveRoleActivityByRoot: params.liveRoleActivityByRoot,
|
|
397
|
+
completionStatusKey: params.completionStatusKey,
|
|
398
|
+
safeUiCall: params.safeUiCall,
|
|
399
|
+
getCtxCwd: params.getCtxCwd,
|
|
400
|
+
getCtxHasUI: params.getCtxHasUI,
|
|
401
|
+
getCtxUi: params.getCtxUi,
|
|
402
|
+
});
|
|
403
|
+
overlay?.setLines(primaryAgentHandoffProgressLines(liveActivity, buildInlineRunningLines));
|
|
404
|
+
};
|
|
405
|
+
const heartbeat = setInterval(() => updateActivity(false), ANALYST_HEARTBEAT_MS);
|
|
406
|
+
const run = async (): Promise<string | undefined> => {
|
|
407
|
+
try {
|
|
408
|
+
updateActivity(true);
|
|
409
|
+
const output = await new Promise<string | undefined>((resolve) => {
|
|
410
|
+
const proc = spawn(invocation.command, invocation.args, {
|
|
411
|
+
cwd: runCwd,
|
|
412
|
+
env: process.env,
|
|
413
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
414
|
+
shell: false,
|
|
415
|
+
});
|
|
416
|
+
let settled = false;
|
|
417
|
+
const resolveOnce = (value: string | undefined) => {
|
|
418
|
+
if (settled) return;
|
|
419
|
+
settled = true;
|
|
420
|
+
resolve(value);
|
|
421
|
+
};
|
|
422
|
+
const abort = () => {
|
|
423
|
+
proc.kill("SIGTERM");
|
|
424
|
+
resolveOnce(undefined);
|
|
425
|
+
};
|
|
426
|
+
const handleSigint = () => abort();
|
|
427
|
+
let buffer = "";
|
|
428
|
+
const messages: RoleMessage[] = [];
|
|
429
|
+
const processLine = (line: string) => {
|
|
430
|
+
if (!line.trim()) return;
|
|
431
|
+
try {
|
|
432
|
+
const event = JSON.parse(line) as JsonRecord;
|
|
433
|
+
if (applyLiveRoleEvent(liveActivity, event, messages)) updateActivity(true);
|
|
434
|
+
} catch {
|
|
435
|
+
// ignore malformed lines
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
proc.stdout.on("data", (chunk) => {
|
|
439
|
+
buffer += chunk.toString();
|
|
440
|
+
const lines = buffer.split("\n");
|
|
441
|
+
buffer = lines.pop() ?? "";
|
|
442
|
+
for (const line of lines) processLine(line);
|
|
443
|
+
});
|
|
444
|
+
proc.stderr.on("data", (_chunk) => {
|
|
445
|
+
// ignore handoff stderr unless the subprocess exits without assistant output
|
|
446
|
+
});
|
|
447
|
+
proc.on("close", (code) => {
|
|
448
|
+
process.off("SIGINT", handleSigint);
|
|
449
|
+
if (buffer.trim()) processLine(buffer);
|
|
450
|
+
resolveOnce(code === 0 ? liveActivity.lastAssistantText?.trim() || undefined : undefined);
|
|
451
|
+
});
|
|
452
|
+
proc.on("error", () => {
|
|
453
|
+
process.off("SIGINT", handleSigint);
|
|
454
|
+
resolveOnce(undefined);
|
|
455
|
+
});
|
|
456
|
+
process.once("SIGINT", handleSigint);
|
|
457
|
+
if (overlay) {
|
|
458
|
+
overlay.onAbort = () => {
|
|
459
|
+
process.off("SIGINT", handleSigint);
|
|
460
|
+
abort();
|
|
461
|
+
};
|
|
381
462
|
}
|
|
382
|
-
};
|
|
383
|
-
proc.stdout.on("data", (chunk) => {
|
|
384
|
-
buffer += chunk.toString();
|
|
385
|
-
const lines = buffer.split("\n");
|
|
386
|
-
buffer = lines.pop() ?? "";
|
|
387
|
-
for (const line of lines) processLine(line);
|
|
388
463
|
});
|
|
389
|
-
|
|
390
|
-
|
|
464
|
+
params.liveRoleActivityByRoot.set(rootKey, cloneLiveRoleActivity(liveActivity, { status: output ? "ok" : "error" }));
|
|
465
|
+
await refreshCompletionStatus({
|
|
466
|
+
ctx,
|
|
467
|
+
liveRoleActivityByRoot: params.liveRoleActivityByRoot,
|
|
468
|
+
completionStatusKey: params.completionStatusKey,
|
|
469
|
+
safeUiCall: params.safeUiCall,
|
|
470
|
+
getCtxCwd: params.getCtxCwd,
|
|
471
|
+
getCtxHasUI: params.getCtxHasUI,
|
|
472
|
+
getCtxUi: params.getCtxUi,
|
|
391
473
|
});
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
474
|
+
return output;
|
|
475
|
+
} finally {
|
|
476
|
+
clearInterval(heartbeat);
|
|
477
|
+
setTimeout(() => {
|
|
478
|
+
const current = params.liveRoleActivityByRoot.get(rootKey);
|
|
479
|
+
if (current && current.role === PRIMARY_AGENT_HANDOFF_ROLE && current.status !== "running") {
|
|
480
|
+
params.liveRoleActivityByRoot.delete(rootKey);
|
|
481
|
+
void refreshCompletionStatus({
|
|
482
|
+
ctx,
|
|
483
|
+
liveRoleActivityByRoot: params.liveRoleActivityByRoot,
|
|
484
|
+
completionStatusKey: params.completionStatusKey,
|
|
485
|
+
safeUiCall: params.safeUiCall,
|
|
486
|
+
getCtxCwd: params.getCtxCwd,
|
|
487
|
+
getCtxHasUI: params.getCtxHasUI,
|
|
488
|
+
getCtxUi: params.getCtxUi,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
}, 10_000);
|
|
492
|
+
await fsp.rm(systemPromptTemp.dir, { recursive: true, force: true });
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
if (params.getCtxHasUI(ctx)) {
|
|
496
|
+
const ui = params.getCtxUi(ctx);
|
|
497
|
+
if (ui) {
|
|
498
|
+
return await ui.custom<string | undefined>((_tui, theme, _kb, done) => {
|
|
499
|
+
finishOverlay = done;
|
|
500
|
+
overlay = new CookStartupOverlay(theme, {
|
|
501
|
+
title: "/cook startup plan",
|
|
502
|
+
footer: "Esc/Ctrl+C cancel • This startup-plan synthesis runs before /cook writes canonical workflow state",
|
|
503
|
+
});
|
|
504
|
+
overlay.setLines(primaryAgentHandoffProgressLines(liveActivity, buildInlineRunningLines));
|
|
505
|
+
run().then(settleOverlay).catch(() => settleOverlay(undefined));
|
|
506
|
+
return overlay;
|
|
395
507
|
});
|
|
396
|
-
|
|
397
|
-
});
|
|
398
|
-
return output;
|
|
399
|
-
} finally {
|
|
400
|
-
await fsp.rm(systemPromptTemp.dir, { recursive: true, force: true });
|
|
508
|
+
}
|
|
401
509
|
}
|
|
510
|
+
return await run();
|
|
402
511
|
}
|
|
403
512
|
|
|
404
513
|
export async function generateCookHandoffWithAgent(params: GenerateCookHandoffWithAgentParams): Promise<string | undefined> {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linimin/pi-letscook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.71",
|
|
4
4
|
"description": "Pi package for long-running completion workflows with canonical .agent state, role-based subagents, continuity, and verification helpers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -48,7 +48,7 @@ assertIncludes('extensions/completion/proposal.ts', 'export function serializeRe
|
|
|
48
48
|
assertIncludes('extensions/completion/proposal.ts', 'export function extractJsonObjectFromText(');
|
|
49
49
|
|
|
50
50
|
assertIncludes('extensions/completion/role-runner.ts', 'export async function analyzeContextProposalWithAgent(');
|
|
51
|
-
assertIncludes('extensions/completion/role-runner.ts', 'class
|
|
51
|
+
assertIncludes('extensions/completion/role-runner.ts', 'class CookStartupOverlay extends Container');
|
|
52
52
|
assertIncludes('extensions/completion/role-runner.ts', 'async function runContextProposalAnalystSubprocess(');
|
|
53
53
|
|
|
54
54
|
assertIncludes('extensions/completion/prompt-surfaces.ts', 'export function buildSystemReminder(');
|
|
@@ -30,6 +30,8 @@ assertIncludes('extensions/completion/role-runner.ts', 'const transcription = ex
|
|
|
30
30
|
assertIncludes('extensions/completion/role-runner.ts', 'env: { ...process.env, PI_COMPLETION_ROLE: params.role },');
|
|
31
31
|
assertIncludes('extensions/completion/role-runner.ts', 'async function runContextProposalAnalystSubprocess(');
|
|
32
32
|
assertIncludes('extensions/completion/role-runner.ts', 'export async function analyzeContextProposalWithAgent(');
|
|
33
|
+
assertIncludes('extensions/completion/role-runner.ts', 'class CookStartupOverlay extends Container');
|
|
34
|
+
assertIncludes('extensions/completion/role-runner.ts', 'overlay = new CookStartupOverlay(theme, {');
|
|
33
35
|
assertIncludes('extensions/completion/index.ts', 'import { analyzeContextProposalWithAgent, generateCookHandoffWithAgent, runCompletionRole } from "./role-runner";');
|
|
34
36
|
assertIncludes('extensions/completion/index.ts', 'const result = await runCompletionRole({');
|
|
35
37
|
assertIncludes('extensions/completion/index.ts', 'const raw = await generateCookHandoffWithAgent({');
|
|
@@ -90,6 +90,8 @@ assertIncludes('extensions/completion/role-reporting.js', 'Reviewer output canno
|
|
|
90
90
|
assertIncludes('extensions/completion/role-reporting.js', 'Auditor output must answer \'Tracked and unignored worktree is clean\' with yes or no.');
|
|
91
91
|
assertIncludes('extensions/completion/role-reporting.js', 'Auditor output must answer \'Stale or conflicting canonical state\' with yes or no.');
|
|
92
92
|
assertIncludes('extensions/completion/role-reporting.js', 'Auditor output must answer \'Plan truthfully captures remaining slice backlog\' with yes or no.');
|
|
93
|
+
assertIncludes('agents/completion-auditor.md', '`Stale or conflicting canonical state: yes/no - ...`');
|
|
94
|
+
assertIncludes('agents/completion-auditor.md', 'For every yes/no audit field, start the value with exactly `yes` or `no`.');
|
|
93
95
|
assertIncludes('extensions/completion/role-reporting.js', 'Stop-judge output cannot mark \'Can the project stop now: yes\' when any rubric line is fail.');
|
|
94
96
|
assertIncludes('extensions/completion/role-reporting.js', 'Stop-judge output must answer \'Docs/config/runbooks match shipped behavior\' with yes or no.');
|
|
95
97
|
assertIncludes('extensions/completion/role-reporting.js', 'Stop-judge output must answer \'Tracked and unignored worktree is clean\' with yes or no.');
|