@linimin/pi-letscook 0.1.66 → 0.1.67
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/.agent/README.md +4 -0
- package/.agent/verify_completion_control_plane.sh +34 -0
- package/CHANGELOG.md +9 -0
- package/README.md +26 -21
- package/agents/completion-bootstrapper.md +2 -1
- package/agents/completion-regrounder.md +16 -10
- package/extensions/completion/driver.ts +66 -17
- package/extensions/completion/index.ts +96 -21
- package/extensions/completion/prompt-surfaces.ts +156 -15
- package/extensions/completion/proposal.ts +21 -21
- package/extensions/completion/role-runner.ts +11 -10
- package/extensions/completion/state-store.ts +87 -2
- package/extensions/completion/types.ts +3 -0
- package/package.json +1 -1
- package/scripts/active-slice-contract-test.sh +1 -1
- package/scripts/canonical-evidence-artifact-test.sh +49 -4
- package/scripts/context-proposal-test.sh +57 -58
- package/scripts/refocus-test.sh +17 -17
- package/scripts/release-check.sh +11 -11
- package/scripts/smoke-test.sh +69 -9
- package/skills/completion-protocol/SKILL.md +9 -3
- package/skills/completion-protocol/references/completion.md +37 -2
- package/skills/cook-handoff-boundary/SKILL.md +16 -16
|
@@ -97,14 +97,15 @@ const STARTUP_ANALYST_ROLE = "cook-proposal-analyst";
|
|
|
97
97
|
const ANALYST_HEARTBEAT_MS = 5_000;
|
|
98
98
|
|
|
99
99
|
const PRIMARY_AGENT_HANDOFF_SYSTEM_PROMPT = [
|
|
100
|
-
"You are the primary agent preparing an explicit /cook
|
|
101
|
-
"Return either exactly one fenced ```cook_handoff JSON block or one brief plain sentence explaining why no concrete
|
|
102
|
-
"If you can prepare a
|
|
103
|
-
"
|
|
104
|
-
"
|
|
100
|
+
"You are the primary agent preparing an explicit /cook startup plan after the user already chose workflow mode.",
|
|
101
|
+
"Return either exactly one fenced ```cook_handoff JSON block or one brief plain sentence explaining why no concrete startup plan can be prepared.",
|
|
102
|
+
"If you can prepare a plan, the JSON must use kind cook_handoff, source primary_agent, and handoff_kind implementation_workflow_handoff.",
|
|
103
|
+
"Author the approved workflow startup plan now from the primary-agent view of the task so /cook can persist it under .agent before completion-regrounder derives canonical slices.",
|
|
104
|
+
"Capture the agreed mission, scope, constraints or non_goals, acceptance, risks, notes, and any concrete planning hints that will help completion-regrounder split slices later.",
|
|
105
|
+
"If a bounded first slice, likely implementation surfaces, or likely verification commands are already obvious, include first_slice_goal, first_slice_non_goals, implementation_surfaces, verification_commands, and why_this_slice_first as optional hints only. They are not required when the overall startup plan is already concrete enough to begin workflow planning.",
|
|
106
|
+
"Do not make /cook infer or rediscover the mission from recent discussion later; author the startup plan now from the primary-agent view of the task.",
|
|
105
107
|
"Do not emit markdown commentary before or after the capsule.",
|
|
106
|
-
"If the task is not concrete enough for
|
|
107
|
-
"A valid implementation-ready handoff must include mission, scope, constraints or non_goals, acceptance, risks, notes, first_slice_goal, first_slice_non_goals, implementation_surfaces, verification_commands, and why_this_slice_first.",
|
|
108
|
+
"If the task is not concrete enough for workflow startup, do not invent missing detail.",
|
|
108
109
|
].join(" ");
|
|
109
110
|
const PRIMARY_AGENT_HANDOFF_ROLE = "cook-primary-agent-handoff";
|
|
110
111
|
|
|
@@ -342,7 +343,7 @@ function buildPrimaryAgentHandoffPrompt(projectName: string, recentEntries: Rece
|
|
|
342
343
|
lines.push(
|
|
343
344
|
"",
|
|
344
345
|
"Task:",
|
|
345
|
-
"The user explicitly invoked /cook. Prepare the primary-agent
|
|
346
|
+
"The user explicitly invoked /cook. Prepare the primary-agent startup plan that /cook should consume immediately for Start/Cancel confirmation, persistence under .agent, and later slice derivation by completion-regrounder.",
|
|
346
347
|
);
|
|
347
348
|
return lines.join("\n");
|
|
348
349
|
}
|
|
@@ -359,7 +360,7 @@ async function runPrimaryAgentHandoffSubprocess(params: GenerateCookHandoffWithA
|
|
|
359
360
|
const invocation = getPiInvocation(args);
|
|
360
361
|
const liveActivity = createLiveRoleActivity(PRIMARY_AGENT_HANDOFF_ROLE);
|
|
361
362
|
liveActivity.progress = "Preparing primary-agent /cook handoff";
|
|
362
|
-
liveActivity.currentAction = "Authoring explicit startup
|
|
363
|
+
liveActivity.currentAction = "Authoring explicit startup plan from current task context";
|
|
363
364
|
liveActivity.assistantSummary = liveActivity.progress;
|
|
364
365
|
try {
|
|
365
366
|
const output = await new Promise<string | undefined>((resolve) => {
|
|
@@ -409,7 +410,7 @@ export async function generateCookHandoffWithAgent(params: GenerateCookHandoffWi
|
|
|
409
410
|
try {
|
|
410
411
|
return await runPrimaryAgentHandoffSubprocess(params);
|
|
411
412
|
} catch (error) {
|
|
412
|
-
console.warn("[completion] primary-agent
|
|
413
|
+
console.warn("[completion] primary-agent startup-plan generation failed", error);
|
|
413
414
|
return undefined;
|
|
414
415
|
}
|
|
415
416
|
}
|
|
@@ -3,6 +3,7 @@ import { spawnSync } from "node:child_process";
|
|
|
3
3
|
import { promises as fsp } from "node:fs";
|
|
4
4
|
import * as os from "node:os";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
+
import { buildApprovedStartupPlanMarkdown } from "./prompt-surfaces";
|
|
6
7
|
import type { CompletionStateSnapshot, JsonRecord } from "./types";
|
|
7
8
|
|
|
8
9
|
const PROTOCOL_ID = "completion";
|
|
@@ -45,6 +46,8 @@ export function resolveFiles(root: string) {
|
|
|
45
46
|
statePath: path.join(agentDir, "state.json"),
|
|
46
47
|
planPath: path.join(agentDir, "plan.json"),
|
|
47
48
|
activePath: path.join(agentDir, "active-slice.json"),
|
|
49
|
+
startupPlanPath: path.join(agentDir, "startup-plan.json"),
|
|
50
|
+
startupPlanMarkdownPath: path.join(agentDir, "startup-plan.md"),
|
|
48
51
|
sliceHistoryPath: path.join(agentDir, "slice-history.jsonl"),
|
|
49
52
|
stopHistoryPath: path.join(agentDir, "stop-check-history.jsonl"),
|
|
50
53
|
verificationEvidencePath: path.join(agentDir, "verification-evidence.json"),
|
|
@@ -141,6 +144,7 @@ export async function loadCompletionSnapshot(startCwd: string): Promise<Completi
|
|
|
141
144
|
const state = await readJson(files.statePath);
|
|
142
145
|
const plan = await readJson(files.planPath);
|
|
143
146
|
const active = await readJson(files.activePath);
|
|
147
|
+
const startupPlan = await readJson(files.startupPlanPath);
|
|
144
148
|
const verificationEvidence = await readJson(files.verificationEvidencePath);
|
|
145
149
|
return {
|
|
146
150
|
files,
|
|
@@ -148,6 +152,7 @@ export async function loadCompletionSnapshot(startCwd: string): Promise<Completi
|
|
|
148
152
|
state,
|
|
149
153
|
plan,
|
|
150
154
|
active,
|
|
155
|
+
startupPlan,
|
|
151
156
|
verificationEvidence,
|
|
152
157
|
activeSlice: findActiveSlice(plan, active),
|
|
153
158
|
};
|
|
@@ -275,6 +280,32 @@ export function defaultPlan(
|
|
|
275
280
|
};
|
|
276
281
|
}
|
|
277
282
|
|
|
283
|
+
export function defaultStartupPlan(
|
|
284
|
+
missionAnchor: string,
|
|
285
|
+
routing?: { taskType?: string; evaluationProfile?: string },
|
|
286
|
+
approvedStartupPlan?: JsonRecord,
|
|
287
|
+
): JsonRecord {
|
|
288
|
+
return approvedStartupPlan ?? {
|
|
289
|
+
schema_version: 1,
|
|
290
|
+
artifact_type: "completion-startup-plan",
|
|
291
|
+
status: "approved",
|
|
292
|
+
source: "recent_discussion",
|
|
293
|
+
captured_at: null,
|
|
294
|
+
mission_anchor: missionAnchor,
|
|
295
|
+
goal_text: `Mission: ${missionAnchor}`,
|
|
296
|
+
task_type: routing?.taskType ?? DEFAULT_TASK_TYPE,
|
|
297
|
+
evaluation_profile: routing?.evaluationProfile ?? DEFAULT_EVALUATION_PROFILE,
|
|
298
|
+
scope: [],
|
|
299
|
+
constraints: [],
|
|
300
|
+
acceptance: [],
|
|
301
|
+
risks: [],
|
|
302
|
+
notes: ["No approved startup plan has been recorded yet."],
|
|
303
|
+
planned_surfaces: [],
|
|
304
|
+
verification_intent: [],
|
|
305
|
+
sequencing_hints: [],
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
278
309
|
export function defaultActiveSlice(
|
|
279
310
|
missionAnchor: string,
|
|
280
311
|
routing?: { taskType?: string; evaluationProfile?: string },
|
|
@@ -321,7 +352,7 @@ export function defaultVerificationEvidence(): JsonRecord {
|
|
|
321
352
|
}
|
|
322
353
|
|
|
323
354
|
export function buildAgentReadme(projectName: string): string {
|
|
324
|
-
return `# Completion Control Plane\n\nThis repository uses the \`completion\` workflow for long-running coding tasks.\n\n## Canonical tracked contract files\n\n- \`.agent/README.md\`\n- \`.agent/mission.md\`\n- \`.agent/profile.json\`\n- \`.agent/verify_completion_stop.sh\`\n- \`.agent/verify_completion_control_plane.sh\`\n\n## Ignored canonical execution state\n\n- \`.agent/state.json\`\n- \`.agent/plan.json\`\n- \`.agent/active-slice.json\`\n- \`.agent/slice-history.jsonl\`\n- \`.agent/stop-check-history.jsonl\`\n- \`.agent/verification-evidence.json\`\n- \`.agent/*.log\`\n- \`.agent/tmp/\`\n\n\`.agent/verification-evidence.json\` is the durable canonical record of deterministic verification for the selected slice or current HEAD. Recovery, review, audit, and stop-check reminder surfaces consume it instead of temp-only artifacts or conversational summaries when it is populated.\n\nThe source of truth for long-running completion work is canonical \`.agent/**\` state plus current repo truth.\n\nProject: ${projectName}\n`;
|
|
355
|
+
return `# Completion Control Plane\n\nThis repository uses the \`completion\` workflow for long-running coding tasks.\n\n## Canonical tracked contract files\n\n- \`.agent/README.md\`\n- \`.agent/mission.md\`\n- \`.agent/profile.json\`\n- \`.agent/verify_completion_stop.sh\`\n- \`.agent/verify_completion_control_plane.sh\`\n\n## Ignored canonical execution state\n\n- \`.agent/state.json\`\n- \`.agent/startup-plan.json\`\n- \`.agent/startup-plan.md\`\n- \`.agent/plan.json\`\n- \`.agent/active-slice.json\`\n- \`.agent/slice-history.jsonl\`\n- \`.agent/stop-check-history.jsonl\`\n- \`.agent/verification-evidence.json\`\n- \`.agent/*.log\`\n- \`.agent/tmp/\`\n\n\`.agent/startup-plan.json\` plus \`.agent/startup-plan.md\` preserve the approved workflow startup plan captured at \`/cook\`. \`completion-regrounder\` consumes that plan as planning input, then derives canonical slices in \`.agent/plan.json\` from current repo truth.\n\n\`.agent/verification-evidence.json\` is the durable canonical record of deterministic verification for the selected slice or current HEAD. Recovery, review, audit, and stop-check reminder surfaces consume it instead of temp-only artifacts or conversational summaries when it is populated.\n\nThe source of truth for long-running completion work is canonical \`.agent/**\` state plus current repo truth.\n\nProject: ${projectName}\n`;
|
|
325
356
|
}
|
|
326
357
|
|
|
327
358
|
export function buildMission(projectName: string, missionAnchor: string): string {
|
|
@@ -424,15 +455,23 @@ function trackedDiffFiles(fromCommit, toCommit) {
|
|
|
424
455
|
|
|
425
456
|
const profile = readJson('.agent/profile.json');
|
|
426
457
|
const state = readJson('.agent/state.json');
|
|
458
|
+
const startupPlan = readJson('.agent/startup-plan.json');
|
|
427
459
|
const plan = readJson('.agent/plan.json');
|
|
428
460
|
const active = readJson('.agent/active-slice.json');
|
|
429
461
|
const evidence = readJson('.agent/verification-evidence.json');
|
|
462
|
+
let startupPlanMarkdown = '';
|
|
463
|
+
try {
|
|
464
|
+
startupPlanMarkdown = fs.readFileSync('.agent/startup-plan.md', 'utf8');
|
|
465
|
+
} catch (error) {
|
|
466
|
+
fail('.agent/startup-plan.md must be present and readable: ' + error.message);
|
|
467
|
+
}
|
|
430
468
|
|
|
431
469
|
ensureTrackedContractFiles();
|
|
432
470
|
|
|
433
471
|
for (const [file, record] of [
|
|
434
472
|
['.agent/profile.json', profile],
|
|
435
473
|
['.agent/state.json', state],
|
|
474
|
+
['.agent/startup-plan.json', startupPlan],
|
|
436
475
|
['.agent/plan.json', plan],
|
|
437
476
|
['.agent/active-slice.json', active],
|
|
438
477
|
]) {
|
|
@@ -443,12 +482,38 @@ for (const [file, record] of [
|
|
|
443
482
|
const taskType = asString(profile.task_type);
|
|
444
483
|
const evaluationProfile = asString(profile.evaluation_profile);
|
|
445
484
|
if (asString(state.task_type) !== taskType) fail('.agent/state.json task_type must match .agent/profile.json task_type');
|
|
485
|
+
if (asString(startupPlan.task_type) !== taskType) fail('.agent/startup-plan.json task_type must match .agent/profile.json task_type');
|
|
446
486
|
if (asString(plan.task_type) !== taskType) fail('.agent/plan.json task_type must match .agent/profile.json task_type');
|
|
447
487
|
if (asString(active.task_type) !== taskType) fail('.agent/active-slice.json task_type must match .agent/profile.json task_type');
|
|
448
488
|
if (asString(state.evaluation_profile) !== evaluationProfile) fail('.agent/state.json evaluation_profile must match .agent/profile.json evaluation_profile');
|
|
489
|
+
if (asString(startupPlan.evaluation_profile) !== evaluationProfile) fail('.agent/startup-plan.json evaluation_profile must match .agent/profile.json evaluation_profile');
|
|
449
490
|
if (asString(plan.evaluation_profile) !== evaluationProfile) fail('.agent/plan.json evaluation_profile must match .agent/profile.json evaluation_profile');
|
|
450
491
|
if (asString(active.evaluation_profile) !== evaluationProfile) fail('.agent/active-slice.json evaluation_profile must match .agent/profile.json evaluation_profile');
|
|
451
492
|
|
|
493
|
+
if (asString(startupPlan.artifact_type) !== 'completion-startup-plan') {
|
|
494
|
+
fail('.agent/startup-plan.json artifact_type must be completion-startup-plan');
|
|
495
|
+
}
|
|
496
|
+
if (asString(startupPlan.status) !== 'approved') {
|
|
497
|
+
fail('.agent/startup-plan.json status must be approved');
|
|
498
|
+
}
|
|
499
|
+
const startupPlanMissionAnchor = asString(startupPlan.mission_anchor);
|
|
500
|
+
if (!startupPlanMissionAnchor) fail('.agent/startup-plan.json mission_anchor must be present');
|
|
501
|
+
if (startupPlanMissionAnchor !== asString(state.mission_anchor)) fail('.agent/startup-plan.json mission_anchor must match .agent/state.json mission_anchor');
|
|
502
|
+
if (startupPlanMissionAnchor !== asString(plan.mission_anchor)) fail('.agent/startup-plan.json mission_anchor must match .agent/plan.json mission_anchor');
|
|
503
|
+
if (startupPlanMissionAnchor !== asString(active.mission_anchor)) fail('.agent/startup-plan.json mission_anchor must match .agent/active-slice.json mission_anchor');
|
|
504
|
+
if (!asString(startupPlan.goal_text)) fail('.agent/startup-plan.json goal_text must be present');
|
|
505
|
+
for (const field of ['scope', 'constraints', 'acceptance', 'risks', 'notes', 'planned_surfaces', 'verification_intent', 'sequencing_hints']) {
|
|
506
|
+
if (!Array.isArray(startupPlan[field])) fail('.agent/startup-plan.json is missing ' + field);
|
|
507
|
+
}
|
|
508
|
+
if (startupPlanMarkdown.trim().length === 0) fail('.agent/startup-plan.md must not be empty');
|
|
509
|
+
if (startupPlanMissionAnchor && !startupPlanMarkdown.includes(startupPlanMissionAnchor)) {
|
|
510
|
+
fail('.agent/startup-plan.md must mention the startup-plan mission_anchor');
|
|
511
|
+
}
|
|
512
|
+
const startupPlanGoalText = asString(startupPlan.goal_text);
|
|
513
|
+
if (startupPlanGoalText && !startupPlanMarkdown.includes(startupPlanGoalText)) {
|
|
514
|
+
fail('.agent/startup-plan.md must render the startup-plan goal_text');
|
|
515
|
+
}
|
|
516
|
+
|
|
452
517
|
if (asString(evidence.artifact_type) !== 'completion-verification-evidence') {
|
|
453
518
|
fail('.agent/verification-evidence.json artifact_type must be completion-verification-evidence');
|
|
454
519
|
}
|
|
@@ -595,7 +660,12 @@ export type ScaffoldResult = {
|
|
|
595
660
|
export async function scaffoldCompletionFiles(
|
|
596
661
|
root: string,
|
|
597
662
|
missionAnchor: string,
|
|
598
|
-
options?: {
|
|
663
|
+
options?: {
|
|
664
|
+
analysis?: { taskType?: string; evaluationProfile?: string };
|
|
665
|
+
continuationReason?: string;
|
|
666
|
+
advisoryStartupBrief?: JsonRecord;
|
|
667
|
+
approvedStartupPlan?: JsonRecord;
|
|
668
|
+
},
|
|
599
669
|
): Promise<ScaffoldResult> {
|
|
600
670
|
const files = resolveFiles(root);
|
|
601
671
|
const created: string[] = [];
|
|
@@ -605,6 +675,10 @@ export async function scaffoldCompletionFiles(
|
|
|
605
675
|
const projectName = path.basename(root);
|
|
606
676
|
const docsSurfaces = await detectDocsSurfaces(root);
|
|
607
677
|
const verifierCommand = await detectVerifierCommand(root);
|
|
678
|
+
const startupPlanRecord =
|
|
679
|
+
options?.approvedStartupPlan ??
|
|
680
|
+
(await readJson(files.startupPlanPath)) ??
|
|
681
|
+
defaultStartupPlan(missionAnchor, { taskType: options?.analysis?.taskType, evaluationProfile: options?.analysis?.evaluationProfile });
|
|
608
682
|
const trackedFiles: Array<{ path: string; content: string; executable?: boolean }> = [
|
|
609
683
|
{ path: path.join(files.agentDir, "README.md"), content: buildAgentReadme(projectName) },
|
|
610
684
|
{ path: path.join(files.agentDir, "mission.md"), content: buildMission(projectName, missionAnchor) },
|
|
@@ -618,6 +692,14 @@ export async function scaffoldCompletionFiles(
|
|
|
618
692
|
path: files.statePath,
|
|
619
693
|
content: `${JSON.stringify(defaultState(missionAnchor, { taskType: options?.analysis?.taskType, evaluationProfile: options?.analysis?.evaluationProfile, continuationReason: options?.continuationReason }, options?.advisoryStartupBrief), null, 2)}\n`,
|
|
620
694
|
},
|
|
695
|
+
{
|
|
696
|
+
path: files.startupPlanPath,
|
|
697
|
+
content: `${JSON.stringify(startupPlanRecord, null, 2)}\n`,
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
path: files.startupPlanMarkdownPath,
|
|
701
|
+
content: buildApprovedStartupPlanMarkdown(startupPlanRecord as any),
|
|
702
|
+
},
|
|
621
703
|
{ path: files.planPath, content: `${JSON.stringify(defaultPlan(missionAnchor, { taskType: options?.analysis?.taskType, evaluationProfile: options?.analysis?.evaluationProfile }), null, 2)}\n` },
|
|
622
704
|
{ path: files.activePath, content: `${JSON.stringify(defaultActiveSlice(missionAnchor, { taskType: options?.analysis?.taskType, evaluationProfile: options?.analysis?.evaluationProfile }), null, 2)}\n` },
|
|
623
705
|
{ path: files.verificationEvidencePath, content: `${JSON.stringify(defaultVerificationEvidence(), null, 2)}\n` },
|
|
@@ -639,6 +721,7 @@ export function currentTaskType(snapshot: CompletionStateSnapshot): string | und
|
|
|
639
721
|
return (
|
|
640
722
|
asString(snapshot.active?.task_type) ??
|
|
641
723
|
asString(snapshot.state?.task_type) ??
|
|
724
|
+
asString(snapshot.startupPlan?.task_type) ??
|
|
642
725
|
asString(snapshot.plan?.task_type) ??
|
|
643
726
|
asString(snapshot.profile?.task_type)
|
|
644
727
|
);
|
|
@@ -648,6 +731,7 @@ export function currentEvaluationProfile(snapshot: CompletionStateSnapshot): str
|
|
|
648
731
|
return (
|
|
649
732
|
asString(snapshot.active?.evaluation_profile) ??
|
|
650
733
|
asString(snapshot.state?.evaluation_profile) ??
|
|
734
|
+
asString(snapshot.startupPlan?.evaluation_profile) ??
|
|
651
735
|
asString(snapshot.plan?.evaluation_profile) ??
|
|
652
736
|
asString(snapshot.profile?.evaluation_profile)
|
|
653
737
|
);
|
|
@@ -656,6 +740,7 @@ export function currentEvaluationProfile(snapshot: CompletionStateSnapshot): str
|
|
|
656
740
|
export function currentMissionAnchor(snapshot: CompletionStateSnapshot): string {
|
|
657
741
|
return (
|
|
658
742
|
asString(snapshot.state?.mission_anchor) ??
|
|
743
|
+
asString(snapshot.startupPlan?.mission_anchor) ??
|
|
659
744
|
asString(snapshot.plan?.mission_anchor) ??
|
|
660
745
|
asString(snapshot.active?.mission_anchor) ??
|
|
661
746
|
path.basename(snapshot.files.root)
|
|
@@ -18,6 +18,8 @@ export type CompletionFiles = {
|
|
|
18
18
|
statePath: string;
|
|
19
19
|
planPath: string;
|
|
20
20
|
activePath: string;
|
|
21
|
+
startupPlanPath: string;
|
|
22
|
+
startupPlanMarkdownPath: string;
|
|
21
23
|
sliceHistoryPath: string;
|
|
22
24
|
stopHistoryPath: string;
|
|
23
25
|
verificationEvidencePath: string;
|
|
@@ -30,6 +32,7 @@ export type CompletionStateSnapshot = {
|
|
|
30
32
|
state?: JsonRecord;
|
|
31
33
|
plan?: JsonRecord;
|
|
32
34
|
active?: JsonRecord;
|
|
35
|
+
startupPlan?: JsonRecord;
|
|
33
36
|
verificationEvidence?: JsonRecord;
|
|
34
37
|
activeSlice?: JsonRecord;
|
|
35
38
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linimin/pi-letscook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.67",
|
|
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,
|
|
@@ -157,7 +157,7 @@ capsule = {
|
|
|
157
157
|
"Keep scripts/active-slice-contract-test.sh aligned with the packaged startup contract."
|
|
158
158
|
],
|
|
159
159
|
"risks": [
|
|
160
|
-
"Active-slice fixture bootstrap must stay anchored to the fresh explicit
|
|
160
|
+
"Active-slice fixture bootstrap must stay anchored to the fresh explicit startup-plan preview."
|
|
161
161
|
],
|
|
162
162
|
"notes": [
|
|
163
163
|
"This handoff exists only to scaffold canonical files before the fixture rewrites them for contract parity coverage."
|
|
@@ -134,11 +134,11 @@ assertIncludes('.agent/README.md', 'durable canonical record of deterministic ve
|
|
|
134
134
|
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Canonical Files', '- `.agent/verification-evidence.json`');
|
|
135
135
|
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Canonical Inputs', '- `.agent/verification-evidence.json`');
|
|
136
136
|
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Compaction And Recovery', '- `.agent/verification-evidence.json`');
|
|
137
|
-
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Compaction And Recovery', '`completion-implementer` must also re-read canonical `.agent/state.json`, `.agent/plan.json`, `.agent/active-slice.json`, and `.agent/verification-evidence.json` before resuming work.');
|
|
137
|
+
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Compaction And Recovery', '`completion-implementer` must also re-read canonical `.agent/state.json`, `.agent/startup-plan.json`, `.agent/plan.json`, `.agent/active-slice.json`, and `.agent/verification-evidence.json` before resuming work.');
|
|
138
138
|
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Ignored Canonical Execution State', '- `.agent/verification-evidence.json`');
|
|
139
139
|
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Canonical Inputs', '- `.agent/verification-evidence.json`');
|
|
140
140
|
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Compaction And Recovery', '- `.agent/verification-evidence.json`');
|
|
141
|
-
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Compaction And Recovery', '`completion-implementer` must also re-read canonical `.agent/state.json`, `.agent/plan.json`, `.agent/active-slice.json`, and `.agent/verification-evidence.json` before resuming work.');
|
|
141
|
+
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Compaction And Recovery', '`completion-implementer` must also re-read canonical `.agent/state.json`, `.agent/startup-plan.json`, `.agent/plan.json`, `.agent/active-slice.json`, and `.agent/verification-evidence.json` before resuming work.');
|
|
142
142
|
assertIncludes('extensions/completion/prompt-surfaces.ts', 'Verification evidence artifact: ${args.evidence.path} (${args.evidence.status})');
|
|
143
143
|
assertIncludes('extensions/completion/prompt-surfaces.ts', 'Verification evidence summary: ${args.evidence.summary}');
|
|
144
144
|
assertIncludes('extensions/completion/index.ts', 'Canonical verification evidence artifact is currently: ${evidence.path} (${evidence.status})');
|
|
@@ -202,7 +202,7 @@ capsule = {
|
|
|
202
202
|
"Keep scripts/canonical-evidence-artifact-test.sh aligned with packaged bootstrap behavior."
|
|
203
203
|
],
|
|
204
204
|
"risks": [
|
|
205
|
-
"Evidence-artifact bootstrap must stay anchored to the fresh explicit
|
|
205
|
+
"Evidence-artifact bootstrap must stay anchored to the fresh explicit startup-plan preview."
|
|
206
206
|
],
|
|
207
207
|
"notes": [
|
|
208
208
|
"This fixture exists only to scaffold canonical files before rewriting them for evidence parity coverage."
|
|
@@ -242,7 +242,7 @@ PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
|
242
242
|
pi --session "$BOOTSTRAP_SESSION" -e "$PKG_ROOT" -p "/cook" \
|
|
243
243
|
>"$TMPDIR/pi-canonical-evidence-bootstrap.out" 2>"$TMPDIR/pi-canonical-evidence-bootstrap.err"
|
|
244
244
|
|
|
245
|
-
for file in .agent/profile.json .agent/state.json .agent/plan.json .agent/active-slice.json .agent/verification-evidence.json; do
|
|
245
|
+
for file in .agent/profile.json .agent/state.json .agent/startup-plan.json .agent/startup-plan.md .agent/plan.json .agent/active-slice.json .agent/verification-evidence.json; do
|
|
246
246
|
[[ -f "$file" ]] || { echo "missing canonical bootstrap file: $file" >&2; exit 1; }
|
|
247
247
|
done
|
|
248
248
|
|
|
@@ -288,6 +288,36 @@ acceptance = [
|
|
|
288
288
|
'Canonical verification evidence is recorded for the selected slice.',
|
|
289
289
|
'Fail-closed verification rejects missing or stale evidence.',
|
|
290
290
|
]
|
|
291
|
+
startup_plan = {
|
|
292
|
+
'schema_version': 1,
|
|
293
|
+
'artifact_type': 'completion-startup-plan',
|
|
294
|
+
'status': 'approved',
|
|
295
|
+
'source': 'primary_agent_handoff',
|
|
296
|
+
'captured_at': '2026-05-03T00:00:00Z',
|
|
297
|
+
'mission_anchor': mission,
|
|
298
|
+
'goal_text': 'Mission: Exercise canonical verification evidence parity.\n\nScope:\n- Persist canonical verification evidence for the selected slice.\n- Keep the verifier fail-closed on stale or missing evidence.\n\nAcceptance:\n- Canonical verification evidence is recorded for the selected slice.\n- Fail-closed verification rejects missing or stale evidence.',
|
|
299
|
+
'task_type': task_type,
|
|
300
|
+
'evaluation_profile': evaluation_profile,
|
|
301
|
+
'scope': [
|
|
302
|
+
'Persist canonical verification evidence for the selected slice.',
|
|
303
|
+
'Keep the verifier fail-closed on stale or missing evidence.',
|
|
304
|
+
],
|
|
305
|
+
'constraints': [
|
|
306
|
+
'Keep the fixture scoped to canonical verification evidence parity.',
|
|
307
|
+
],
|
|
308
|
+
'acceptance': acceptance,
|
|
309
|
+
'risks': [
|
|
310
|
+
'Stale startup-plan parity could mask canonical evidence regressions.',
|
|
311
|
+
],
|
|
312
|
+
'notes': [
|
|
313
|
+
'Use startup-plan parity to prove the verifier reads the approved startup plan alongside other canonical state.',
|
|
314
|
+
],
|
|
315
|
+
'planned_surfaces': implementation_surfaces,
|
|
316
|
+
'verification_intent': verification_commands,
|
|
317
|
+
'sequencing_hints': [
|
|
318
|
+
'First slice goal: Persist canonical verification evidence for the selected slice.',
|
|
319
|
+
],
|
|
320
|
+
}
|
|
291
321
|
state = {
|
|
292
322
|
'schema_version': 1,
|
|
293
323
|
'mission_anchor': mission,
|
|
@@ -365,6 +395,21 @@ active = {
|
|
|
365
395
|
}
|
|
366
396
|
|
|
367
397
|
Path('.agent/state.json').write_text(json.dumps(state, indent=2) + '\n')
|
|
398
|
+
Path('.agent/startup-plan.json').write_text(json.dumps(startup_plan, indent=2) + '\n')
|
|
399
|
+
Path('.agent/startup-plan.md').write_text(
|
|
400
|
+
'# Approved Startup Plan\n\n'
|
|
401
|
+
f'Mission anchor: {mission}\n'
|
|
402
|
+
'Source: primary_agent_handoff\n'
|
|
403
|
+
'Captured at: 2026-05-03T00:00:00Z\n'
|
|
404
|
+
f'Task type: {task_type}\n'
|
|
405
|
+
f'Evaluation profile: {evaluation_profile}\n\n'
|
|
406
|
+
'## Goal\n\n'
|
|
407
|
+
f"{startup_plan['goal_text']}\n\n"
|
|
408
|
+
'## Planned surfaces\n\n'
|
|
409
|
+
+ ''.join(f'- {item}\n' for item in startup_plan['planned_surfaces'])
|
|
410
|
+
+ '\n## Verification intent\n\n'
|
|
411
|
+
+ ''.join(f'- {item}\n' for item in startup_plan['verification_intent'])
|
|
412
|
+
)
|
|
368
413
|
Path('.agent/plan.json').write_text(json.dumps(plan, indent=2) + '\n')
|
|
369
414
|
Path('.agent/active-slice.json').write_text(json.dumps(active, indent=2) + '\n')
|
|
370
415
|
PY
|