@linimin/pi-letscook 0.1.53 → 0.1.55
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 +12 -0
- package/README.md +17 -38
- package/extensions/completion/driver.ts +44 -110
- package/extensions/completion/index.ts +10 -74
- package/extensions/completion/prompt-surfaces.ts +53 -380
- package/extensions/completion/proposal.ts +5 -65
- package/extensions/completion/role-runner.ts +4 -311
- package/extensions/completion/state-store.ts +212 -5
- package/extensions/completion/transcription.ts +0 -8
- package/extensions/completion/types.ts +0 -114
- package/package.json +15 -4
- package/scripts/active-slice-contract-test.sh +61 -6
- package/scripts/context-proposal-test.sh +33 -29
- package/scripts/legacy-cleanup-test.sh +11 -0
- package/scripts/refocus-test.sh +10 -11
- package/scripts/release-check.sh +21 -29
- package/scripts/role-runner-contract-test.sh +1 -2
- package/scripts/rubric-contract-test.sh +0 -1
- package/scripts/smoke-test.sh +14 -10
- package/extensions/completion/input-routing.ts +0 -819
- package/scripts/cook-trigger-routing-test.sh +0 -1122
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
1
|
import * as fs from "node:fs";
|
|
3
2
|
import { promises as fsp } from "node:fs";
|
|
4
3
|
import * as os from "node:os";
|
|
@@ -14,7 +13,6 @@ import {
|
|
|
14
13
|
markQueuedDriverPromptInFlight,
|
|
15
14
|
registerCookCommand,
|
|
16
15
|
} from "./driver";
|
|
17
|
-
import { handleCookNaturalLanguageTrigger } from "./input-routing";
|
|
18
16
|
import {
|
|
19
17
|
assessMissionAnchor,
|
|
20
18
|
collectRecentDiscussionEntries,
|
|
@@ -42,7 +40,6 @@ import {
|
|
|
42
40
|
buildContextProposalContinuationReason as buildExtractedContextProposalContinuationReason,
|
|
43
41
|
buildEvaluationRoleContextLines as buildExtractedEvaluationRoleContextLines,
|
|
44
42
|
buildEvaluationRoleReminderText as buildExtractedEvaluationRoleReminderText,
|
|
45
|
-
buildNaturalLanguageHandoffMetadataLines,
|
|
46
43
|
buildResumeCapsule as buildExtractedResumeCapsule,
|
|
47
44
|
buildSystemReminder as buildExtractedSystemReminder,
|
|
48
45
|
maybeWriteContextProposalConfirmationSnapshot,
|
|
@@ -77,11 +74,9 @@ import {
|
|
|
77
74
|
readText,
|
|
78
75
|
scaffoldCompletionFiles as scaffoldCompletionFilesOnDisk,
|
|
79
76
|
} from "./state-store";
|
|
80
|
-
import { parseFirstNumber, parseYesNo } from "./transcription";
|
|
81
77
|
import type { TranscriptionResult } from "./transcription";
|
|
82
|
-
import type { CompletionStateSnapshot, CompletionRole,
|
|
78
|
+
import type { CompletionStateSnapshot, CompletionRole, JsonRecord, LiveRoleActivity } from "./types";
|
|
83
79
|
|
|
84
|
-
const PROTOCOL_ID = "completion";
|
|
85
80
|
const ROLE_NAMES = [
|
|
86
81
|
"completion-bootstrapper",
|
|
87
82
|
"completion-regrounder",
|
|
@@ -124,10 +119,6 @@ function candidateSlices(plan: JsonRecord | undefined): JsonRecord[] {
|
|
|
124
119
|
return Array.isArray(slices) ? slices.filter(isRecord) : [];
|
|
125
120
|
}
|
|
126
121
|
|
|
127
|
-
type ExistingWorkflowDecision =
|
|
128
|
-
| { action: "continue"; currentMissionAnchor: string }
|
|
129
|
-
| { action: "refocus"; currentMissionAnchor: string; missionAnchor: string };
|
|
130
|
-
|
|
131
122
|
type ActiveWorkflowProposalAssessment = {
|
|
132
123
|
action: "continue" | "refocus" | "unclear";
|
|
133
124
|
currentMissionAnchor: string;
|
|
@@ -135,13 +126,6 @@ type ActiveWorkflowProposalAssessment = {
|
|
|
135
126
|
reason: "matching_mission" | "clear_refocus" | "missing_proposal" | "ambiguous_discussion";
|
|
136
127
|
};
|
|
137
128
|
|
|
138
|
-
type ExistingWorkflowChooserOptions = {
|
|
139
|
-
intro?: string;
|
|
140
|
-
proposedMissionLabel?: string;
|
|
141
|
-
refocusChoiceLabel?: string;
|
|
142
|
-
comparison?: "semantic" | "strict";
|
|
143
|
-
};
|
|
144
|
-
|
|
145
129
|
function completionTestWorkflowActionOverride(): "continue" | "refocus" | "cancel" | undefined {
|
|
146
130
|
const raw = process.env.PI_COMPLETION_EXISTING_WORKFLOW_ACTION?.trim().toLowerCase();
|
|
147
131
|
return raw === "continue" || raw === "refocus" || raw === "cancel" ? raw : undefined;
|
|
@@ -208,26 +192,8 @@ function maybeWriteTestSnapshot(targetPath: string | undefined, content: string)
|
|
|
208
192
|
}
|
|
209
193
|
|
|
210
194
|
const COOK_MAIN_CHAT_RERUN_GUIDANCE = "Discuss changes in the main chat and rerun /cook.";
|
|
211
|
-
const COOK_BARE_ONLY_GUIDANCE =
|
|
212
|
-
"/cook remains the canonical workflow boundary. Natural-language routing can stay off or run in router mode to review each non-bypass user turn before implementation starts, but the shared /cook flow still owns mission selection and confirmation.";
|
|
213
195
|
const COOK_STRUCTURED_DISCUSSION_FAILURE_DETAIL =
|
|
214
|
-
"/cook failed closed because recent discussion did not produce a clear execution-ready Mission/Scope/Constraints/Acceptance
|
|
215
|
-
|
|
216
|
-
function buildCookCancellationMessage(prefix: string): string {
|
|
217
|
-
return `${prefix}. ${COOK_MAIN_CHAT_RERUN_GUIDANCE}`;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function buildCookStructuredDiscussionFailureMessage(prefix?: string): string {
|
|
221
|
-
return prefix ? `${prefix} ${COOK_STRUCTURED_DISCUSSION_FAILURE_DETAIL}` : COOK_STRUCTURED_DISCUSSION_FAILURE_DETAIL;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function shouldDisableContextProposalAnalyst(): boolean {
|
|
225
|
-
return process.env.PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST === "1";
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function completionTestContextProposalAnalystOutput(): string | undefined {
|
|
229
|
-
return asString(process.env.PI_COMPLETION_CONTEXT_PROPOSAL_ANALYST_OUTPUT);
|
|
230
|
-
}
|
|
196
|
+
"/cook failed closed because recent discussion did not produce a clear execution-ready startup brief with Mission/Scope/Constraints/Acceptance for concrete repo changes. Clarify the concrete repo changes in the main chat and rerun /cook.";
|
|
231
197
|
|
|
232
198
|
function isWorkflowDone(snapshot: CompletionStateSnapshot | undefined): boolean {
|
|
233
199
|
return asString(snapshot?.state?.continuation_policy) === "done";
|
|
@@ -379,7 +345,6 @@ async function promptContextProposalConfirmationAction(
|
|
|
379
345
|
async function deriveCookContextProposal(
|
|
380
346
|
ctx: { cwd: string; hasUI: boolean; ui: any; sessionManager: any; model?: any; modelRegistry?: any },
|
|
381
347
|
projectName: string,
|
|
382
|
-
hintText?: string,
|
|
383
348
|
): Promise<ContextProposal | undefined> {
|
|
384
349
|
const recentEntries = collectRecentDiscussionEntries(ctx, { isRecord, asString, isStaleContextError });
|
|
385
350
|
const snapshot = await loadCompletionSnapshot(getCtxCwd(ctx));
|
|
@@ -395,11 +360,9 @@ async function deriveCookContextProposal(
|
|
|
395
360
|
`verification summary: ${asString(snapshot.verificationEvidence?.summary) ?? "(none)"}`,
|
|
396
361
|
]
|
|
397
362
|
: [];
|
|
398
|
-
if (hintText) workflowContextLines.push(`cook hint: ${hintText}`);
|
|
399
363
|
return await deriveCookContextProposalFromRecentDiscussion(projectName, recentEntries, {
|
|
400
364
|
asString,
|
|
401
365
|
asStringArray,
|
|
402
|
-
hintText,
|
|
403
366
|
workflowContext: snapshot
|
|
404
367
|
? {
|
|
405
368
|
currentMissionAnchor:
|
|
@@ -413,15 +376,12 @@ async function deriveCookContextProposal(
|
|
|
413
376
|
continuationPolicy: asString(snapshot.state?.continuation_policy),
|
|
414
377
|
}
|
|
415
378
|
: undefined,
|
|
416
|
-
analyzeContextProposal: async (entries
|
|
379
|
+
analyzeContextProposal: async (entries) =>
|
|
417
380
|
await analyzeContextProposalWithAgent({
|
|
418
381
|
ctx,
|
|
419
382
|
projectName,
|
|
420
383
|
recentEntries: entries,
|
|
421
|
-
workflowContextLines
|
|
422
|
-
derivedHintText && !workflowContextLines.includes(`cook hint: ${derivedHintText}`)
|
|
423
|
-
? [...workflowContextLines, `cook hint: ${derivedHintText}`]
|
|
424
|
-
: workflowContextLines,
|
|
384
|
+
workflowContextLines,
|
|
425
385
|
liveRoleActivityByRoot,
|
|
426
386
|
completionStatusKey: COMPLETION_STATUS_KEY,
|
|
427
387
|
safeUiCall,
|
|
@@ -471,12 +431,13 @@ async function confirmContextProposal(
|
|
|
471
431
|
async function scaffoldCompletionFiles(
|
|
472
432
|
root: string,
|
|
473
433
|
missionAnchor: string,
|
|
474
|
-
options?: { analysis?: ContextProposalAnalysis; continuationReason?: string },
|
|
434
|
+
options?: { analysis?: ContextProposalAnalysis; continuationReason?: string; advisoryStartupBrief?: JsonRecord },
|
|
475
435
|
) {
|
|
476
436
|
const routing = finalizeContextProposalAnalysis(options?.analysis, [missionAnchor]);
|
|
477
437
|
return await scaffoldCompletionFilesOnDisk(root, missionAnchor, {
|
|
478
438
|
analysis: { taskType: routing.taskType, evaluationProfile: routing.evaluationProfile },
|
|
479
439
|
continuationReason: options?.continuationReason,
|
|
440
|
+
advisoryStartupBrief: options?.advisoryStartupBrief,
|
|
480
441
|
});
|
|
481
442
|
}
|
|
482
443
|
|
|
@@ -876,45 +837,24 @@ function composeResumeCapsule(snapshot: CompletionStateSnapshot, sliceHistory: J
|
|
|
876
837
|
});
|
|
877
838
|
}
|
|
878
839
|
|
|
879
|
-
async function gitHeadSha(cwd: string): Promise<string | undefined> {
|
|
880
|
-
return await new Promise((resolve) => {
|
|
881
|
-
const proc = spawn("git", ["rev-parse", "HEAD"], { cwd, stdio: ["ignore", "pipe", "ignore"] });
|
|
882
|
-
let stdout = "";
|
|
883
|
-
proc.stdout.on("data", (chunk) => {
|
|
884
|
-
stdout += chunk.toString();
|
|
885
|
-
});
|
|
886
|
-
proc.on("close", (code) => {
|
|
887
|
-
resolve(code === 0 ? asString(stdout) : undefined);
|
|
888
|
-
});
|
|
889
|
-
proc.on("error", () => resolve(undefined));
|
|
890
|
-
});
|
|
891
|
-
}
|
|
892
|
-
|
|
893
840
|
function completionKickoff(
|
|
894
841
|
goal: string,
|
|
895
842
|
taskType: string,
|
|
896
843
|
evaluationProfile: string,
|
|
897
844
|
intent: "auto" | "continue" | "refocus" = "auto",
|
|
898
845
|
missionAnchor?: string,
|
|
899
|
-
naturalLanguageHandoff?: CookNaturalLanguageHandoff,
|
|
900
846
|
): string {
|
|
901
|
-
const naturalLanguageHandoffBlock = buildNaturalLanguageHandoffMetadataLines(naturalLanguageHandoff).join("\n");
|
|
902
847
|
const intentBlock =
|
|
903
848
|
intent === "continue" && missionAnchor
|
|
904
849
|
? `Existing canonical mission anchor:\n${missionAnchor}\n\nWorkflow intent:\n- Continue the existing workflow.\n- Treat the new user text as supplemental direction unless canonical reconciliation proves the mission itself must change.\n\n`
|
|
905
850
|
: intent === "refocus" && missionAnchor
|
|
906
851
|
? `Updated canonical mission anchor:\n${missionAnchor}\n\nWorkflow intent:\n- The user explicitly refocused the workflow before this kickoff.\n- Re-read canonical .agent/** state and continue from the refocused mission.\n\n`
|
|
907
852
|
: "";
|
|
908
|
-
return `/skill:completion-protocol Start or continue the completion workflow for this repo.\n\nBefore acting, read:\n- ${SKILL_PATH}\n- ${REFERENCE_PATH}\n\nCanonical routing profile:\n- task_type: ${taskType}\n- evaluation_profile: ${evaluationProfile}\n\nUser goal:\n${goal}\n\n${
|
|
853
|
+
return `/skill:completion-protocol Start or continue the completion workflow for this repo.\n\nBefore acting, read:\n- ${SKILL_PATH}\n- ${REFERENCE_PATH}\n\nCanonical routing profile:\n- task_type: ${taskType}\n- evaluation_profile: ${evaluationProfile}\n\nUser goal:\n${goal}\n\n${intentBlock}Driver instructions:\n- Canonical truth is in .agent/**. Re-read .agent/state.json, .agent/plan.json, .agent/active-slice.json, and .agent/verification-evidence.json before acting when they exist.\n- If tracked completion contract files are missing or onboarding is required, invoke completion_role with role completion-bootstrapper.\n- Otherwise follow the mandatory dispatch rules from completion-protocol.\n- For selected, in-progress, committed, or done slices, treat .agent/active-slice.json as the canonical implementation contract and route to completion-regrounder if it drifts from the selected plan slice or the exact handoff is unclear.\n- Consume .agent/verification-evidence.json instead of temp-only verification summaries when it is populated.\n- Use completion_role for all completion-* role work. Do not directly implement tracked product changes yourself.\n- Continue dispatching mandatory roles while continuation_policy == continue.\n- Only stop for the user when continuation_policy is await_user_input, blocked, paused, or done.`;
|
|
909
854
|
}
|
|
910
855
|
|
|
911
|
-
function completionResumePrompt(
|
|
912
|
-
taskType:
|
|
913
|
-
evaluationProfile: string,
|
|
914
|
-
naturalLanguageHandoff?: CookNaturalLanguageHandoff,
|
|
915
|
-
): string {
|
|
916
|
-
const naturalLanguageHandoffBlock = buildNaturalLanguageHandoffMetadataLines(naturalLanguageHandoff).join("\n");
|
|
917
|
-
return `/skill:completion-protocol Resume the completion workflow from canonical state.\n\nBefore acting, read:\n- ${SKILL_PATH}\n- ${REFERENCE_PATH}\n\nCanonical routing profile:\n- task_type: ${taskType}\n- evaluation_profile: ${evaluationProfile}\n\n${naturalLanguageHandoffBlock}Resume instructions:\n- Re-read .agent/state.json, .agent/plan.json, .agent/active-slice.json, and .agent/verification-evidence.json before acting.\n- If canonical state is missing, invalid, contradictory, stale, or ambiguous, route to completion-regrounder first.\n- For selected, in-progress, committed, or done slices, treat .agent/active-slice.json as the canonical implementation contract and route to completion-regrounder if it drifts from the selected plan slice or the exact handoff is unclear.\n- Consume .agent/verification-evidence.json instead of temp-only verification summaries when it is populated.\n- Continue from next_mandatory_role and next_mandatory_action.\n- Use completion_role for all completion-* role work.\n- Continue dispatching mandatory roles while continuation_policy == continue.\n- Only stop for the user when continuation_policy is await_user_input, blocked, paused, or done.`;
|
|
856
|
+
function completionResumePrompt(taskType: string, evaluationProfile: string): string {
|
|
857
|
+
return `/skill:completion-protocol Resume the completion workflow from canonical state.\n\nBefore acting, read:\n- ${SKILL_PATH}\n- ${REFERENCE_PATH}\n\nCanonical routing profile:\n- task_type: ${taskType}\n- evaluation_profile: ${evaluationProfile}\n\nResume instructions:\n- Re-read .agent/state.json, .agent/plan.json, .agent/active-slice.json, and .agent/verification-evidence.json before acting.\n- If canonical state is missing, invalid, contradictory, stale, or ambiguous, route to completion-regrounder first.\n- For selected, in-progress, committed, or done slices, treat .agent/active-slice.json as the canonical implementation contract and route to completion-regrounder if it drifts from the selected plan slice or the exact handoff is unclear.\n- Consume .agent/verification-evidence.json instead of temp-only verification summaries when it is populated.\n- Continue from next_mandatory_role and next_mandatory_action.\n- Use completion_role for all completion-* role work.\n- Continue dispatching mandatory roles while continuation_policy == continue.\n- Only stop for the user when continuation_policy is await_user_input, blocked, paused, or done.`;
|
|
918
858
|
}
|
|
919
859
|
|
|
920
860
|
export default function completionExtension(pi: ExtensionAPI) {
|
|
@@ -927,11 +867,10 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
927
867
|
getCtxUi,
|
|
928
868
|
};
|
|
929
869
|
const driverDeps = {
|
|
930
|
-
bareOnlyGuidance: COOK_BARE_ONLY_GUIDANCE,
|
|
931
870
|
structuredDiscussionFailureDetail: COOK_STRUCTURED_DISCUSSION_FAILURE_DETAIL,
|
|
932
871
|
mainChatRerunGuidance: COOK_MAIN_CHAT_RERUN_GUIDANCE,
|
|
933
872
|
cookCommandSpec: {
|
|
934
|
-
description: "/cook workflow: start, continue, refocus, or start the next round
|
|
873
|
+
description: "/cook workflow: derive a startup brief from recent discussion, then start, continue, refocus, or start the next round from the explicit /cook command",
|
|
935
874
|
},
|
|
936
875
|
buildContextProposalContinuationReason,
|
|
937
876
|
completionKickoff,
|
|
@@ -961,9 +900,6 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
961
900
|
shouldTreatBareActiveWorkflowProposalAsClearRefocus,
|
|
962
901
|
};
|
|
963
902
|
|
|
964
|
-
pi.on("input", async (event, ctx) => {
|
|
965
|
-
return await handleCookNaturalLanguageTrigger(pi, event, ctx, driverDeps);
|
|
966
|
-
});
|
|
967
903
|
|
|
968
904
|
pi.on("session_start", async (_event, ctx) => {
|
|
969
905
|
await refreshCompletionStatus({ ctx, ...statusSurfaceArgs });
|