@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.
@@ -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, CookNaturalLanguageHandoff, JsonRecord, LiveRoleActivity } from "./types";
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 proposal for concrete repo changes. Router mode only offers the same /cook flow, and router recovery only replays to normal chat when you explicitly choose Send as normal chat, so clarify the concrete repo changes in the main chat and rerun /cook.";
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, derivedHintText) =>
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${naturalLanguageHandoffBlock}${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.`;
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: string,
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; /cook stays canonical while natural-language routing can be off or router",
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 });