@linimin/pi-letscook 0.1.55 → 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 +1 -0
- package/README.md +3 -0
- package/extensions/completion/index.ts +44 -19
- package/extensions/completion/prompt-surfaces.ts +12 -0
- package/package.json +1 -1
- package/scripts/release-check.sh +6 -3
- package/scripts/smoke-test.sh +10 -3
- package/skills/cook-handoff-boundary/SKILL.md +64 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
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
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
|
@@ -62,10 +62,13 @@ If you pass inline arguments to `/cook`, it also fails closed and tells you to m
|
|
|
62
62
|
|
|
63
63
|
Only explicit `/cook` enters the workflow. Ordinary prompts stay in the main chat and go straight to the primary agent.
|
|
64
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.
|
|
66
|
+
|
|
65
67
|
Important behavior:
|
|
66
68
|
- `/cook` is the canonical workflow boundary and manual entry point
|
|
67
69
|
- startup, refocus, and next-round routing stay confirm-first; nothing silently starts a workflow
|
|
68
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`
|
|
69
72
|
|
|
70
73
|
## Typical examples
|
|
71
74
|
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
buildContextProposalConfirmationLayout as buildExtractedContextProposalConfirmationLayout,
|
|
39
39
|
buildContextProposalConfirmationSelectItems,
|
|
40
40
|
buildContextProposalContinuationReason as buildExtractedContextProposalContinuationReason,
|
|
41
|
+
buildCookHandoffBoundaryReminder as buildExtractedCookHandoffBoundaryReminder,
|
|
41
42
|
buildEvaluationRoleContextLines as buildExtractedEvaluationRoleContextLines,
|
|
42
43
|
buildEvaluationRoleReminderText as buildExtractedEvaluationRoleReminderText,
|
|
43
44
|
buildResumeCapsule as buildExtractedResumeCapsule,
|
|
@@ -181,6 +182,10 @@ function completionTestSystemReminderPath(): string | undefined {
|
|
|
181
182
|
return asString(process.env.PI_COMPLETION_TEST_SYSTEM_REMINDER_PATH);
|
|
182
183
|
}
|
|
183
184
|
|
|
185
|
+
function completionTestCookHandoffReminderPath(): string | undefined {
|
|
186
|
+
return asString(process.env.PI_COMPLETION_TEST_COOK_HANDOFF_REMINDER_PATH);
|
|
187
|
+
}
|
|
188
|
+
|
|
184
189
|
function maybeWriteTestSnapshot(targetPath: string | undefined, content: string): void {
|
|
185
190
|
if (!targetPath) return;
|
|
186
191
|
try {
|
|
@@ -225,6 +230,19 @@ function shouldInjectCompletionWorkflowContext(snapshot: CompletionStateSnapshot
|
|
|
225
230
|
return hasCompletionRoutingActivation(snapshot) && isCompletionDriverPromptTurn(ctx);
|
|
226
231
|
}
|
|
227
232
|
|
|
233
|
+
function shouldInjectCookHandoffBoundary(event: { prompt?: string }, ctx: { sessionManager?: any }): boolean {
|
|
234
|
+
if (roleFromEnv()) return false;
|
|
235
|
+
if (isCompletionDriverPromptTurn(ctx)) return false;
|
|
236
|
+
const prompt = typeof event.prompt === "string" ? event.prompt.trim() : "";
|
|
237
|
+
if (!prompt) return false;
|
|
238
|
+
if (prompt.startsWith("/")) return false;
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function buildCookHandoffBoundaryReminder(): string {
|
|
243
|
+
return buildExtractedCookHandoffBoundaryReminder();
|
|
244
|
+
}
|
|
245
|
+
|
|
228
246
|
function buildDoneWorkflowBoundaryReminder(snapshot: CompletionStateSnapshot): string {
|
|
229
247
|
const missionAnchor = asString(snapshot.state?.mission_anchor) ?? asString(snapshot.plan?.mission_anchor) ?? "(unknown)";
|
|
230
248
|
const continuationReason = asString(snapshot.state?.continuation_reason) ?? "(unknown)";
|
|
@@ -926,7 +944,7 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
926
944
|
}
|
|
927
945
|
});
|
|
928
946
|
|
|
929
|
-
pi.on("before_agent_start", async (
|
|
947
|
+
pi.on("before_agent_start", async (event, ctx) => {
|
|
930
948
|
const loaded = await loadCompletionDataForReminder(getCtxCwd(ctx));
|
|
931
949
|
const driverPromptTurn = isCompletionDriverPromptTurn(ctx);
|
|
932
950
|
if (loaded && driverPromptTurn) {
|
|
@@ -934,28 +952,35 @@ export default function completionExtension(pi: ExtensionAPI) {
|
|
|
934
952
|
const fingerprint = completionContinuationFingerprint(loaded.snapshot);
|
|
935
953
|
if (fingerprint) markQueuedDriverPromptInFlight(rootKey, fingerprint);
|
|
936
954
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
955
|
+
const systemPrompt = getSystemPromptSafe(ctx);
|
|
956
|
+
if (!systemPrompt) return;
|
|
957
|
+
if (loaded && shouldInjectCompletionWorkflowContext(loaded.snapshot, ctx)) {
|
|
958
|
+
const additions = isWorkflowDone(loaded.snapshot)
|
|
959
|
+
? [buildDoneWorkflowBoundaryReminder(loaded.snapshot)]
|
|
960
|
+
: [composeSystemReminder(loaded.snapshot, loaded.sliceHistory, loaded.stopHistory)];
|
|
961
|
+
if (!isWorkflowDone(loaded.snapshot)) {
|
|
962
|
+
const markerText = await readText(loaded.snapshot.files.compactionMarkerPath);
|
|
963
|
+
let marker: JsonRecord | undefined;
|
|
964
|
+
if (markerText) {
|
|
965
|
+
try {
|
|
966
|
+
const parsed = JSON.parse(markerText);
|
|
967
|
+
marker = isRecord(parsed) ? parsed : undefined;
|
|
968
|
+
} catch {
|
|
969
|
+
marker = undefined;
|
|
970
|
+
}
|
|
950
971
|
}
|
|
972
|
+
if (marker) additions.push(buildPostCompactionDriverInstructions(loaded.snapshot, marker));
|
|
951
973
|
}
|
|
952
|
-
|
|
974
|
+
maybeWriteTestSnapshot(completionTestSystemReminderPath(), additions.join("\n\n"));
|
|
975
|
+
return {
|
|
976
|
+
systemPrompt: `${systemPrompt}\n\n${additions.join("\n\n")}`,
|
|
977
|
+
};
|
|
953
978
|
}
|
|
954
|
-
|
|
955
|
-
const
|
|
956
|
-
|
|
979
|
+
if (!shouldInjectCookHandoffBoundary(event, ctx)) return;
|
|
980
|
+
const handoffReminder = buildCookHandoffBoundaryReminder();
|
|
981
|
+
maybeWriteTestSnapshot(completionTestCookHandoffReminderPath(), handoffReminder);
|
|
957
982
|
return {
|
|
958
|
-
systemPrompt: `${systemPrompt}\n\n${
|
|
983
|
+
systemPrompt: `${systemPrompt}\n\n${handoffReminder}`,
|
|
959
984
|
};
|
|
960
985
|
});
|
|
961
986
|
|
|
@@ -24,6 +24,18 @@ export type AdvisoryStartupBrief = {
|
|
|
24
24
|
evaluation_profile?: string;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
export function buildCookHandoffBoundaryReminder(): string {
|
|
28
|
+
return [
|
|
29
|
+
"You are still in ordinary main chat before any explicit /cook workflow entry.",
|
|
30
|
+
"Use ordinary chat to clarify requirements, discuss tradeoffs, and propose implementation approaches.",
|
|
31
|
+
"/cook is the only explicit entrypoint into long-running completion workflow.",
|
|
32
|
+
"When you judge that the task has matured into completion-workflow scope — for example the user has clearly shifted from exploration into implementation intent, you have just produced a concrete plan or proposal whose next step would naturally be implementation, or the task spans multiple files, steps, or verification surfaces — stop short of long-running implementation and tell the user to run /cook.",
|
|
33
|
+
"At that handoff point, do not begin long-running product implementation in ordinary chat, do not edit tracked product files for that workflow-level task, and do not act as though /cook had already been invoked.",
|
|
34
|
+
"When handing off, explain that /cook will derive a startup brief from recent discussion and ask for confirmation before workflow start.",
|
|
35
|
+
"If the task is still ordinary Q&A, lightweight brainstorming, or a tiny one-off fix, continue normally without forcing /cook.",
|
|
36
|
+
].join(" ");
|
|
37
|
+
}
|
|
38
|
+
|
|
27
39
|
export function buildContextProposalGoalText(proposal: {
|
|
28
40
|
mission: string;
|
|
29
41
|
scope: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linimin/pi-letscook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.56",
|
|
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,
|
package/scripts/release-check.sh
CHANGED
|
@@ -17,6 +17,7 @@ checks = {
|
|
|
17
17
|
"README.md": [
|
|
18
18
|
"`/cook` is the explicit workflow boundary for starting, continuing, refocusing, or beginning the next round of long-running repo work.",
|
|
19
19
|
"Only explicit `/cook` enters the workflow. Ordinary prompts stay in the main chat and go straight to the primary agent.",
|
|
20
|
+
"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.",
|
|
20
21
|
"`/cook` is the canonical workflow boundary and manual entry point",
|
|
21
22
|
"Discuss the concrete repo change in the main chat, then run `/cook`",
|
|
22
23
|
"The confirmed startup brief is also preserved there as advisory intake for later re-grounding.",
|
|
@@ -24,10 +25,12 @@ checks = {
|
|
|
24
25
|
"CHANGELOG.md": [
|
|
25
26
|
"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",
|
|
26
27
|
"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",
|
|
28
|
+
"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",
|
|
27
29
|
],
|
|
28
|
-
"extensions/completion/
|
|
29
|
-
'
|
|
30
|
-
'"
|
|
30
|
+
"extensions/completion/prompt-surfaces.ts": [
|
|
31
|
+
'"/cook is the only explicit entrypoint into long-running completion workflow."',
|
|
32
|
+
'"When you judge that the task has matured into completion-workflow scope',
|
|
33
|
+
'"If the task is still ordinary Q&A, lightweight brainstorming, or a tiny one-off fix, continue normally without forcing /cook."',
|
|
31
34
|
],
|
|
32
35
|
}
|
|
33
36
|
|
package/scripts/smoke-test.sh
CHANGED
|
@@ -51,6 +51,7 @@ ROOT="$TMPDIR/repo"
|
|
|
51
51
|
KICKOFF_PROMPT="$TMPDIR/kickoff-prompt.txt"
|
|
52
52
|
RESUME_PROMPT="$TMPDIR/resume-prompt.txt"
|
|
53
53
|
ORDINARY_SYSTEM_REMINDER="$TMPDIR/ordinary-system-reminder.txt"
|
|
54
|
+
ORDINARY_HANDOFF_REMINDER="$TMPDIR/ordinary-handoff-reminder.txt"
|
|
54
55
|
UNCLEAR_ROUTING_SNAPSHOT="$TMPDIR/active-unclear-routing.json"
|
|
55
56
|
UNCLEAR_CHOOSER_SNAPSHOT="$TMPDIR/unexpected-existing-workflow-chooser.json"
|
|
56
57
|
ORDINARY_AUTO_RESUME_PROMPT="$TMPDIR/ordinary-auto-resume-prompt.txt"
|
|
@@ -146,23 +147,29 @@ assert f'- task_type: {expected_task_type}' in kickoff, 'kickoff prompt missing
|
|
|
146
147
|
assert f'- evaluation_profile: {expected_eval_profile}' in kickoff, 'kickoff prompt missing canonical evaluation_profile'
|
|
147
148
|
PY
|
|
148
149
|
|
|
149
|
-
rm -f "$ORDINARY_SYSTEM_REMINDER" "$ORDINARY_AUTO_RESUME_PROMPT"
|
|
150
|
+
rm -f "$ORDINARY_SYSTEM_REMINDER" "$ORDINARY_HANDOFF_REMINDER" "$ORDINARY_AUTO_RESUME_PROMPT"
|
|
150
151
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
151
152
|
PI_COMPLETION_TEST_SYSTEM_REMINDER_PATH="$ORDINARY_SYSTEM_REMINDER" \
|
|
153
|
+
PI_COMPLETION_TEST_COOK_HANDOFF_REMINDER_PATH="$ORDINARY_HANDOFF_REMINDER" \
|
|
152
154
|
PI_COMPLETION_TEST_AUTO_CONTINUE_ON_SESSION_START=1 \
|
|
153
155
|
PI_COMPLETION_TEST_AUTO_CONTINUE_PROMPT_PATH="$ORDINARY_AUTO_RESUME_PROMPT" \
|
|
154
156
|
pi -e "$PKG_ROOT" -p "Summarize the repo briefly." \
|
|
155
157
|
>"$TMPDIR/pi-completion-smoke-ordinary.out" 2>"$TMPDIR/pi-completion-smoke-ordinary.err"
|
|
156
158
|
|
|
157
|
-
python3 - "$TMPDIR/pi-completion-smoke-ordinary.out" "$TMPDIR/pi-completion-smoke-ordinary.err" "$ORDINARY_SYSTEM_REMINDER" "$ORDINARY_AUTO_RESUME_PROMPT" <<'PY'
|
|
159
|
+
python3 - "$TMPDIR/pi-completion-smoke-ordinary.out" "$TMPDIR/pi-completion-smoke-ordinary.err" "$ORDINARY_SYSTEM_REMINDER" "$ORDINARY_HANDOFF_REMINDER" "$ORDINARY_AUTO_RESUME_PROMPT" <<'PY'
|
|
158
160
|
import sys
|
|
159
161
|
from pathlib import Path
|
|
160
162
|
|
|
161
163
|
output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
162
164
|
reminder = Path(sys.argv[3])
|
|
163
|
-
|
|
165
|
+
handoff = Path(sys.argv[4])
|
|
166
|
+
auto_resume = Path(sys.argv[5])
|
|
164
167
|
|
|
165
168
|
assert not reminder.exists(), 'ordinary non-/cook turn should not inject completion reminder solely from canonical state'
|
|
169
|
+
assert handoff.exists(), 'ordinary non-/cook turn should inject the /cook handoff boundary reminder'
|
|
170
|
+
handoff_text = handoff.read_text()
|
|
171
|
+
assert '/cook is the only explicit entrypoint into long-running completion workflow.' in handoff_text, 'ordinary handoff reminder should preserve the explicit /cook workflow boundary'
|
|
172
|
+
assert 'stop short of long-running implementation and tell the user to run /cook.' in handoff_text, 'ordinary handoff reminder should require primary-agent handoff before implementation'
|
|
166
173
|
assert not auto_resume.exists(), 'ordinary non-/cook turn should not queue auto-resume before /cook activation'
|
|
167
174
|
assert 'Skipped completion workflow auto-resume prompt (test mode)' not in output, 'ordinary non-/cook turn should not attempt auto-resume'
|
|
168
175
|
PY
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cook-handoff-boundary
|
|
3
|
+
description: Ordinary-chat boundary contract for deciding when a task has matured enough that the primary agent must stop short of long-running implementation and hand the user off to `/cook`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /cook Handoff Boundary
|
|
7
|
+
|
|
8
|
+
Load or summarize this contract when the primary agent is operating in ordinary main chat before the user has explicitly entered `/cook`.
|
|
9
|
+
|
|
10
|
+
This skill governs the boundary between:
|
|
11
|
+
|
|
12
|
+
- ordinary main-chat discussion, clarification, and proposal work
|
|
13
|
+
- explicit transition into long-running completion workflow through `/cook`
|
|
14
|
+
|
|
15
|
+
## Core Contract
|
|
16
|
+
|
|
17
|
+
- Ordinary chat may be used to clarify requirements, discuss tradeoffs, and propose implementation approaches.
|
|
18
|
+
- `/cook` is the only explicit entrypoint into long-running completion workflow.
|
|
19
|
+
- When the primary agent judges that a task has matured into completion-workflow scope, it must stop short of implementation and direct the user to `/cook`.
|
|
20
|
+
|
|
21
|
+
## When To Hand Off To `/cook`
|
|
22
|
+
|
|
23
|
+
The primary agent should consider `/cook` handoff appropriate when one or more of the following are true:
|
|
24
|
+
|
|
25
|
+
- the user has clearly shifted from exploration into implementation intent
|
|
26
|
+
- the agent has just produced a concrete plan or proposal whose natural next step would be implementation
|
|
27
|
+
- the task spans multiple files, steps, or verification surfaces
|
|
28
|
+
- the task needs resumability, review, audit, or canonical workflow state
|
|
29
|
+
- the task is better treated as a long-running repo mission than a one-off answer or tiny fix
|
|
30
|
+
|
|
31
|
+
## Required Handoff Behavior
|
|
32
|
+
|
|
33
|
+
When the task is judged ready for completion workflow, the primary agent must:
|
|
34
|
+
|
|
35
|
+
- stop before long-running implementation
|
|
36
|
+
- not edit tracked product files in ordinary chat for that workflow-level task
|
|
37
|
+
- tell the user to run `/cook`
|
|
38
|
+
- explain that `/cook` will derive a startup brief from recent discussion and ask for confirmation before workflow start
|
|
39
|
+
|
|
40
|
+
Suggested wording:
|
|
41
|
+
|
|
42
|
+
> This task is now mature enough for the `/cook` workflow. If you want me to start implementation, run `/cook`. I’ll use our recent discussion to generate a startup brief for confirmation before the workflow begins.
|
|
43
|
+
|
|
44
|
+
A short recap may include mission, scope, or acceptance, but that recap must not be presented as canonical plan state.
|
|
45
|
+
|
|
46
|
+
## Forbidden Behaviors
|
|
47
|
+
|
|
48
|
+
Once the task is judged ready for completion workflow, the primary agent must not:
|
|
49
|
+
|
|
50
|
+
- directly begin long-running implementation in ordinary chat
|
|
51
|
+
- modify tracked product files as part of that workflow-level task
|
|
52
|
+
- act as though `/cook` had already been invoked
|
|
53
|
+
- silently rewrite ordinary-chat discussion into active workflow state
|
|
54
|
+
|
|
55
|
+
## Relationship To `completion-protocol`
|
|
56
|
+
|
|
57
|
+
This skill is only about pre-`/cook` ordinary-chat handoff behavior.
|
|
58
|
+
|
|
59
|
+
After the user explicitly enters `/cook`, the separate `completion-protocol` skill governs:
|
|
60
|
+
|
|
61
|
+
- canonical `.agent/**` workflow state
|
|
62
|
+
- workflow-driver behavior
|
|
63
|
+
- mandatory completion-role dispatch
|
|
64
|
+
- review, audit, and stop-wave rules
|