@astrosheep/keiyaku 4.0.3 → 4.0.5

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 (238) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +4 -4
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +1 -1
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +15 -1
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +3 -1
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +34 -13
  9. package/build/src/akuma/akuma.d.ts +34 -12
  10. package/build/src/akuma/akuma.js +118 -63
  11. package/build/src/akuma/allowed.d.ts +7 -0
  12. package/build/src/akuma/allowed.js +33 -0
  13. package/build/src/akuma/archetype.d.ts +7 -4
  14. package/build/src/akuma/archetype.js +15 -16
  15. package/build/src/akuma/body.d.ts +6 -1
  16. package/build/src/akuma/body.js +36 -27
  17. package/build/src/akuma/heart/facts.d.ts +82 -14
  18. package/build/src/akuma/heart/index.d.ts +5 -18
  19. package/build/src/akuma/heart/index.js +14 -84
  20. package/build/src/akuma/heart/request-authority.d.ts +12 -0
  21. package/build/src/akuma/heart/request-authority.js +119 -0
  22. package/build/src/akuma/heart/request-rows.d.ts +16 -0
  23. package/build/src/akuma/heart/request-rows.js +88 -0
  24. package/build/src/akuma/heart/rows.d.ts +1 -26
  25. package/build/src/akuma/heart/rows.js +0 -50
  26. package/build/src/akuma/heart/schema.d.ts +1 -1
  27. package/build/src/akuma/heart/schema.js +22 -10
  28. package/build/src/akuma/heart/soul.js +2 -36
  29. package/build/src/akuma/heart/storage.d.ts +1 -0
  30. package/build/src/akuma/heart/storage.js +15 -0
  31. package/build/src/akuma/heart/timeline.d.ts +1 -5
  32. package/build/src/akuma/heart/timeline.js +8 -17
  33. package/build/src/akuma/index.d.ts +5 -2
  34. package/build/src/akuma/index.js +1 -0
  35. package/build/src/akuma/projection.d.ts +17 -3
  36. package/build/src/akuma/projection.js +40 -3
  37. package/build/src/akuma/provider-recipe.js +1 -11
  38. package/build/src/akuma/provider.d.ts +2 -7
  39. package/build/src/akuma/provider.js +2 -1
  40. package/build/src/akuma/providers/acp/core.d.ts +3 -1
  41. package/build/src/akuma/providers/acp/core.js +10 -6
  42. package/build/src/akuma/providers/acp/events.d.ts +11 -3
  43. package/build/src/akuma/providers/acp/events.js +78 -4
  44. package/build/src/akuma/providers/acp/index.js +0 -1
  45. package/build/src/akuma/providers/claude/events.js +62 -3
  46. package/build/src/akuma/providers/claude/index.d.ts +0 -4
  47. package/build/src/akuma/providers/claude/index.js +7 -3
  48. package/build/src/akuma/providers/codex-app-server/events.js +1 -13
  49. package/build/src/akuma/providers/codex-app-server/index.d.ts +2 -27
  50. package/build/src/akuma/providers/codex-app-server/index.js +0 -2
  51. package/build/src/akuma/providers/grok-build/index.d.ts +2 -1
  52. package/build/src/akuma/providers/grok-build/index.js +72 -3
  53. package/build/src/akuma/providers/opencode-sdk/events.js +71 -6
  54. package/build/src/akuma/providers/opencode-sdk/index.d.ts +2 -28
  55. package/build/src/akuma/providers/opencode-sdk/index.js +8 -4
  56. package/build/src/akuma/providers/opencode-sdk/session.d.ts +1 -1
  57. package/build/src/akuma/providers/opencode-sdk/session.js +1 -1
  58. package/build/src/akuma/providers/pi/events.js +17 -3
  59. package/build/src/akuma/providers/pi/index.js +11 -4
  60. package/build/src/akuma/providers/unified-patch.d.ts +4 -0
  61. package/build/src/akuma/providers/unified-patch.js +14 -0
  62. package/build/src/akuma/publication.d.ts +1 -1
  63. package/build/src/akuma/publication.js +1 -1
  64. package/build/src/akuma/request-serve.d.ts +87 -0
  65. package/build/src/akuma/request-serve.js +484 -0
  66. package/build/src/akuma/request-wire.d.ts +124 -0
  67. package/build/src/akuma/request-wire.js +380 -0
  68. package/build/src/akuma/requests.d.ts +41 -41
  69. package/build/src/akuma/requests.js +75 -374
  70. package/build/src/akuma-body.d.ts +8 -0
  71. package/build/src/akuma-body.js +84 -0
  72. package/build/src/body/arc.js +4 -29
  73. package/build/src/body/decode.js +5 -39
  74. package/build/src/body/envelope.d.ts +7 -0
  75. package/build/src/body/envelope.js +37 -0
  76. package/build/src/cli/accepted.d.ts +4 -1
  77. package/build/src/cli/accepted.js +39 -9
  78. package/build/src/cli/commands/akuma-invoke.d.ts +8 -7
  79. package/build/src/cli/commands/akuma-invoke.js +18 -10
  80. package/build/src/cli/commands/akuma.d.ts +11 -2
  81. package/build/src/cli/commands/akuma.js +67 -28
  82. package/build/src/cli/commands/amend.d.ts +1 -1
  83. package/build/src/cli/commands/amend.js +1 -1
  84. package/build/src/cli/commands/contract.d.ts +8 -8
  85. package/build/src/cli/commands/contract.js +3 -3
  86. package/build/src/cli/commands/install.js +2 -2
  87. package/build/src/cli/commands/task-invoke.js +98 -9
  88. package/build/src/cli/commands/task-query.d.ts +1 -1
  89. package/build/src/cli/commands/task-query.js +11 -5
  90. package/build/src/cli/coordinates.d.ts +2 -0
  91. package/build/src/cli/coordinates.js +12 -5
  92. package/build/src/cli/invoke.d.ts +1 -0
  93. package/build/src/cli/invoke.js +116 -75
  94. package/build/src/cli/main.d.ts +2 -0
  95. package/build/src/cli/main.js +29 -4
  96. package/build/src/cli/parse.d.ts +3 -2
  97. package/build/src/cli/parse.js +25 -8
  98. package/build/src/cli/render/akuma.d.ts +2 -2
  99. package/build/src/cli/render/akuma.js +138 -24
  100. package/build/src/cli/render/audit.js +18 -8
  101. package/build/src/cli/render/contract.d.ts +2 -0
  102. package/build/src/cli/render/contract.js +243 -36
  103. package/build/src/cli/render/kanshi.js +64 -29
  104. package/build/src/cli/render/receipt.d.ts +2 -1
  105. package/build/src/cli/render/receipt.js +37 -2
  106. package/build/src/cli/render/terminal.d.ts +0 -2
  107. package/build/src/cli/render/terminal.js +0 -29
  108. package/build/src/cli/render/text.js +3 -1
  109. package/build/src/cli/result.d.ts +52 -9
  110. package/build/src/cli/selectors.d.ts +1 -0
  111. package/build/src/cli/selectors.js +9 -6
  112. package/build/src/contract-worktree.d.ts +1 -2
  113. package/build/src/contract-worktree.js +7 -9
  114. package/build/src/core/facts/codec.js +9 -0
  115. package/build/src/core/facts/fold.js +13 -1
  116. package/build/src/core/facts/types.d.ts +8 -1
  117. package/build/src/core/subject.js +4 -3
  118. package/build/src/core/verbs/placement.d.ts +9 -1
  119. package/build/src/core/verbs/placement.js +24 -6
  120. package/build/src/core/verbs/reintegrate.d.ts +13 -0
  121. package/build/src/core/verbs/reintegrate.js +24 -0
  122. package/build/src/dispatch/index.d.ts +1 -1
  123. package/build/src/dispatch/index.js +50 -39
  124. package/build/src/git/admission.d.ts +2 -1
  125. package/build/src/git/hooks.d.ts +0 -4
  126. package/build/src/git/hooks.js +0 -36
  127. package/build/src/git/integration.d.ts +7 -8
  128. package/build/src/git/integration.js +62 -9
  129. package/build/src/git/observe.d.ts +2 -1
  130. package/build/src/git/observe.js +6 -5
  131. package/build/src/git/process.d.ts +26 -0
  132. package/build/src/git/process.js +94 -0
  133. package/build/src/git/read-observation.d.ts +2 -1
  134. package/build/src/git/read-observation.js +3 -2
  135. package/build/src/git/reconcile.d.ts +8 -2
  136. package/build/src/git/reconcile.js +63 -14
  137. package/build/src/git/repository.d.ts +2 -29
  138. package/build/src/git/repository.js +4 -118
  139. package/build/src/git/scratch.d.ts +1 -1
  140. package/build/src/git/scratch.js +1 -1
  141. package/build/src/git/target-placement.d.ts +1 -1
  142. package/build/src/git/target-placement.js +9 -7
  143. package/build/src/git/tender.d.ts +20 -5
  144. package/build/src/git/tender.js +45 -13
  145. package/build/src/git/terminal-seal.d.ts +16 -2
  146. package/build/src/git/terminal-seal.js +15 -5
  147. package/build/src/git/workspace.d.ts +2 -1
  148. package/build/src/git/workspace.js +13 -5
  149. package/build/src/index.d.ts +1 -2
  150. package/build/src/index.js +1 -1
  151. package/build/src/kanshi/index.d.ts +1 -1
  152. package/build/src/kanshi/index.js +1 -1
  153. package/build/src/kanshi/read.d.ts +9 -1
  154. package/build/src/kanshi/read.js +91 -37
  155. package/build/src/kanshi/report.d.ts +1 -0
  156. package/build/src/library/address.d.ts +5 -14
  157. package/build/src/library/address.js +27 -23
  158. package/build/src/library/akuma-creation.d.ts +4 -2
  159. package/build/src/library/akuma-creation.js +43 -26
  160. package/build/src/library/audit.d.ts +2 -1
  161. package/build/src/library/audit.js +1 -1
  162. package/build/src/library/bind.d.ts +2 -1
  163. package/build/src/library/bind.js +4 -4
  164. package/build/src/library/catalog.d.ts +1 -2
  165. package/build/src/library/catalog.js +11 -6
  166. package/build/src/library/configuration.d.ts +5 -1
  167. package/build/src/library/configuration.js +71 -18
  168. package/build/src/library/contract.d.ts +70 -3
  169. package/build/src/library/contract.js +213 -27
  170. package/build/src/library/delivery.d.ts +1 -1
  171. package/build/src/library/fleet.d.ts +70 -12
  172. package/build/src/library/fleet.js +236 -56
  173. package/build/src/library/input.d.ts +0 -1
  174. package/build/src/library/input.js +1 -5
  175. package/build/src/library/keiyaku.d.ts +4 -4
  176. package/build/src/library/keiyaku.js +1 -2
  177. package/build/src/library/mutation.d.ts +2 -1
  178. package/build/src/library/reconcile.d.ts +2 -1
  179. package/build/src/library/reconcile.js +3 -1
  180. package/build/src/library/region.d.ts +1 -1
  181. package/build/src/library/repo.d.ts +3 -1
  182. package/build/src/library/repo.js +8 -4
  183. package/build/src/protocol/abandon.d.ts +9 -0
  184. package/build/src/protocol/abandon.js +15 -0
  185. package/build/src/protocol/amend.d.ts +16 -0
  186. package/build/src/protocol/amend.js +77 -0
  187. package/build/src/protocol/arc.d.ts +6 -0
  188. package/build/src/protocol/arc.js +12 -0
  189. package/build/src/protocol/attempt.d.ts +2 -1
  190. package/build/src/protocol/audit.d.ts +53 -0
  191. package/build/src/protocol/audit.js +140 -0
  192. package/build/src/protocol/bind.d.ts +2 -3
  193. package/build/src/protocol/bind.js +2 -16
  194. package/build/src/protocol/completion.d.ts +32 -0
  195. package/build/src/protocol/completion.js +130 -0
  196. package/build/src/protocol/deliver.d.ts +37 -0
  197. package/build/src/protocol/deliver.js +160 -0
  198. package/build/src/protocol/intent.d.ts +1 -1
  199. package/build/src/protocol/intent.js +1 -1
  200. package/build/src/protocol/operations.d.ts +65 -198
  201. package/build/src/protocol/operations.js +21 -634
  202. package/build/src/protocol/placement.d.ts +4 -13
  203. package/build/src/protocol/placement.js +3 -15
  204. package/build/src/protocol/read/status.d.ts +4 -2
  205. package/build/src/protocol/read/status.js +27 -15
  206. package/build/src/protocol/reconcile.d.ts +35 -0
  207. package/build/src/protocol/reconcile.js +41 -0
  208. package/build/src/protocol/reintegrate.d.ts +31 -0
  209. package/build/src/protocol/reintegrate.js +74 -0
  210. package/build/src/protocol/review.d.ts +33 -0
  211. package/build/src/protocol/review.js +148 -0
  212. package/build/src/protocol/run.d.ts +1 -1
  213. package/build/src/runtime/proc/run.d.ts +1 -0
  214. package/build/src/runtime/proc/run.js +9 -2
  215. package/build/src/settlement/fence.d.ts +1 -1
  216. package/build/src/settlement/holder.d.ts +1 -1
  217. package/build/src/settlement/settle.d.ts +2 -1
  218. package/build/src/settlement/settle.js +4 -1
  219. package/build/src/task/board.d.ts +18 -4
  220. package/build/src/task/board.js +73 -29
  221. package/build/src/task/compose.d.ts +1 -1
  222. package/build/src/task/compose.js +11 -4
  223. package/build/src/task/index.d.ts +4 -4
  224. package/build/src/task/index.js +8 -131
  225. package/build/src/task/input.d.ts +18 -0
  226. package/build/src/task/input.js +189 -0
  227. package/build/src/task/mutation.d.ts +39 -0
  228. package/build/src/task/mutation.js +85 -0
  229. package/build/src/task/operations.d.ts +4 -19
  230. package/build/src/task/operations.js +64 -18
  231. package/build/src/task/query.d.ts +9 -2
  232. package/build/src/task/query.js +32 -64
  233. package/build/src/task/store.js +0 -2
  234. package/build/src/verification/execution.d.ts +1 -1
  235. package/build/src/verification/execution.js +2 -1
  236. package/build/src/workspace-place.d.ts +1 -4
  237. package/build/src/workspace-place.js +0 -15
  238. package/package.json +5 -3
@@ -193,7 +193,56 @@ function endpointFact(id, observed) {
193
193
  return `-> ${id} (unavailable)`;
194
194
  return `-> ${id}`;
195
195
  }
196
- function renderContracts(report, context, selection) {
196
+ function renderNamespaceTasks(row, context) {
197
+ if (row.namespaceTasks.kind === "absent")
198
+ return plumbFacts(["namespace tasks absent"], context.columns);
199
+ if (row.namespaceTasks.kind === "failed") {
200
+ return plumbFacts([`namespace tasks failed ${row.namespaceTasks.failure.message}`], context.columns);
201
+ }
202
+ const lines = [...plumbFacts([`namespace tasks ${row.namespaceTasks.value.length}`], context.columns)];
203
+ for (const task of row.namespaceTasks.value) {
204
+ const scan = `${taskMark(task)} ${task.id} · P${task.priority} ${task.disposition}`;
205
+ const title = safeText(task.title);
206
+ const inline = `${scan} — ${title}`;
207
+ if (displayColumns(inline) <= context.columns - displayColumns(PLUMB)) {
208
+ lines.push(...plumbFacts([inline], context.columns));
209
+ }
210
+ else {
211
+ lines.push(...plumbFacts([`${scan} —`], context.columns));
212
+ lines.push(...plumbBlock(title, context.columns));
213
+ }
214
+ }
215
+ return lines;
216
+ }
217
+ function renderContractRow(row, report, context, selection) {
218
+ const hot = contractHot(row);
219
+ const compact = !hot && selection !== "contract";
220
+ const title = row.title ?? "title unavailable";
221
+ const phase = `${row.phase} · ${formatAge(row.phaseAt, report.observedAt)}`;
222
+ const lines = [identityLine(contractMark(row), row.id)];
223
+ lines.push(...plumbFacts(compact ? [title, phase, ...targetFacts(row)] : [title], context.columns));
224
+ if (!compact)
225
+ lines.push(...plumbFacts([phase, ...targetFacts(row)], context.columns));
226
+ lines.push(...plumbFacts([workspaceState(row)], context.columns));
227
+ if (showWorkspacePath(row, hot || selection === "contract")
228
+ && row.workspaceObservation.kind !== "unappointed"
229
+ && row.workspaceObservation.location.kind === "worktree") {
230
+ lines.push(plumbPath(row.workspaceObservation.location.path));
231
+ }
232
+ lines.push(...renderGates(row.gates.reports, report.observedAt, context.columns, selection === "contract"));
233
+ if (row.holder.kind === "held")
234
+ lines.push(...plumbFacts([`task ${row.holder.taskId}`], context.columns));
235
+ if (row.holder.kind === "unavailable")
236
+ lines.push(...plumbFacts(["holder unavailable"], context.columns));
237
+ for (const attached of row.fleet) {
238
+ const aliases = attached.aliases.length === 0 ? "" : ` (${attached.aliases.join(" ")})`;
239
+ lines.push(...plumbFacts([`akuma ${attached.id}${aliases}`], context.columns));
240
+ }
241
+ if (selection === "contract")
242
+ lines.push(...renderNamespaceTasks(row, context));
243
+ return lines;
244
+ }
245
+ function renderContracts(report, context) {
197
246
  const section = report.contracts;
198
247
  if (section.kind === "absent")
199
248
  return sectionAbsent("KEIYAKU", context.columns);
@@ -204,37 +253,21 @@ function renderContracts(report, context, selection) {
204
253
  ...section.value.rows.filter((row) => !contractHot(row)),
205
254
  ];
206
255
  const lines = [aperture("KEIYAKU", context.columns)];
207
- for (const row of rows) {
208
- const hot = contractHot(row);
209
- const compact = !hot && selection !== "contract";
210
- const title = row.title ?? "title unavailable";
211
- const phase = `${row.phase} · ${formatAge(row.phaseAt, report.observedAt)}`;
212
- lines.push(identityLine(contractMark(row), row.id));
213
- lines.push(...plumbFacts(compact
214
- ? [title, phase, ...targetFacts(row)]
215
- : [title], context.columns));
216
- if (!compact)
217
- lines.push(...plumbFacts([phase, ...targetFacts(row)], context.columns));
218
- lines.push(...plumbFacts([workspaceState(row)], context.columns));
219
- if (showWorkspacePath(row, hot || selection === "contract")
220
- && row.workspaceObservation.kind !== "unappointed"
221
- && row.workspaceObservation.location.kind === "worktree") {
222
- lines.push(plumbPath(row.workspaceObservation.location.path));
223
- }
224
- lines.push(...renderGates(row.gates.reports, report.observedAt, context.columns, selection === "contract"));
225
- if (row.holder.kind === "held")
226
- lines.push(...plumbFacts([`task ${row.holder.taskId}`], context.columns));
227
- if (row.holder.kind === "unavailable")
228
- lines.push(...plumbFacts(["holder unavailable"], context.columns));
229
- for (const attached of row.fleet) {
230
- const aliases = attached.aliases.length === 0 ? "" : ` (${attached.aliases.join(" ")})`;
231
- lines.push(...plumbFacts([`akuma ${attached.id}${aliases}`], context.columns));
232
- }
233
- }
256
+ for (const row of rows)
257
+ lines.push(...renderContractRow(row, report, context, "world"));
234
258
  const attention = rows.filter(contractHot).length;
235
259
  lines.push(aperture(`${rows.length} keiyaku · ${attention} attention`, context.columns));
236
260
  return lines;
237
261
  }
262
+ function renderSelectedContract(report, context) {
263
+ const section = report.contracts;
264
+ if (section.kind === "absent")
265
+ return [`${PLUMB}keiyaku absent`];
266
+ if (section.kind === "failed")
267
+ return [tone(`! ${safeText(section.failure.message)}`, "alert", context.color)];
268
+ const row = section.value.rows[0];
269
+ return row === undefined ? [`${PLUMB}keiyaku absent`] : renderContractRow(row, report, context, "contract");
270
+ }
238
271
  function renderTasks(report, context) {
239
272
  const section = report.tasks;
240
273
  if (section.kind === "absent")
@@ -335,10 +368,12 @@ function splitHorizon(report, columns) {
335
368
  return [`kanshi ${HORIZON}${RULE.repeat(left)} ${aggregate} ${HORIZON}${RULE.repeat(right)} ${world}`];
336
369
  }
337
370
  export function renderKanshiText(report, context = { columns: 80, color: false }, selection = "world") {
371
+ if (selection === "contract")
372
+ return renderSelectedContract(report, context).join("\n");
338
373
  return [
339
374
  ...splitHorizon(report, context.columns),
340
375
  "",
341
- ...renderContracts(report, context, selection),
376
+ ...renderContracts(report, context),
342
377
  "",
343
378
  ...renderTasks(report, context),
344
379
  "",
@@ -10,10 +10,11 @@ type HookFailure = Extract<Lag, {
10
10
  export declare function receiptRow(lines: string[], mark: string, label: string, segments: readonly ReceiptSegment[], columns: number): void;
11
11
  export declare function receiptPayload(lines: string[], label: string, payload: string): void;
12
12
  export declare function outcomeLines(mark: "✓" | "!" | "?", verb: string, word: "accepted" | "refused" | "retry", contract: string | undefined, columns?: number): string[];
13
+ export declare function titleLines(mark: string, title: string, contract: string, columns?: number): string[];
13
14
  export declare function hookFailureSummary(failure: HookFailure): string;
14
15
  export declare function appendHookPayload(lines: string[], failure: HookFailure): void;
15
16
  export declare function reuseLines(reuse: VerificationReuse | undefined, columns: number): readonly string[];
16
- export declare function stopLines(label: "verification" | "claim", stop: VerificationStop | PlacementStop, columns: number, addressed: string): readonly string[];
17
+ export declare function stopLines(label: "verification" | "completion", stop: VerificationStop | PlacementStop, columns: number, addressed: string): readonly string[];
17
18
  export declare function cleanupLines(cleanup: NonNullable<AcceptedDeliverResult["cleanup"]>, columns: number): readonly string[];
18
19
  export declare function leakLines(leak: NonNullable<AcceptedDeliverResult["leak"]>, columns: number): readonly string[];
19
20
  export {};
@@ -30,6 +30,13 @@ export function outcomeLines(mark, verb, word, contract, columns = 80) {
30
30
  return [inline];
31
31
  return [`${base} —`, ` ${safeText(contract)}`];
32
32
  }
33
+ export function titleLines(mark, title, contract, columns = 80) {
34
+ const base = `${mark} ${title}`;
35
+ const inline = `${base} — ${contract}`;
36
+ if (displayColumns(inline) <= columns)
37
+ return [inline];
38
+ return [`${base} —`, ` ${safeText(contract)}`];
39
+ }
33
40
  export function hookFailureSummary(failure) {
34
41
  if (failure.kind === "timeout" || failure.kind === "unknown-exit")
35
42
  return failure.kind;
@@ -52,6 +59,32 @@ export function reuseLines(reuse, columns) {
52
59
  return [];
53
60
  return renderOpaqueBlock(`reuse verification ${reuse.entry} ${reuse.verdict}`, " ", columns);
54
61
  }
62
+ function prerequisiteRows(stop, columns) {
63
+ if (!("refusal" in stop) || stop.refusal?.kind !== "prerequisites-unsatisfied")
64
+ return [];
65
+ const lines = [];
66
+ for (const prerequisite of stop.refusal.unmet) {
67
+ receiptRow(lines, " ", "prerequisite", [
68
+ { text: prerequisite.contractId, opaque: true },
69
+ { text: "·" },
70
+ { text: prerequisite.state },
71
+ ], columns);
72
+ }
73
+ return lines;
74
+ }
75
+ function targetMovedDetail(stop) {
76
+ if ("integratedAt" in stop) {
77
+ return [
78
+ { text: stop.target, opaque: true },
79
+ { text: `${stop.integratedAt} -> ${stop.observed}`, opaque: true },
80
+ { text: `attempts=${stop.attempts}` },
81
+ ];
82
+ }
83
+ return [
84
+ { text: stop.target, opaque: true },
85
+ { text: `${stop.expected} -> ${stop.observed}`, opaque: true },
86
+ ];
87
+ }
55
88
  export function stopLines(label, stop, columns, addressed) {
56
89
  const detail = [];
57
90
  if ("refusal" in stop && stop.refusal !== undefined) {
@@ -69,11 +102,13 @@ export function stopLines(label, stop, columns, addressed) {
69
102
  detail.push({ text: `command=${stop.command}` }, { text: hookFailureSummary(stop.detail), opaque: true });
70
103
  }
71
104
  else if (stop.failure === "target-moved") {
72
- detail.push({ text: stop.target, opaque: true }, { text: `${stop.expected} -> ${stop.observed}`, opaque: true });
105
+ detail.push(...targetMovedDetail(stop));
73
106
  }
74
107
  }
75
108
  const lines = [];
76
- receiptRow(lines, "!", label, detail, columns);
109
+ const state = label === "verification" ? "failed" : "blocked";
110
+ receiptRow(lines, "!", label, [{ text: state }, { text: "·" }, ...detail], columns);
111
+ lines.push(...prerequisiteRows(stop, columns));
77
112
  if ("failure" in stop && stop.failure === "environment-failure" && "command" in stop) {
78
113
  appendHookPayload(lines, stop.detail);
79
114
  }
@@ -23,8 +23,6 @@ export declare function renderBoundedTextBlock(value: string, input: Readonly<{
23
23
  truncated?: boolean;
24
24
  }>): readonly string[];
25
25
  export declare function safeText(value: string): string;
26
- export declare function renderFacts(primary: string, facts: readonly string[], columns: number): readonly string[];
27
26
  export declare function renderTextBlock(value: string, indent: string, columns: number): readonly string[];
28
27
  export declare function renderOpaqueBlock(value: string, indent: string, columns: number): readonly string[];
29
- export declare function renderVoiceRuler(left: string, right: string, columns: number): string;
30
28
  export declare function tone(value: string, kind: "dim" | "alert", color: boolean): string;
@@ -110,28 +110,6 @@ export function renderBoundedTextBlock(value, input) {
110
110
  export function safeText(value) {
111
111
  return value.replaceAll(/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/gu, (character) => /\s/u.test(character) ? " " : "�");
112
112
  }
113
- export function renderFacts(primary, facts, columns) {
114
- const head = safeText(primary);
115
- const clean = facts.map(safeText);
116
- if (clean.length === 0)
117
- return [head];
118
- const inline = `${head} ${clean.join(" · ")}`;
119
- if (displayColumns(inline) <= columns)
120
- return [inline];
121
- const lines = [head];
122
- let current = " ";
123
- for (const fact of clean) {
124
- const candidate = current === " " ? `${current}${fact}` : `${current} · ${fact}`;
125
- if (current !== " " && displayColumns(candidate) > columns) {
126
- lines.push(current);
127
- current = ` ${fact}`;
128
- }
129
- else
130
- current = candidate;
131
- }
132
- lines.push(current);
133
- return lines;
134
- }
135
113
  export function renderTextBlock(value, indent, columns) {
136
114
  const words = safeText(value).trim().split(/\s+/u).filter((word) => word.length > 0);
137
115
  if (words.length === 0)
@@ -183,13 +161,6 @@ export function renderOpaqueBlock(value, indent, columns) {
183
161
  }
184
162
  return lines;
185
163
  }
186
- export function renderVoiceRuler(left, right, columns) {
187
- const width = Math.max(20, Math.min(80, columns));
188
- const occupied = displayColumns(left) + displayColumns(right) + 2;
189
- if (occupied >= width)
190
- return `${left}\n${"─".repeat(Math.max(1, width - displayColumns(right) - 1))} ${right}`;
191
- return `${left} ${"─".repeat(width - occupied)} ${right}`;
192
- }
193
164
  export function tone(value, kind, color) {
194
165
  if (!color)
195
166
  return value;
@@ -1,5 +1,5 @@
1
1
  import { renderObservation } from "./board.js";
2
- import { renderAccepted, renderRetry } from "./contract.js";
2
+ import { renderAccepted, renderContractHistory, renderRetry } from "./contract.js";
3
3
  import { renderKanshiText } from "./kanshi.js";
4
4
  import { renderRefusal } from "./refusal.js";
5
5
  import { renderCatalogText } from "./catalog.js";
@@ -11,6 +11,8 @@ export function renderText(result, context) {
11
11
  return renderKanshiText(result.report, context, result.selection);
12
12
  if (result.kind === "catalog")
13
13
  return renderCatalogText(result.catalog);
14
+ if (result.kind === "contract-history")
15
+ return renderContractHistory(result.history);
14
16
  if (result.kind === "region")
15
17
  return renderRegionText(result.region);
16
18
  if (result.kind === "accepted")
@@ -1,4 +1,4 @@
1
- import type { AuditReport, ContractId, Fact, MutationResult, PlacementStop, ReconcileReport, Review, VerificationReuse, VerificationStop } from "../index.js";
1
+ import type { AuditReport, ContractHistory, ContractId, Fact, MutationResult, PlacementStop, ReconcileReport, Review, VerificationReuse, VerificationStop } from "../index.js";
2
2
  import type { KanshiReport } from "../kanshi/index.js";
3
3
  import type { RegionRead, Section } from "../kanshi/index.js";
4
4
  import type { Catalog } from "../index.js";
@@ -11,11 +11,19 @@ export type BindDraftReceipt = Readonly<{
11
11
  warning: string;
12
12
  }>;
13
13
  export type Effect = ReconcileReport["effects"][number];
14
- export type AcceptedFact = Readonly<{
14
+ type AcceptedFactEnvelope = Readonly<{
15
15
  contract: ContractId;
16
16
  entry: string;
17
- kind: Fact["kind"];
18
17
  }>;
18
+ export type AcceptedFact = (AcceptedFactEnvelope & Readonly<{
19
+ kind: Exclude<Fact["kind"], "reintegrated">;
20
+ data?: never;
21
+ }>) | (AcceptedFactEnvelope & Readonly<{
22
+ kind: "reintegrated";
23
+ data: Extract<Fact, {
24
+ kind: "reintegrated";
25
+ }>["data"];
26
+ }>);
19
27
  export type Lag = ReconcileReport["lag"][number];
20
28
  type MutationEnvelope = Pick<MutationResult<unknown>, "head" | "effects" | "settlement">;
21
29
  export type AcceptedEnvelope = Readonly<{
@@ -29,6 +37,7 @@ export type AcceptedEnvelope = Readonly<{
29
37
  }>;
30
38
  export type AcceptedBindResult = AcceptedEnvelope & Readonly<{
31
39
  verb: "bind";
40
+ workspace: "worktree" | "here";
32
41
  target: string | null;
33
42
  verification?: never;
34
43
  verificationReuse?: never;
@@ -36,8 +45,11 @@ export type AcceptedBindResult = AcceptedEnvelope & Readonly<{
36
45
  cleanup?: never;
37
46
  leak?: never;
38
47
  report?: never;
39
- workspace?: never;
40
48
  diff?: never;
49
+ verificationVerdict?: never;
50
+ verdict?: never;
51
+ chapter?: never;
52
+ note?: never;
41
53
  }> & RegionObservation;
42
54
  export type AcceptedAmendResult = AcceptedEnvelope & Readonly<{
43
55
  verb: "amend";
@@ -50,9 +62,14 @@ export type AcceptedAmendResult = AcceptedEnvelope & Readonly<{
50
62
  leak?: never;
51
63
  report?: never;
52
64
  workspace?: never;
65
+ verificationVerdict?: never;
66
+ verdict?: never;
67
+ chapter?: never;
68
+ note?: never;
53
69
  }> & RegionObservation;
54
70
  export type AcceptedDeliverResult = AcceptedEnvelope & Readonly<{
55
71
  verb: "deliver";
72
+ verificationVerdict?: "satisfied" | "unsatisfied";
56
73
  verification?: VerificationStop;
57
74
  verificationReuse?: VerificationReuse;
58
75
  placement?: PlacementStop;
@@ -64,23 +81,34 @@ export type AcceptedDeliverResult = AcceptedEnvelope & Readonly<{
64
81
  report?: never;
65
82
  workspace?: never;
66
83
  diff?: never;
84
+ verdict?: never;
85
+ chapter?: never;
86
+ note?: never;
67
87
  }>;
68
88
  export type AcceptedReviewResult = AcceptedEnvelope & Readonly<{
69
89
  verb: "review";
90
+ verdict: "satisfied" | "unsatisfied";
91
+ verificationVerdict?: "satisfied" | "unsatisfied";
92
+ verification?: VerificationStop;
93
+ verificationReuse?: VerificationReuse;
70
94
  placement?: PlacementStop;
71
95
  workspace?: Review["workspace"];
96
+ cleanup?: MutationResult<unknown>["cleanup"];
97
+ leak?: MutationResult<unknown>["leak"];
72
98
  target?: never;
73
- verification?: never;
74
- verificationReuse?: never;
75
- cleanup?: never;
76
- leak?: never;
77
99
  overlaps?: never;
78
100
  overlapFailure?: never;
79
101
  report?: never;
80
102
  diff?: never;
103
+ chapter?: never;
104
+ note?: never;
81
105
  }>;
82
106
  export type AcceptedArcResult = AcceptedEnvelope & Readonly<{
83
107
  verb: "arc";
108
+ chapter: Readonly<{
109
+ seq: number;
110
+ title: string;
111
+ }>;
84
112
  target?: never;
85
113
  verification?: never;
86
114
  verificationReuse?: never;
@@ -92,9 +120,13 @@ export type AcceptedArcResult = AcceptedEnvelope & Readonly<{
92
120
  report?: never;
93
121
  workspace?: never;
94
122
  diff?: never;
123
+ verificationVerdict?: never;
124
+ verdict?: never;
125
+ note?: never;
95
126
  }>;
96
127
  export type AcceptedAbandonResult = AcceptedEnvelope & Readonly<{
97
128
  verb: "abandon";
129
+ note?: string;
98
130
  target?: never;
99
131
  verification?: never;
100
132
  verificationReuse?: never;
@@ -106,6 +138,9 @@ export type AcceptedAbandonResult = AcceptedEnvelope & Readonly<{
106
138
  report?: never;
107
139
  workspace?: never;
108
140
  diff?: never;
141
+ verificationVerdict?: never;
142
+ verdict?: never;
143
+ chapter?: never;
109
144
  }>;
110
145
  export type AcceptedAuditResult = AcceptedEnvelope & Readonly<{
111
146
  verb: "audit";
@@ -120,6 +155,10 @@ export type AcceptedAuditResult = AcceptedEnvelope & Readonly<{
120
155
  overlapFailure?: never;
121
156
  workspace?: never;
122
157
  diff?: never;
158
+ verificationVerdict?: never;
159
+ verdict?: never;
160
+ chapter?: never;
161
+ note?: never;
123
162
  }>;
124
163
  export type AcceptedResult = AcceptedBindResult | AcceptedAmendResult | AcceptedDeliverResult | AcceptedReviewResult | AcceptedArcResult | AcceptedAbandonResult | AcceptedAuditResult;
125
164
  export type RefusedResult = Readonly<{
@@ -158,5 +197,9 @@ export type CatalogResult = Readonly<{
158
197
  kind: "catalog";
159
198
  catalog: Catalog;
160
199
  }>;
161
- export type InvocationResult = AcceptedResult | RefusedResult | RetryResult | ObservationResult | GuidanceResult | StatusResult | RegionResult | CatalogResult;
200
+ export type ContractHistoryResult = Readonly<{
201
+ kind: "contract-history";
202
+ history: ContractHistory;
203
+ }>;
204
+ export type InvocationResult = AcceptedResult | RefusedResult | RetryResult | ObservationResult | GuidanceResult | StatusResult | RegionResult | CatalogResult | ContractHistoryResult;
162
205
  export {};
@@ -6,4 +6,5 @@ export type SelectedContract = Readonly<{
6
6
  }>;
7
7
  export declare function contractFromInput(repo: Repo, value: string): SelectedContract;
8
8
  export declare function resolveContextualContract(board: ContractBoard, selector: string | undefined, scope: string): ContractId;
9
+ export declare function canonicalContractSelector(selector: string): ContractId;
9
10
  export declare function resolveKanshiContract(report: KanshiReport, selector: string): string;
@@ -50,12 +50,7 @@ export function resolveContextualContract(board, selector, scope) {
50
50
  return resolveShortContract(board.rows, selector);
51
51
  return selectorError(`contract selector must be kei/<contract-segment> or @<contract-segment>: ${selector}`);
52
52
  }
53
- export function resolveKanshiContract(report, selector) {
54
- if (report.contracts.kind !== "present") {
55
- return selectorError(`cannot select a contract while the Contract world is ${report.contracts.kind}`);
56
- }
57
- if (selector.startsWith("@"))
58
- return resolveShortContract(report.contracts.value.rows, selector);
53
+ export function canonicalContractSelector(selector) {
59
54
  try {
60
55
  identitySegments({ family: "kei", value: selector });
61
56
  }
@@ -64,3 +59,11 @@ export function resolveKanshiContract(report, selector) {
64
59
  }
65
60
  return selector;
66
61
  }
62
+ export function resolveKanshiContract(report, selector) {
63
+ if (report.contracts.kind !== "present") {
64
+ return selectorError(`cannot select a contract while the Contract world is ${report.contracts.kind}`);
65
+ }
66
+ if (selector.startsWith("@"))
67
+ return resolveShortContract(report.contracts.value.rows, selector);
68
+ return canonicalContractSelector(selector);
69
+ }
@@ -1,6 +1,6 @@
1
1
  import { type DerivedFileAction } from "./coordination/durable-file.js";
2
2
  import { type ContractId, type ContractState } from "./core/facts/types.js";
3
- import { type GitRepository } from "./git/repository.js";
3
+ import { type GitRepository } from "./git/process.js";
4
4
  import { type PlaceRegister } from "./workspace-place.js";
5
5
  export declare function renderContractGuidance(state: ContractState): string;
6
6
  export type ContractFileEffect = Readonly<{
@@ -40,5 +40,4 @@ export type ContractReservation = Readonly<{
40
40
  export declare function reserveContractWorktree(repository: GitRepository, contract: ContractId): Promise<ContractReservation>;
41
41
  export declare function withContractWorktreeAppointment<T>(repository: GitRepository, action: () => T | Promise<T>): Promise<T>;
42
42
  export declare function releaseContractWorktree(repository: GitRepository, contract: ContractId): Promise<void>;
43
- export declare function removeContractWorktreeAppointment(repository: GitRepository, contract: ContractId): Promise<void>;
44
43
  export declare function projectContractWorktree(repository: GitRepository, state: ContractState | null, register?: PlaceRegister): Promise<ContractWorktreeResult>;
@@ -3,9 +3,10 @@ import { join } from "node:path";
3
3
  import { acquireSqliteTransactionLock } from "./coordination/sqlite-transaction-lock.js";
4
4
  import { createFileDurablyExclusive, repairDerivedFile, } from "./coordination/durable-file.js";
5
5
  import { contractId } from "./core/facts/types.js";
6
- import { GitPlumbingError, runGit, worktreeGitDirectory, worktreeRoot, } from "./git/repository.js";
6
+ import { worktreeGitDirectory, worktreeRoot, } from "./git/repository.js";
7
+ import { GitPlumbingError, runGit } from "./git/process.js";
7
8
  import { worktreePath } from "./git/workspace.js";
8
- import { appointmentFor, placeRegisterPath, readPlaceRegister, } from "./workspace-place.js";
9
+ import { appointmentFor, placeRegisterPath, } from "./workspace-place.js";
9
10
  const IGNORE_BYTES = ".gitignore\nKEIYAKU.md\n";
10
11
  const APPOINTMENT_DESCRIPTION = "This is a read-only projection. Do not edit manually.";
11
12
  function appointmentBytes(contract) {
@@ -48,6 +49,9 @@ const FULFILLMENT = [
48
49
  "### Deliverer", "",
49
50
  "Implement and verify the Objective under the Design, Region, and Criteria in this Contract.",
50
51
  "When an Arc is active, stay within that current chapter.",
52
+ "For work requiring three or more steps, prefer `keiyaku task -C <worktree>` "
53
+ + "to organize and manage Tasks.",
54
+ "Promptly update progress for Tasks already present in the current worktree.",
51
55
  "Leave lifecycle decisions to the caller; report the candidate, verification performed, and any unmet term.", "",
52
56
  "### Reviewer", "",
53
57
  "Review this Contract worktree against the complete Contract.",
@@ -129,12 +133,6 @@ export async function releaseContractWorktree(repository, contract) {
129
133
  }
130
134
  catch { /* reservation cleanup is best effort */ }
131
135
  }
132
- export async function removeContractWorktreeAppointment(repository, contract) {
133
- const appointment = await readContractAppointment(repository);
134
- if (appointment.kind !== "appointed" || appointment.contract !== contract)
135
- return;
136
- await unlink(appointment.path);
137
- }
138
136
  async function repair(repository, worktree, relativePath, bytes) {
139
137
  const path = join(worktree, relativePath);
140
138
  if (await isTracked(repository, relativePath))
@@ -235,7 +233,7 @@ export async function projectContractWorktree(repository, state, register) {
235
233
  if (state.coordinates.workspace === "here") {
236
234
  return await here(repository, state, renderContractGuidance(state));
237
235
  }
238
- const appointed = appointmentFor(register ?? await readPlaceRegister(repository), state.id);
236
+ const appointed = register === undefined ? undefined : appointmentFor(register, state.id);
239
237
  if (appointed === undefined) {
240
238
  return {
241
239
  effects: [],
@@ -6,6 +6,7 @@ const VERSION_BY_KIND = {
6
6
  amend: 1,
7
7
  bound: 1,
8
8
  deliver: 1,
9
+ reintegrated: 1,
9
10
  attestation: 1,
10
11
  claimed: 1,
11
12
  arc: 1,
@@ -182,6 +183,14 @@ function validateData(kind, value) {
182
183
  },
183
184
  };
184
185
  }
186
+ case "reintegrated": {
187
+ const object = requireRecord(value, path);
188
+ requireKeys(object, ["predecessor", "snapshot"], path);
189
+ return {
190
+ predecessor: brandedValue(object.predecessor, `${path}.predecessor`, snapshotId),
191
+ snapshot: brandedValue(object.snapshot, `${path}.snapshot`, snapshotId),
192
+ };
193
+ }
185
194
  case "attestation":
186
195
  return validateAttestation(value, path);
187
196
  case "claimed": {
@@ -24,6 +24,7 @@ function stateFromBind(id, head, bind, attestations) {
24
24
  terms: cloneTerms(bind.data.terms),
25
25
  bound: null,
26
26
  delivery: null,
27
+ currentIntegration: null,
27
28
  attestations,
28
29
  terminal: null,
29
30
  };
@@ -55,7 +56,18 @@ function foldEntry(state, entry, attestations) {
55
56
  case "deliver":
56
57
  if (state.bound === null)
57
58
  foldError("deliver requires bound");
58
- return { ...state, delivery: entry };
59
+ return { ...state, delivery: entry, currentIntegration: { ...entry.data.integration } };
60
+ case "reintegrated":
61
+ if (state.delivery === null)
62
+ foldError("reintegrated requires a deliver");
63
+ return {
64
+ ...state,
65
+ currentIntegration: {
66
+ predecessor: entry.data.predecessor,
67
+ snapshot: entry.data.snapshot,
68
+ changeId: state.delivery.data.integration.changeId,
69
+ },
70
+ };
59
71
  case "attestation":
60
72
  attestations.push(entry);
61
73
  return { ...state, attestations };
@@ -85,6 +85,11 @@ export type DeliverData = Readonly<{
85
85
  requireBranchesToBeUpToDate: boolean;
86
86
  }>;
87
87
  }>;
88
+ export type CurrentIntegration = DeliverData["integration"];
89
+ export type ReintegratedData = Readonly<{
90
+ predecessor: SnapshotId;
91
+ snapshot: SnapshotId;
92
+ }>;
88
93
  export type AttestationData = Readonly<{
89
94
  gate: Gate;
90
95
  subject: DependencyKeySet;
@@ -116,11 +121,12 @@ export type BindEntry = JournalEnvelope<"bind", BindData>;
116
121
  type AmendEntry = JournalEnvelope<"amend", AmendData>;
117
122
  type BoundEntry = JournalEnvelope<"bound", BoundData>;
118
123
  type DeliverEntry = JournalEnvelope<"deliver", DeliverData>;
124
+ export type ReintegratedEntry = JournalEnvelope<"reintegrated", ReintegratedData>;
119
125
  export type AttestationEntry = JournalEnvelope<"attestation", AttestationData>;
120
126
  type ClaimedEntry = JournalEnvelope<"claimed", ClaimedData>;
121
127
  export type ArcEntry = JournalEnvelope<"arc", ArcData>;
122
128
  type AbandonedEntry = JournalEnvelope<"abandoned", AbandonedData>;
123
- export type JournalEntry = BindEntry | AmendEntry | BoundEntry | DeliverEntry | AttestationEntry | ClaimedEntry | ArcEntry | AbandonedEntry;
129
+ export type JournalEntry = BindEntry | AmendEntry | BoundEntry | DeliverEntry | ReintegratedEntry | AttestationEntry | ClaimedEntry | ArcEntry | AbandonedEntry;
124
130
  export type FactKind = JournalEntry["kind"];
125
131
  type ContractTerminal = ClaimedEntry | AbandonedEntry;
126
132
  export type ContractState = Readonly<{
@@ -130,6 +136,7 @@ export type ContractState = Readonly<{
130
136
  terms: ContractTerms;
131
137
  bound: BoundEntry | null;
132
138
  delivery: DeliverEntry | null;
139
+ currentIntegration: CurrentIntegration | null;
133
140
  attestations: readonly AttestationEntry[];
134
141
  currentArc?: ArcEntry;
135
142
  terminal: ContractTerminal | null;
@@ -65,12 +65,13 @@ export function parseDependencyKeySet(value) {
65
65
  return decodeDependencyKeySet(value).canonical;
66
66
  }
67
67
  function currentKeys(state) {
68
+ const integration = state.currentIntegration ?? state.delivery?.data.integration;
68
69
  return new Set([
69
70
  encodeKey({ kind: "document", value: state.terms.document.key }),
70
71
  ...state.terms.segments.map((value) => encodeKey({ kind: "segment", value })),
71
- ...(state.delivery === null ? [] : [
72
- encodeKey({ kind: "snapshot", value: state.delivery.data.integration.snapshot }),
73
- encodeKey({ kind: "change", value: state.delivery.data.integration.changeId }),
72
+ ...(integration === undefined ? [] : [
73
+ encodeKey({ kind: "snapshot", value: integration.snapshot }),
74
+ encodeKey({ kind: "change", value: integration.changeId }),
74
75
  ]),
75
76
  ]);
76
77
  }
@@ -5,9 +5,17 @@ type PlacementInput = Readonly<{
5
5
  actor?: ActorId;
6
6
  at: string;
7
7
  }>;
8
+ export type UnmetPrerequisite = Readonly<{
9
+ contractId: ContractId;
10
+ state: "missing" | "active" | "abandoned";
11
+ }>;
8
12
  export type PlacementRefusal = Readonly<{
9
- kind: "contract-missing" | "delivery-missing" | "terminal" | "prerequisites-unsatisfied" | "gates-unsatisfied";
13
+ kind: "contract-missing" | "delivery-missing" | "terminal" | "gates-unsatisfied";
14
+ contractId: ContractId;
15
+ }> | Readonly<{
16
+ kind: "prerequisites-unsatisfied";
10
17
  contractId: ContractId;
18
+ unmet: readonly UnmetPrerequisite[];
11
19
  }>;
12
20
  export declare function decidePlacement({ input, attempt, observation }: DecideInput<PlacementInput>): OfferDecision<PlacementRefusal>;
13
21
  export {};