@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
@@ -33,14 +33,22 @@ 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;
39
45
  last_review_batch?: unknown;
40
46
  /**
41
47
  * The last `/pr-review` outcome posted via the `post_pr_review` warm tool (§8.3):
42
- * `{pr, verdict, angles, comment_count, mode, at}`. Best-effort tier (per-field LWW in
43
- * `rebuildWorkflowState`, no rebuild change). The PR comment stays canonical.
48
+ * `{pr, verdict, angles, covered_angles, comment_count, mode, at}`. After a recorded wave,
49
+ * `angles` is the authoritative attempted manifest and `covered_angles` is its schema-valid
50
+ * subset; standalone posts use the caller's `angles` for both. Best-effort tier (per-field LWW
51
+ * in `rebuildWorkflowState`, no rebuild change). The PR comment stays canonical.
44
52
  */
45
53
  last_pr_review?: unknown;
46
54
  /**
@@ -58,6 +66,15 @@ export interface WorkflowState {
58
66
  * node and after a successful node-linked plan save. Best-effort tier.
59
67
  */
60
68
  objective_node_claim?: { objective: string; node: string } | null;
69
+ /**
70
+ * The dream-wave finalized-bundle digest marker (§8.61) — the freshness/integrity authority
71
+ * the dream-report recovery (§8.63) trusts over the bare run-scratch bundle file. `""` =
72
+ * invalidated (cleared unconditionally at wave entry BEFORE the stale-bundle removal attempt,
73
+ * so a failed cleanup leaves prior files behind but recovery refuses them); `sha256:<hex>` =
74
+ * the digest of the current finalized bundle bytes, set only after a successful finalize
75
+ * write. Per-field LWW; no rebuild change.
76
+ */
77
+ dream_bundle_digest?: string;
61
78
  /**
62
79
  * The bounded conflict-resolution re-drive counter (§8.3). Incremented each time
63
80
  * `/submit` drives the `perk.conflict-resolver` subagent on a definitively-unmergeable PR;
@@ -72,6 +89,8 @@ export interface BranchEntry {
72
89
  type: string;
73
90
  customType?: string;
74
91
  data?: Record<string, unknown>;
92
+ /** Present on Pi custom_message entries (hidden model-context messages). */
93
+ content?: unknown;
75
94
  }
76
95
 
77
96
  /** The minimal read-only session surface the branch accessor needs. */
@@ -101,6 +120,35 @@ export function branchCarries(branch: readonly BranchEntry[], needle: string): b
101
120
  return branch.some((entry) => JSON.stringify(entry).includes(needle));
102
121
  }
103
122
 
123
+ /**
124
+ * The branch entries still represented directly in model context. Before compaction that is the
125
+ * full branch. After compaction, Pi keeps entries from `firstKeptEntryId` onward plus anything
126
+ * appended later; historical entries before that cutoff survive only through the summary.
127
+ * Compaction entries are excluded because text quoted by a summary is not a live custom block.
128
+ */
129
+ export function activeContextWindow(branch: readonly BranchEntry[]): BranchEntry[] {
130
+ let latestCompaction = -1;
131
+ for (let i = branch.length - 1; i >= 0; i--) {
132
+ if (branch[i]?.type === "compaction") {
133
+ latestCompaction = i;
134
+ break;
135
+ }
136
+ }
137
+ if (latestCompaction === -1) return [...branch];
138
+
139
+ const firstKeptEntryId = (branch[latestCompaction] as { firstKeptEntryId?: unknown })
140
+ .firstKeptEntryId;
141
+ const firstKept =
142
+ typeof firstKeptEntryId === "string"
143
+ ? branch.findIndex(
144
+ (entry, index) =>
145
+ index < latestCompaction && (entry as { id?: unknown }).id === firstKeptEntryId,
146
+ )
147
+ : -1;
148
+ const start = firstKept === -1 ? latestCompaction + 1 : firstKept;
149
+ return branch.slice(start).filter((entry) => entry.type !== "compaction");
150
+ }
151
+
104
152
  /**
105
153
  * Per-field last-write-wins over the `perk:workflow-state` custom entries on a branch.
106
154
  * Non-perk entries are ignored; `undefined` fields never clobber (but explicit `null` does).
@@ -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
  */
@@ -1,20 +1,39 @@
1
- // The one headless-safe report seam — owns the `perk: <scope> — <message>` prefix, the severity,
2
- // and the `hasUI ? notify : console.error` routing so callers inherit the headless-fail-safe
3
- // invariant for free (cf. the `branchOf`/`BranchSource` seam in workflowState.ts).
1
+ // The one terminal-safe report seam — owns the `perk: <scope> — <message>` prefix, the severity,
2
+ // and the projection of complete diagnostics into a managed headline plus an optional durable detail
3
+ // sink (cf. the `branchOf`/`BranchSource` seam in workflowState.ts).
4
4
 
5
5
  export type Severity = "info" | "warning" | "error";
6
+ export type ReportDetailSink = (text: string, severity: Severity) => void;
6
7
 
7
8
  /** The minimal headless-aware surface report() needs. `ExtensionContext` satisfies it; tests fake it. */
8
9
  export interface ReportTarget {
9
10
  hasUI: boolean;
11
+ mode?: "tui" | "rpc" | "json" | "print";
10
12
  ui: { notify(message: string, type?: Severity): void };
11
13
  }
12
14
 
15
+ const detailSinks = new WeakMap<ReportTarget, ReportDetailSink>();
16
+ const LOGICAL_LINE = /\r\n|\n|\r/;
17
+ const HORIZONTAL_WHITESPACE = /[^\S\r\n]+/g;
18
+
19
+ /** Attach display-only multiline report detail to this exact context object. */
20
+ export function attachReportDetailSink(target: ReportTarget, sink: ReportDetailSink): void {
21
+ detailSinks.set(target, sink);
22
+ }
23
+
24
+ function headlineFor(prefix: string, message: string): string {
25
+ for (const line of message.split(LOGICAL_LINE)) {
26
+ const trimmed = line.trim();
27
+ if (trimmed.length > 0) return `${prefix}${trimmed.replace(HORIZONTAL_WHITESPACE, " ")}`;
28
+ }
29
+ return prefix;
30
+ }
31
+
13
32
  /**
14
- * The single headless-safe report seam. Builds `perk: <scope> — <message>`, notifies the UI when
15
- * present and otherwise writes to stderr (the headless-fail-safe invariant callers inherit it for
16
- * free). Pass { alsoLog: true } to ALSO write to stderr when headful (cold-door failures land in run
17
- * logs even in a TUI). Returns the prefixed string for reuse (tool-result text, etc.).
33
+ * Build and return the complete `perk: <scope> — <message>` value. Headless targets receive that
34
+ * value on stderr. Headful targets receive a managed one-line headline; multiline detail goes to an
35
+ * attached display-only sink in every non-RPC mode. `{ alsoLog: true }` is narrowly an RPC/headless
36
+ * diagnostic mirror and never permits raw terminal output in a headful non-RPC context.
18
37
  */
19
38
  export function report(
20
39
  target: ReportTarget,
@@ -23,12 +42,19 @@ export function report(
23
42
  message: string,
24
43
  opts?: { alsoLog?: boolean },
25
44
  ): string {
26
- const full = `perk: ${scope} — ${message}`;
27
- if (target.hasUI) {
28
- target.ui.notify(full, severity);
29
- if (opts?.alsoLog) console.error(full);
30
- } else {
45
+ const prefix = `perk: ${scope} — `;
46
+ const full = `${prefix}${message}`;
47
+ if (!target.hasUI) {
31
48
  console.error(full);
49
+ return full;
32
50
  }
51
+
52
+ target.ui.notify(headlineFor(prefix, message), severity);
53
+ if (target.mode === "rpc") {
54
+ if (opts?.alsoLog) console.error(full);
55
+ return full;
56
+ }
57
+
58
+ if (message.split(LOGICAL_LINE).length > 1) detailSinks.get(target)?.(full, severity);
33
59
  return full;
34
60
  }