@astrosheep/keiyaku 4.0.2 → 4.0.4

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/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 +1 -1
  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 +5 -0
  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 +9 -8
  9. package/build/src/akuma/akuma.d.ts +34 -11
  10. package/build/src/akuma/akuma.js +121 -61
  11. package/build/src/akuma/allowed.d.ts +7 -0
  12. package/build/src/akuma/allowed.js +40 -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 +3 -1
  16. package/build/src/akuma/body.js +19 -8
  17. package/build/src/akuma/heart/facts.d.ts +49 -7
  18. package/build/src/akuma/heart/index.d.ts +4 -8
  19. package/build/src/akuma/heart/index.js +76 -15
  20. package/build/src/akuma/heart/rows.d.ts +7 -5
  21. package/build/src/akuma/heart/rows.js +98 -11
  22. package/build/src/akuma/heart/schema.d.ts +1 -1
  23. package/build/src/akuma/heart/schema.js +15 -10
  24. package/build/src/akuma/heart/soul.js +3 -1
  25. package/build/src/akuma/heart/storage.d.ts +2 -0
  26. package/build/src/akuma/heart/storage.js +20 -0
  27. package/build/src/akuma/heart/timeline.d.ts +1 -5
  28. package/build/src/akuma/heart/timeline.js +8 -17
  29. package/build/src/akuma/index.d.ts +4 -1
  30. package/build/src/akuma/index.js +1 -0
  31. package/build/src/akuma/projection.d.ts +17 -3
  32. package/build/src/akuma/projection.js +40 -3
  33. package/build/src/akuma/provider.d.ts +1 -1
  34. package/build/src/akuma/provider.js +2 -1
  35. package/build/src/akuma/providers/acp/core.d.ts +3 -1
  36. package/build/src/akuma/providers/acp/core.js +4 -4
  37. package/build/src/akuma/providers/acp/events.d.ts +11 -3
  38. package/build/src/akuma/providers/acp/events.js +78 -4
  39. package/build/src/akuma/providers/claude/events.js +62 -3
  40. package/build/src/akuma/providers/codex-app-server/events.js +1 -13
  41. package/build/src/akuma/providers/grok-build/index.d.ts +2 -1
  42. package/build/src/akuma/providers/grok-build/index.js +72 -2
  43. package/build/src/akuma/providers/opencode-sdk/events.js +71 -6
  44. package/build/src/akuma/providers/pi/events.js +17 -3
  45. package/build/src/akuma/providers/unified-patch.d.ts +4 -0
  46. package/build/src/akuma/providers/unified-patch.js +14 -0
  47. package/build/src/akuma/publication.d.ts +1 -1
  48. package/build/src/akuma/publication.js +36 -7
  49. package/build/src/akuma/requests.d.ts +70 -4
  50. package/build/src/akuma/requests.js +288 -77
  51. package/build/src/akuma-body.d.ts +1 -0
  52. package/build/src/akuma-body.js +31 -0
  53. package/build/src/cli/accepted.d.ts +4 -1
  54. package/build/src/cli/accepted.js +26 -4
  55. package/build/src/cli/commands/akuma-invoke.d.ts +8 -7
  56. package/build/src/cli/commands/akuma-invoke.js +18 -10
  57. package/build/src/cli/commands/akuma.d.ts +11 -2
  58. package/build/src/cli/commands/akuma.js +67 -28
  59. package/build/src/cli/commands/amend.d.ts +1 -1
  60. package/build/src/cli/commands/amend.js +1 -1
  61. package/build/src/cli/commands/contract.d.ts +3 -3
  62. package/build/src/cli/commands/contract.js +1 -1
  63. package/build/src/cli/commands/install.js +4 -4
  64. package/build/src/cli/commands/task-query.d.ts +1 -1
  65. package/build/src/cli/commands/task-query.js +11 -5
  66. package/build/src/cli/commands/task.js +4 -4
  67. package/build/src/cli/coordinates.d.ts +1 -0
  68. package/build/src/cli/coordinates.js +5 -1
  69. package/build/src/cli/invoke.d.ts +1 -0
  70. package/build/src/cli/invoke.js +90 -73
  71. package/build/src/cli/main.d.ts +2 -0
  72. package/build/src/cli/main.js +29 -4
  73. package/build/src/cli/parse.d.ts +1 -0
  74. package/build/src/cli/parse.js +8 -4
  75. package/build/src/cli/render/akuma.d.ts +2 -2
  76. package/build/src/cli/render/akuma.js +84 -13
  77. package/build/src/cli/render/audit.js +16 -2
  78. package/build/src/cli/render/contract.d.ts +2 -0
  79. package/build/src/cli/render/contract.js +203 -36
  80. package/build/src/cli/render/kanshi.js +64 -29
  81. package/build/src/cli/render/receipt.d.ts +2 -1
  82. package/build/src/cli/render/receipt.js +9 -1
  83. package/build/src/cli/render/text.js +3 -1
  84. package/build/src/cli/result.d.ts +38 -3
  85. package/build/src/cli/selectors.d.ts +1 -0
  86. package/build/src/cli/selectors.js +9 -6
  87. package/build/src/cli/usage.d.ts +2 -0
  88. package/build/src/cli/usage.js +4 -0
  89. package/build/src/contract-worktree.js +3 -0
  90. package/build/src/dispatch/index.js +50 -39
  91. package/build/src/git/hooks.d.ts +0 -4
  92. package/build/src/git/hooks.js +0 -36
  93. package/build/src/git/integration.d.ts +2 -6
  94. package/build/src/git/integration.js +8 -8
  95. package/build/src/git/read-observation.js +1 -0
  96. package/build/src/git/reconcile.d.ts +6 -1
  97. package/build/src/git/reconcile.js +55 -9
  98. package/build/src/git/tender.d.ts +19 -4
  99. package/build/src/git/tender.js +44 -13
  100. package/build/src/git/terminal-seal.d.ts +14 -0
  101. package/build/src/git/terminal-seal.js +15 -2
  102. package/build/src/git/workspace.d.ts +1 -0
  103. package/build/src/git/workspace.js +12 -4
  104. package/build/src/index.d.ts +1 -1
  105. package/build/src/kanshi/index.d.ts +1 -1
  106. package/build/src/kanshi/index.js +1 -1
  107. package/build/src/kanshi/read.d.ts +9 -1
  108. package/build/src/kanshi/read.js +91 -37
  109. package/build/src/kanshi/report.d.ts +1 -0
  110. package/build/src/library/address.d.ts +5 -14
  111. package/build/src/library/address.js +20 -22
  112. package/build/src/library/akuma-creation.d.ts +4 -2
  113. package/build/src/library/akuma-creation.js +43 -26
  114. package/build/src/library/bind.js +3 -3
  115. package/build/src/library/catalog.d.ts +1 -2
  116. package/build/src/library/catalog.js +11 -6
  117. package/build/src/library/configuration.d.ts +4 -0
  118. package/build/src/library/configuration.js +19 -0
  119. package/build/src/library/contract.d.ts +15 -1
  120. package/build/src/library/contract.js +51 -4
  121. package/build/src/library/fleet.d.ts +47 -9
  122. package/build/src/library/fleet.js +184 -44
  123. package/build/src/library/input.js +1 -0
  124. package/build/src/library/keiyaku.d.ts +4 -4
  125. package/build/src/library/keiyaku.js +1 -2
  126. package/build/src/protocol/bind.d.ts +1 -2
  127. package/build/src/protocol/bind.js +2 -16
  128. package/build/src/protocol/operations.d.ts +4 -1
  129. package/build/src/protocol/operations.js +33 -27
  130. package/build/src/protocol/read/status.d.ts +3 -1
  131. package/build/src/protocol/read/status.js +24 -14
  132. package/build/src/runtime/proc/run.d.ts +1 -0
  133. package/build/src/runtime/proc/run.js +9 -2
  134. package/build/src/settlement/settle.d.ts +1 -0
  135. package/build/src/settlement/settle.js +4 -1
  136. package/build/src/task/board.d.ts +18 -3
  137. package/build/src/task/board.js +73 -26
  138. package/build/src/task/index.d.ts +3 -3
  139. package/build/src/task/index.js +7 -5
  140. package/build/src/task/operations.d.ts +2 -19
  141. package/build/src/task/operations.js +29 -7
  142. package/build/src/task/query.d.ts +9 -2
  143. package/build/src/task/query.js +32 -64
  144. package/build/src/verification/execution.js +2 -1
  145. package/package.json +3 -1
@@ -1,5 +1,5 @@
1
1
  import { renderAcceptedAudit } from "./audit.js";
2
- import { appendHookPayload, cleanupLines, hookFailureSummary, leakLines, outcomeLines, receiptPayload, receiptRow, reuseLines, stopLines, } from "./receipt.js";
2
+ import { appendHookPayload, cleanupLines, hookFailureSummary, leakLines, outcomeLines, receiptPayload, receiptRow, reuseLines, stopLines, titleLines, } from "./receipt.js";
3
3
  import { gitShortStat, renderOpaqueBlock } from "./terminal.js";
4
4
  const HANG = " ";
5
5
  function isRecord(value) {
@@ -30,6 +30,13 @@ function effectRows(effect, columns) {
30
30
  { text: effect.path, opaque: true },
31
31
  ], columns);
32
32
  }
33
+ else if (effect.kind === "recovery-snapshot") {
34
+ receiptRow(lines, mark, "recovery-snapshot", [
35
+ { text: effect.action },
36
+ { text: effect.snapshot, opaque: true },
37
+ { text: effect.retention },
38
+ ], columns);
39
+ }
33
40
  else {
34
41
  receiptRow(lines, mark, "ref", [
35
42
  { text: effect.action },
@@ -104,7 +111,6 @@ function pushBlock(lines, block) {
104
111
  }
105
112
  function acceptedRecord(result, columns) {
106
113
  const record = [];
107
- receiptRow(record, " ", "head", [{ text: result.head, opaque: true }], columns);
108
114
  for (const fact of result.facts) {
109
115
  const contract = fact.contract === result.contract ? [] : [{ text: fact.contract, opaque: true }];
110
116
  receiptRow(record, " ", "journal", [
@@ -113,15 +119,10 @@ function acceptedRecord(result, columns) {
113
119
  { text: `· ${fact.kind}` },
114
120
  ], columns);
115
121
  }
116
- if (result.verb === "bind") {
117
- receiptRow(record, " ", "target", [{ text: result.target ?? "null", opaque: true }], columns);
118
- }
122
+ receiptRow(record, " ", "head", [{ text: result.head, opaque: true }], columns);
119
123
  if (result.verb === "deliver") {
120
124
  pushBlock(record, reuseLines(result.verificationReuse, columns));
121
125
  }
122
- if (result.verb === "amend") {
123
- receiptPayload(record, "diff", result.diff);
124
- }
125
126
  const changed = result.effects.filter(changedEffect);
126
127
  const unchanged = result.effects.filter((effect) => !changedEffect(effect));
127
128
  for (const effect of [...changed, ...unchanged])
@@ -146,22 +147,15 @@ function acceptedLagRows(result, columns) {
146
147
  }
147
148
  return obligations;
148
149
  }
149
- function acceptedObligations(result, columns) {
150
- const obligations = [];
151
- if (result.verb === "deliver" && result.verification !== undefined) {
152
- obligations.push(...stopLines("verification", result.verification, columns, result.contract));
153
- }
154
- if (result.placement !== undefined) {
155
- obligations.push(...stopLines("claim", result.placement, columns, result.contract));
156
- }
157
- if (result.verb === "deliver") {
158
- if (result.cleanup !== undefined)
159
- pushBlock(obligations, cleanupLines(result.cleanup, columns));
160
- if (result.leak !== undefined)
161
- pushBlock(obligations, leakLines(result.leak, columns));
162
- }
163
- obligations.push(...acceptedLagRows(result, columns));
164
- return obligations;
150
+ function indentRecord(lines) {
151
+ let payload = false;
152
+ return lines.map((line) => {
153
+ if (line.length === 0) {
154
+ payload = !payload;
155
+ return line;
156
+ }
157
+ return payload ? line : ` ${line}`;
158
+ });
165
159
  }
166
160
  function acceptedDeviations(result, columns) {
167
161
  const deviations = [];
@@ -178,32 +172,120 @@ function acceptedDeviations(result, columns) {
178
172
  }
179
173
  return deviations;
180
174
  }
181
- function renderAcceptedReceipt(result, context) {
182
- const columns = context?.columns ?? 80;
183
- const lines = outcomeLines("✓", result.verb, "accepted", result.contract, columns);
184
- if (result.verb === "deliver" || result.verb === "review") {
185
- lines.push(...acceptedObligations(result, columns));
175
+ function recordBlock(result, columns) {
176
+ const rows = [...acceptedRecord(result, columns), ...acceptedLagRows(result, columns)];
177
+ return [" record", ...indentRecord(rows)];
178
+ }
179
+ function verificationVerdictLine(verdict, columns) {
180
+ const lines = [];
181
+ receiptRow(lines, verdict === "satisfied" ? "✓" : "!", "verification", [
182
+ { text: verdict === "satisfied" ? "passed" : "failed" },
183
+ ], columns);
184
+ return lines;
185
+ }
186
+ function renderAcceptedBind(result, columns) {
187
+ const lines = titleLines("✓", "bound", result.contract, columns);
188
+ receiptRow(lines, " ", "workspace", [
189
+ { text: result.workspace === "worktree" ? "managed worktree" : "here" },
190
+ ], columns);
191
+ if (result.target === null)
192
+ receiptRow(lines, " ", "no target", [], columns);
193
+ else
194
+ receiptRow(lines, " ", "target", [{ text: result.target, opaque: true }], columns);
195
+ lines.push(...acceptedDeviations(result, columns), ...recordBlock(result, columns));
196
+ return lines.join("\n");
197
+ }
198
+ function renderAcceptedAmend(result, columns) {
199
+ const lines = titleLines("✓", "terms replaced", result.contract, columns);
200
+ receiptPayload(lines, " terms diff", result.diff);
201
+ lines.push(...acceptedDeviations(result, columns), ...recordBlock(result, columns));
202
+ return lines.join("\n");
203
+ }
204
+ function renderAcceptedDeliver(result, columns) {
205
+ const complete = result.facts.some((fact) => fact.kind === "claimed");
206
+ const title = complete ? "delivered" : "deliver — not complete";
207
+ const lines = titleLines("✓", title, result.contract, columns);
208
+ if (!complete)
209
+ receiptRow(lines, " ", "candidate", [{ text: "kept" }], columns);
210
+ if (result.verification !== undefined) {
211
+ lines.push(...stopLines("verification", result.verification, columns, result.contract));
186
212
  }
187
- else {
188
- lines.push(...acceptedLagRows(result, columns));
213
+ else if (result.verificationVerdict !== undefined) {
214
+ lines.push(...verificationVerdictLine(result.verificationVerdict, columns));
215
+ }
216
+ if (!complete && result.placement !== undefined) {
217
+ lines.push(...stopLines("completion", result.placement, columns, result.contract));
218
+ }
219
+ else if (!complete && (result.verification !== undefined || result.verificationVerdict === "unsatisfied")) {
220
+ receiptRow(lines, "·", "completion", [{ text: "not attempted" }], columns);
221
+ }
222
+ if (result.cleanup !== undefined)
223
+ pushBlock(lines, cleanupLines(result.cleanup, columns));
224
+ if (result.leak !== undefined)
225
+ pushBlock(lines, leakLines(result.leak, columns));
226
+ lines.push(...recordBlock(result, columns));
227
+ return lines.join("\n");
228
+ }
229
+ function renderAcceptedReview(result, columns) {
230
+ const complete = result.facts.some((fact) => fact.kind === "claimed");
231
+ const lines = titleLines("✓", `review ${result.verdict}`, result.contract, columns);
232
+ receiptRow(lines, complete ? "✓" : "!", "contract", [
233
+ { text: complete ? "complete" : "not complete" },
234
+ ], columns);
235
+ if (result.placement !== undefined) {
236
+ lines.push(...stopLines("completion", result.placement, columns, result.contract));
189
237
  }
190
- if (result.verb === "bind" || result.verb === "amend" || result.verb === "review") {
191
- lines.push(...acceptedDeviations(result, columns));
238
+ lines.push(...acceptedDeviations(result, columns), ...recordBlock(result, columns));
239
+ return lines.join("\n");
240
+ }
241
+ function renderAcceptedArc(result, columns) {
242
+ const lines = titleLines("✓", "chapter recorded", result.contract, columns);
243
+ receiptRow(lines, " ", "chapter", [
244
+ { text: String(result.chapter.seq) },
245
+ { text: "·" },
246
+ { text: result.chapter.title },
247
+ ], columns);
248
+ lines.push(...recordBlock(result, columns));
249
+ return lines.join("\n");
250
+ }
251
+ function renderAcceptedAbandon(result, columns) {
252
+ const lines = titleLines("✓", "abandoned", result.contract, columns);
253
+ if (result.note !== undefined)
254
+ receiptRow(lines, " ", "note", [{ text: result.note }], columns);
255
+ for (const effect of result.effects) {
256
+ if (effect.kind === "worktree") {
257
+ receiptRow(lines, " ", "workspace", [
258
+ { text: effect.action },
259
+ { text: effect.path, opaque: true },
260
+ ], columns);
261
+ }
262
+ else if (effect.kind === "recovery-snapshot") {
263
+ receiptRow(lines, " ", "recovery snapshot", [
264
+ { text: effect.snapshot, opaque: true },
265
+ { text: `· ${effect.retention}` },
266
+ ], columns);
267
+ }
192
268
  }
193
- lines.push(...acceptedRecord(result, columns));
269
+ lines.push(...recordBlock(result, columns));
194
270
  return lines.join("\n");
195
271
  }
196
272
  export function renderAccepted(result, context) {
273
+ const columns = context?.columns ?? 80;
197
274
  switch (result.verb) {
198
275
  case "audit":
199
276
  return renderAcceptedAudit(result, context);
200
277
  case "bind":
278
+ return renderAcceptedBind(result, columns);
201
279
  case "amend":
202
- case "deliver":
280
+ return renderAcceptedAmend(result, columns);
203
281
  case "review":
282
+ return renderAcceptedReview(result, columns);
204
283
  case "arc":
284
+ return renderAcceptedArc(result, columns);
205
285
  case "abandon":
206
- return renderAcceptedReceipt(result, context);
286
+ return renderAcceptedAbandon(result, columns);
287
+ case "deliver":
288
+ return renderAcceptedDeliver(result, columns);
207
289
  }
208
290
  }
209
291
  export function renderRetry(result, context) {
@@ -213,3 +295,88 @@ export function renderRetry(result, context) {
213
295
  : [];
214
296
  return [...outcomeLines("?", result.verb, "retry", result.contract, columns), ...detail].join("\n");
215
297
  }
298
+ function journalCount(events, source) {
299
+ return events.filter((event) => event.source === source).length;
300
+ }
301
+ function journalHead(fact) {
302
+ return fact.actor === undefined
303
+ ? `${fact.at} ${fact.kind} · ${fact.entry}`
304
+ : `${fact.at} ${fact.kind} · ${fact.entry} · ${fact.actor}`;
305
+ }
306
+ function listFact(label, values) {
307
+ return values.length === 0 ? [` ${label} 0`] : [` ${label} ${values.join(" · ")}`];
308
+ }
309
+ function journalBody(fact) {
310
+ switch (fact.kind) {
311
+ case "bind": {
312
+ const { coordinates, terms } = fact.data;
313
+ return [
314
+ ` start ${coordinates.start}`,
315
+ ...(coordinates.target === undefined ? [] : [` target ${coordinates.target}`]),
316
+ ` workspace ${coordinates.workspace}`,
317
+ ` document ${terms.document.key}`,
318
+ ...listFact("gates", terms.gates),
319
+ ...listFact("after", terms.after),
320
+ ];
321
+ }
322
+ case "amend":
323
+ return [
324
+ ` document ${fact.data.document.key}`,
325
+ ...listFact("gates", fact.data.gates),
326
+ ...listFact("after", fact.data.after),
327
+ ];
328
+ case "bound":
329
+ return [];
330
+ case "deliver": {
331
+ const { tenderSnapshot, integration, method, policy } = fact.data;
332
+ return [
333
+ ` tender ${tenderSnapshot}`,
334
+ ` predecessor ${integration.predecessor}`,
335
+ ` snapshot ${integration.snapshot}`,
336
+ ` change ${integration.changeId}`,
337
+ ` method ${method}`,
338
+ ` require-branches-to-be-up-to-date ${String(policy.requireBranchesToBeUpToDate)}`,
339
+ ];
340
+ }
341
+ case "attestation": {
342
+ const lines = [
343
+ ` gate ${fact.data.gate}`,
344
+ ` verdict ${fact.data.verdict}`,
345
+ ` subject ${fact.data.subject}`,
346
+ ];
347
+ if (fact.data.summary !== undefined)
348
+ receiptPayload(lines, "summary", fact.data.summary);
349
+ return lines;
350
+ }
351
+ case "claimed":
352
+ return [` delivery ${fact.data.delivery}`];
353
+ case "arc": {
354
+ const lines = [` sequence ${String(fact.data.seq)}`, ` title ${fact.data.title}`];
355
+ receiptPayload(lines, "objective", fact.data.objective);
356
+ receiptPayload(lines, "brief", fact.data.brief);
357
+ return lines;
358
+ }
359
+ case "abandoned": {
360
+ if (fact.data.note === undefined)
361
+ return [];
362
+ const lines = [];
363
+ receiptPayload(lines, "note", fact.data.note);
364
+ return lines;
365
+ }
366
+ }
367
+ }
368
+ function contractHistoryEventLines(event) {
369
+ if (event.source === "dispatch") {
370
+ return [`${event.dispatch.dispatchedAt} dispatch · ${event.dispatch.akuId}`];
371
+ }
372
+ return [journalHead(event.fact), ...journalBody(event.fact)];
373
+ }
374
+ export function renderContractHistory(history) {
375
+ const journals = journalCount(history.events, "journal");
376
+ const dispatches = journalCount(history.events, "dispatch");
377
+ return [
378
+ `history ${history.id} · ${journals} journal · ${dispatches} dispatch`,
379
+ "",
380
+ ...history.events.flatMap(contractHistoryEventLines),
381
+ ].join("\n");
382
+ }
@@ -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;
@@ -73,7 +80,8 @@ export function stopLines(label, stop, columns, addressed) {
73
80
  }
74
81
  }
75
82
  const lines = [];
76
- receiptRow(lines, "!", label, detail, columns);
83
+ const state = label === "verification" ? "failed" : "blocked";
84
+ receiptRow(lines, "!", label, [{ text: state }, { text: "·" }, ...detail], columns);
77
85
  if ("failure" in stop && stop.failure === "environment-failure" && "command" in stop) {
78
86
  appendHookPayload(lines, stop.detail);
79
87
  }
@@ -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";
@@ -29,6 +29,7 @@ export type AcceptedEnvelope = Readonly<{
29
29
  }>;
30
30
  export type AcceptedBindResult = AcceptedEnvelope & Readonly<{
31
31
  verb: "bind";
32
+ workspace: "worktree" | "here";
32
33
  target: string | null;
33
34
  verification?: never;
34
35
  verificationReuse?: never;
@@ -36,8 +37,11 @@ export type AcceptedBindResult = AcceptedEnvelope & Readonly<{
36
37
  cleanup?: never;
37
38
  leak?: never;
38
39
  report?: never;
39
- workspace?: never;
40
40
  diff?: never;
41
+ verificationVerdict?: never;
42
+ verdict?: never;
43
+ chapter?: never;
44
+ note?: never;
41
45
  }> & RegionObservation;
42
46
  export type AcceptedAmendResult = AcceptedEnvelope & Readonly<{
43
47
  verb: "amend";
@@ -50,9 +54,14 @@ export type AcceptedAmendResult = AcceptedEnvelope & Readonly<{
50
54
  leak?: never;
51
55
  report?: never;
52
56
  workspace?: never;
57
+ verificationVerdict?: never;
58
+ verdict?: never;
59
+ chapter?: never;
60
+ note?: never;
53
61
  }> & RegionObservation;
54
62
  export type AcceptedDeliverResult = AcceptedEnvelope & Readonly<{
55
63
  verb: "deliver";
64
+ verificationVerdict?: "satisfied" | "unsatisfied";
56
65
  verification?: VerificationStop;
57
66
  verificationReuse?: VerificationReuse;
58
67
  placement?: PlacementStop;
@@ -64,9 +73,13 @@ export type AcceptedDeliverResult = AcceptedEnvelope & Readonly<{
64
73
  report?: never;
65
74
  workspace?: never;
66
75
  diff?: never;
76
+ verdict?: never;
77
+ chapter?: never;
78
+ note?: never;
67
79
  }>;
68
80
  export type AcceptedReviewResult = AcceptedEnvelope & Readonly<{
69
81
  verb: "review";
82
+ verdict: "satisfied" | "unsatisfied";
70
83
  placement?: PlacementStop;
71
84
  workspace?: Review["workspace"];
72
85
  target?: never;
@@ -78,9 +91,16 @@ export type AcceptedReviewResult = AcceptedEnvelope & Readonly<{
78
91
  overlapFailure?: never;
79
92
  report?: never;
80
93
  diff?: never;
94
+ verificationVerdict?: never;
95
+ chapter?: never;
96
+ note?: never;
81
97
  }>;
82
98
  export type AcceptedArcResult = AcceptedEnvelope & Readonly<{
83
99
  verb: "arc";
100
+ chapter: Readonly<{
101
+ seq: number;
102
+ title: string;
103
+ }>;
84
104
  target?: never;
85
105
  verification?: never;
86
106
  verificationReuse?: never;
@@ -92,9 +112,13 @@ export type AcceptedArcResult = AcceptedEnvelope & Readonly<{
92
112
  report?: never;
93
113
  workspace?: never;
94
114
  diff?: never;
115
+ verificationVerdict?: never;
116
+ verdict?: never;
117
+ note?: never;
95
118
  }>;
96
119
  export type AcceptedAbandonResult = AcceptedEnvelope & Readonly<{
97
120
  verb: "abandon";
121
+ note?: string;
98
122
  target?: never;
99
123
  verification?: never;
100
124
  verificationReuse?: never;
@@ -106,6 +130,9 @@ export type AcceptedAbandonResult = AcceptedEnvelope & Readonly<{
106
130
  report?: never;
107
131
  workspace?: never;
108
132
  diff?: never;
133
+ verificationVerdict?: never;
134
+ verdict?: never;
135
+ chapter?: never;
109
136
  }>;
110
137
  export type AcceptedAuditResult = AcceptedEnvelope & Readonly<{
111
138
  verb: "audit";
@@ -120,6 +147,10 @@ export type AcceptedAuditResult = AcceptedEnvelope & Readonly<{
120
147
  overlapFailure?: never;
121
148
  workspace?: never;
122
149
  diff?: never;
150
+ verificationVerdict?: never;
151
+ verdict?: never;
152
+ chapter?: never;
153
+ note?: never;
123
154
  }>;
124
155
  export type AcceptedResult = AcceptedBindResult | AcceptedAmendResult | AcceptedDeliverResult | AcceptedReviewResult | AcceptedArcResult | AcceptedAbandonResult | AcceptedAuditResult;
125
156
  export type RefusedResult = Readonly<{
@@ -158,5 +189,9 @@ export type CatalogResult = Readonly<{
158
189
  kind: "catalog";
159
190
  catalog: Catalog;
160
191
  }>;
161
- export type InvocationResult = AcceptedResult | RefusedResult | RetryResult | ObservationResult | GuidanceResult | StatusResult | RegionResult | CatalogResult;
192
+ export type ContractHistoryResult = Readonly<{
193
+ kind: "contract-history";
194
+ history: ContractHistory;
195
+ }>;
196
+ export type InvocationResult = AcceptedResult | RefusedResult | RetryResult | ObservationResult | GuidanceResult | StatusResult | RegionResult | CatalogResult | ContractHistoryResult;
162
197
  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
+ }
@@ -3,5 +3,7 @@ export declare class CliUsageError extends Error {
3
3
  readonly projection?: string | undefined;
4
4
  constructor(diagnostic: string, projection?: string | undefined);
5
5
  }
6
+ export declare const JSON_AUTOMATION_HELP = "--json is only for automation script input/output and should not be used for daily interactive use.";
7
+ export declare function withJsonAutomationHelp(help: string): string;
6
8
  export declare function isBlankInput(value: string): boolean;
7
9
  export declare function usageLine(usage: string): string;
@@ -8,6 +8,10 @@ export class CliUsageError extends Error {
8
8
  this.name = "CliUsageError";
9
9
  }
10
10
  }
11
+ export const JSON_AUTOMATION_HELP = "--json is only for automation script input/output and should not be used for daily interactive use.";
12
+ export function withJsonAutomationHelp(help) {
13
+ return help.includes("--json") ? `${help}\n\n${JSON_AUTOMATION_HELP}` : help;
14
+ }
11
15
  export function isBlankInput(value) {
12
16
  return value.trim().length === 0;
13
17
  }
@@ -48,6 +48,9 @@ const FULFILLMENT = [
48
48
  "### Deliverer", "",
49
49
  "Implement and verify the Objective under the Design, Region, and Criteria in this Contract.",
50
50
  "When an Arc is active, stay within that current chapter.",
51
+ "For work requiring three or more steps, prefer `keiyaku task -C <worktree>` "
52
+ + "to organize and manage Tasks.",
53
+ "Promptly update progress for Tasks already present in the current worktree.",
51
54
  "Leave lifecycle decisions to the caller; report the candidate, verification performed, and any unmet term.", "",
52
55
  "### Reviewer", "",
53
56
  "Review this Contract worktree against the complete Contract.",