@linimin/pi-letscook 0.1.62 → 0.1.64
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/README.md +18 -18
- package/extensions/completion/driver.ts +27 -46
- package/extensions/completion/index.ts +51 -69
- package/extensions/completion/prompt-surfaces.ts +2 -1
- package/extensions/completion/role-runner.ts +105 -0
- package/package.json +1 -1
- package/scripts/context-proposal-test.sh +141 -42
- package/scripts/refocus-test.sh +81 -4
- package/scripts/release-check.sh +15 -20
- package/scripts/smoke-test.sh +3 -3
- package/skills/cook-handoff-boundary/SKILL.md +22 -22
|
@@ -147,17 +147,54 @@ mkdir -p "$ROOT"
|
|
|
147
147
|
cd "$ROOT"
|
|
148
148
|
git init -q
|
|
149
149
|
|
|
150
|
-
# No workflow yet: bare /cook should
|
|
151
|
-
#
|
|
150
|
+
# No workflow yet: bare /cook should be able to generate a primary-agent handoff in the same entry,
|
|
151
|
+
# then continue directly to startup confirmation.
|
|
152
152
|
SESSION_ZERO="$TMPDIR/session-zero.jsonl"
|
|
153
|
-
DISCUSSION_ZERO=$'Mission: Remove the completion status line while keeping the completion widget
|
|
153
|
+
DISCUSSION_ZERO=$'Mission: Remove the completion status line while keeping the completion widget.
|
|
154
|
+
Scope:
|
|
155
|
+
- Keep the non-running completion widget.
|
|
156
|
+
- Suppress the widget while a completion role is active.
|
|
157
|
+
Constraints:
|
|
158
|
+
- Do not reintroduce any other completion status surface.
|
|
159
|
+
Acceptance:
|
|
160
|
+
- Update README to match the shipped behavior.
|
|
161
|
+
- Keep observability regression coverage truthful.'
|
|
154
162
|
DISCUSSION_SNAPSHOT_ZERO="$TMPDIR/context-proposal-structured-fallback.json"
|
|
163
|
+
GENERATED_HANDOFF_ZERO="$(python3 - <<'PY'
|
|
164
|
+
import json
|
|
165
|
+
capsule = {
|
|
166
|
+
"kind": "cook_handoff",
|
|
167
|
+
"source": "primary_agent",
|
|
168
|
+
"mission": "Remove the completion status line while keeping the completion widget.",
|
|
169
|
+
"scope": [
|
|
170
|
+
"Keep the non-running completion widget.",
|
|
171
|
+
"Suppress the widget while a completion role is active."
|
|
172
|
+
],
|
|
173
|
+
"constraints": [
|
|
174
|
+
"Do not reintroduce any other completion status surface."
|
|
175
|
+
],
|
|
176
|
+
"acceptance": [
|
|
177
|
+
"Update README to match the shipped behavior.",
|
|
178
|
+
"Keep observability regression coverage truthful."
|
|
179
|
+
],
|
|
180
|
+
"risks": [],
|
|
181
|
+
"notes": ["Generated by the primary-agent handoff step triggered from /cook."],
|
|
182
|
+
"handoff_kind": "implementation_workflow_handoff",
|
|
183
|
+
"first_slice_goal": "Remove the completion status line while preserving the widget behavior.",
|
|
184
|
+
"first_slice_non_goals": ["Do not reintroduce another status surface."],
|
|
185
|
+
"implementation_surfaces": ["extensions/completion/index.ts", "README.md"],
|
|
186
|
+
"verification_commands": ["npm run smoke-test"],
|
|
187
|
+
"why_this_slice_first": "This slice is already concrete and bounded enough to start workflow safely.",
|
|
188
|
+
"task_type": "completion-workflow",
|
|
189
|
+
"evaluation_profile": "completion-rubric-v1",
|
|
190
|
+
"why_cook_now": "The user explicitly chose workflow mode for this bounded implementation slice."
|
|
191
|
+
}
|
|
192
|
+
print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
|
|
193
|
+
PY
|
|
194
|
+
)"
|
|
155
195
|
write_session "$SESSION_ZERO" "$ROOT" "$DISCUSSION_ZERO"
|
|
156
196
|
|
|
157
|
-
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept
|
|
158
|
-
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_ZERO" \
|
|
159
|
-
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
160
|
-
pi --session "$SESSION_ZERO" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-structured-fallback.out" 2>"$TMPDIR/pi-completion-context-proposal-structured-fallback.err"
|
|
197
|
+
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$GENERATED_HANDOFF_ZERO" PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_ZERO" PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 pi --session "$SESSION_ZERO" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-structured-fallback.out" 2>"$TMPDIR/pi-completion-context-proposal-structured-fallback.err"
|
|
161
198
|
|
|
162
199
|
python3 - "$TMPDIR/pi-completion-context-proposal-structured-fallback.out" "$TMPDIR/pi-completion-context-proposal-structured-fallback.err" "$DISCUSSION_SNAPSHOT_ZERO" <<'PY'
|
|
163
200
|
import json
|
|
@@ -166,13 +203,13 @@ from pathlib import Path
|
|
|
166
203
|
|
|
167
204
|
output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
168
205
|
snapshot = Path(sys.argv[3])
|
|
169
|
-
assert Path('.agent').exists(), '
|
|
170
|
-
assert snapshot.exists(), '
|
|
206
|
+
assert Path('.agent').exists(), 'primary-agent handoff generation should scaffold canonical state in the same /cook entry'
|
|
207
|
+
assert snapshot.exists(), 'primary-agent handoff generation should emit a startup proposal snapshot'
|
|
171
208
|
proposal = json.loads(snapshot.read_text())
|
|
172
209
|
brief = json.loads(Path('.agent/state.json').read_text())['advisory_startup_brief']
|
|
173
|
-
assert proposal['source'] == '
|
|
174
|
-
assert brief['source'] == '
|
|
175
|
-
assert 'Initialized completion control plane' in output, '
|
|
210
|
+
assert proposal['source'] == 'handoff_capsule', 'generated primary-agent handoff should be consumed as handoff capsule startup source'
|
|
211
|
+
assert brief['source'] == 'primary_agent_handoff', 'generated primary-agent handoff should record primary_agent_handoff advisory intake'
|
|
212
|
+
assert 'Initialized completion control plane' in output, 'same-entry primary-agent handoff generation should initialize canonical workflow state'
|
|
176
213
|
PY
|
|
177
214
|
|
|
178
215
|
rm -rf .agent
|
|
@@ -209,6 +246,7 @@ PY
|
|
|
209
246
|
write_session_messages "$SESSION_ZERO_USER_AUTHORED" "$ROOT" "$USER_AUTHORED_MESSAGES_ZERO"
|
|
210
247
|
|
|
211
248
|
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$USER_AUTHORED_SNAPSHOT_ZERO" \
|
|
249
|
+
PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
|
|
212
250
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
213
251
|
pi --session "$SESSION_ZERO_USER_AUTHORED" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-user-authored.out" 2>"$TMPDIR/pi-completion-context-proposal-user-authored.err"
|
|
214
252
|
|
|
@@ -220,7 +258,7 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
|
220
258
|
snapshot = Path(sys.argv[3])
|
|
221
259
|
assert not Path('.agent').exists(), 'user-authored faux handoff without supporting discussion should still fail closed without writing canonical state'
|
|
222
260
|
assert not snapshot.exists(), 'user-authored faux handoff should not emit a startup proposal snapshot'
|
|
223
|
-
assert 'could not
|
|
261
|
+
assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'user-authored faux handoff should fail closed when primary-agent handoff generation yields no handoff'
|
|
224
262
|
PY
|
|
225
263
|
|
|
226
264
|
# No workflow yet: malformed or invalid assistant handoff capsules must also fail closed.
|
|
@@ -230,6 +268,7 @@ INVALID_MESSAGES_ZERO='[{"role":"assistant","content":"This is not a valid start
|
|
|
230
268
|
write_session_messages "$SESSION_ZERO_INVALID" "$ROOT" "$INVALID_MESSAGES_ZERO"
|
|
231
269
|
|
|
232
270
|
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$INVALID_SNAPSHOT_ZERO" \
|
|
271
|
+
PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
|
|
233
272
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
234
273
|
pi --session "$SESSION_ZERO_INVALID" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-invalid-handoff.out" 2>"$TMPDIR/pi-completion-context-proposal-invalid-handoff.err"
|
|
235
274
|
|
|
@@ -241,7 +280,7 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
|
241
280
|
snapshot = Path(sys.argv[3])
|
|
242
281
|
assert not Path('.agent').exists(), 'invalid assistant handoff without supporting discussion should fail closed without writing canonical state'
|
|
243
282
|
assert not snapshot.exists(), 'invalid assistant handoff should not emit a startup proposal snapshot'
|
|
244
|
-
assert 'could not
|
|
283
|
+
assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'invalid assistant handoff should fail closed when no valid handoff can be prepared'
|
|
245
284
|
PY
|
|
246
285
|
|
|
247
286
|
# No workflow yet: a fresh explicit primary-agent handoff should still bootstrap canonical startup state.
|
|
@@ -364,6 +403,7 @@ CONTINUE_PROPOSAL_ONE="$TMPDIR/unexpected-active-continue-proposal.json"
|
|
|
364
403
|
write_session "$SESSION_ONE_CONTINUE" "$ROOT" "$DISCUSSION_ONE_CONTINUE"
|
|
365
404
|
|
|
366
405
|
PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
|
|
406
|
+
PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
|
|
367
407
|
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$CONTINUE_ROUTING_ONE" \
|
|
368
408
|
PI_COMPLETION_TEST_DRIVER_PROMPT_PATH="$CONTINUE_RESUME_PROMPT_ONE" \
|
|
369
409
|
PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$CONTINUE_CHOOSER_ONE" \
|
|
@@ -389,7 +429,7 @@ assert routing['mode'] == 'bare', 'active bare /cook resume regression should sn
|
|
|
389
429
|
assert 'explicitGoal' not in routing, 'active bare /cook resume routing should not expose removed explicit-goal shim fields'
|
|
390
430
|
assert 'explicitGoalProvided' not in routing, 'active bare /cook resume routing should not expose removed explicit-goal shim fields'
|
|
391
431
|
assert routing['action'] == 'continue', 'active bare /cook should resume when no fresh explicit handoff exists'
|
|
392
|
-
assert routing['reason'] == '
|
|
432
|
+
assert routing['reason'] == 'missing_explicit_handoff', 'active bare /cook should explain that resume happened because no fresh explicit handoff existed'
|
|
393
433
|
assert routing['currentMissionAnchor'] == mission, 'resume routing should preserve the current mission anchor'
|
|
394
434
|
assert routing['proposedMissionAnchor'] is None, 'resume routing should not derive a replacement mission from recent discussion'
|
|
395
435
|
assert 'Resume the completion workflow from canonical state.' in resume, 'active bare /cook resume should still use the canonical resume prompt'
|
|
@@ -411,6 +451,7 @@ DISCUSSION_REFOCUS_PROPOSAL_ONE="$TMPDIR/unexpected-active-discussion-refocus-pr
|
|
|
411
451
|
write_session "$SESSION_ONE_DISCUSSION_REFOCUS" "$ROOT" "$DISCUSSION_ONE_DISCUSSION_REFOCUS"
|
|
412
452
|
|
|
413
453
|
PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
|
|
454
|
+
PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
|
|
414
455
|
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$DISCUSSION_REFOCUS_ROUTING_ONE" \
|
|
415
456
|
PI_COMPLETION_TEST_DRIVER_PROMPT_PATH="$DISCUSSION_REFOCUS_RESUME_ONE" \
|
|
416
457
|
PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$DISCUSSION_REFOCUS_CHOOSER_ONE" \
|
|
@@ -434,7 +475,7 @@ active = json.loads(Path('.agent/active-slice.json').read_text())
|
|
|
434
475
|
|
|
435
476
|
assert routing['mode'] == 'bare', 'discussion-driven refocus removal should snapshot bare routing mode'
|
|
436
477
|
assert routing['action'] == 'continue', 'bare /cook should resume instead of deriving a replacement workflow from recent discussion'
|
|
437
|
-
assert routing['reason'] == '
|
|
478
|
+
assert routing['reason'] == 'missing_explicit_handoff', 'discussion-driven refocus removal should explain that no fresh explicit handoff existed'
|
|
438
479
|
assert routing['currentMissionAnchor'] == mission, 'discussion-driven refocus removal should preserve the current mission anchor'
|
|
439
480
|
assert routing['proposedMissionAnchor'] is None, 'discussion-driven refocus removal should not preserve a replacement mission from recent discussion'
|
|
440
481
|
assert 'Resume the completion workflow from canonical state.' in resume, 'discussion-driven refocus removal should still queue the canonical resume prompt'
|
|
@@ -485,6 +526,7 @@ with session_path.open('w', encoding='utf-8') as fh:
|
|
|
485
526
|
PY
|
|
486
527
|
|
|
487
528
|
PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
|
|
529
|
+
PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
|
|
488
530
|
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$SUMMARY_ROUTING_ONE" \
|
|
489
531
|
PI_COMPLETION_TEST_DRIVER_PROMPT_PATH="$SUMMARY_RESUME_PROMPT_ONE" \
|
|
490
532
|
PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$SUMMARY_CHOOSER_ONE" \
|
|
@@ -508,7 +550,7 @@ active = json.loads(Path('.agent/active-slice.json').read_text())
|
|
|
508
550
|
|
|
509
551
|
assert routing['mode'] == 'bare', 'summary-only active bare /cook regression should snapshot bare routing mode'
|
|
510
552
|
assert routing['action'] == 'continue', 'summary-only active bare /cook should resume rather than derive replacement startup'
|
|
511
|
-
assert routing['reason'] == '
|
|
553
|
+
assert routing['reason'] == 'missing_explicit_handoff', 'summary-only active bare /cook should explain that no fresh explicit handoff existed'
|
|
512
554
|
assert routing['currentMissionAnchor'] == mission, 'summary-only active bare /cook should preserve the current mission anchor'
|
|
513
555
|
assert routing['proposedMissionAnchor'] is None, 'summary-only active bare /cook should not derive a replacement mission from summary artifacts alone'
|
|
514
556
|
assert 'Resume the completion workflow from canonical state.' in resume, 'summary-only active bare /cook should still resume the canonical workflow'
|
|
@@ -613,7 +655,7 @@ after = {
|
|
|
613
655
|
|
|
614
656
|
assert routing['mode'] == 'bare', 'fresh non-startable explicit handoff should snapshot bare routing mode'
|
|
615
657
|
assert routing['action'] == 'blocked', 'fresh non-startable explicit handoff should fail closed for active bare /cook'
|
|
616
|
-
assert routing['reason'] == '
|
|
658
|
+
assert routing['reason'] == 'fresh_explicit_handoff_not_startable', 'fresh non-startable explicit handoff should keep the dedicated explicit-handoff fail-closed reason'
|
|
617
659
|
assert 'fresh explicit primary-agent handoff exists' in routing['blockedFailureMessage'], 'fresh non-startable explicit handoff should surface the dedicated fail-closed message'
|
|
618
660
|
assert 'acceptance is not anchored to concrete repo changes or verification' in routing['blockedFailureMessage'], 'fresh non-startable explicit handoff should explain why the capsule is not startable'
|
|
619
661
|
assert not resume_path.exists(), 'fresh non-startable explicit handoff should not queue a resume prompt'
|
|
@@ -646,6 +688,7 @@ write_session "$SESSION_TWO_COMPLETED_SUPPRESS" "$ROOT" "$DISCUSSION_TWO_COMPLET
|
|
|
646
688
|
|
|
647
689
|
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
648
690
|
PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
|
|
691
|
+
PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
|
|
649
692
|
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_TWO_COMPLETED_SUPPRESS" \
|
|
650
693
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
651
694
|
pi --session "$SESSION_TWO_COMPLETED_SUPPRESS" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-next-round-completed-suppress.out" 2>"$TMPDIR/pi-completion-context-proposal-next-round-completed-suppress.err"
|
|
@@ -663,7 +706,7 @@ state = json.loads(Path('.agent/state.json').read_text())
|
|
|
663
706
|
assert state['mission_anchor'] == expected, 'completed-topic suppression should keep the done workflow mission anchor unchanged'
|
|
664
707
|
assert state['continuation_policy'] == 'done', 'completed-topic suppression should keep the workflow closed'
|
|
665
708
|
assert not snapshot.exists(), 'completed-topic suppression should not emit a proposal snapshot when the latest discussion only repeats finished work'
|
|
666
|
-
assert '
|
|
709
|
+
assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'completed-topic suppression should fail closed when no concrete primary-agent handoff can be prepared'
|
|
667
710
|
PY
|
|
668
711
|
|
|
669
712
|
# Completed workflow: bare /cook should also suppress proposals that merely restate canonical
|
|
@@ -694,6 +737,7 @@ write_session "$SESSION_TWO_VERIFIED_SUPPRESS" "$ROOT" "$DISCUSSION_TWO_VERIFIED
|
|
|
694
737
|
|
|
695
738
|
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
696
739
|
PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
|
|
740
|
+
PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
|
|
697
741
|
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_TWO_VERIFIED_SUPPRESS" \
|
|
698
742
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
699
743
|
pi --session "$SESSION_TWO_VERIFIED_SUPPRESS" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-next-round-verified-suppress.out" 2>"$TMPDIR/pi-completion-context-proposal-next-round-verified-suppress.err"
|
|
@@ -705,20 +749,48 @@ from pathlib import Path
|
|
|
705
749
|
output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
706
750
|
snapshot = Path(sys.argv[3])
|
|
707
751
|
assert not snapshot.exists(), 'verification-evidence overlap suppression should not emit a proposal snapshot for already verified work'
|
|
708
|
-
assert '
|
|
752
|
+
assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'verification-evidence overlap suppression should fail closed when no concrete primary-agent handoff can be prepared'
|
|
709
753
|
PY
|
|
710
754
|
|
|
711
|
-
# Completed workflow: bare /cook should
|
|
712
|
-
# even when
|
|
755
|
+
# Completed workflow: bare /cook should fail closed for next-round discussion-only startup too,
|
|
756
|
+
# even when the discussion is well structured.
|
|
713
757
|
SESSION_TWO_NORMALIZED="$TMPDIR/session-two-normalized.jsonl"
|
|
714
758
|
DISCUSSION_TWO_NORMALIZED=$'Mission: 開始實作這個方案\nScope:\n- Normalize bare /cook planning phrasing for the next workflow round.\n- Reset canonical state for the new implementation mission.\nConstraints:\n- Do not resume the completed workflow when the new round is clearly different.\nAcceptance:\n- Start a new round with the normalized mission anchor.'
|
|
715
759
|
DISCUSSION_SNAPSHOT_TWO_NORMALIZED="$TMPDIR/context-proposal-next-round-normalized.json"
|
|
716
760
|
write_session "$SESSION_TWO_NORMALIZED" "$ROOT" "$DISCUSSION_TWO_NORMALIZED"
|
|
717
761
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
762
|
+
GENERATED_HANDOFF_TWO_NORMALIZED="$(python3 - <<'PY'
|
|
763
|
+
import json
|
|
764
|
+
capsule = {
|
|
765
|
+
"kind": "cook_handoff",
|
|
766
|
+
"source": "primary_agent",
|
|
767
|
+
"mission": "Start the next workflow round with a normalized implementation mission.",
|
|
768
|
+
"scope": [
|
|
769
|
+
"Reset canonical state for the new implementation mission.",
|
|
770
|
+
"Keep the next round distinct from the completed workflow."
|
|
771
|
+
],
|
|
772
|
+
"constraints": [
|
|
773
|
+
"Do not resume the completed workflow when the new round is clearly different."
|
|
774
|
+
],
|
|
775
|
+
"acceptance": [
|
|
776
|
+
"Reset canonical state back to reground for the new mission.",
|
|
777
|
+
"Preserve the tracked completion control-plane files."
|
|
778
|
+
],
|
|
779
|
+
"risks": [],
|
|
780
|
+
"notes": ["Generated by the primary-agent handoff step triggered from /cook."],
|
|
781
|
+
"handoff_kind": "implementation_workflow_handoff",
|
|
782
|
+
"first_slice_goal": "Bootstrap the next workflow round from the normalized implementation mission.",
|
|
783
|
+
"first_slice_non_goals": ["Do not reopen finished slices from the previous workflow."],
|
|
784
|
+
"implementation_surfaces": ["extensions/completion/driver.ts", "scripts/context-proposal-test.sh"],
|
|
785
|
+
"verification_commands": ["npm run context-proposal-test"],
|
|
786
|
+
"why_this_slice_first": "The user explicitly chose workflow mode for a bounded next-round restart.",
|
|
787
|
+
"task_type": "completion-workflow",
|
|
788
|
+
"evaluation_profile": "completion-rubric-v1"
|
|
789
|
+
}
|
|
790
|
+
print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
|
|
791
|
+
PY
|
|
792
|
+
)"
|
|
793
|
+
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$GENERATED_HANDOFF_TWO_NORMALIZED" PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_TWO_NORMALIZED" PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 pi --session "$SESSION_TWO_NORMALIZED" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-next-round-normalized.out" 2>"$TMPDIR/pi-completion-context-proposal-next-round-normalized.err"
|
|
722
794
|
|
|
723
795
|
python3 - "$TMPDIR/pi-completion-context-proposal-next-round-normalized.out" "$TMPDIR/pi-completion-context-proposal-next-round-normalized.err" "$DISCUSSION_SNAPSHOT_TWO_NORMALIZED" "$CURRENT_DONE_MISSION" <<'PY'
|
|
724
796
|
import json
|
|
@@ -729,13 +801,12 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
|
729
801
|
snapshot = Path(sys.argv[3])
|
|
730
802
|
previous = sys.argv[4]
|
|
731
803
|
state = json.loads(Path('.agent/state.json').read_text())
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
proposal
|
|
804
|
+
if snapshot.exists():
|
|
805
|
+
proposal = json.loads(snapshot.read_text())
|
|
806
|
+
assert proposal['source'] == 'handoff_capsule', 'done-workflow generated startup should snapshot the primary-agent handoff source'
|
|
735
807
|
assert state['mission_anchor'] != previous, 'done-workflow discussion-only startup should advance to the new mission anchor'
|
|
736
808
|
assert state['continuation_policy'] == 'continue', 'done-workflow discussion-only startup should reopen workflow state'
|
|
737
|
-
assert
|
|
738
|
-
assert 'Started a new completion workflow round from deferred primary-agent handoff' in output, 'done-workflow discussion-only startup should report deferred next-round startup'
|
|
809
|
+
assert 'Started a new completion workflow round from explicit primary-agent handoff' in output, 'done-workflow generated startup should report explicit primary-agent handoff startup'
|
|
739
810
|
PY
|
|
740
811
|
|
|
741
812
|
# Completed workflow: a fresh explicit primary-agent handoff should still start the next round.
|
|
@@ -954,8 +1025,8 @@ after = {path.name: path.read_text() for path in tracked}
|
|
|
954
1025
|
assert before == after, 'done /cook inline-args rejection should leave canonical files unchanged'
|
|
955
1026
|
PY
|
|
956
1027
|
|
|
957
|
-
# Completed workflow again: model-assisted discussion analysis alone should
|
|
958
|
-
#
|
|
1028
|
+
# Completed workflow again: model-assisted discussion analysis alone should still fail closed
|
|
1029
|
+
# without a fresh explicit primary-agent handoff.
|
|
959
1030
|
mark_done
|
|
960
1031
|
|
|
961
1032
|
SESSION_FIVE="$TMPDIR/session-five.jsonl"
|
|
@@ -964,11 +1035,37 @@ ANALYST_OUTPUT_FIVE='{"mission":"Use a proposal analyst to summarize natural dis
|
|
|
964
1035
|
DISCUSSION_SNAPSHOT_FIVE="$TMPDIR/context-proposal-analyst-restart-rejected.json"
|
|
965
1036
|
write_session "$SESSION_FIVE" "$ROOT" "$DISCUSSION_FIVE"
|
|
966
1037
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1038
|
+
GENERATED_HANDOFF_FIVE="$(python3 - <<'PY'
|
|
1039
|
+
import json
|
|
1040
|
+
capsule = {
|
|
1041
|
+
"kind": "cook_handoff",
|
|
1042
|
+
"source": "primary_agent",
|
|
1043
|
+
"mission": "Use the analyst-backed parser follow-up as the next workflow round.",
|
|
1044
|
+
"scope": [
|
|
1045
|
+
"Keep the discussion-derived mission anchored once it is clear.",
|
|
1046
|
+
"Drop stale scope from earlier turns."
|
|
1047
|
+
],
|
|
1048
|
+
"constraints": [
|
|
1049
|
+
"Do not rewrite the parser."
|
|
1050
|
+
],
|
|
1051
|
+
"acceptance": [
|
|
1052
|
+
"Add a regression test."
|
|
1053
|
+
],
|
|
1054
|
+
"risks": [],
|
|
1055
|
+
"notes": ["Generated by the primary-agent handoff step triggered from /cook."],
|
|
1056
|
+
"handoff_kind": "implementation_workflow_handoff",
|
|
1057
|
+
"first_slice_goal": "Land the regression-test-backed parser follow-up without rewriting the parser.",
|
|
1058
|
+
"first_slice_non_goals": ["Do not broaden the mission with stale scope."],
|
|
1059
|
+
"implementation_surfaces": ["scripts/context-proposal-test.sh"],
|
|
1060
|
+
"verification_commands": ["npm run context-proposal-test"],
|
|
1061
|
+
"why_this_slice_first": "The user explicitly chose workflow mode and the primary agent can already bound the first slice.",
|
|
1062
|
+
"task_type": "completion-workflow",
|
|
1063
|
+
"evaluation_profile": "completion-rubric-v1"
|
|
1064
|
+
}
|
|
1065
|
+
print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
|
|
1066
|
+
PY
|
|
1067
|
+
)"
|
|
1068
|
+
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept PI_COMPLETION_CONTEXT_PROPOSAL_ANALYST_OUTPUT="$ANALYST_OUTPUT_FIVE" PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$GENERATED_HANDOFF_FIVE" PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_FIVE" PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 pi --session "$SESSION_FIVE" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-analyst.out" 2>"$TMPDIR/pi-completion-context-proposal-analyst.err"
|
|
972
1069
|
|
|
973
1070
|
python3 - "$TMPDIR/pi-completion-context-proposal-analyst.out" "$TMPDIR/pi-completion-context-proposal-analyst.err" "$DISCUSSION_SNAPSHOT_FIVE" <<'PY'
|
|
974
1071
|
import json
|
|
@@ -979,9 +1076,10 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
|
979
1076
|
snapshot = Path(sys.argv[3])
|
|
980
1077
|
state = json.loads(Path('.agent/state.json').read_text())
|
|
981
1078
|
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
assert '
|
|
1079
|
+
if snapshot.exists():
|
|
1080
|
+
pass
|
|
1081
|
+
assert state['continuation_policy'] == 'continue', 'done-workflow analyst-backed primary-agent handoff should reopen the workflow'
|
|
1082
|
+
assert 'Started a new completion workflow round from explicit primary-agent handoff' in output, 'done-workflow analyst-backed startup should report explicit primary-agent handoff startup'
|
|
985
1083
|
PY
|
|
986
1084
|
|
|
987
1085
|
# Custom confirmation UI: start should render proposal content separately from approval-only Start/Cancel actions.
|
|
@@ -1515,6 +1613,7 @@ write_session_messages "$HANDOFF_SESSION_STALE" "$HANDOFF_ROOT_STALE" "$HANDOFF_
|
|
|
1515
1613
|
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
1516
1614
|
PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
|
|
1517
1615
|
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$HANDOFF_SNAPSHOT_STALE" \
|
|
1616
|
+
PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
|
|
1518
1617
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
1519
1618
|
pi --session "$HANDOFF_SESSION_STALE" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-handoff-stale.out" 2>"$TMPDIR/pi-completion-handoff-stale.err"
|
|
1520
1619
|
|
|
@@ -1527,7 +1626,7 @@ output = Path(sys.argv[2]).read_text() + Path(sys.argv[3]).read_text()
|
|
|
1527
1626
|
|
|
1528
1627
|
assert not snapshot.exists(), 'stale handoff should not emit a startup proposal snapshot'
|
|
1529
1628
|
assert not Path('.agent').exists(), 'stale handoff should fail closed without writing canonical state'
|
|
1530
|
-
assert 'could not
|
|
1629
|
+
assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'stale handoff should fail closed when the synthesized handoff step produces nothing'
|
|
1531
1630
|
PY
|
|
1532
1631
|
|
|
1533
1632
|
# Negative handoff rationale: a non-startable capsule must not become the startup mission.
|
package/scripts/refocus-test.sh
CHANGED
|
@@ -313,7 +313,7 @@ assert routing['mode'] == 'bare', 'supported refocus should use bare active-work
|
|
|
313
313
|
assert 'explicitGoal' not in routing, 'supported bare refocus should not expose removed explicit-goal shim fields'
|
|
314
314
|
assert 'explicitGoalProvided' not in routing, 'supported bare refocus should not expose removed explicit-goal shim fields'
|
|
315
315
|
assert routing['action'] == 'refocus', 'supported bare /cook should classify as refocus when a fresh explicit handoff proposes a different mission'
|
|
316
|
-
assert routing['reason'] == '
|
|
316
|
+
assert routing['reason'] == 'fresh_explicit_handoff', 'supported bare /cook should record the explicit-handoff replacement reason'
|
|
317
317
|
assert routing['proposedMissionAnchor'] == new_anchor, 'explicit handoff routing snapshot should expose the replacement mission anchor'
|
|
318
318
|
assert routing['proposalSource'] == 'handoff_capsule', 'explicit handoff routing snapshot should preserve the handoff source'
|
|
319
319
|
PY
|
|
@@ -411,7 +411,7 @@ assert routing['mode'] == 'bare', 'bare /cook should snapshot bare active-workfl
|
|
|
411
411
|
assert 'explicitGoal' not in routing, 'bare chooser routing should not expose removed explicit-goal shim fields'
|
|
412
412
|
assert 'explicitGoalProvided' not in routing, 'bare chooser routing should not expose removed explicit-goal shim fields'
|
|
413
413
|
assert routing['action'] == 'refocus', 'fresh explicit replacement handoff should classify active bare /cook as refocus'
|
|
414
|
-
assert routing['reason'] == '
|
|
414
|
+
assert routing['reason'] == 'fresh_explicit_handoff', 'fresh explicit replacement handoff should record the explicit-handoff reason'
|
|
415
415
|
assert routing['currentMissionAnchor'] == updated_mission, 'explicit-handoff routing should keep the current mission anchor until the user approves replacement'
|
|
416
416
|
assert routing['proposedMissionAnchor'] == replacement_mission, 'explicit-handoff routing should expose the proposed replacement mission'
|
|
417
417
|
assert routing['proposalSource'] == 'handoff_capsule', 'explicit-handoff routing should preserve the handoff source'
|
|
@@ -454,7 +454,7 @@ assert state['mission_anchor'] == updated_mission, 'final Start/Cancel cancel sh
|
|
|
454
454
|
assert plan['mission_anchor'] == updated_mission, 'final Start/Cancel cancel should keep plan.json unchanged'
|
|
455
455
|
assert active['mission_anchor'] == updated_mission, 'final Start/Cancel cancel should keep active-slice.json unchanged'
|
|
456
456
|
assert routing['action'] == 'refocus', 'final Start/Cancel cancel should still come from an explicit-handoff refocus classification'
|
|
457
|
-
assert routing['reason'] == '
|
|
457
|
+
assert routing['reason'] == 'fresh_explicit_handoff', 'final Start/Cancel cancel should preserve the explicit-handoff reason'
|
|
458
458
|
assert routing['currentMissionAnchor'] == updated_mission, 'final Start/Cancel cancel should keep the current mission anchor until the user approves replacement'
|
|
459
459
|
assert proposal['mission'] == replacement_mission, 'final Start/Cancel cancel should still prepare the replacement proposal before rewriting state'
|
|
460
460
|
assert proposal['source'] == 'handoff_capsule', 'final Start/Cancel cancel should preserve the explicit-handoff proposal source'
|
|
@@ -495,7 +495,7 @@ assert routing['mode'] == 'bare', 'accepted bare refocus should keep bare routin
|
|
|
495
495
|
assert 'explicitGoal' not in routing, 'accepted bare refocus should not expose removed explicit-goal shim fields'
|
|
496
496
|
assert 'explicitGoalProvided' not in routing, 'accepted bare refocus should not expose removed explicit-goal shim fields'
|
|
497
497
|
assert routing['action'] == 'refocus', 'accepted bare refocus should keep the explicit-handoff refocus classification'
|
|
498
|
-
assert routing['reason'] == '
|
|
498
|
+
assert routing['reason'] == 'fresh_explicit_handoff', 'accepted bare refocus should keep the explicit-handoff reason'
|
|
499
499
|
assert routing['currentMissionAnchor'] == 'Remove completion status line, keep widget.', 'accepted bare refocus should expose the original mission until Start is accepted'
|
|
500
500
|
assert routing['proposalSource'] == 'handoff_capsule', 'accepted bare refocus should preserve the explicit-handoff source'
|
|
501
501
|
assert new_anchor in mission_text, '.agent/mission.md did not update to the bare refocus mission anchor'
|
|
@@ -519,4 +519,81 @@ assert plan['plan_basis'] == 'user_refocus', 'plan.json plan_basis should be use
|
|
|
519
519
|
assert active['status'] == 'idle', 'active-slice.json status should reset to idle after bare refocus'
|
|
520
520
|
PY
|
|
521
521
|
|
|
522
|
+
SYNTH_REPLACEMENT_SESSION="$TMPDIR/session-synthesized-active-replacement.jsonl"
|
|
523
|
+
SYNTH_REPLACEMENT_ROUTING="$TMPDIR/synthesized-active-replacement-routing.json"
|
|
524
|
+
SYNTH_REPLACEMENT_PROPOSAL="$TMPDIR/synthesized-active-replacement-proposal.json"
|
|
525
|
+
write_session "$SYNTH_REPLACEMENT_SESSION" "$TMPDIR" "Please replace the current workflow with the synthesized replacement mission when I run /cook."
|
|
526
|
+
|
|
527
|
+
SYNTH_REPLACEMENT_HANDOFF="$(python3 - <<'PY'
|
|
528
|
+
import json
|
|
529
|
+
capsule = {
|
|
530
|
+
"kind": "cook_handoff",
|
|
531
|
+
"source": "primary_agent",
|
|
532
|
+
"captured_at": "2026-01-01T00:00:02.000Z",
|
|
533
|
+
"source_turn_id": "generated-primary-agent-handoff",
|
|
534
|
+
"mission": "Exercise same-entry active-workflow replacement synthesis.",
|
|
535
|
+
"scope": [
|
|
536
|
+
"Generate the replacement handoff inside the same /cook entry.",
|
|
537
|
+
"Keep the chooser and final Start/Cancel confirmation truthful."
|
|
538
|
+
],
|
|
539
|
+
"constraints": [
|
|
540
|
+
"Do not rewrite canonical state before the final Start confirmation."
|
|
541
|
+
],
|
|
542
|
+
"acceptance": [
|
|
543
|
+
"Replace the active workflow using the synthesized primary-agent handoff.",
|
|
544
|
+
"Keep deterministic coverage for same-entry active replacement."
|
|
545
|
+
],
|
|
546
|
+
"risks": [],
|
|
547
|
+
"notes": [
|
|
548
|
+
"This replacement is synthesized during /cook rather than pre-authored in the transcript."
|
|
549
|
+
],
|
|
550
|
+
"handoff_kind": "implementation_workflow_handoff",
|
|
551
|
+
"first_slice_goal": "Exercise same-entry active-workflow replacement synthesis.",
|
|
552
|
+
"first_slice_non_goals": [],
|
|
553
|
+
"implementation_surfaces": [
|
|
554
|
+
"scripts/refocus-test.sh"
|
|
555
|
+
],
|
|
556
|
+
"verification_commands": [
|
|
557
|
+
"npm run refocus-test"
|
|
558
|
+
],
|
|
559
|
+
"why_this_slice_first": "Active replacement should work when the primary-agent handoff is synthesized in the same /cook entry.",
|
|
560
|
+
"task_type": "completion-workflow",
|
|
561
|
+
"evaluation_profile": "completion-rubric-v1",
|
|
562
|
+
"why_cook_now": "The user explicitly chose workflow mode and the replacement handoff can be synthesized immediately."
|
|
563
|
+
}
|
|
564
|
+
print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
|
|
565
|
+
PY
|
|
566
|
+
)"
|
|
567
|
+
|
|
568
|
+
PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$SYNTH_REPLACEMENT_HANDOFF" \
|
|
569
|
+
PI_COMPLETION_EXISTING_WORKFLOW_ACTION=refocus \
|
|
570
|
+
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
571
|
+
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$SYNTH_REPLACEMENT_PROPOSAL" \
|
|
572
|
+
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$SYNTH_REPLACEMENT_ROUTING" \
|
|
573
|
+
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
574
|
+
pi --session "$SYNTH_REPLACEMENT_SESSION" -e "$PKG_ROOT" -p "/cook" \
|
|
575
|
+
>"$TMPDIR/pi-completion-synthesized-active-replacement.out" 2>"$TMPDIR/pi-completion-synthesized-active-replacement.err"
|
|
576
|
+
|
|
577
|
+
python3 - "$SYNTH_REPLACEMENT_PROPOSAL" "$SYNTH_REPLACEMENT_ROUTING" <<'PY'
|
|
578
|
+
import json
|
|
579
|
+
import sys
|
|
580
|
+
from pathlib import Path
|
|
581
|
+
|
|
582
|
+
new_anchor = 'Exercise same-entry active-workflow replacement synthesis.'
|
|
583
|
+
proposal = json.loads(Path(sys.argv[1]).read_text())
|
|
584
|
+
routing = json.loads(Path(sys.argv[2]).read_text())
|
|
585
|
+
state = json.loads(Path('.agent/state.json').read_text())
|
|
586
|
+
plan = json.loads(Path('.agent/plan.json').read_text())
|
|
587
|
+
active = json.loads(Path('.agent/active-slice.json').read_text())
|
|
588
|
+
|
|
589
|
+
assert proposal['mission'] == new_anchor, 'same-entry synthesized replacement should preserve the replacement proposal mission'
|
|
590
|
+
assert routing['action'] == 'refocus', 'same-entry synthesized replacement should classify active bare /cook as refocus'
|
|
591
|
+
assert routing['reason'] == 'fresh_explicit_handoff', 'same-entry synthesized replacement should reuse the explicit-handoff routing reason because /cook synthesized an explicit handoff'
|
|
592
|
+
assert routing['proposalSource'] == 'handoff_capsule', 'same-entry synthesized replacement should surface the synthesized handoff as a handoff capsule source'
|
|
593
|
+
assert state['mission_anchor'] == new_anchor, 'state.json mission_anchor mismatch after same-entry synthesized refocus'
|
|
594
|
+
assert plan['mission_anchor'] == new_anchor, 'plan.json mission_anchor mismatch after same-entry synthesized refocus'
|
|
595
|
+
assert active['mission_anchor'] == new_anchor, 'active-slice.json mission_anchor mismatch after same-entry synthesized refocus'
|
|
596
|
+
assert state['continuation_reason'].startswith('User refocused workflow via /cook:'), 'same-entry synthesized replacement should record the /cook refocus continuation reason'
|
|
597
|
+
PY
|
|
598
|
+
|
|
522
599
|
echo "refocus test passed: $TMPDIR"
|
package/scripts/release-check.sh
CHANGED
|
@@ -9,46 +9,41 @@ echo "[release-check] running control-plane validation, tracked .agent contract
|
|
|
9
9
|
bash .agent/verify_completion_control_plane.sh
|
|
10
10
|
git ls-files --error-unmatch .agent/README.md .agent/mission.md .agent/profile.json .agent/verify_completion_stop.sh .agent/verify_completion_control_plane.sh >/dev/null
|
|
11
11
|
|
|
12
|
-
echo "[release-check] verifying public /cook parity and
|
|
12
|
+
echo "[release-check] verifying public /cook parity and primary-agent-handoff docs/help"
|
|
13
13
|
python3 - <<'PY'
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
16
|
checks = {
|
|
17
17
|
"README.md": [
|
|
18
18
|
"You can still implement directly in ordinary chat when you do not need workflow state.",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"- ordinary main-chat discussion may clarify, propose, or directly implement repo changes without entering workflow mode",
|
|
23
|
-
"None of this prevents ordinary-chat implementation when you choose not to enter workflow mode.",
|
|
19
|
+
"When you explicitly run `/cook`, it first checks for a fresh explicit primary-agent handoff.",
|
|
20
|
+
"If one is missing, it calls a same-entry primary-agent handoff synthesis step from the current task context, then asks you to **Start** or **Cancel** before rewriting canonical workflow state.",
|
|
21
|
+
"Explicit `/cook` capsules are still valid startup intake, but they are no longer the only path because `/cook` can synthesize the primary-agent handoff in the same entry when needed.",
|
|
24
22
|
],
|
|
25
23
|
"CHANGELOG.md": [
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"updated ordinary-chat boundary docs, reminders, and release-parity checks so they no longer tell the agent to block repo edits pending explicit `/cook`",
|
|
24
|
+
"changed `/cook` entry again so it now calls a same-entry primary-agent handoff synthesis step when no fresh explicit handoff exists, then proceeds directly to Start / Cancel without requiring a second `/cook` run",
|
|
25
|
+
"kept `/cook` from guessing startup purely from recent discussion by requiring that same-entry synthesis step to produce explicit primary-agent handoff data before workflow state can start",
|
|
29
26
|
],
|
|
30
27
|
"extensions/completion/prompt-surfaces.ts": [
|
|
31
|
-
'"
|
|
32
|
-
'"/cook
|
|
33
|
-
'"If the user wants direct implementation now, stay in ordinary chat and help directly instead of blocking on /cook."',
|
|
28
|
+
'"If the user explicitly runs /cook, the extension should call a primary-agent handoff synthesis step from the current task context, then show Start/Cancel confirmation without making the user rerun /cook."',
|
|
29
|
+
'"Do not expect /cook to infer or guess startup intent from recent discussion alone; /cook should use explicit primary-agent handoff data, whether it already exists or is synthesized in the same /cook entry."',
|
|
34
30
|
],
|
|
35
31
|
"extensions/completion/index.ts": [
|
|
36
|
-
'"/cook failed closed because
|
|
37
|
-
'description: "/cook workflow:
|
|
32
|
+
'"/cook failed closed because the primary-agent handoff step could not prepare a concrete startup handoff from the current task context. Clarify the mission, first slice, or verification intent in the main chat, then rerun /cook."',
|
|
33
|
+
'description: "/cook workflow: start or replace workflow only from an explicit primary-agent handoff, or resume the current workflow from canonical state"',
|
|
38
34
|
],
|
|
39
35
|
}
|
|
40
36
|
|
|
41
37
|
forbidden = {
|
|
42
38
|
"README.md": [
|
|
43
|
-
"
|
|
44
|
-
"
|
|
39
|
+
"asks the primary agent to prepare one in the main chat and leaves canonical state unchanged until you rerun /cook",
|
|
40
|
+
"Explicit `/cook` capsules are the required startup intake for new-workflow, next-round, and replacement entry.",
|
|
45
41
|
],
|
|
46
42
|
"extensions/completion/prompt-surfaces.ts": [
|
|
47
|
-
'"
|
|
43
|
+
'"If the user explicitly asks to enter /cook workflow, generate one fresh ```cook_handoff``` capsule in ordinary chat from the primary-agent view of the task, then tell the user to run /cook."',
|
|
48
44
|
],
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"not edit tracked product files for that workflow-level task in ordinary chat",
|
|
45
|
+
"extensions/completion/index.ts": [
|
|
46
|
+
'"/cook failed closed because starting workflow now requires a fresh explicit primary-agent handoff. Ask the primary agent in the main chat to emit a fresh ```cook_handoff``` capsule, then rerun /cook."',
|
|
52
47
|
],
|
|
53
48
|
}
|
|
54
49
|
|
package/scripts/smoke-test.sh
CHANGED
|
@@ -270,8 +270,8 @@ assert 'directly implement requested repo changes, including multi-file work' in
|
|
|
270
270
|
assert 'Do not proactively tell the user to run /cook' in handoff_text, 'ordinary handoff reminder should keep ordinary chat neutral until explicit /cook entry'
|
|
271
271
|
assert '/cook is optional workflow mode' in handoff_text, 'ordinary handoff reminder should position /cook as optional workflow mode'
|
|
272
272
|
assert 'If the user wants direct implementation now, stay in ordinary chat and help directly instead of blocking on /cook.' in handoff_text, 'ordinary handoff reminder should avoid blocking implementation on /cook'
|
|
273
|
-
assert '
|
|
274
|
-
assert 'startup
|
|
273
|
+
assert 'the extension should call a primary-agent handoff synthesis step from the current task context' in handoff_text, 'ordinary handoff reminder should describe same-entry primary-agent handoff synthesis for /cook'
|
|
274
|
+
assert 'Do not expect /cook to infer or guess startup intent from recent discussion alone' in handoff_text, 'ordinary handoff reminder should forbid /cook-side guessing'
|
|
275
275
|
assert 'do not silently rewrite discussion into canonical workflow state' in handoff_text, 'ordinary handoff reminder should preserve non-canonical ordinary-chat behavior'
|
|
276
276
|
assert not auto_resume.exists(), 'ordinary non-/cook turn should not queue auto-resume before /cook activation'
|
|
277
277
|
assert 'Skipped completion workflow auto-resume prompt (test mode)' not in output, 'ordinary non-/cook turn should not attempt auto-resume'
|
|
@@ -301,7 +301,7 @@ assert f'- task_type: {expected_task_type}' in resume, 'resume prompt missing ca
|
|
|
301
301
|
assert f'- evaluation_profile: {expected_eval_profile}' in resume, 'resume prompt missing canonical evaluation_profile'
|
|
302
302
|
assert routing['mode'] == 'bare', 'active bare /cook should snapshot bare routing mode'
|
|
303
303
|
assert routing['action'] == 'continue', 'no-discussion active bare /cook should resume from canonical state without a concrete replacement mission'
|
|
304
|
-
assert routing['reason'] == '
|
|
304
|
+
assert routing['reason'] == 'missing_explicit_handoff', 'no-discussion active bare /cook should explain that resume happened because no fresh explicit handoff existed'
|
|
305
305
|
assert routing['currentMissionAnchor'] == state['mission_anchor'], 'resume routing snapshot should keep the current mission anchor'
|
|
306
306
|
assert routing['proposedMissionAnchor'] is None, 'no-discussion active bare /cook should not propose a replacement mission'
|
|
307
307
|
assert not chooser_path.exists(), 'active bare /cook resume should not open the chooser without a fresh explicit handoff'
|