@mgiles/perk 3.1.0 → 3.3.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 (211) hide show
  1. package/README.md +5 -0
  2. package/extension/authoring/gist/draft.ts +198 -0
  3. package/extension/authoring/gist/prose.ts +46 -0
  4. package/extension/authoring/gist/review.ts +133 -0
  5. package/extension/authoring/gist/save.ts +118 -0
  6. package/extension/authoring/objective/draft.ts +345 -0
  7. package/extension/{factories/objectiveDreamReport.ts → authoring/objective/dreamReportGate.ts} +74 -131
  8. package/extension/authoring/objective/planning.ts +124 -0
  9. package/extension/authoring/objective/prose.ts +103 -0
  10. package/extension/authoring/objective/review.ts +128 -0
  11. package/extension/authoring/objective/save.ts +224 -0
  12. package/extension/authoring/plan/draft.ts +84 -0
  13. package/extension/authoring/plan/prose.ts +41 -0
  14. package/extension/authoring/plan/review.ts +269 -0
  15. package/extension/authoring/plan/save.ts +256 -0
  16. package/extension/authoring/plan/source.ts +82 -0
  17. package/extension/authoring/refinement/context.ts +468 -0
  18. package/extension/authoring/refinement/draft.ts +261 -0
  19. package/extension/authoring/refinement/prose.ts +79 -0
  20. package/extension/authoring/refinement/review.ts +111 -0
  21. package/extension/authoring/refinement/save.ts +119 -0
  22. package/extension/authoring/review/approvalGate.ts +34 -0
  23. package/extension/authoring/review/draftContext.ts +68 -0
  24. package/extension/codeReview/automated.ts +352 -0
  25. package/extension/codeReview/submission.ts +229 -0
  26. package/extension/delivery/address.ts +295 -0
  27. package/extension/delivery/ci.ts +355 -0
  28. package/extension/delivery/commitCompact.ts +93 -0
  29. package/extension/delivery/conflictResolution.ts +247 -0
  30. package/extension/delivery/ready.ts +193 -0
  31. package/extension/delivery/stackConflict.ts +361 -0
  32. package/extension/delivery/stackObjective.ts +16 -0
  33. package/extension/delivery/stackReconcile.ts +165 -0
  34. package/extension/delivery/submit.ts +171 -0
  35. package/extension/index.ts +369 -359
  36. package/extension/learning/analystWave.ts +324 -0
  37. package/extension/learning/audit.ts +667 -0
  38. package/extension/learning/capture.ts +92 -0
  39. package/extension/learning/containment.ts +104 -0
  40. package/extension/{waves/dreamWave.ts → learning/dream.ts} +112 -94
  41. package/extension/learning/dreamAnalysis.ts +435 -0
  42. package/extension/{waves/dreamReducerWave.ts → learning/dreamReducer.ts} +46 -41
  43. package/extension/{waves → learning}/dreamReport.ts +35 -31
  44. package/extension/learning/harvest.ts +491 -0
  45. package/extension/learning/prose.ts +66 -0
  46. package/extension/learning/routing.ts +79 -0
  47. package/extension/pi/v1/bashScanTimeout.ts +64 -0
  48. package/extension/{doors/prReview.ts → pi/v1/codeReview/automated.ts} +215 -310
  49. package/extension/{doors/prReviewBrowser.ts → pi/v1/codeReview/browser.ts} +125 -57
  50. package/extension/{doors/hunkHandoff.ts → pi/v1/codeReview/checkout.ts} +12 -8
  51. package/extension/{doors/reviewWaveTools.ts → pi/v1/codeReview/reviewWave.ts} +169 -116
  52. package/extension/pi/v1/codeReview/stack.ts +606 -0
  53. package/extension/pi/v1/codeReview/submit.ts +354 -0
  54. package/extension/{doors/prReviewTerminal.ts → pi/v1/codeReview/terminal.ts} +32 -27
  55. package/extension/pi/v1/contextEvidence.ts +80 -0
  56. package/extension/pi/v1/contextInjection.ts +207 -0
  57. package/extension/{doors → pi/v1/delivery}/address.ts +163 -265
  58. package/extension/pi/v1/delivery/ci.ts +570 -0
  59. package/extension/pi/v1/delivery/commitCompact.ts +201 -0
  60. package/extension/pi/v1/delivery/conflictResolverEngine.ts +425 -0
  61. package/extension/{doors → pi/v1/delivery}/land.ts +128 -60
  62. package/extension/pi/v1/delivery/ready.ts +322 -0
  63. package/extension/pi/v1/delivery/stackConflictResolver.ts +172 -0
  64. package/extension/pi/v1/delivery/stackDrive.ts +120 -0
  65. package/extension/pi/v1/delivery/stackLand.ts +223 -0
  66. package/extension/pi/v1/delivery/stackRecover.ts +265 -0
  67. package/extension/pi/v1/delivery/stackStatus.ts +237 -0
  68. package/extension/pi/v1/delivery/stackSync.ts +658 -0
  69. package/extension/pi/v1/delivery/submit.ts +389 -0
  70. package/extension/pi/v1/delivery/submitConflict.ts +186 -0
  71. package/extension/pi/v1/draftReview.ts +431 -0
  72. package/extension/{doors → pi/v1}/draftReviewWaveTools.ts +141 -151
  73. package/extension/pi/v1/gist.ts +794 -0
  74. package/extension/pi/v1/learning/audit.ts +186 -0
  75. package/extension/pi/v1/learning/dream.ts +207 -0
  76. package/extension/{doors/learnFactory.ts → pi/v1/learning/factory.ts} +18 -65
  77. package/extension/{doors/harvestWaveTools.ts → pi/v1/learning/harvest.ts} +46 -100
  78. package/extension/pi/v1/learning/learn.ts +585 -0
  79. package/extension/{doors → pi/v1}/lifecycleGates.ts +14 -59
  80. package/extension/{factories → pi/v1}/objective.ts +53 -33
  81. package/extension/pi/v1/objectiveAuthoring.ts +672 -0
  82. package/extension/pi/v1/objectiveDreamGate.ts +160 -0
  83. package/extension/pi/v1/objectivePlanning.ts +776 -0
  84. package/extension/pi/v1/objectiveRefinement.ts +1320 -0
  85. package/extension/pi/v1/objectiveReview.ts +451 -0
  86. package/extension/{doors → pi/v1}/objectiveReviewBrowser.ts +259 -172
  87. package/extension/pi/v1/plan.ts +812 -0
  88. package/extension/pi/v1/planReview.ts +820 -0
  89. package/extension/{doors → pi/v1}/planReviewBrowser.ts +228 -152
  90. package/extension/{doors/annotationPush.ts → pi/v1/providers/annotations.ts} +158 -89
  91. package/extension/pi/v1/providers/plannotator.ts +487 -0
  92. package/extension/{doors → pi/v1/providers}/plannotatorHandoff.ts +152 -34
  93. package/extension/pi/v1/providers/selection.ts +43 -0
  94. package/extension/{adapters/planAdapterTombell.ts → pi/v1/providers/tombell.ts} +43 -72
  95. package/extension/pi/v1/review.ts +538 -0
  96. package/extension/pi/v1/reviewOutcome.ts +9 -0
  97. package/extension/pi/v1/scoutWave.ts +318 -0
  98. package/extension/{doors → pi/v1}/selfcheck.ts +4 -4
  99. package/extension/session/branchWorkflowSession.ts +60 -0
  100. package/extension/session/lifecycle.ts +644 -0
  101. package/extension/session/lifecycleGates.ts +64 -0
  102. package/extension/session/saveDestination.ts +87 -0
  103. package/extension/session/workflowSession.ts +971 -0
  104. package/extension/substrate/agentScratch.ts +27 -54
  105. package/extension/substrate/bashScanTimeout.ts +181 -0
  106. package/extension/substrate/bindingDelivery.ts +38 -30
  107. package/extension/substrate/bindings.ts +4 -5
  108. package/extension/substrate/cache.ts +64 -12
  109. package/extension/substrate/childRestrictions.ts +39 -0
  110. package/extension/substrate/coldDoor.ts +17 -1
  111. package/extension/substrate/config.ts +157 -19
  112. package/extension/substrate/git.ts +88 -6
  113. package/extension/substrate/modelVisible.ts +53 -0
  114. package/extension/substrate/paths.ts +2 -7
  115. package/extension/substrate/prompts.ts +22 -0
  116. package/extension/substrate/registry.ts +2 -0
  117. package/extension/substrate/resolverLease.ts +364 -0
  118. package/extension/substrate/sessionData.ts +85 -152
  119. package/extension/substrate/toolGating.ts +279 -84
  120. package/extension/substrate/unifiedDiff.ts +1 -1
  121. package/extension/substrate/workflowState.ts +191 -166
  122. package/extension/substrate/worktreeResolverLock.ts +261 -0
  123. package/extension/surfaces/surfaces.ts +79 -27
  124. package/extension/waves/adversarialReviewWave.ts +103 -48
  125. package/extension/waves/blockedReports.ts +59 -0
  126. package/extension/waves/draftReviewWave.ts +42 -42
  127. package/extension/waves/laneIdentity.ts +77 -0
  128. package/extension/waves/objectiveExplorerWave.ts +24 -24
  129. package/extension/waves/prReviewWave.ts +89 -77
  130. package/extension/waves/reportWave.ts +438 -578
  131. package/extension/waves/reviewClassifierWave.ts +22 -22
  132. package/extension/waves/rpcAdapter.ts +100 -15
  133. package/extension/waves/scoutWave.ts +192 -0
  134. package/extension/waves/transport.ts +480 -0
  135. package/extension/worker/sdkAdapter.ts +494 -0
  136. package/extension/worker/stageExecution.ts +679 -0
  137. package/extension/workerMain.ts +18 -19
  138. package/package.json +6 -4
  139. package/prompts/_fixtures/live.yaml +98 -10
  140. package/prompts/contexts/adapters/plannotator-gist.md +6 -0
  141. package/prompts/contexts/adapters/plannotator-objective.md +6 -0
  142. package/prompts/contexts/adapters/plannotator-plan.md +8 -1
  143. package/prompts/contexts/adapters/plannotator-refinement.md +22 -0
  144. package/prompts/contexts/adapters/tombell-plan.md +4 -0
  145. package/prompts/contexts/objective-refinement.md +17 -0
  146. package/prompts/contexts/plan-authoring.md +6 -5
  147. package/prompts/contexts/read-only.md +1 -1
  148. package/prompts/stages/conflict-resolution-continuation.md +9 -0
  149. package/prompts/stages/conflict-resolution.md +4 -4
  150. package/prompts/stages/objective-author/adopt.md +1 -1
  151. package/prompts/stages/objective-author/file.md +1 -1
  152. package/prompts/stages/objective-author/seed.md +1 -1
  153. package/prompts/stages/objective-plan/guidance.md +2 -2
  154. package/prompts/stages/objective-plan/seed.md +9 -1
  155. package/prompts/stages/objective-reconcile-ready.md +7 -0
  156. package/prompts/stages/objective-reconcile.md +1 -1
  157. package/prompts/stages/objective-refine/seed.md +18 -0
  158. package/prompts/stages/objective-review-browser.md +4 -4
  159. package/prompts/stages/objective-sync.md +1 -1
  160. package/prompts/stages/plan-review-browser.md +4 -4
  161. package/prompts/stages/pr-review-browser/active.md +3 -4
  162. package/prompts/stages/pr-review-browser/foreign.md +3 -4
  163. package/prompts/stages/pr-review-terminal/active.md +3 -3
  164. package/prompts/stages/pr-review-terminal/foreign.md +3 -3
  165. package/prompts/stages/pr-review.md +3 -3
  166. package/prompts/stages/stack-review/cold.md +1 -0
  167. package/prompts/stages/stack-review-browser/stack.md +22 -0
  168. package/shared/README.md +8 -3
  169. package/shared/bindings.yaml +6 -3
  170. package/shared/contracts.md +4499 -2147
  171. package/shared/fixtures/issues-table.json +130 -0
  172. package/shared/registry.yaml +29 -1
  173. package/shared/schemas/outputs/objective-node-engagement.schema.json +318 -0
  174. package/shared/schemas/outputs/objective-stack-status.schema.json +178 -2
  175. package/shared/schemas/outputs/pr-ready.schema.json +110 -2
  176. package/shared/schemas/outputs/pr-review-context.schema.json +54 -9
  177. package/shared/schemas/outputs/pr-review-stack-context.schema.json +196 -0
  178. package/extension/adapters/planAdapterPlannotator.ts +0 -362
  179. package/extension/doors/auditWaveTools.ts +0 -352
  180. package/extension/doors/ciExecutor.ts +0 -756
  181. package/extension/doors/commitCompact.ts +0 -251
  182. package/extension/doors/dreamWaveTools.ts +0 -475
  183. package/extension/doors/learn.ts +0 -655
  184. package/extension/doors/objectiveStack.ts +0 -1143
  185. package/extension/doors/prReviewDynamic.ts +0 -276
  186. package/extension/doors/ready.ts +0 -87
  187. package/extension/doors/submit.ts +0 -347
  188. package/extension/doors/submitPrReview.ts +0 -408
  189. package/extension/factories/gistAuthor.ts +0 -94
  190. package/extension/factories/gistDraft.ts +0 -265
  191. package/extension/factories/gistSave.ts +0 -251
  192. package/extension/factories/implementHere.ts +0 -116
  193. package/extension/factories/objectiveAuthor.ts +0 -98
  194. package/extension/factories/objectiveDraft.ts +0 -466
  195. package/extension/factories/objectivePlan.ts +0 -975
  196. package/extension/factories/objectiveSave.ts +0 -363
  197. package/extension/factories/planDraft.ts +0 -140
  198. package/extension/factories/planMode.ts +0 -205
  199. package/extension/factories/planReview.ts +0 -1237
  200. package/extension/factories/planSave.ts +0 -604
  201. package/extension/factories/planTitle.ts +0 -141
  202. package/extension/substrate/structuredOutput.ts +0 -202
  203. package/extension/waves/auditWave.ts +0 -312
  204. package/extension/waves/harvestWave.ts +0 -399
  205. package/extension/waves/learnWave.ts +0 -155
  206. package/extension/waves/memoryAdapter.ts +0 -139
  207. package/extension/waves/prReviewDynamicWave.ts +0 -777
  208. package/extension/worker/readOnlySession.ts +0 -294
  209. package/extension/worker/worker.ts +0 -899
  210. package/prompts/stages/pr-review-dynamic.md +0 -7
  211. package/shared/contracts-history.md +0 -605
@@ -1,251 +0,0 @@
1
- // The warm `/commit-and-compact` door: commit the work so far, then compact the session.
2
- //
3
- // Human-only slash command (no model-facing tool twin, no cold door, no workflow-state field —
4
- // warm-plane only). The commit half needs the model (real staging judgment + a real commit
5
- // message), so the dirty arm DRIVES the session (`pi.sendUserMessage`, warm-door discipline);
6
- // the compaction half is deterministic extension work keyed on `agent_settled` (the one-shot
7
- // "the driven run fully settled" hook — `turn_end` would compact mid-run). Fail-safe posture:
8
- // never compact when uncommitted work might exist — the undeterminable-git-state and no-commit
9
- // arms skip compaction with a loud warning naming pi's builtin `/compact` escape hatch. Clean
10
- // and read-only trees compact immediately (the commit half is vacuous there).
11
- //
12
- // The pending record is in-memory by design (lost on `/reload` — the user re-runs the command);
13
- // re-invoking while a drive is in flight simply overwrites it.
14
-
15
- import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
16
- import { bindingSuffix } from "../substrate/bindingDelivery.ts";
17
- import type { PlanRef } from "../substrate/cache.ts";
18
- import { registerPerkCommand } from "../substrate/command.ts";
19
- import { commitsSince, headSha, worktreeDirty } from "../substrate/git.ts";
20
- import { render } from "../substrate/prompts.ts";
21
- import type { ToolGating } from "../substrate/toolGating.ts";
22
- import { branchOf, rebuildWorkflowState } from "../substrate/workflowState.ts";
23
- import { report, type Severity } from "../surfaces/report.ts";
24
- import { planReadInstruction } from "./lifecycleGates.ts";
25
-
26
- /** The driven-commit guidance (pure + exported for offline tests and the drive-coverage guard). */
27
- export function commitAndCompactGuidance(): string {
28
- return render("commit-and-compact.md", {});
29
- }
30
-
31
- /**
32
- * Compaction instructions for the arms with nothing to commit (read-only / clean tree). Inline,
33
- * not a `prompts/` template — compaction `customInstructions` stay inline (the objective
34
- * threshold-compaction precedent); only injected user-message prose goes to `prompts/`.
35
- */
36
- export const DIRECT_COMPACT_INSTRUCTIONS =
37
- "Preserve the current task's intent, progress so far, and the concrete next steps.";
38
-
39
- /**
40
- * Compaction instructions for the committed arm: embed the `git log --oneline` listing of the
41
- * new commit(s) so the summary references them. Pure + exported for offline tests.
42
- */
43
- export function compactInstructions(commits: string | null): string {
44
- return [
45
- "The work completed so far was just committed:",
46
- "",
47
- commits ?? "(commit list unavailable)",
48
- "",
49
- "Preserve in the summary: the task being implemented and its current progress, what the new " +
50
- "commit(s) contain, and the concrete next steps for the remaining work. The committed diff " +
51
- "is recoverable via git, so prefer intent and next steps over restating the diff.",
52
- ].join("\n");
53
- }
54
-
55
- /** The one-shot record the dirty/drive arm leaves for the `agent_settled` handler. */
56
- export interface PendingCompact {
57
- cwd: string;
58
- /** HEAD at invocation (null on an unborn HEAD) — the advance gate compares against this. */
59
- headBefore: string | null;
60
- }
61
-
62
- export type CommitCompactCompletion =
63
- | { outcome: "committed"; commits: string | null }
64
- | { outcome: "clean" }
65
- | { outcome: "read-only" };
66
-
67
- /** The door's side-effect surface — `ExtensionContext`-backed in wiring, recorder fakes in tests. */
68
- export interface CommitCompactIo {
69
- report(severity: Severity, message: string): void;
70
- send(guidance: string): void;
71
- compact(customInstructions: string, completion: CommitCompactCompletion): void;
72
- }
73
-
74
- function isNonEmptyString(value: unknown): value is string {
75
- return typeof value === "string" && value.trim() !== "";
76
- }
77
-
78
- /**
79
- * The command-specific active-plan resolver. Session-tier `active_plan_ref` is the only authority:
80
- * a checkout cache ref can select a future plan and is unrelated to this live session.
81
- */
82
- export function activeSessionPlanRef(ctx: ExtensionContext): PlanRef | null {
83
- try {
84
- const ref: unknown = rebuildWorkflowState(branchOf(ctx)).active_plan_ref;
85
- if (typeof ref !== "object" || ref === null) return null;
86
- const candidate = ref as Record<string, unknown>;
87
- if (
88
- !isNonEmptyString(candidate.provider) ||
89
- !isNonEmptyString(candidate.pr_id) ||
90
- !isNonEmptyString(candidate.url)
91
- ) {
92
- return null;
93
- }
94
- if (
95
- !Array.isArray(candidate.labels) ||
96
- !candidate.labels.every((label) => typeof label === "string")
97
- ) {
98
- return null;
99
- }
100
- if (candidate.objective_id !== null && typeof candidate.objective_id !== "string") return null;
101
- if (
102
- candidate.base !== undefined &&
103
- candidate.base !== null &&
104
- typeof candidate.base !== "string"
105
- ) {
106
- return null;
107
- }
108
- return {
109
- provider: candidate.provider,
110
- pr_id: candidate.pr_id,
111
- url: candidate.url,
112
- labels: candidate.labels,
113
- objective_id: candidate.objective_id,
114
- ...(candidate.base !== undefined ? { base: candidate.base } : {}),
115
- };
116
- } catch {
117
- return null;
118
- }
119
- }
120
-
121
- /** Render the completion-gated turn that reorients the resumed agent from repository evidence. */
122
- export function commitAndCompactContinuation(
123
- planRef: PlanRef | null,
124
- completion: CommitCompactCompletion,
125
- ): string {
126
- const provider = planRef?.provider ?? "";
127
- const planId = planRef?.pr_id ?? "";
128
- const planUrl = planRef?.url ?? "";
129
- const readCmd =
130
- planRef === null ? "" : planReadInstruction(planRef.provider, planRef.pr_id, planRef.url);
131
- return render("commit-and-compact-continuation.md", {
132
- provider,
133
- plan_id: planId,
134
- plan_url: planUrl,
135
- read_cmd: readCmd,
136
- is_github: provider === "github" ? "x" : "",
137
- committed: completion.outcome === "committed" ? "x" : "",
138
- clean: completion.outcome === "clean" ? "x" : "",
139
- read_only: completion.outcome === "read-only" ? "x" : "",
140
- commits: completion.outcome === "committed" ? (completion.commits ?? "") : "",
141
- });
142
- }
143
-
144
- /**
145
- * The invocation arms (gate → undeterminable → clean → dirty, in that order). Returns the
146
- * pending record only on the dirty/drive arm — every other arm resolves immediately.
147
- */
148
- export function startCommitAndCompact(
149
- cwd: string,
150
- gateActive: boolean,
151
- io: CommitCompactIo,
152
- ): PendingCompact | null {
153
- if (gateActive) {
154
- io.report("info", "read-only session — nothing to commit; compacting…");
155
- io.compact(DIRECT_COMPACT_INSTRUCTIONS, { outcome: "read-only" });
156
- return null;
157
- }
158
- const dirty = worktreeDirty(cwd);
159
- if (dirty === null) {
160
- // Fail-safe: never compact when uncommitted work might exist.
161
- io.report(
162
- "warning",
163
- "cannot determine the git worktree state — compaction skipped; run /compact to compact anyway.",
164
- );
165
- return null;
166
- }
167
- if (!dirty) {
168
- io.report("info", "worktree clean — nothing to commit; compacting…");
169
- io.compact(DIRECT_COMPACT_INSTRUCTIONS, { outcome: "clean" });
170
- return null;
171
- }
172
- io.report("info", "driving a commit of the work completed so far…");
173
- const headBefore = headSha(cwd);
174
- io.send(commitAndCompactGuidance());
175
- return { cwd, headBefore };
176
- }
177
-
178
- /**
179
- * The settle arms: compact only when HEAD actually advanced past the invocation-time sha;
180
- * otherwise (model declined / commit failed / HEAD unreadable) warn and skip — same fail-safe.
181
- */
182
- export function settleCommitAndCompact(pending: PendingCompact, io: CommitCompactIo): void {
183
- const headNow = headSha(pending.cwd);
184
- if (headNow === null || headNow === pending.headBefore) {
185
- io.report(
186
- "warning",
187
- "no commit was made — compaction skipped; run /compact to compact anyway.",
188
- );
189
- return;
190
- }
191
- io.report("info", "committed — compacting the session…");
192
- const commits = commitsSince(pending.cwd, pending.headBefore);
193
- io.compact(compactInstructions(commits), { outcome: "committed", commits });
194
- }
195
-
196
- /** Register the `/commit-and-compact` command + its one-shot `agent_settled` consumer. */
197
- export function registerCommitAndCompact(pi: ExtensionAPI, gating: ToolGating): void {
198
- let pending: PendingCompact | null = null;
199
-
200
- const ioFor = (ctx: ExtensionContext): CommitCompactIo => ({
201
- report: (severity, message) => {
202
- report(ctx, "commit-and-compact", severity, message);
203
- },
204
- send: (guidance) => {
205
- // The trigger lets repos bind a skill via `[[bindings]]`; drive unconditionally — report()
206
- // already carries the headless stderr fallback.
207
- pi.sendUserMessage(guidance + bindingSuffix(ctx.cwd, "command:commit-and-compact"));
208
- },
209
- compact: (customInstructions, completion) => {
210
- // Render while the command/event context is current. Manual compaction stays in the same
211
- // AgentSession + extension runner, so onComplete may use captured `pi`; it must not read
212
- // `ctx` or recompute session/filesystem state after compaction.
213
- const continuation = commitAndCompactContinuation(activeSessionPlanRef(ctx), completion);
214
- ctx.compact({
215
- customInstructions,
216
- onComplete: () => {
217
- try {
218
- // Optionless on purpose: resume immediately under the active stage's own bindings.
219
- pi.sendUserMessage(continuation);
220
- } catch (error) {
221
- console.error(`perk: commit-and-compact — continuation dispatch failed — ${error}`);
222
- }
223
- },
224
- onError: (error) => {
225
- console.error(`perk: commit-and-compact — compaction failed — ${error}`);
226
- },
227
- });
228
- },
229
- });
230
-
231
- pi.on("agent_settled", async (_event, ctx) => {
232
- if (pending === null) return;
233
- const record = pending;
234
- pending = null; // consume-then-clear: the record is strictly one-shot
235
- try {
236
- settleCommitAndCompact(record, ioFor(ctx));
237
- } catch (error) {
238
- console.error(`perk: commit-and-compact — settle handling failed — ${error}`);
239
- }
240
- });
241
-
242
- registerPerkCommand(pi, "commit-and-compact", {
243
- description:
244
- "Commit the work completed so far (a driven model turn stages and writes the message), " +
245
- "compact, then continue automatically after compaction succeeds. Clean or read-only " +
246
- "sessions compact immediately; a skipped or failed compaction never continues.",
247
- handler: async (_args, ctx) => {
248
- pending = startCommitAndCompact(ctx.cwd, gating.isActive(), ioFor(ctx));
249
- },
250
- });
251
- }