@mgiles/perk 2.2.0 → 3.0.0

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.
Files changed (129) hide show
  1. package/README.md +1 -1
  2. package/extension/adapters/planAdapterPlannotator.ts +132 -91
  3. package/extension/adapters/planAdapterTombell.ts +5 -3
  4. package/extension/doors/address.ts +235 -37
  5. package/extension/doors/annotationPush.ts +924 -0
  6. package/extension/doors/auditWaveTools.ts +352 -0
  7. package/extension/doors/ciExecutor.ts +220 -55
  8. package/extension/doors/draftReviewWaveTools.ts +384 -0
  9. package/extension/doors/harvestWaveTools.ts +279 -0
  10. package/extension/doors/land.ts +1 -0
  11. package/extension/doors/learn.ts +238 -24
  12. package/extension/doors/learnFactory.ts +33 -7
  13. package/extension/doors/lifecycleGates.ts +1 -1
  14. package/extension/doors/objectiveReviewBrowser.ts +514 -0
  15. package/extension/doors/objectiveStack.ts +1143 -0
  16. package/extension/doors/planReviewBrowser.ts +453 -0
  17. package/extension/doors/plannotatorHandoff.ts +120 -49
  18. package/extension/doors/prReview.ts +203 -22
  19. package/extension/doors/prReviewBrowser.ts +31 -23
  20. package/extension/doors/prReviewDynamic.ts +256 -0
  21. package/extension/doors/prReviewTerminal.ts +6 -11
  22. package/extension/doors/reviewWaveTools.ts +374 -0
  23. package/extension/doors/selfcheck.ts +1 -1
  24. package/extension/doors/submit.ts +86 -10
  25. package/extension/factories/gistAuthor.ts +4 -4
  26. package/extension/factories/gistDraft.ts +1 -1
  27. package/extension/factories/gistSave.ts +2 -2
  28. package/extension/factories/objective.ts +7 -7
  29. package/extension/factories/objectiveAuthor.ts +5 -4
  30. package/extension/factories/objectiveDraft.ts +61 -6
  31. package/extension/factories/objectivePlan.ts +163 -8
  32. package/extension/factories/objectiveSave.ts +16 -1
  33. package/extension/factories/planMode.ts +5 -3
  34. package/extension/factories/planReview.ts +131 -36
  35. package/extension/factories/planTitle.ts +27 -9
  36. package/extension/hunkFeedback/inbox.ts +389 -0
  37. package/extension/hunkFeedback/perkFeedback.ts +364 -0
  38. package/extension/hunkFeedback/receiver.ts +296 -0
  39. package/extension/hunkFeedback/store.ts +533 -0
  40. package/extension/index.ts +116 -44
  41. package/extension/substrate/cache.ts +75 -22
  42. package/extension/substrate/coldDoor.ts +2 -3
  43. package/extension/substrate/config.ts +42 -14
  44. package/extension/substrate/git.ts +10 -0
  45. package/extension/substrate/providers.ts +4 -33
  46. package/extension/substrate/resources.ts +11 -0
  47. package/extension/substrate/result.ts +13 -5
  48. package/extension/substrate/sessionData.ts +3 -3
  49. package/extension/substrate/sessionPointers.ts +3 -3
  50. package/extension/substrate/structuredOutput.ts +78 -19
  51. package/extension/substrate/terminalLaunch.ts +1 -1
  52. package/extension/substrate/toolGating.ts +206 -26
  53. package/extension/substrate/workflowState.ts +6 -0
  54. package/extension/surfaces/footerProvider.ts +6 -6
  55. package/extension/surfaces/surfaces.ts +98 -282
  56. package/extension/vendor/btw/btw.ts +57 -12
  57. package/extension/waves/adversarialReviewWave.ts +164 -0
  58. package/extension/waves/auditWave.ts +312 -0
  59. package/extension/waves/draftReviewWave.ts +189 -0
  60. package/extension/waves/harvestWave.ts +399 -0
  61. package/extension/waves/learnWave.ts +155 -0
  62. package/extension/waves/memoryAdapter.ts +139 -0
  63. package/extension/waves/objectiveExplorerWave.ts +120 -0
  64. package/extension/waves/prReviewDynamicWave.ts +696 -0
  65. package/extension/waves/prReviewWave.ts +274 -0
  66. package/extension/waves/reportWave.ts +749 -0
  67. package/extension/waves/reviewClassifierWave.ts +109 -0
  68. package/extension/waves/rpcAdapter.ts +264 -0
  69. package/extension/worker/readOnlySession.ts +3 -3
  70. package/extension/worker/worker.ts +71 -93
  71. package/extension/workerMain.ts +4 -6
  72. package/package.json +20 -5
  73. package/prompts/README.md +19 -0
  74. package/prompts/_fixtures/live.yaml +71 -72
  75. package/prompts/common/resume-advisory.md +1 -0
  76. package/prompts/contexts/adapters/plannotator-gist.md +13 -0
  77. package/prompts/contexts/adapters/plannotator-objective.md +1 -2
  78. package/prompts/contexts/adapters/plannotator-plan.md +1 -2
  79. package/prompts/contexts/gist-authoring.md +6 -20
  80. package/prompts/contexts/objective-authoring.md +6 -18
  81. package/prompts/stages/address/action.md +4 -4
  82. package/prompts/stages/address/preview.md +3 -3
  83. package/prompts/stages/audit.md +18 -0
  84. package/prompts/stages/conflict-resolution.md +1 -1
  85. package/prompts/stages/gist-author/seed.md +4 -4
  86. package/prompts/stages/gist-save.md +1 -1
  87. package/prompts/stages/implement.md +3 -1
  88. package/prompts/stages/learn-code.md +1 -1
  89. package/prompts/stages/learn-docs.md +2 -2
  90. package/prompts/stages/learn-harvest.md +15 -0
  91. package/prompts/stages/learn-orchestrate.md +7 -5
  92. package/prompts/stages/objective-author/adopt.md +5 -3
  93. package/prompts/stages/objective-author/file.md +5 -4
  94. package/prompts/stages/objective-author/seed.md +5 -4
  95. package/prompts/stages/objective-land.md +7 -0
  96. package/prompts/stages/objective-plan/guidance.md +2 -2
  97. package/prompts/stages/objective-plan/seed.md +5 -1
  98. package/prompts/stages/objective-recover.md +8 -0
  99. package/prompts/stages/objective-replan.md +4 -2
  100. package/prompts/stages/objective-review-browser.md +9 -0
  101. package/prompts/stages/objective-sync.md +6 -0
  102. package/prompts/stages/plan-from/adopt.md +2 -2
  103. package/prompts/stages/plan-from/file.md +2 -2
  104. package/prompts/stages/plan-review-browser.md +9 -0
  105. package/prompts/stages/pr-review-browser/active.md +6 -6
  106. package/prompts/stages/pr-review-browser/foreign.md +6 -6
  107. package/prompts/stages/pr-review-dynamic.md +7 -0
  108. package/prompts/stages/pr-review-terminal/active.md +7 -7
  109. package/prompts/stages/pr-review-terminal/foreign.md +7 -7
  110. package/prompts/stages/pr-review.md +7 -6
  111. package/prompts/stages/replan.md +3 -3
  112. package/shared/README.md +2 -2
  113. package/shared/bindings.yaml +15 -0
  114. package/shared/contracts-history.md +11 -0
  115. package/shared/contracts.md +3713 -227
  116. package/shared/providers.yaml +27 -60
  117. package/shared/registry.yaml +32 -8
  118. package/shared/schemas/outputs/objective-doctor.schema.json +449 -0
  119. package/shared/schemas/outputs/objective-stack-land.schema.json +732 -0
  120. package/shared/schemas/outputs/objective-stack-recover.schema.json +397 -0
  121. package/shared/schemas/outputs/objective-stack-status.schema.json +577 -0
  122. package/shared/schemas/outputs/objective-stack-sync.schema.json +184 -0
  123. package/shared/schemas/outputs/plan-save.schema.json +12 -0
  124. package/shared/schemas/outputs/pr-submit.schema.json +177 -1
  125. package/extension/adapters/todoAdapterJuicesharp.ts +0 -102
  126. package/extension/checkpoints/checkpoints.ts +0 -550
  127. package/extension/checkpoints/planSteps.ts +0 -108
  128. package/extension/doors/askUser.ts +0 -198
  129. package/prompts/contexts/adapters/juicesharp-todo.md +0 -7
@@ -89,8 +89,9 @@ export const LINEAR_MUTATING_TOOLS: readonly string[] = [
89
89
  * (≈830 schema chars — accepted, documented, test-pinned). A later `session_tree` re-apply
90
90
  * filters over the original snapshot (which lacks the late names), so a tree navigation drops
91
91
  * them — the pre-existing snapshot behavior, unchanged. Child-side tools (`contact_supervisor`,
92
- * `structured_output`) are out of scope: spawned children are unscoped by design (§8.40
93
- * adopt-never-impersonates).
92
+ * `structured_output`) are out of scope for the STAGE census spawned children stay
93
+ * stage-unscoped by design (§8.40 adopt-never-impersonates) — but they DO ride READ_ONLY_TOOLS,
94
+ * because the read-only gate IS inherited by adopted children (see SUBAGENT_CHILD_TOOLS).
94
95
  */
95
96
  export const SUBAGENT_TOOLS: readonly string[] = [
96
97
  "subagent",
@@ -99,6 +100,47 @@ export const SUBAGENT_TOOLS: readonly string[] = [
99
100
  "intercom",
100
101
  ];
101
102
 
103
+ /**
104
+ * pi-subagents' CHILD-side engine tools. `structured_output` and `contact_supervisor` register
105
+ * only inside spawned child sessions (the env-keyed prompt-runtime registration — never in
106
+ * parents, so those names are inert in every gated parent session; `setActiveTools` ignores
107
+ * unknown names). `subagent_wait` is ALSO registered by the top-level parent extension
108
+ * (pi-subagents 0.45.1's `registerWaitTool`) — the accepted widening: a wait-only,
109
+ * non-repo-mutating tool active in gated parents. A gated ADOPTED child (mode inherited via the
110
+ * `adopt` arm, contracts.md §8.3) must keep them active:
111
+ * - `structured_output` is the engine-REQUIRED completion call when the launch carries an
112
+ * `outputSchema` — stripping it makes the child physically unable to finish and fails the
113
+ * run with `structuredOutputFailed`;
114
+ * - `contact_supervisor` is the child→parent intercom door;
115
+ * - `subagent_wait` is the fanout-child wait door.
116
+ * None mutates the repo (`structured_output` writes only the engine's capture file under
117
+ * `.pi-subagents/` scratch). Census decision, recorded: these names deliberately join NEITHER
118
+ * PERK_TOOLS nor BORROWED_TOOLS — the stage-filter universe never sees them because children
119
+ * are stage-unscoped by design (adopt never impersonates a stage), so gate membership is their
120
+ * only governance surface.
121
+ */
122
+ export const SUBAGENT_CHILD_TOOLS: readonly string[] = [
123
+ "structured_output",
124
+ "contact_supervisor",
125
+ "subagent_wait",
126
+ ];
127
+
128
+ /**
129
+ * @ff-labs/pi-fff's search tools. BOTH mode name-sets are enumerated (static names, inert
130
+ * when absent — the code_search version-tolerance precedent): warm sessions run pi-fff's
131
+ * default tools-and-ui mode (fffind/ffgrep [+ fff-multi-grep when enabled upstream]);
132
+ * perk cold launches inject PI_FFF_MODE=override, where FFF registers under the builtin
133
+ * names find/grep (already allowlisted/pass-through) plus multi_grep. All register at
134
+ * load time. Frecency/history state lives under ~/.pi/agent/fff/ — outside the worktree
135
+ * (the fetch_content cache-write precedent), so the read-only bar holds.
136
+ */
137
+ export const FFF_SEARCH_TOOLS: readonly string[] = [
138
+ "fffind",
139
+ "ffgrep",
140
+ "fff-multi-grep",
141
+ "multi_grep",
142
+ ];
143
+
102
144
  /**
103
145
  * The enumerated borrowed-package tool census (contracts.md §8.40): every foreign tool name perk
104
146
  * wires — via `BORROWED_PACKAGES`, a provider package, or the linear issue backend — joins the
@@ -115,16 +157,27 @@ export const SUBAGENT_TOOLS: readonly string[] = [
115
157
  * stage set over a foreign restriction. Pre-existing interplay, recorded, not re-engineered.
116
158
  * - Zero-tool packages: @tombell/pi-diff (commands only), the footer providers, and the hunk
117
159
  * review CLI (not a Pi package) register nothing — nothing to enumerate.
118
- * - Single-governance rule: `ask_user_question` must stay OUT of this census — the
119
- * @juicesharp/rpiv-ask-user-question provider registers the IDENTICAL name perk does, so the
120
- * name-keyed PERK_TOOLS entry already governs both registrations (hygiene-tested).
160
+ * - Single-governance rule: a name is governed ONCE it lives in exactly one census. perk
161
+ * registers no same-named `ask_user_question` anymore (the first-party tool is deleted), so
162
+ * the name lives HERE, in the borrowed census, not in PERK_TOOLS (hygiene-tested).
163
+ * Registration timing nuance: @juicesharp/rpiv-ask-user-question registers the tool at load
164
+ * time, then a `hasUI`-keyed reconcile strips/restores it — headless sessions carry no
165
+ * `ask_user_question` schema at all.
166
+ * - @ff-labs/pi-fff (FFF_SEARCH_TOOLS): registration timing load-time (both modes); no
167
+ * `setFooter` (only a keyed optional-chained `setStatus`); zero bundled skills.
121
168
  */
122
169
  export const BORROWED_TOOLS: readonly string[] = [
123
170
  ...WEB_RESEARCH_TOOLS,
124
171
  ...LINEAR_READ_TOOLS,
125
172
  ...LINEAR_MUTATING_TOOLS,
126
173
  ...SUBAGENT_TOOLS,
127
- "todo", // @juicesharp/rpiv-todo (the juicesharp-todo provider) — load-time
174
+ ...FFF_SEARCH_TOOLS,
175
+ // @juicesharp/rpiv-todo (required borrow) — registers at load; its checklist overlay is
176
+ // `hasUI`-gated (headless-safe).
177
+ "todo",
178
+ // @juicesharp/rpiv-ask-user-question (required borrow) — registers at load; strips itself
179
+ // headlessly (!hasUI reconcile).
180
+ "ask_user_question",
128
181
  // @plannotator/pi-extension: perk never drives its plan phases (the adapter bridges
129
182
  // `plan_review` to its event API), so the submit tool is dead weight in stage sessions.
130
183
  "plannotator_submit_plan",
@@ -167,23 +220,55 @@ export const READ_ONLY_TOOLS = [
167
220
  // The borrowed research families (extracted to family constants; set + order byte-identical).
168
221
  ...WEB_RESEARCH_TOOLS,
169
222
  ...LINEAR_READ_TOOLS,
170
- // The delegation carve-in: the gated objective-plan seed/guidance names the
171
- // `perk.objective-explorer` spawn, so `subagent`/`wait` (+ the parent supervisor pair, which
172
- // already leaks active into cold-door gated sessions via late registration — keeping
173
- // warm-entered gates consistent, and letting the parent answer child `contact_supervisor`
174
- // asks) must be reachable while gated. ACCEPTED LENIENCY, deliberately documented: spawned
175
- // children are unscoped by design (§8.40 adopt-never-impersonates). The explorer's agent def
176
- // is structurally write-blocked (`tools: read, grep, find, ls, bash` frontmatter in
177
- // agents/objective-explorer.md), but the `subagent` tool itself can spawn ad-hoc read-write
223
+ // FFF local search belongs in read-only exploration (the override names find/grep are
224
+ // already present above; these are the additive tools-and-ui names + multi_grep).
225
+ ...FFF_SEARCH_TOOLS,
226
+ // The delegation carve-in: `subagent`/`wait` (+ the parent supervisor pair, which already
227
+ // leaks active into cold-door gated sessions via late registration — keeping warm-entered
228
+ // gates consistent, and letting the parent answer child `contact_supervisor` asks) stay
229
+ // reachable while gated for the other delegation flows (the gated objective-plan guidance now
230
+ // names the `explore_objective_node` tool below, not a direct spawn). ACCEPTED LENIENCY,
231
+ // deliberately documented: spawned children are unscoped by design (§8.40
232
+ // adopt-never-impersonates), and the `subagent` tool itself can spawn ad-hoc read-write
178
233
  // children — a posture choice with NO agent-allowlist backstop, consistent with the arg-blind
179
234
  // `curl`/`agent-browser` precedents (contracts.md §8.3).
180
235
  ...SUBAGENT_TOOLS,
236
+ // The explorer-wave carve-in: the gated objective-plan session's OPTIONAL explore step is the
237
+ // `explore_objective_node` tool — it spawns the read-only `perk.objective-explorer` child over
238
+ // the already-carved-in SUBAGENT tools (the draft-review-wave precedent) and writes nothing to
239
+ // the worktree.
240
+ "explore_objective_node",
241
+ // The child-side carve-in: gated adopt-children must keep the engine's injected tools — see
242
+ // SUBAGENT_CHILD_TOOLS.
243
+ ...SUBAGENT_CHILD_TOOLS,
244
+ // The draft-review-door carve-in: plan-authoring sessions run GATED, so the
245
+ // /plan-review-browser companions must be reachable while read-only. `push_annotations` only
246
+ // POSTs findings to the door-primed local plannotator server (no worktree writes — the
247
+ // fetch_content cache-write precedent class); the wave pair spawns the read-only
248
+ // `perk.draft-reviewer` over the already-carved-in SUBAGENT_TOOLS/SUBAGENT_CHILD_TOOLS.
249
+ "push_annotations",
250
+ "start_draft_review_wave",
251
+ "collect_draft_review_wave",
252
+ // The audit-wave carve-in: the seeded `perk-dev audit judge` session runs GATED (the `audit`
253
+ // stage is read-only), so `run_audit_wave` must be reachable while read-only. Its one write
254
+ // (`<bundle>/verdicts.json`) is structurally bound to the cold door's workflow-state
255
+ // `audit_bundle_dir` — the tool takes NO parameters, so no caller-supplied path exists and a
256
+ // gated session cannot aim the writer anywhere (contracts.md §8.50).
257
+ "run_audit_wave",
258
+ // The harvest-wave carve-in: the seeded learn-harvest session runs GATED (the read-only
259
+ // objective-author borrow), so `run_harvest_wave` must be reachable while read-only. Its
260
+ // manifest read is structurally bound to the session's claimed run-scoped scratch path (the
261
+ // `manifest_path` param is verified against it and any other path refused — the
262
+ // `run_audit_wave` no-aimable-writer posture, read-side), it spawns the read-only
263
+ // `perk.harvest-analyst` over the already-carved-in SUBAGENT_TOOLS/SUBAGENT_CHILD_TOOLS, and
264
+ // it writes nothing to the worktree (contracts.md §8.48).
265
+ "run_harvest_wave",
181
266
  ];
182
267
 
183
268
  /**
184
269
  * Every tool perk itself registers (contracts.md §8.40). Name-keyed: `setActiveTools` ignores
185
- * unknown names, so a vacated registration (e.g. `ask_user_question` under a foreign
186
- * `[providers] askuser` selection registers the IDENTICAL name) or an absent tool is inert.
270
+ * unknown names, so an absent tool is inert (e.g. a borrowed census name whose package stripped
271
+ * or never registered it `ask_user_question` in a headless session has nothing to enable).
187
272
  * Stage scoping filters the scoped universe `PERK_TOOLS ∪ BORROWED_TOOLS` — builtins and
188
273
  * un-enumerated foreign names pass through untouched (fail-open).
189
274
  */
@@ -199,21 +284,46 @@ export const PERK_TOOLS: readonly string[] = [
199
284
  "gist_draft",
200
285
  "gist_save",
201
286
  "learn",
202
- "ask_user_question",
287
+ "run_learn_wave",
288
+ "run_audit_wave",
289
+ "run_harvest_wave",
203
290
  "land",
204
291
  "post_pr_review",
205
292
  "ready",
206
- "resolve_review_threads",
293
+ "classify_review_feedback",
294
+ "finalize_address",
295
+ "explore_objective_node",
296
+ "run_pr_review_wave",
297
+ "run_pr_review_dynamic_wave",
207
298
  "submit_pr_review",
299
+ "start_review_wave",
300
+ "collect_review_wave",
301
+ "push_annotations",
302
+ "start_draft_review_wave",
303
+ "collect_draft_review_wave",
208
304
  "run_ci",
209
305
  "submit",
306
+ // The stacked-delivery warm surface (contracts.md §8.51/§8.56): read + control tools over
307
+ // the cold `objective stack` workers. Never in READ_ONLY_TOOLS — sync/adopt/recover/land
308
+ // mutate published branches and PRs; the gated posture is the driving commands' soft
309
+ // refusal.
310
+ "objective_stack_status",
311
+ "objective_stack_sync",
312
+ "objective_stack_adopt",
313
+ "objective_stack_recover",
314
+ "objective_stack_land",
210
315
  ];
211
316
 
212
317
  /**
213
- * The research bundle EVERY stage list carries: web research + Linear reads are useful in every
214
- * stage session (authoring and worktree alike) and mutate nothing.
318
+ * The universal non-mutating bundle EVERY stage list carries: web research + Linear reads +
319
+ * FFF local search are useful in every stage session (authoring and worktree alike) and
320
+ * mutate nothing (FFF's frecency state lives under ~/.pi/agent/fff/, outside the worktree).
215
321
  */
216
- const RESEARCH_TOOLS: readonly string[] = [...WEB_RESEARCH_TOOLS, ...LINEAR_READ_TOOLS];
322
+ const RESEARCH_TOOLS: readonly string[] = [
323
+ ...WEB_RESEARCH_TOOLS,
324
+ ...LINEAR_READ_TOOLS,
325
+ ...FFF_SEARCH_TOOLS,
326
+ ];
217
327
 
218
328
  /**
219
329
  * The PR-loop family shared by ALL FIVE worktree stages (implement/submit/address/land/learn) —
@@ -223,7 +333,7 @@ const RESEARCH_TOOLS: readonly string[] = [...WEB_RESEARCH_TOOLS, ...LINEAR_READ
223
333
  * the post-land reconcile drive — `/land` auto-drives `/objective-reconcile` in-session, whose
224
334
  * guidance names the reconcile trio, so the trio must be active in every worktree stage). The
225
335
  * headless worker also REQUIRES the model-invoked `submit` (implement) /
226
- * `resolve_review_threads` (address) to reach its completion bar. Borrowed additions: delegation
336
+ * `finalize_address` (address) to reach its completion bar. Borrowed additions: delegation
227
337
  * (SUBAGENT_TOOLS — the `/pr-review`/`/address`/`/submit`-conflict/`/learn` orchestration flows)
228
338
  * and `todo` (the foreign checklist overlay the implement-progress discipline rides) are
229
339
  * worktree-family only.
@@ -235,15 +345,35 @@ const WORKTREE_STAGE_TOOLS: readonly string[] = [
235
345
  "run_ci",
236
346
  "land",
237
347
  "learn",
238
- "resolve_review_threads",
348
+ "run_learn_wave",
349
+ "classify_review_feedback",
350
+ "finalize_address",
239
351
  "post_pr_review",
352
+ "run_pr_review_wave",
353
+ "run_pr_review_dynamic_wave",
240
354
  "submit_pr_review",
355
+ // The human review doors' companion tools (/pr-review-terminal, /pr-review-browser): the
356
+ // review-wave pair + the door-primed annotation push. The plan-stage widening landed via the
357
+ // draft-review door (/plan-review-browser): the plan-family stage lists carry the draft-wave
358
+ // pair + push_annotations.
359
+ "start_review_wave",
360
+ "collect_review_wave",
361
+ "push_annotations",
241
362
  // The reconcile trio: `/land` auto-drives the objective-reconcile pass inside the CURRENT
242
363
  // worktree session (driveReconcileAfterLand), and the manual `/objective-reconcile` gesture is
243
364
  // registered globally — both inject guidance naming these three tools.
244
365
  "reconcile_objective",
245
366
  "add_objective_node",
246
367
  "objective_node",
368
+ // The stacked-delivery quintet: `/objective-sync`/`/objective-recover`/`/objective-land`
369
+ // drive worktree sessions (post-amend sync from implement/address; recovery and the atomic
370
+ // landing from anywhere in the PR loop), so their guidance-named tools must be active
371
+ // across the whole family.
372
+ "objective_stack_status",
373
+ "objective_stack_sync",
374
+ "objective_stack_adopt",
375
+ "objective_stack_recover",
376
+ "objective_stack_land",
247
377
  ...RESEARCH_TOOLS,
248
378
  ...SUBAGENT_TOOLS,
249
379
  "todo",
@@ -253,7 +383,8 @@ const WORKTREE_STAGE_TOOLS: readonly string[] = [
253
383
  * Per-stage active perk tools for gate-OFF sessions (contracts.md §8.40). Keys = the registry
254
384
  * stage ids; an unknown/absent stage id is fail-open (no filtering — version-skew safety).
255
385
  * Rationale pins:
256
- * - `ask_user_question` is universal (every stage list carries it).
386
+ * - `ask_user_question` is universal (every stage list carries it); the name is BORROWED now
387
+ * (the @juicesharp questionnaire, via BORROWED_TOOLS — headless sessions carry no schema).
257
388
  * - `plan`/`save` cover the plan-family stage borrowers (`plan from`/`plan replan`/
258
389
  * `learn docs`/`learn code` borrow `plan`; `skills create/refine` borrow `save`).
259
390
  * - `objective-author`/`objective-save` cover `objective replan` + `objective author --from`.
@@ -263,6 +394,12 @@ const WORKTREE_STAGE_TOOLS: readonly string[] = [
263
394
  * three objective stages (the post-save `/objective-reconcile` gesture) AND the worktree
264
395
  * family (the post-land `driveReconcileAfterLand` drive + the manual `/objective-reconcile`
265
396
  * gesture — its guidance names all three).
397
+ * - the draft-review companions (`start_draft_review_wave`/`collect_draft_review_wave`/
398
+ * `push_annotations`) also ride the two objective stages (§8.23's
399
+ * `/objective-review-browser` — gate-OFF coverage: after `objectiveApprovalSave` exits the
400
+ * gate mid-flow, late collects/pushes must not dead-end), and `plan_review` rides them
401
+ * because the door guidance names it (in both objective stages it routes to the objective
402
+ * review arm; the drive-coverage guard forces both the moment the guidance names them).
266
403
  */
267
404
  export const STAGE_TOOLS: Readonly<Record<string, readonly string[]>> = {
268
405
  "gist-author": ["ask_user_question", "gist_draft", "gist_save", ...RESEARCH_TOOLS],
@@ -274,6 +411,13 @@ export const STAGE_TOOLS: Readonly<Record<string, readonly string[]>> = {
274
411
  "reconcile_objective",
275
412
  "add_objective_node",
276
413
  "objective_node",
414
+ // The /objective-review-browser companions (gate-OFF coverage: after objectiveApprovalSave
415
+ // exits the gate mid-flow, late collects/pushes must not dead-end) + plan_review (the door
416
+ // guidance names it; it routes to the objective review arm here).
417
+ "start_draft_review_wave",
418
+ "collect_draft_review_wave",
419
+ "push_annotations",
420
+ "plan_review",
277
421
  ...RESEARCH_TOOLS,
278
422
  ],
279
423
  "objective-save": [
@@ -283,6 +427,11 @@ export const STAGE_TOOLS: Readonly<Record<string, readonly string[]>> = {
283
427
  "reconcile_objective",
284
428
  "add_objective_node",
285
429
  "objective_node",
430
+ // The /objective-review-browser companions + plan_review (see the objective-author note).
431
+ "start_draft_review_wave",
432
+ "collect_draft_review_wave",
433
+ "push_annotations",
434
+ "plan_review",
286
435
  ...RESEARCH_TOOLS,
287
436
  ],
288
437
  "objective-plan": [
@@ -291,17 +440,48 @@ export const STAGE_TOOLS: Readonly<Record<string, readonly string[]>> = {
291
440
  "plan_review",
292
441
  "plan_save",
293
442
  "objective_node",
443
+ "explore_objective_node",
294
444
  "reconcile_objective",
295
445
  "add_objective_node",
446
+ // The /plan-review-browser companions (gate-OFF coverage: after approvalSave exits the gate
447
+ // mid-flow, late collects/pushes must not dead-end — the drive-coverage guard forces this
448
+ // the moment the guidance names them).
449
+ "start_draft_review_wave",
450
+ "collect_draft_review_wave",
451
+ "push_annotations",
452
+ ...RESEARCH_TOOLS,
453
+ ],
454
+ plan: [
455
+ "ask_user_question",
456
+ "plan_draft",
457
+ "plan_review",
458
+ "plan_save",
459
+ // The /plan-review-browser companions (see the objective-plan note).
460
+ "start_draft_review_wave",
461
+ "collect_draft_review_wave",
462
+ "push_annotations",
463
+ ...RESEARCH_TOOLS,
464
+ ],
465
+ save: [
466
+ "ask_user_question",
467
+ "plan_draft",
468
+ "plan_review",
469
+ "plan_save",
470
+ // The /plan-review-browser companions (see the objective-plan note).
471
+ "start_draft_review_wave",
472
+ "collect_draft_review_wave",
473
+ "push_annotations",
296
474
  ...RESEARCH_TOOLS,
297
475
  ],
298
- plan: ["ask_user_question", "plan_draft", "plan_review", "plan_save", ...RESEARCH_TOOLS],
299
- save: ["ask_user_question", "plan_draft", "plan_review", "plan_save", ...RESEARCH_TOOLS],
300
476
  implement: WORKTREE_STAGE_TOOLS,
301
477
  submit: WORKTREE_STAGE_TOOLS,
302
478
  address: WORKTREE_STAGE_TOOLS,
303
479
  land: WORKTREE_STAGE_TOOLS,
304
480
  learn: WORKTREE_STAGE_TOOLS,
481
+ // The dev-only session-audit orchestrator (`perk-dev audit judge`). The session runs GATED
482
+ // (read-only mode), where this list is inert; it exists for the keys≡registry pin and the
483
+ // defensive gate-off arm.
484
+ audit: ["ask_user_question", "run_audit_wave", ...RESEARCH_TOOLS],
305
485
  };
306
486
 
307
487
  /** The read-only marker / custom-message type injected into context while active. */
@@ -33,6 +33,12 @@ export interface WorkflowState {
33
33
  mode?: string;
34
34
  /** The registry stage id this run is acting on (recorded at cold claim from the handoff). */
35
35
  stage?: string;
36
+ /**
37
+ * The running @mgiles/perk version stamped when run identity is established (§8.3) —
38
+ * claim/fork/adopt/mint in session_start. The session-audit vintage layer's exact basis;
39
+ * omitted when only the perkVersion() failure sentinel is available. Best-effort tier.
40
+ */
41
+ perk_version?: string;
36
42
  predecessor?: string;
37
43
  active_plan_ref?: PlanRef | null;
38
44
  active_objective?: string | null;
@@ -1,16 +1,16 @@
1
- // The footer provider seam (INSTALL-SITE / runtime vacating). The footer is the SECOND interface
2
- // seam (no durable artifact to bridge), mirroring askuser but with a different vacating mechanism:
1
+ // The footer provider seam (INSTALL-SITE / runtime vacating). The footer is an interface
2
+ // seam (no durable artifact to bridge) with a runtime vacating mechanism:
3
3
  // perk installs its own footer (`installPerkFooter`) inside `index.ts`'s `session_start` event
4
4
  // handler, so under a foreign `[providers] footer` selection perk simply does NOT call
5
5
  // `installPerkFooter` — a runtime guard at that single install site, keyed off `ctx.cwd`. That
6
6
  // leaves the foreign footer (`pi-powerline-footer` or `pi-bar`) as the sole footer surface;
7
- // perk's objective/checkpoints progress still reaches it automatically via the already-publishing
8
- // composed `perk` `setStatus` slot (both foreign footers render extension statuses), so the
7
+ // perk's objective progress still reaches it automatically via the already-publishing
8
+ // single-value `perk` `setStatus` slot (both foreign footers render extension statuses), so the
9
9
  // adapter is vacate-only (`adapter: null`, no shim, no injected context).
10
10
  //
11
11
  // This module reads config (via `resolveProviders`/`loadPerkConfig`) so it does NOT belong in the
12
12
  // dependency-free `surfaces.ts`; it contains no rich-UI calls, so `surfacesGuard.test.ts` passes
13
- // it cleanly. Mirror of `askUser.ts`'s `resolvedAskUserProviderId` / `isPerkAskUserReferenceSelected`.
13
+ // it cleanly. Mirror of `planMode.ts`'s `resolvedPlanProviderId` / `isPerkPlanReferenceSelected`.
14
14
 
15
15
  import { loadPerkConfig } from "../substrate/config.ts";
16
16
  import {
@@ -22,7 +22,7 @@ import {
22
22
  /**
23
23
  * The resolved `[providers] footer` selection id for `cwd`. Fail-safe to the perk-footer
24
24
  * reference: any load/resolution failure returns the reference id so perk keeps installing its
25
- * own footer — the default path is the hard guarantee. Mirror of `resolvedAskUserProviderId`: the
25
+ * own footer — the default path is the hard guarantee. Mirror of `resolvedPlanProviderId`: the
26
26
  * catch narrows to genuine file-read/parse failures (the resolver is per-seam fail-open) and is
27
27
  * logged, never silent.
28
28
  */