@mgiles/perk 2.3.0 → 3.1.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 (145) hide show
  1. package/README.md +1 -1
  2. package/extension/adapters/planAdapterPlannotator.ts +135 -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/commitCompact.ts +98 -10
  9. package/extension/doors/draftReviewWaveTools.ts +412 -0
  10. package/extension/doors/dreamWaveTools.ts +475 -0
  11. package/extension/doors/harvestWaveTools.ts +279 -0
  12. package/extension/doors/land.ts +1 -0
  13. package/extension/doors/learn.ts +24 -6
  14. package/extension/doors/learnFactory.ts +33 -7
  15. package/extension/doors/lifecycleGates.ts +1 -1
  16. package/extension/doors/objectiveReviewBrowser.ts +537 -0
  17. package/extension/doors/objectiveStack.ts +1143 -0
  18. package/extension/doors/planReviewBrowser.ts +475 -0
  19. package/extension/doors/plannotatorHandoff.ts +120 -49
  20. package/extension/doors/prReview.ts +180 -63
  21. package/extension/doors/prReviewBrowser.ts +31 -23
  22. package/extension/doors/prReviewDynamic.ts +57 -30
  23. package/extension/doors/prReviewTerminal.ts +6 -11
  24. package/extension/doors/reviewWaveTools.ts +397 -0
  25. package/extension/doors/selfcheck.ts +1 -1
  26. package/extension/doors/submit.ts +82 -7
  27. package/extension/factories/gistAuthor.ts +4 -4
  28. package/extension/factories/gistDraft.ts +1 -1
  29. package/extension/factories/gistSave.ts +2 -2
  30. package/extension/factories/objective.ts +7 -7
  31. package/extension/factories/objectiveAuthor.ts +5 -4
  32. package/extension/factories/objectiveDraft.ts +153 -30
  33. package/extension/factories/objectiveDreamReport.ts +347 -0
  34. package/extension/factories/objectivePlan.ts +163 -9
  35. package/extension/factories/objectiveSave.ts +90 -2
  36. package/extension/factories/planMode.ts +5 -3
  37. package/extension/factories/planReview.ts +304 -46
  38. package/extension/factories/planTitle.ts +27 -9
  39. package/extension/hunkFeedback/inbox.ts +389 -0
  40. package/extension/hunkFeedback/perkFeedback.ts +364 -0
  41. package/extension/hunkFeedback/receiver.ts +296 -0
  42. package/extension/hunkFeedback/store.ts +533 -0
  43. package/extension/index.ts +169 -57
  44. package/extension/substrate/agentScratch.ts +171 -0
  45. package/extension/substrate/bindingDelivery.ts +9 -11
  46. package/extension/substrate/cache.ts +166 -23
  47. package/extension/substrate/coldDoor.ts +2 -3
  48. package/extension/substrate/command.ts +9 -6
  49. package/extension/substrate/config.ts +41 -12
  50. package/extension/substrate/git.ts +95 -2
  51. package/extension/substrate/providers.ts +4 -33
  52. package/extension/substrate/resources.ts +11 -0
  53. package/extension/substrate/result.ts +16 -7
  54. package/extension/substrate/sessionData.ts +8 -6
  55. package/extension/substrate/sessionPointers.ts +4 -5
  56. package/extension/substrate/structuredOutput.ts +78 -19
  57. package/extension/substrate/toolGating.ts +179 -23
  58. package/extension/substrate/workflowState.ts +50 -2
  59. package/extension/surfaces/footerProvider.ts +6 -6
  60. package/extension/surfaces/report.ts +38 -12
  61. package/extension/surfaces/surfaces.ts +213 -275
  62. package/extension/vendor/btw/btw.ts +94 -17
  63. package/extension/waves/adversarialReviewWave.ts +181 -0
  64. package/extension/waves/auditWave.ts +312 -0
  65. package/extension/waves/draftReviewWave.ts +205 -0
  66. package/extension/waves/dreamReducerWave.ts +700 -0
  67. package/extension/waves/dreamReport.ts +1494 -0
  68. package/extension/waves/dreamWave.ts +927 -0
  69. package/extension/waves/harvestWave.ts +399 -0
  70. package/extension/waves/memoryAdapter.ts +14 -1
  71. package/extension/waves/objectiveExplorerWave.ts +120 -0
  72. package/extension/waves/ponytail.ts +104 -0
  73. package/extension/waves/prReviewDynamicWave.ts +383 -72
  74. package/extension/waves/prReviewWave.ts +175 -25
  75. package/extension/waves/reportWave.ts +503 -107
  76. package/extension/waves/reviewClassifierWave.ts +109 -0
  77. package/extension/waves/rpcAdapter.ts +65 -2
  78. package/extension/worker/readOnlySession.ts +4 -5
  79. package/extension/worker/worker.ts +71 -93
  80. package/extension/workerMain.ts +4 -6
  81. package/package.json +18 -5
  82. package/prompts/README.md +19 -0
  83. package/prompts/_fixtures/live.yaml +115 -65
  84. package/prompts/commit-and-compact-continuation.md +13 -0
  85. package/prompts/common/resume-advisory.md +1 -0
  86. package/prompts/contexts/adapters/plannotator-gist.md +13 -0
  87. package/prompts/contexts/adapters/plannotator-objective.md +8 -3
  88. package/prompts/contexts/adapters/plannotator-plan.md +8 -3
  89. package/prompts/contexts/gist-authoring.md +6 -20
  90. package/prompts/contexts/objective-authoring.md +6 -18
  91. package/prompts/stages/address/action.md +3 -14
  92. package/prompts/stages/address/preview.md +2 -13
  93. package/prompts/stages/audit.md +18 -0
  94. package/prompts/stages/conflict-resolution.md +1 -1
  95. package/prompts/stages/gist-author/seed.md +4 -4
  96. package/prompts/stages/gist-save.md +1 -1
  97. package/prompts/stages/implement.md +3 -1
  98. package/prompts/stages/learn-code.md +1 -1
  99. package/prompts/stages/learn-docs.md +2 -2
  100. package/prompts/stages/learn-dream.md +10 -0
  101. package/prompts/stages/learn-harvest.md +15 -0
  102. package/prompts/stages/learn-orchestrate.md +1 -1
  103. package/prompts/stages/objective-author/adopt.md +5 -3
  104. package/prompts/stages/objective-author/file.md +5 -4
  105. package/prompts/stages/objective-author/seed.md +5 -4
  106. package/prompts/stages/objective-land.md +7 -0
  107. package/prompts/stages/objective-plan/guidance.md +2 -13
  108. package/prompts/stages/objective-plan/seed.md +5 -12
  109. package/prompts/stages/objective-recover.md +8 -0
  110. package/prompts/stages/objective-replan.md +4 -2
  111. package/prompts/stages/objective-review-browser.md +9 -0
  112. package/prompts/stages/objective-sync.md +6 -0
  113. package/prompts/stages/plan-from/adopt.md +2 -2
  114. package/prompts/stages/plan-from/file.md +2 -2
  115. package/prompts/stages/plan-review-browser.md +9 -0
  116. package/prompts/stages/pr-review-browser/active.md +6 -14
  117. package/prompts/stages/pr-review-browser/foreign.md +6 -14
  118. package/prompts/stages/pr-review-dynamic.md +6 -6
  119. package/prompts/stages/pr-review-terminal/active.md +7 -15
  120. package/prompts/stages/pr-review-terminal/foreign.md +7 -15
  121. package/prompts/stages/pr-review-terminal/local.md +1 -1
  122. package/prompts/stages/pr-review.md +5 -5
  123. package/prompts/stages/replan.md +3 -3
  124. package/shared/README.md +2 -2
  125. package/shared/bindings.yaml +15 -0
  126. package/shared/contracts-history.md +11 -0
  127. package/shared/contracts.md +5373 -281
  128. package/shared/providers.yaml +27 -60
  129. package/shared/registry.yaml +42 -18
  130. package/shared/schemas/inputs/review-post-batch.schema.json +14 -1
  131. package/shared/schemas/outputs/objective-doctor.schema.json +487 -0
  132. package/shared/schemas/outputs/objective-stack-land.schema.json +732 -0
  133. package/shared/schemas/outputs/objective-stack-recover.schema.json +397 -0
  134. package/shared/schemas/outputs/objective-stack-status.schema.json +577 -0
  135. package/shared/schemas/outputs/objective-stack-sync.schema.json +184 -0
  136. package/shared/schemas/outputs/plan-save.schema.json +12 -0
  137. package/shared/schemas/outputs/pr-land.schema.json +3 -3
  138. package/shared/schemas/outputs/pr-submit.schema.json +177 -1
  139. package/extension/adapters/todoAdapterJuicesharp.ts +0 -102
  140. package/extension/checkpoints/checkpoints.ts +0 -550
  141. package/extension/checkpoints/planSteps.ts +0 -108
  142. package/extension/doors/askUser.ts +0 -198
  143. package/prompts/common/output-schemas/objective-explorer.md +0 -36
  144. package/prompts/common/output-schemas/review-classifier.md +0 -47
  145. package/prompts/contexts/adapters/juicesharp-todo.md +0 -7
@@ -15,8 +15,10 @@
15
15
  // FAILSAFE invocation of the same seam, keeping the legacy drive-the-session behavior as the
16
16
  // no-draft fallback (objectives have no transcript scrape by design).
17
17
 
18
+ import { join } from "node:path";
18
19
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
19
20
  import { bindingSuffix } from "../substrate/bindingDelivery.ts";
21
+ import { atomicWriteFileSync, ensureRunScratch } from "../substrate/cache.ts";
20
22
  import {
21
23
  booleanField,
22
24
  type ColdJson,
@@ -32,10 +34,25 @@ import { appendWorkflowState, branchOf, rebuildWorkflowState } from "../substrat
32
34
  import { report, type Severity } from "../surfaces/report.ts";
33
35
  import { OBJECTIVE_BUDGET_TYPE } from "./objective.ts";
34
36
  import {
37
+ DELIVERY_PARAM_SCHEMA,
38
+ type DeliveryChoice,
39
+ DREAM_REPORT_PARAM_SCHEMA,
35
40
  decodeObjectiveSaveParams,
36
41
  ROADMAP_PARAM_SCHEMA,
37
42
  readObjectiveDraft,
38
43
  } from "./objectiveDraft.ts";
44
+ import { resolveDreamReportGate } from "./objectiveDreamReport.ts";
45
+
46
+ /** The `objective-save` registry stage id (the objectiveAuthor.ts constant's sibling). */
47
+ export const OBJECTIVE_SAVE_STAGE = "objective-save";
48
+
49
+ /**
50
+ * The run-scoped dream-report transfer filename (contracts §8.64) — the extension→door handoff
51
+ * carrying the reviewed CANONICAL parts. The Python mirror is
52
+ * `perk.learn.dream_companion.DREAM_REPORT_TRANSFER_FILENAME` (parity-pinned by test), beside
53
+ * the existing `DREAM_MANIFEST_FILENAME` mirror pair.
54
+ */
55
+ export const DREAM_REPORT_TRANSFER_FILENAME = "dream-report-transfer.json";
39
56
 
40
57
  /** The ok-arm fields — the structured `details` surface doubles as branch-safe persisted state. */
41
58
  export interface ObjectiveSaveOk {
@@ -65,11 +82,25 @@ function decodeObjectiveCreate(payload: ColdJson): ObjectiveCreatePayload | null
65
82
  * The single save implementation both surfaces call. Delegates the GitHub write to the Python cold
66
83
  * door, then links the live session (`active_objective` + budget marker). Returns a soft result
67
84
  * (never throws); failures set `details.ok = false` and append no linkage.
85
+ *
86
+ * `dream_report` is ONE carrier with two sources (§8.63): the direct tool path supplies
87
+ * `{input}` and the save stamps `generated_at`; the approval path passes the artifact block
88
+ * through with its stored stamp AND stored parts — the stored parts are byte-compared against
89
+ * the freshly re-rendered ones, so run-scratch drift or artifact tamper between draft-write
90
+ * and save refuses `bad_state` (nothing saved, the gate stays on). The parts do NOT cross to
91
+ * the Python plane yet — companion persistence is deferred (explicit in §8.63, not silent).
68
92
  */
69
93
  export async function saveObjective(
70
94
  pi: ExtensionAPI,
71
95
  ctx: ExtensionContext,
72
- opts: { prose: string; title?: string; roadmap?: unknown[]; base?: string },
96
+ opts: {
97
+ prose: string;
98
+ title?: string;
99
+ roadmap?: unknown[];
100
+ base?: string;
101
+ delivery?: DeliveryChoice;
102
+ dream_report?: { input: unknown; generated_at?: string; parts?: string[] };
103
+ },
73
104
  ): Promise<ObjectiveSaveResult> {
74
105
  const fail = failFor(ctx, "objective-save");
75
106
 
@@ -80,12 +111,57 @@ export async function saveObjective(
80
111
  return fail("roadmap must be a JSON array of nodes", "invalid_input");
81
112
  }
82
113
 
114
+ // The §8.63 fail-closed re-validation, before anything reaches the cold door. Presence is
115
+ // the `opts.dream_report === undefined` boundary — an `{input: undefined}` carrier is never
116
+ // constructed (the execute wraps only a present decoded value; the approval path passes the
117
+ // validated artifact block).
118
+ const generatedAt = opts.dream_report?.generated_at ?? new Date().toISOString();
119
+ const gate =
120
+ opts.dream_report === undefined
121
+ ? resolveDreamReportGate(ctx, undefined, generatedAt)
122
+ : resolveDreamReportGate(ctx, opts.dream_report.input, generatedAt);
123
+ if (gate.kind === "refuse") {
124
+ return fail(gate.detail, gate.errorType);
125
+ }
126
+ if (gate.kind === "block" && opts.dream_report?.parts !== undefined) {
127
+ // The approval path: the reviewed (stored) parts must byte-match the re-render against
128
+ // freshly recovered context — the same stored `generated_at` stamp keeps the comparison
129
+ // deterministic.
130
+ if (JSON.stringify(gate.block.parts) !== JSON.stringify(opts.dream_report.parts)) {
131
+ return fail(
132
+ "the reviewed report no longer matches the wave state — re-draft and re-review",
133
+ "bad_state",
134
+ );
135
+ }
136
+ }
137
+
83
138
  const branch = () => branchOf(ctx);
84
139
  const runId = rebuildWorkflowState(branch()).run_id ?? "";
85
140
 
141
+ if (gate.kind === "block") {
142
+ // The §8.64 transfer write (the dream arm only): the reviewed CANONICAL parts cross to the
143
+ // Python save door through the run-scoped scratch handoff — written atomically BEFORE the
144
+ // cold door is invoked. A write failure is the soft `scratch_failed` failure (the
145
+ // runColdDoor stdin-staging precedent): the cold door is NOT invoked, nothing activates,
146
+ // and the read-only gate stays on. Non-dream saves write nothing (byte-identical).
147
+ try {
148
+ const dir = ensureRunScratch(ctx.cwd, runId);
149
+ const content = `${JSON.stringify(
150
+ { schema_version: "1", run_id: runId, parts: gate.block.parts },
151
+ null,
152
+ 2,
153
+ )}\n`;
154
+ atomicWriteFileSync(join(dir, DREAM_REPORT_TRANSFER_FILENAME), content);
155
+ } catch (err) {
156
+ return fail(`could not stage the dream-report transfer: ${String(err)}`, "scratch_failed");
157
+ }
158
+ }
159
+
86
160
  const args = ["objective", "create", "--json"];
87
161
  if (opts.title) args.push("--title", opts.title);
88
162
  if (opts.base) args.push("--base", opts.base);
163
+ // The reviewed delivery choice rides verbatim; the cold door owns validation + preflight.
164
+ if (opts.delivery) args.push("--delivery", opts.delivery);
89
165
  if (runId) args.push("--run-id", runId);
90
166
  if (opts.roadmap && opts.roadmap.length > 0) {
91
167
  args.push("--roadmap", JSON.stringify(opts.roadmap));
@@ -161,6 +237,10 @@ export async function objectiveApprovalSave(
161
237
  title: opts.title ?? draft.title,
162
238
  roadmap: draft.roadmap,
163
239
  base: draft.base,
240
+ delivery: draft.delivery,
241
+ // The approval path passes the artifact block through whole — stored stamp + stored parts
242
+ // (the save re-validates and byte-compares, §8.63).
243
+ ...(draft.dream_report !== undefined ? { dream_report: draft.dream_report } : {}),
164
244
  });
165
245
  let gateExited = false;
166
246
  if (result.details.ok && wasReadOnly) {
@@ -216,6 +296,8 @@ export function registerObjectiveSave(pi: ExtensionAPI, gating: ToolGating): voi
216
296
  description:
217
297
  "Optional target branch for this objective's plans (omit to use the repo default).",
218
298
  },
299
+ delivery: DELIVERY_PARAM_SCHEMA,
300
+ dream_report: DREAM_REPORT_PARAM_SCHEMA,
219
301
  roadmap: {
220
302
  type: "array",
221
303
  description:
@@ -236,7 +318,13 @@ export function registerObjectiveSave(pi: ExtensionAPI, gating: ToolGating): voi
236
318
  "bad_input",
237
319
  );
238
320
  }
239
- return saveObjective(pi, ctx, decoded);
321
+ // The direct tool path wraps ONLY a present decoded value as the `{input}` carrier (the
322
+ // save stamps generated_at); no stored parts, so no byte-compare on this path.
323
+ const { dream_report, ...rest } = decoded;
324
+ return saveObjective(pi, ctx, {
325
+ ...rest,
326
+ ...(dream_report !== undefined ? { dream_report: { input: dream_report } } : {}),
327
+ });
240
328
  },
241
329
  });
242
330
 
@@ -13,7 +13,7 @@
13
13
  //
14
14
  // Grounded in pi's official `examples/extensions/plan-mode/` recipe, but perk adopts ONLY the
15
15
  // read-only authoring half: there is no in-session "execution mode" flip — perk separates plan
16
- // (read-only session) from implement (cold-door fresh worktree session), and `[DONE:n]` tracking
16
+ // (read-only session) from implement (cold-door fresh worktree session), and progress tracking
17
17
  // lives in the implement session.
18
18
  //
19
19
  // REGISTRATION-TIME DEFERRAL, now THREE-TIER. `registerPlanMode` resolves the plan
@@ -56,8 +56,10 @@ const PLAN_MARKER = "[PLAN AUTHORING]";
56
56
  /**
57
57
  * The cooperative gather-then-plan contract. This is prompting, NOT enforcement (the gate is the
58
58
  * enforcement). It never leaks internal policy text — it tells the model how to materialize a
59
- * decision-complete plan an executor with zero prior context can follow (mirrors
60
- * skills/perk-plan/SKILL.md). Durable anchors only, no line numbers.
59
+ * decision-complete plan an executor with zero prior context can follow. Per contracts.md §8.57
60
+ * this mode context is the plan stage's DESIGNATED FLOW CARRIER in every plan-stage session
61
+ * shape (seeded doors carry launch-shape deltas only; the `perk-plan` skill is the detail tier).
62
+ * Durable anchors only, no line numbers.
61
63
  */
62
64
  export const PLAN_AUTHORING_CONTEXT = render("contexts/plan-authoring.md", {
63
65
  marker: PLAN_MARKER,