@linimin/pi-letscook 0.1.54 → 0.1.56
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 +3 -2
- package/README.md +15 -17
- package/extensions/completion/driver.ts +44 -110
- package/extensions/completion/index.ts +54 -89
- package/extensions/completion/prompt-surfaces.ts +65 -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 +15 -12
- package/scripts/role-runner-contract-test.sh +1 -2
- package/scripts/rubric-contract-test.sh +0 -1
- package/scripts/smoke-test.sh +24 -13
- package/skills/cook-handoff-boundary/SKILL.md +64 -0
- package/extensions/completion/input-routing.ts +0 -819
- package/scripts/cook-trigger-routing-test.sh +0 -1122
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
### Changed
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
7
|
+
- made `/cook` derive a confirmable startup brief from recent discussion before any canonical workflow rewrite, then preserve the confirmed brief in canonical state as advisory intake for later re-grounding
|
|
8
|
+
- removed inline `/cook` arguments from the shipped entry path again so explicit bare `/cook` is the only public command, and fail closed when recent discussion is insufficient or unreliable
|
|
9
|
+
- added a pre-`/cook` ordinary-chat handoff boundary so the primary agent is instructed to stop at `/cook` once a task has matured into completion-workflow scope instead of starting long-running implementation directly in ordinary chat
|
|
9
10
|
|
|
10
11
|
## 0.1.54
|
|
11
12
|
|
package/README.md
CHANGED
|
@@ -31,13 +31,12 @@ Then run `/reload` in Pi.
|
|
|
31
31
|
`pi install npm:@linimin/pi-letscook`
|
|
32
32
|
2. Run `/reload` in Pi.
|
|
33
33
|
3. In the main chat, describe the concrete repo change you want.
|
|
34
|
-
4. Run `/cook
|
|
35
|
-
5. Review the
|
|
34
|
+
4. Run `/cook`.
|
|
35
|
+
5. Review the startup brief and choose **Start** or **Cancel**.
|
|
36
36
|
6. Later, run `/cook` again to continue, refocus, or start the next round.
|
|
37
37
|
|
|
38
38
|
```text
|
|
39
39
|
/cook
|
|
40
|
-
/cook login redirect
|
|
41
40
|
```
|
|
42
41
|
|
|
43
42
|
## Common actions
|
|
@@ -45,28 +44,31 @@ Then run `/reload` in Pi.
|
|
|
45
44
|
| If you want to... | Do this |
|
|
46
45
|
|---|---|
|
|
47
46
|
| Start a long-running task | Discuss the concrete repo change in the main chat, then run `/cook` |
|
|
48
|
-
| Bias mission detection toward one intent | Run `/cook <hint>` |
|
|
49
47
|
| Continue the current workflow | Run `/cook` |
|
|
50
48
|
| Refocus or start the next round | Discuss the new concrete repo change in the main chat, then run `/cook` |
|
|
51
49
|
|
|
52
50
|
## What `/cook` expects
|
|
53
51
|
|
|
54
52
|
- recent main-chat discussion about concrete repo changes
|
|
53
|
+
- enough detail to derive a startup brief with mission, scope, constraints or non-goals, acceptance, and notes or risks
|
|
55
54
|
- README/CHANGELOG updates still count as concrete repo changes
|
|
56
55
|
- assistant-produced summaries and plan/spec/design-doc/proposal-only artifacts do not
|
|
57
56
|
|
|
58
|
-
`/cook <hint>` acts as a high-priority intent hint for interpreting recent discussion, but it does not bypass fail-closed behavior or the approval-only Start/Cancel confirmation flow.
|
|
59
|
-
|
|
60
57
|
If recent discussion is missing, weak, ambiguous, assistant-produced, or only describes planning artifacts instead of concrete repo changes, `/cook` fails closed, leaves canonical `.agent/**` state unchanged, and tells you to clarify the mission in the main chat before rerunning `/cook`.
|
|
61
58
|
|
|
59
|
+
If you pass inline arguments to `/cook`, it also fails closed and tells you to move that intent into the main chat before rerunning bare `/cook`.
|
|
60
|
+
|
|
62
61
|
## Workflow entry
|
|
63
62
|
|
|
64
|
-
Only explicit `/cook`
|
|
63
|
+
Only explicit `/cook` enters the workflow. Ordinary prompts stay in the main chat and go straight to the primary agent.
|
|
64
|
+
|
|
65
|
+
If a task has clearly matured into completion-workflow scope, the primary agent should hand you off to `/cook` instead of starting long-running implementation directly in ordinary chat.
|
|
65
66
|
|
|
66
67
|
Important behavior:
|
|
67
68
|
- `/cook` is the canonical workflow boundary and manual entry point
|
|
68
69
|
- startup, refocus, and next-round routing stay confirm-first; nothing silently starts a workflow
|
|
69
70
|
- explicit slash commands other than `/cook` continue normally in the main chat
|
|
71
|
+
- ordinary main-chat discussion may clarify or propose, but mature long-running implementation should be handed off to `/cook`
|
|
70
72
|
|
|
71
73
|
## Typical examples
|
|
72
74
|
|
|
@@ -77,21 +79,15 @@ I want to add login redirect handling and tests.
|
|
|
77
79
|
/cook
|
|
78
80
|
```
|
|
79
81
|
|
|
80
|
-
Bias proposal derivation toward a specific intent:
|
|
81
|
-
|
|
82
|
-
```text
|
|
83
|
-
/cook login redirect
|
|
84
|
-
```
|
|
85
|
-
|
|
86
82
|
## What happens when you run `/cook`
|
|
87
83
|
|
|
88
|
-
`/cook`
|
|
84
|
+
`/cook` first derives a startup brief from recent discussion, then shows the existing approval-only Start/Cancel gate.
|
|
89
85
|
|
|
90
86
|
| Repo state | What you'll see |
|
|
91
87
|
|---|---|
|
|
92
|
-
| No workflow yet | A startup
|
|
93
|
-
| Active workflow exists | Usually a resume of the current workflow. If recent discussion clearly points to a different concrete repo change, `/cook` shows a chooser first and only rewrites canonical state after
|
|
94
|
-
| Previous workflow is `done` | A next-round
|
|
88
|
+
| No workflow yet | A startup brief built from recent main-chat discussion. You choose **Start** or **Cancel**. Weak, unreliable, or planning-only discussion fails closed. |
|
|
89
|
+
| Active workflow exists | Usually a resume of the current workflow. If recent discussion clearly points to a different concrete repo change, `/cook` shows a chooser first and only rewrites canonical state after you confirm the new startup brief. Ambiguous discussion stays conservative. |
|
|
90
|
+
| Previous workflow is `done` | A next-round startup brief from recent main-chat discussion, again behind **Start** or **Cancel**. Discussion that only restates already-finished work fails closed. |
|
|
95
91
|
|
|
96
92
|
## Confirmation and fail-closed behavior
|
|
97
93
|
|
|
@@ -105,6 +101,8 @@ Bias proposal derivation toward a specific intent:
|
|
|
105
101
|
|
|
106
102
|
When you accept startup or refocus, `/cook` persists the chosen workflow state in canonical `.agent/**` files before the re-ground round begins.
|
|
107
103
|
|
|
104
|
+
The confirmed startup brief is also preserved there as advisory intake for later re-grounding. It does not replace `.agent/plan.json` or `.agent/active-slice.json`, which remain under regrounder authority.
|
|
105
|
+
|
|
108
106
|
## Observability
|
|
109
107
|
|
|
110
108
|
When canonical `.agent/**` state exists and no role is actively running, the extension shows a completion widget sourced from that state. The widget summarizes:
|
|
@@ -2,7 +2,11 @@ import { promises as fsp } from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
4
4
|
import {
|
|
5
|
+
buildMission,
|
|
5
6
|
buildProfileRecord,
|
|
7
|
+
currentEvaluationProfile,
|
|
8
|
+
currentMissionAnchor,
|
|
9
|
+
currentTaskType,
|
|
6
10
|
defaultActiveSlice,
|
|
7
11
|
defaultPlan,
|
|
8
12
|
defaultState,
|
|
@@ -12,7 +16,8 @@ import {
|
|
|
12
16
|
loadCompletionSnapshot,
|
|
13
17
|
writeJsonFile,
|
|
14
18
|
} from "./state-store";
|
|
15
|
-
import
|
|
19
|
+
import { buildAdvisoryStartupBrief } from "./prompt-surfaces";
|
|
20
|
+
import type { CompletionStateSnapshot } from "./types";
|
|
16
21
|
|
|
17
22
|
type ContextProposalAnalysis = {
|
|
18
23
|
taskType?: string;
|
|
@@ -82,7 +87,6 @@ type DriverContinuationTracker = {
|
|
|
82
87
|
};
|
|
83
88
|
|
|
84
89
|
export type CompletionDriverDeps = {
|
|
85
|
-
bareOnlyGuidance: string;
|
|
86
90
|
structuredDiscussionFailureDetail: string;
|
|
87
91
|
mainChatRerunGuidance: string;
|
|
88
92
|
cookCommandSpec: {
|
|
@@ -104,14 +108,9 @@ export type CompletionDriverDeps = {
|
|
|
104
108
|
evaluationProfile: string,
|
|
105
109
|
intent?: "auto" | "continue" | "refocus",
|
|
106
110
|
missionAnchor?: string,
|
|
107
|
-
naturalLanguageHandoff?: CookNaturalLanguageHandoff,
|
|
108
111
|
) => string;
|
|
109
|
-
completionResumePrompt: (
|
|
110
|
-
|
|
111
|
-
evaluationProfile: string,
|
|
112
|
-
naturalLanguageHandoff?: CookNaturalLanguageHandoff,
|
|
113
|
-
) => string;
|
|
114
|
-
deriveCookContextProposal: (ctx: DriverContext, projectName: string, hintText?: string) => Promise<ContextProposal | undefined>;
|
|
112
|
+
completionResumePrompt: (taskType: string, evaluationProfile: string) => string;
|
|
113
|
+
deriveCookContextProposal: (ctx: DriverContext, projectName: string) => Promise<ContextProposal | undefined>;
|
|
115
114
|
confirmContextProposal: (
|
|
116
115
|
ctx: { hasUI: boolean; ui: any },
|
|
117
116
|
proposal: ContextProposal,
|
|
@@ -122,7 +121,7 @@ export type CompletionDriverDeps = {
|
|
|
122
121
|
scaffoldCompletionFiles: (
|
|
123
122
|
root: string,
|
|
124
123
|
missionAnchor: string,
|
|
125
|
-
options?: { analysis?: ContextProposalAnalysis; continuationReason?: string },
|
|
124
|
+
options?: { analysis?: ContextProposalAnalysis; continuationReason?: string; advisoryStartupBrief?: Record<string, unknown> },
|
|
126
125
|
) => Promise<{ root: string; created: string[] }>;
|
|
127
126
|
maybeWriteActiveWorkflowRoutingSnapshot: (assessment: ActiveWorkflowProposalAssessment) => void;
|
|
128
127
|
missionAnchorsLikelyEquivalent: (left: string, right: string) => boolean;
|
|
@@ -168,33 +167,6 @@ function buildCookStructuredDiscussionFailureMessage(deps: CompletionDriverDeps,
|
|
|
168
167
|
return prefix ? `${prefix} ${deps.structuredDiscussionFailureDetail}` : deps.structuredDiscussionFailureDetail;
|
|
169
168
|
}
|
|
170
169
|
|
|
171
|
-
function currentMissionAnchor(snapshot: CompletionStateSnapshot): string {
|
|
172
|
-
return (
|
|
173
|
-
asString(snapshot.state?.mission_anchor) ??
|
|
174
|
-
asString(snapshot.plan?.mission_anchor) ??
|
|
175
|
-
asString(snapshot.active?.mission_anchor) ??
|
|
176
|
-
path.basename(snapshot.files.root)
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function currentTaskType(snapshot: CompletionStateSnapshot): string | undefined {
|
|
181
|
-
return (
|
|
182
|
-
asString(snapshot.active?.task_type) ??
|
|
183
|
-
asString(snapshot.state?.task_type) ??
|
|
184
|
-
asString(snapshot.plan?.task_type) ??
|
|
185
|
-
asString(snapshot.profile?.task_type)
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function currentEvaluationProfile(snapshot: CompletionStateSnapshot): string | undefined {
|
|
190
|
-
return (
|
|
191
|
-
asString(snapshot.active?.evaluation_profile) ??
|
|
192
|
-
asString(snapshot.state?.evaluation_profile) ??
|
|
193
|
-
asString(snapshot.plan?.evaluation_profile) ??
|
|
194
|
-
asString(snapshot.profile?.evaluation_profile)
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
170
|
export function completionContinuationFingerprint(snapshot: CompletionStateSnapshot): string | undefined {
|
|
199
171
|
if (asString(snapshot.state?.continuation_policy) !== "continue") return undefined;
|
|
200
172
|
const nextMandatoryRole = asString(snapshot.state?.next_mandatory_role);
|
|
@@ -330,11 +302,10 @@ async function assessActiveWorkflowProposalRouting(
|
|
|
330
302
|
ctx: DriverContext,
|
|
331
303
|
snapshot: CompletionStateSnapshot,
|
|
332
304
|
deps: CompletionDriverDeps,
|
|
333
|
-
hintText?: string,
|
|
334
305
|
): Promise<ActiveWorkflowProposalAssessment> {
|
|
335
306
|
const currentMission = currentMissionAnchor(snapshot);
|
|
336
307
|
const projectName = path.basename(snapshot.files.root);
|
|
337
|
-
const proposal = await deps.deriveCookContextProposal(ctx, projectName
|
|
308
|
+
const proposal = await deps.deriveCookContextProposal(ctx, projectName);
|
|
338
309
|
if (!proposal) {
|
|
339
310
|
const assessment: ActiveWorkflowProposalAssessment = {
|
|
340
311
|
action: "unclear",
|
|
@@ -379,15 +350,10 @@ async function resumeActiveWorkflowFromCanonicalState(
|
|
|
379
350
|
ctx: { cwd: string; hasUI: boolean; ui: any },
|
|
380
351
|
snapshot: CompletionStateSnapshot,
|
|
381
352
|
deps: CompletionDriverDeps,
|
|
382
|
-
naturalLanguageHandoff?: CookNaturalLanguageHandoff,
|
|
383
353
|
): Promise<void> {
|
|
384
354
|
const mission = currentMissionAnchor(snapshot);
|
|
385
355
|
pi.setSessionName(`completion: ${mission.slice(0, 60)}`);
|
|
386
|
-
const resumePrompt = deps.completionResumePrompt(
|
|
387
|
-
currentTaskType(snapshot) ?? "(missing)",
|
|
388
|
-
currentEvaluationProfile(snapshot) ?? "(missing)",
|
|
389
|
-
naturalLanguageHandoff,
|
|
390
|
-
);
|
|
356
|
+
const resumePrompt = deps.completionResumePrompt(currentTaskType(snapshot) ?? "(missing)", currentEvaluationProfile(snapshot) ?? "(missing)");
|
|
391
357
|
const rootKey = deps.completionRootKey(snapshot, deps.getCtxCwd(ctx));
|
|
392
358
|
const fingerprint = completionContinuationFingerprint(snapshot) ?? JSON.stringify({
|
|
393
359
|
kind: "resume",
|
|
@@ -495,6 +461,7 @@ async function refocusCompletionMission(
|
|
|
495
461
|
rawGoal: string,
|
|
496
462
|
analysis: ContextProposalAnalysis | undefined,
|
|
497
463
|
deps: CompletionDriverDeps,
|
|
464
|
+
advisoryStartupBrief?: Record<string, unknown>,
|
|
498
465
|
): Promise<void> {
|
|
499
466
|
const requiredStopJudges = asNumber(snapshot.profile?.required_stop_judges) ?? 3;
|
|
500
467
|
const root = snapshot.files.root;
|
|
@@ -513,7 +480,7 @@ async function refocusCompletionMission(
|
|
|
513
480
|
taskType: routing.taskType,
|
|
514
481
|
evaluationProfile: routing.evaluationProfile,
|
|
515
482
|
continuationReason: deps.buildContextProposalContinuationReason("User refocused workflow via /cook:", rawGoal, routing),
|
|
516
|
-
}),
|
|
483
|
+
}, advisoryStartupBrief),
|
|
517
484
|
remaining_stop_judges: requiredStopJudges,
|
|
518
485
|
next_mandatory_action: "Reconcile canonical state from current repo truth for the refocused mission",
|
|
519
486
|
};
|
|
@@ -536,59 +503,11 @@ function isWorkflowDone(snapshot: CompletionStateSnapshot | undefined): boolean
|
|
|
536
503
|
return asString(snapshot?.state?.continuation_policy) === "done";
|
|
537
504
|
}
|
|
538
505
|
|
|
539
|
-
function buildMission(projectName: string, missionAnchor: string): string {
|
|
540
|
-
return `# Mission\n\nProject: ${projectName}\n\nMission anchor:\n${missionAnchor}\n\nThis file is a tracked human-readable statement of the repo's completion mission. Re-grounders may refine this file when repo truth becomes clearer, but it must stay truthful to shipped behavior and the active completion objective.\n`;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
export type CookInvocationOrigin = "command" | "natural-language-trigger";
|
|
544
|
-
|
|
545
|
-
export type RunCookEntryOptions = {
|
|
546
|
-
origin: CookInvocationOrigin;
|
|
547
|
-
hintText?: string;
|
|
548
|
-
originalInput?: string;
|
|
549
|
-
triggerText?: string;
|
|
550
|
-
preferredRoutingBias?: CookTriggerWorkflowBias;
|
|
551
|
-
clarificationCapsule?: CookNaturalLanguageHandoff["clarificationCapsule"];
|
|
552
|
-
adoptedArtifact?: CookNaturalLanguageHandoff["adoptedArtifact"];
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
function buildNaturalLanguageDerivationHint(handoff: CookNaturalLanguageHandoff | undefined): string | undefined {
|
|
556
|
-
if (!handoff) return undefined;
|
|
557
|
-
const lines: string[] = [];
|
|
558
|
-
if (handoff.hintText) lines.push(`Focus hint: ${handoff.hintText}`);
|
|
559
|
-
if (handoff.clarificationCapsule?.goal) lines.push(`Clarified goal: ${handoff.clarificationCapsule.goal}`);
|
|
560
|
-
if (handoff.clarificationCapsule?.scope?.length) lines.push(`Clarified scope: ${handoff.clarificationCapsule.scope.join(" | ")}`);
|
|
561
|
-
if (handoff.clarificationCapsule?.nonGoal?.length) lines.push(`Clarified non-goal: ${handoff.clarificationCapsule.nonGoal.join(" | ")}`);
|
|
562
|
-
if (handoff.clarificationCapsule?.doneWhen?.length) lines.push(`Clarified done-when: ${handoff.clarificationCapsule.doneWhen.join(" | ")}`);
|
|
563
|
-
if (handoff.clarificationCapsule?.selectedWorkflowBias) {
|
|
564
|
-
lines.push(`Clarified routing bias: ${handoff.clarificationCapsule.selectedWorkflowBias}`);
|
|
565
|
-
}
|
|
566
|
-
if (handoff.adoptedArtifact) {
|
|
567
|
-
lines.push(`User explicitly adopted artifact: ${handoff.adoptedArtifact.title}`);
|
|
568
|
-
if (handoff.adoptedArtifact.path) lines.push(`Adopted artifact path: ${handoff.adoptedArtifact.path}`);
|
|
569
|
-
if (handoff.adoptedArtifact.preview) lines.push(`Adopted artifact preview: ${handoff.adoptedArtifact.preview}`);
|
|
570
|
-
}
|
|
571
|
-
return lines.length > 0 ? lines.join("\n") : undefined;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
506
|
export async function runCookEntry(
|
|
575
507
|
pi: ExtensionAPI,
|
|
576
508
|
ctx: DriverContext,
|
|
577
509
|
deps: CompletionDriverDeps,
|
|
578
|
-
options: RunCookEntryOptions,
|
|
579
510
|
): Promise<void> {
|
|
580
|
-
const naturalLanguageHandoff =
|
|
581
|
-
options.origin === "natural-language-trigger"
|
|
582
|
-
? {
|
|
583
|
-
preferredRoutingBias: options.preferredRoutingBias,
|
|
584
|
-
triggerText: options.triggerText?.trim() ? options.triggerText.trim() : options.originalInput?.trim() ? options.originalInput.trim() : undefined,
|
|
585
|
-
hintText: options.hintText?.trim() ? options.hintText.trim() : undefined,
|
|
586
|
-
clarificationCapsule: options.clarificationCapsule,
|
|
587
|
-
adoptedArtifact: options.adoptedArtifact,
|
|
588
|
-
}
|
|
589
|
-
: undefined;
|
|
590
|
-
const derivationHint = buildNaturalLanguageDerivationHint(naturalLanguageHandoff);
|
|
591
|
-
const explicitHint = [options.hintText?.trim(), derivationHint].filter((value): value is string => Boolean(value)).join("\n\n") || undefined;
|
|
592
511
|
let goal: string | undefined;
|
|
593
512
|
const cwd = deps.getCtxCwd(ctx);
|
|
594
513
|
let snapshot = await loadCompletionSnapshot(cwd);
|
|
@@ -600,13 +519,13 @@ export async function runCookEntry(
|
|
|
600
519
|
if (!snapshot) {
|
|
601
520
|
const root = findRepoRoot(cwd) ?? cwd;
|
|
602
521
|
const projectName = path.basename(root);
|
|
603
|
-
const proposal = await deps.deriveCookContextProposal(ctx, projectName
|
|
522
|
+
const proposal = await deps.deriveCookContextProposal(ctx, projectName);
|
|
604
523
|
if (!proposal) {
|
|
605
524
|
deps.emitCommandText(ctx, buildCookStructuredDiscussionFailureMessage(deps), "info");
|
|
606
525
|
return;
|
|
607
526
|
}
|
|
608
527
|
const decision = await deps.confirmContextProposal(ctx, proposal, {
|
|
609
|
-
title: "Start a completion workflow from
|
|
528
|
+
title: "Start a completion workflow from this startup brief?",
|
|
610
529
|
});
|
|
611
530
|
if (!decision) {
|
|
612
531
|
deps.emitCommandText(ctx, buildCookCancellationMessage("Cancelled recent-discussion workflow proposal", deps), "info");
|
|
@@ -623,6 +542,7 @@ export async function runCookEntry(
|
|
|
623
542
|
goal ?? kickoffMissionAnchor ?? projectName,
|
|
624
543
|
startupRouting,
|
|
625
544
|
),
|
|
545
|
+
advisoryStartupBrief: buildAdvisoryStartupBrief({ proposal, analysis: decision.analysis }),
|
|
626
546
|
});
|
|
627
547
|
deps.emitCommandText(
|
|
628
548
|
ctx,
|
|
@@ -639,13 +559,13 @@ export async function runCookEntry(
|
|
|
639
559
|
if (!goal) {
|
|
640
560
|
if (workflowDone) {
|
|
641
561
|
const projectName = path.basename(snapshot.files.root);
|
|
642
|
-
const proposal = await deps.deriveCookContextProposal(ctx, projectName
|
|
562
|
+
const proposal = await deps.deriveCookContextProposal(ctx, projectName);
|
|
643
563
|
if (!proposal) {
|
|
644
564
|
deps.emitCommandText(ctx, buildCookStructuredDiscussionFailureMessage(deps, "The previous completion workflow is already done."), "info");
|
|
645
565
|
return;
|
|
646
566
|
}
|
|
647
567
|
const decision = await deps.confirmContextProposal(ctx, proposal, {
|
|
648
|
-
title: "The previous completion workflow is done. Start the next workflow round from
|
|
568
|
+
title: "The previous completion workflow is done. Start the next workflow round from this startup brief?",
|
|
649
569
|
});
|
|
650
570
|
if (!decision) {
|
|
651
571
|
deps.emitCommandText(ctx, buildCookCancellationMessage("Cancelled next workflow round proposal", deps), "info");
|
|
@@ -654,13 +574,20 @@ export async function runCookEntry(
|
|
|
654
574
|
goal = decision.goalText;
|
|
655
575
|
kickoffIntent = "refocus";
|
|
656
576
|
kickoffMissionAnchor = decision.missionAnchor;
|
|
657
|
-
await refocusCompletionMission(
|
|
577
|
+
await refocusCompletionMission(
|
|
578
|
+
snapshot,
|
|
579
|
+
decision.missionAnchor,
|
|
580
|
+
decision.goalText,
|
|
581
|
+
decision.analysis,
|
|
582
|
+
deps,
|
|
583
|
+
buildAdvisoryStartupBrief({ proposal, analysis: decision.analysis }),
|
|
584
|
+
);
|
|
658
585
|
snapshot = (await loadCompletionSnapshot(snapshot.files.root)) ?? snapshot;
|
|
659
586
|
deps.emitCommandText(ctx, `Started a new completion workflow round from recent discussion: ${decision.missionAnchor}`, "info");
|
|
660
587
|
} else {
|
|
661
|
-
const assessment = await assessActiveWorkflowProposalRouting(ctx, snapshot, deps
|
|
588
|
+
const assessment = await assessActiveWorkflowProposalRouting(ctx, snapshot, deps);
|
|
662
589
|
if (!assessment.proposal || assessment.action === "continue") {
|
|
663
|
-
await resumeActiveWorkflowFromCanonicalState(pi, ctx, snapshot, deps
|
|
590
|
+
await resumeActiveWorkflowFromCanonicalState(pi, ctx, snapshot, deps);
|
|
664
591
|
return;
|
|
665
592
|
}
|
|
666
593
|
const decision = await confirmExistingWorkflowProposal(ctx, snapshot, assessment.proposal, deps, {
|
|
@@ -678,15 +605,15 @@ export async function runCookEntry(
|
|
|
678
605
|
return;
|
|
679
606
|
}
|
|
680
607
|
if (decision.action === "continue") {
|
|
681
|
-
await resumeActiveWorkflowFromCanonicalState(pi, ctx, snapshot, deps
|
|
608
|
+
await resumeActiveWorkflowFromCanonicalState(pi, ctx, snapshot, deps);
|
|
682
609
|
return;
|
|
683
610
|
}
|
|
684
611
|
const selectedProposal = decision.proposal;
|
|
685
612
|
const proposalDecision = await deps.confirmContextProposal(ctx, selectedProposal, {
|
|
686
613
|
title:
|
|
687
614
|
assessment.action === "refocus"
|
|
688
|
-
? "Start the replacement workflow from
|
|
689
|
-
: "Start the latest inferred workflow from
|
|
615
|
+
? "Start the replacement workflow from this startup brief?"
|
|
616
|
+
: "Start the latest inferred workflow from this startup brief?",
|
|
690
617
|
});
|
|
691
618
|
if (!proposalDecision) {
|
|
692
619
|
deps.emitCommandText(ctx, buildCookCancellationMessage("Cancelled replacement workflow proposal", deps), "info");
|
|
@@ -695,7 +622,14 @@ export async function runCookEntry(
|
|
|
695
622
|
goal = proposalDecision.goalText;
|
|
696
623
|
kickoffIntent = "refocus";
|
|
697
624
|
kickoffMissionAnchor = proposalDecision.missionAnchor;
|
|
698
|
-
await refocusCompletionMission(
|
|
625
|
+
await refocusCompletionMission(
|
|
626
|
+
snapshot,
|
|
627
|
+
proposalDecision.missionAnchor,
|
|
628
|
+
proposalDecision.goalText,
|
|
629
|
+
proposalDecision.analysis,
|
|
630
|
+
deps,
|
|
631
|
+
buildAdvisoryStartupBrief({ proposal: selectedProposal, analysis: proposalDecision.analysis }),
|
|
632
|
+
);
|
|
699
633
|
snapshot = (await loadCompletionSnapshot(snapshot.files.root)) ?? snapshot;
|
|
700
634
|
deps.emitCommandText(ctx, `Refocused completion mission from recent discussion to: ${proposalDecision.missionAnchor}`, "info");
|
|
701
635
|
}
|
|
@@ -709,7 +643,6 @@ export async function runCookEntry(
|
|
|
709
643
|
currentEvaluationProfile(snapshot) ?? "(missing)",
|
|
710
644
|
kickoffIntent,
|
|
711
645
|
kickoffMissionAnchor,
|
|
712
|
-
naturalLanguageHandoff,
|
|
713
646
|
);
|
|
714
647
|
const rootKey = deps.completionRootKey(snapshot, deps.getCtxCwd(ctx));
|
|
715
648
|
const fingerprint = completionContinuationFingerprint(snapshot) ?? JSON.stringify({
|
|
@@ -727,10 +660,11 @@ export function registerCookCommand(pi: ExtensionAPI, deps: CompletionDriverDeps
|
|
|
727
660
|
pi.registerCommand("cook", {
|
|
728
661
|
description: deps.cookCommandSpec.description,
|
|
729
662
|
handler: async (args, ctx) => {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
}
|
|
663
|
+
if (args.trim().length > 0) {
|
|
664
|
+
deps.emitCommandText(ctx, "/cook no longer accepts inline arguments. Discuss the concrete repo change in the main chat and rerun /cook.", "info");
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
await runCookEntry(pi, ctx, deps);
|
|
734
668
|
},
|
|
735
669
|
});
|
|
736
670
|
}
|