@astrosheep/keiyaku 2.9.11 → 2.9.13

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 (218) hide show
  1. package/README.md +79 -85
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/call-terms.js +1 -0
  4. package/build/agents/providers/claude-agent-sdk/adapter.js +17 -4
  5. package/build/cli/commands/akuma/akuma/handler.js +2 -1
  6. package/build/cli/commands/akuma/akuma/meta.js +4 -3
  7. package/build/cli/commands/akuma/catalog.js +2 -0
  8. package/build/cli/commands/akuma/list/handler.js +1 -1
  9. package/build/cli/commands/akuma/list/meta-list.js +12 -0
  10. package/build/cli/commands/akuma/list/meta-ls.js +2 -2
  11. package/build/cli/commands/akuma.js +5 -0
  12. package/build/cli/commands/contract/amend/meta.js +4 -3
  13. package/build/cli/commands/contract/arc/meta.js +2 -0
  14. package/build/cli/commands/contract/audit/handler.js +28 -2
  15. package/build/cli/commands/contract/audit/meta.js +4 -3
  16. package/build/cli/commands/contract/bind/meta.js +4 -4
  17. package/build/cli/commands/contract/petition/handler.js +2 -1
  18. package/build/cli/commands/contract/petition/meta.js +2 -2
  19. package/build/cli/commands/contract/renew/handler.js +44 -3
  20. package/build/cli/commands/contract/renew/meta.js +5 -4
  21. package/build/cli/commands/metadata.js +14 -10
  22. package/build/cli/commands/projection/call/handler.js +1 -1
  23. package/build/cli/commands/projection/call/meta.js +1 -1
  24. package/build/cli/commands/projection/catalog.js +2 -2
  25. package/build/cli/commands/projection/{revive → fork}/handler.js +10 -5
  26. package/build/cli/commands/projection/fork/meta.js +12 -0
  27. package/build/cli/commands/projection/history/handler.js +46 -2
  28. package/build/cli/commands/projection/history/meta.js +3 -3
  29. package/build/cli/commands/projection/kill/handler.js +4 -5
  30. package/build/cli/commands/projection/kill/meta.js +2 -2
  31. package/build/cli/commands/projection/status/handler.js +29 -13
  32. package/build/cli/commands/projection/status/meta.js +14 -3
  33. package/build/cli/commands/projection/tell/handler.js +8 -4
  34. package/build/cli/commands/projection/tell/meta.js +1 -1
  35. package/build/cli/commands/projection/wait/handler.js +45 -20
  36. package/build/cli/commands/projection/wait/meta.js +1 -1
  37. package/build/cli/commands/shared.js +2 -2
  38. package/build/cli/commands/system/catalog.js +2 -0
  39. package/build/cli/commands/task/add/handler.js +28 -12
  40. package/build/cli/commands/task/add/meta.js +18 -6
  41. package/build/cli/commands/task/catalog.js +4 -0
  42. package/build/cli/commands/task/compose/handler.js +18 -0
  43. package/build/cli/commands/task/compose/meta.js +10 -0
  44. package/build/cli/commands/task/doctor/handler.js +2 -3
  45. package/build/cli/commands/task/doctor/meta.js +2 -2
  46. package/build/cli/commands/task/done/meta.js +2 -2
  47. package/build/cli/commands/task/drop/handler.js +7 -2
  48. package/build/cli/commands/task/drop/meta.js +6 -3
  49. package/build/cli/commands/task/hold/meta.js +2 -2
  50. package/build/cli/commands/task/log/meta.js +2 -2
  51. package/build/cli/commands/task/ls/meta.js +2 -2
  52. package/build/cli/commands/task/note/handler.js +6 -0
  53. package/build/cli/commands/task/note/meta.js +11 -0
  54. package/build/cli/commands/task/resume/meta.js +2 -2
  55. package/build/cli/commands/task/shared.js +29 -15
  56. package/build/cli/commands/task/show/meta.js +2 -2
  57. package/build/cli/commands/task/start/meta.js +2 -2
  58. package/build/cli/commands/task/stop/meta.js +2 -2
  59. package/build/cli/commands/task/update/meta.js +3 -2
  60. package/build/cli/commands/verification/handler.js +43 -0
  61. package/build/cli/commands/verification/meta.js +13 -0
  62. package/build/cli/completion.js +16 -13
  63. package/build/cli/flags.js +48 -12
  64. package/build/cli/help.js +29 -30
  65. package/build/cli/index.js +14 -8
  66. package/build/cli/parse-flags.js +60 -21
  67. package/build/cli/parse-metadata.js +10 -4
  68. package/build/cli/parse-selectors.js +22 -4
  69. package/build/cli/parse.js +43 -30
  70. package/build/cli/projection-address.js +7 -7
  71. package/build/cli/render/arc.js +12 -3
  72. package/build/cli/render/audit.js +2 -2
  73. package/build/cli/render/call.js +4 -4
  74. package/build/cli/render/kanshi.js +122 -85
  75. package/build/cli/render/misc.js +2 -2
  76. package/build/cli/render/petition.js +16 -1
  77. package/build/cli/render/projection-history.js +17 -4
  78. package/build/cli/render/shared.js +5 -5
  79. package/build/cli/render/status-indicator.js +47 -0
  80. package/build/cli/render/status.js +106 -76
  81. package/build/cli/render/success-response.js +20 -5
  82. package/build/cli/render/task.js +33 -5
  83. package/build/cli/render/tell.js +10 -4
  84. package/build/cli/render/tool-command-normalization.js +137 -0
  85. package/build/cli/render/tool-presentation.js +2 -1
  86. package/build/cli/render/verification.js +23 -0
  87. package/build/cli/render/wait.js +101 -33
  88. package/build/cli/types.js +2 -1
  89. package/build/config/akuma-loader.js +21 -1
  90. package/build/config/settings/knobs.js +7 -1
  91. package/build/config/settings/schema.js +10 -5
  92. package/build/core/addressing.js +3 -3
  93. package/build/core/amend.js +102 -17
  94. package/build/core/arc.js +4 -4
  95. package/build/core/audit/candidate.js +10 -18
  96. package/build/core/audit/coordinates.js +12 -17
  97. package/build/core/audit/evidence.js +6 -4
  98. package/build/core/audit/facade.js +3 -3
  99. package/build/core/audit/report.js +1 -1
  100. package/build/core/bind-reconciliation.js +42 -23
  101. package/build/core/bind.js +182 -81
  102. package/build/core/call/call.js +6 -7
  103. package/build/core/call/context.js +46 -33
  104. package/build/core/call/execution.js +21 -6
  105. package/build/core/call/prompt.js +11 -42
  106. package/build/core/contract-carrier-runtime.js +209 -105
  107. package/build/core/contract-carrier.js +156 -73
  108. package/build/core/contract-view.js +43 -6
  109. package/build/core/contract.js +2 -1
  110. package/build/core/derived-replay.js +168 -35
  111. package/build/core/draft.js +60 -27
  112. package/build/core/forfeit.js +1 -1
  113. package/build/core/lifecycle-history.js +13 -0
  114. package/build/core/lifecycle-recovery.js +32 -27
  115. package/build/core/lifecycle-runner.js +14 -14
  116. package/build/core/log.js +1 -1
  117. package/build/core/outcome-base.js +2 -2
  118. package/build/core/projection/akuma-name.js +43 -0
  119. package/build/core/projection/generation/database.js +141 -79
  120. package/build/core/projection/generation/ledger.js +91 -0
  121. package/build/core/projection/generation/model.js +19 -14
  122. package/build/core/projection/generation/projection-generation-continuation.js +1 -1
  123. package/build/core/projection/generation/projection-generation-doorbell.js +88 -0
  124. package/build/core/projection/generation/projection-generation-execution.js +24 -0
  125. package/build/core/projection/generation/projection-generation-identity.js +4 -0
  126. package/build/core/projection/generation/projection-generation-launcher.js +72 -138
  127. package/build/core/projection/generation/projection-generation-process.js +16 -15
  128. package/build/core/projection/generation/projection-generation-runner.js +132 -76
  129. package/build/core/projection/generation/projection-generation-runtime.js +10 -61
  130. package/build/core/projection/generation/protocol.js +68 -0
  131. package/build/core/projection/generation/store.js +17 -7
  132. package/build/core/projection/generation/transitions.js +24 -14
  133. package/build/core/projection/index.js +5 -5
  134. package/build/core/projection/projection-core.js +6 -2
  135. package/build/core/projection/projection-execution-observer.js +1 -1
  136. package/build/core/projection/projection-history.js +8 -8
  137. package/build/core/projection/projection-kill.js +20 -10
  138. package/build/core/projection/projection-life-observer.js +8 -8
  139. package/build/core/projection/projection-mint.js +6 -8
  140. package/build/core/projection/projection-status-observation.js +77 -8
  141. package/build/core/projection/projection-status.js +151 -4
  142. package/build/core/projection/projection-wait.js +48 -29
  143. package/build/core/projection/projection-wake.js +28 -88
  144. package/build/core/projection/tell/launch-store.js +1 -1
  145. package/build/core/projection/tell/store.js +1 -1
  146. package/build/core/renew-build.js +204 -74
  147. package/build/core/renew-plan.js +34 -9
  148. package/build/core/renew-rewrite.js +56 -15
  149. package/build/core/renew.js +39 -35
  150. package/build/core/repository-ledger/accepted-fold-read.js +6 -3
  151. package/build/core/repository-ledger/claim-evidence.js +1 -1
  152. package/build/core/repository-ledger/codec.js +11 -5
  153. package/build/core/repository-ledger/current-state-store.js +464 -349
  154. package/build/core/repository-ledger/fold-repository.js +5 -6
  155. package/build/core/repository-ledger/identity.js +60 -0
  156. package/build/core/repository-ledger/inventory.js +3 -3
  157. package/build/core/repository-ledger/read-model.js +57 -9
  158. package/build/core/repository-ledger/write-transaction.js +24 -17
  159. package/build/core/run-control/connection-bound-close.js +41 -0
  160. package/build/core/run-control/detached-lease-bootstrap.js +208 -0
  161. package/build/core/run-control/detached-process.js +14 -0
  162. package/build/core/run-control/index.js +6 -0
  163. package/build/core/{process-group.js → run-control/process-tree.js} +1 -1
  164. package/build/core/run-control/runner-lease.js +172 -0
  165. package/build/core/run-control/sqlite-process-lifetime-lock.js +174 -0
  166. package/build/core/seal.js +44 -32
  167. package/build/core/settlement/claim-delivery.js +22 -9
  168. package/build/core/settlement/claim.js +8 -6
  169. package/build/core/settlement/petition-claim-gates.js +9 -8
  170. package/build/core/settlement/petition-head-guard.js +5 -6
  171. package/build/core/settlement/petition-preview.js +21 -5
  172. package/build/core/settlement/petition.js +51 -17
  173. package/build/core/settlement/settlement.js +20 -15
  174. package/build/core/settlement/verdict.js +2 -2
  175. package/build/core/settlement/verification.js +492 -364
  176. package/build/core/status/board.js +184 -75
  177. package/build/core/status/drift.js +8 -10
  178. package/build/core/task/board.js +1 -0
  179. package/build/core/task/commands.js +25 -0
  180. package/build/core/task/compose.js +328 -0
  181. package/build/core/task/document.js +102 -39
  182. package/build/core/task/index.js +4 -3
  183. package/build/core/task/settlement-git.js +70 -30
  184. package/build/core/task/settlement-policy.js +27 -14
  185. package/build/core/task/source-board.js +1 -0
  186. package/build/core/task/task-bind-preparation.js +59 -9
  187. package/build/core/task/task-contract.js +2 -2
  188. package/build/core/task/task-git-store.js +1 -0
  189. package/build/core/task/task-store-repository.js +2 -0
  190. package/build/core/task/task.js +2 -2
  191. package/build/core/transcripts.js +4 -4
  192. package/build/core/verification-declaration.js +95 -0
  193. package/build/core/worktree-bootstrap.js +1 -1
  194. package/build/core/worktree-path.js +7 -11
  195. package/build/flow-error.js +15 -2
  196. package/build/generated/version.js +2 -2
  197. package/build/git/branches.js +41 -70
  198. package/build/git/commits.js +92 -21
  199. package/build/git/core.js +9 -161
  200. package/build/git/diff/preview.js +4 -4
  201. package/build/git/diff/read.js +4 -4
  202. package/build/git/diff/structured.js +5 -5
  203. package/build/git/process.js +229 -0
  204. package/build/git/refs.js +30 -5
  205. package/build/git/staging.js +39 -115
  206. package/build/git/streaming-batch.js +9 -16
  207. package/build/git/worktree.js +104 -91
  208. package/build/index.js +7 -0
  209. package/package.json +2 -2
  210. package/skills/keiyaku-akuma/SKILL.md +27 -21
  211. package/skills/keiyaku-task/SKILL.md +61 -5
  212. package/skills/keiyaku-workflow/SKILL.md +81 -26
  213. package/build/cli/commands/projection/revive/meta.js +0 -12
  214. package/build/core/projection/projection-life-protocol.js +0 -115
  215. package/build/core/projection/projection-runner-lock.js +0 -382
  216. package/build/core/projection/tell/database.js +0 -127
  217. package/build/core/settlement/verification-coordination.js +0 -305
  218. package/build/core/settlement/verification-supervisor.js +0 -275
@@ -1,9 +1,10 @@
1
1
  import { getConfig } from "../../config/env.js";
2
2
  import { formatAgeMs } from "./format.js";
3
3
  import { displayColumns, resolveLineColumns, truncateColumns } from "./line-width.js";
4
- import { renderPendingProjectionTell, renderProjectionActivity, selectProjectionActivityWindow, } from "./projection-activity.js";
4
+ import { renderProjectionActivitySummary, } from "./projection-activity.js";
5
+ import { contractStatusIndicator, projectionStatusIndicator, STATUS_INDICATOR_LEGEND, taskStatusIndicator, } from "./status-indicator.js";
5
6
  const KANSHI_MAX_COLUMNS = 120;
6
- const KANSHI_ACTIVITY_ROWS = 3;
7
+ const KANSHI_MAX_LINES = 40;
7
8
  function shortHead(hash) {
8
9
  return hash?.slice(0, 7);
9
10
  }
@@ -80,27 +81,31 @@ export function orderKanshiContracts(contracts) {
80
81
  }
81
82
  function renderDriftMark(drift) {
82
83
  if (drift.state === "drift")
83
- return `▲${drift.behindBy}`;
84
+ return `behind ${drift.defaultBranch} by ${drift.behindBy}`;
84
85
  if (drift.state === "orphaned")
85
- return "▲orphaned";
86
+ return `base not on ${drift.defaultBranch}`;
86
87
  return undefined;
87
88
  }
88
- function contractGlyph(contract) {
89
- if (contract.state.state === "corrupt")
90
- return "×";
91
- return pendingAfterIds(contract).length > 0 ? "⧗" : "□";
89
+ function contractIndicator(contract) {
90
+ return contractStatusIndicator({
91
+ state: contract.state.state,
92
+ waiting: pendingAfterIds(contract).length > 0,
93
+ broken: contract.queueHeadStalled || contract.replayBlockers.length > 0,
94
+ });
92
95
  }
93
96
  function contractFacts(contract) {
94
97
  const facts = [];
95
98
  const spark = arcSparkline(contract.arcs);
96
99
  if (spark)
97
100
  facts.push({ text: spark });
101
+ const waitingOn = pendingAfterIds(contract);
102
+ if (waitingOn.length > 0)
103
+ facts.push({ text: `waiting on ${waitingOn.join(", ")}` });
98
104
  const drift = renderDriftMark(contract.baseDrift);
99
105
  if (drift)
100
106
  facts.push({ text: drift });
101
- const lifecycle = contract.state.state === "active" ? "open" : contract.state.state;
102
107
  const age = formatAgeMs(contract.lastActiveMs);
103
- facts.push({ text: age ? `${lifecycle} ${age}` : lifecycle });
108
+ facts.push({ text: age ? `${contract.state.state} ${age}` : contract.state.state });
104
109
  if (contract.queueHeadStalled) {
105
110
  facts.push({ text: age ? `stalled ${age}` : "stalled", tone: "alert" });
106
111
  }
@@ -112,11 +117,26 @@ function renderKeiyakuSection(board, width) {
112
117
  const lines = [`keiyaku ${board.contracts.length}`];
113
118
  for (const contract of orderKanshiContracts(board.contracts)) {
114
119
  lines.push(alignedBoardRow({
115
- prefix: `${contractGlyph(contract)} ${contract.place ?? contract.slug}`,
120
+ prefix: `${contractIndicator(contract)} ${contract.place ?? contract.slug}`,
116
121
  title: contract.title,
117
122
  facts: contractFacts(contract),
118
123
  width,
119
124
  }));
125
+ if (contract.tasks) {
126
+ const progress = contract.tasks;
127
+ const summary = `${progress.done}/${progress.total} done`;
128
+ if (board.commissionFilter === contract.id) {
129
+ for (const task of progress.tasks) {
130
+ lines.push(` ${taskStatusIndicator(task)} task ${task.coordinate} · ${task.state} · ${task.title}`);
131
+ }
132
+ }
133
+ else if (progress.current) {
134
+ lines.push(` ${taskStatusIndicator(progress.current)} task ${summary} · ${progress.current.state} · ${progress.current.coordinate} · ${progress.current.title}`);
135
+ }
136
+ else {
137
+ lines.push(` task ${summary}`);
138
+ }
139
+ }
120
140
  if (contract.replayBlockers.length > 0) {
121
141
  lines.push(` ! incomplete replay · ${contract.replayBlockers.map((blocker) => blocker.surface).join(", ")}`);
122
142
  lines.push(` • ${contract.replayBlockers[0].recoveryCommand}`);
@@ -147,81 +167,71 @@ function projectionBinding(board, row) {
147
167
  }
148
168
  function projectionFacts(row) {
149
169
  const facts = [];
150
- if (row.durationMs !== undefined)
151
- facts.push({ text: `up ${formatAgeMs(row.durationMs) ?? "0s"}` });
170
+ const terminal = row.state === "done" || row.state === "failed" || row.state === "dead"
171
+ || row.state === "killed" || row.state === "dismissed" || row.state === "incompatible";
172
+ const terminalAge = row.terminalAgeMs === undefined ? undefined : formatAgeMs(row.terminalAgeMs);
173
+ facts.push({ text: terminalAge ? `${row.state} ${terminalAge} ago` : row.state, tone: row.state === "startup-timeout" ? "alert" : "normal" });
174
+ if (row.durationMs !== undefined) {
175
+ facts.push({ text: `${terminal ? "ran" : "running for"} ${formatAgeMs(row.durationMs) ?? "0s"}` });
176
+ }
152
177
  if (row.activityAgeMs !== undefined)
153
- facts.push({ text: `active ${formatAgeMs(row.activityAgeMs) ?? "0s"}` });
154
- if (row.state !== "out" && row.state !== "minting")
155
- facts.push({ text: row.state, tone: row.state === "startup-timeout" ? "alert" : "normal" });
178
+ facts.push({ text: `last activity ${formatAgeMs(row.activityAgeMs) ?? "0s"} ago` });
156
179
  return facts;
157
180
  }
158
- function renderEmbeddedActivity(row, width) {
159
- const observedAtMs = row.observedAtMs ?? Date.now();
160
- const selection = row.activity
161
- ? selectProjectionActivityWindow(row.activity, KANSHI_ACTIVITY_ROWS)
162
- : undefined;
163
- const ordinary = row.activity
164
- ? renderProjectionActivity(selection.activity, {
165
- anchorMs: observedAtMs,
166
- state: activityState(row),
167
- showPlan: false,
168
- showSilence: false,
169
- ...(row.workspaceRoot ? { workspaceRoot: row.workspaceRoot } : {}),
170
- maxColumns: width,
171
- leadingOmittedCount: selection.leadingOmittedCount,
172
- })
173
- : undefined;
174
- const rendered = ordinary?.lines.map((line, index) => ({
175
- line,
176
- at: ordinary.rowAts[index],
177
- order: index,
178
- })) ?? [];
179
- const tells = (row.pendingTells ?? []).map((tell, index) => ({
180
- line: renderPendingProjectionTell(tell, {
181
- anchorMs: observedAtMs,
182
- maxColumns: width,
183
- renderUnconsumedTail: (tail) => tone(tail, "alert"),
184
- }),
185
- at: tell.createdAt,
186
- order: rendered.length + index,
187
- }));
188
- return [...rendered, ...tells]
189
- .sort((left, right) => {
190
- const leftAt = Date.parse(left.at ?? "");
191
- const rightAt = Date.parse(right.at ?? "");
192
- const safeLeft = Number.isFinite(leftAt) ? leftAt : Number.POSITIVE_INFINITY;
193
- const safeRight = Number.isFinite(rightAt) ? rightAt : Number.POSITIVE_INFINITY;
194
- return safeLeft - safeRight || left.order - right.order;
195
- })
196
- .map((entry) => entry.line);
197
- }
198
- function terminalSummary(board) {
199
- const omitted = board.projections?.omitted;
200
- if (!omitted)
201
- return undefined;
202
- const compatibleStates = ["failed", "dead", "done", "killed", "dismissed"];
203
- const details = compatibleStates
204
- .flatMap((state) => omitted.byState[state] > 0 ? [`${omitted.byState[state]} ${state}`] : []);
205
- return details.length > 0 ? `+ ${details.join(" · ")}` : undefined;
181
+ function renderSnapshot(row) {
182
+ if (!row.activity)
183
+ return "";
184
+ return renderProjectionActivitySummary(row.activity, {
185
+ state: activityState(row),
186
+ ...(row.workspaceRoot ? { workspaceRoot: row.workspaceRoot } : {}),
187
+ }) ?? "";
206
188
  }
207
- function renderAkumaSection(board, width) {
189
+ function renderAkumaSection(board, width, includeRosterFooter = true) {
208
190
  if (!board.projections)
209
- return undefined;
210
- const lines = [`akuma ${board.projections.rows.length}`];
211
- for (const row of board.projections.rows) {
212
- const alias = row.alias ? ` ${row.alias}` : "";
213
- lines.push(alignedBoardRow({
214
- prefix: `◆ ${row.id}${alias}`,
215
- title: projectionBinding(board, row),
216
- titleTone: "normal",
217
- facts: projectionFacts(row),
218
- width,
219
- }));
220
- lines.push(...renderEmbeddedActivity(row, width));
191
+ return "akuma 0\nno akuma out there · full roster: keiyaku status --akuma";
192
+ const triage = board.projections.triage;
193
+ const sections = triage
194
+ ? [
195
+ ["startup failed", triage.startupFailed],
196
+ ["unknown", triage.unknown],
197
+ ["running", triage.active],
198
+ ["recent terminal", triage.recentTerminal],
199
+ ]
200
+ : [[null, board.projections.rows]];
201
+ const total = board.projections.rows.length + (triage?.overflow ?? board.projections.omitted?.total ?? 0);
202
+ const lines = [`akuma ${board.projections.rows.length}/${total}`];
203
+ for (const [label, rows] of sections) {
204
+ if (triage && rows.length === 0)
205
+ continue;
206
+ if (label !== null) {
207
+ const sectionTotal = label === "startup failed"
208
+ ? triage.totals.startupFailed
209
+ : label === "unknown"
210
+ ? triage.totals.unknown
211
+ : label === "running"
212
+ ? triage.totals.active
213
+ : triage.totals.terminal;
214
+ lines.push(`${label} ${rows.length}/${sectionTotal}`);
215
+ }
216
+ for (const row of rows) {
217
+ const identity = row.alias ? `${row.identity.canonicalId} (${row.alias})` : row.identity.canonicalId;
218
+ const pending = (row.pendingTells?.length ?? 0) > 0 ? [{ text: `pending tell ${row.pendingTells.length}` }] : [];
219
+ const snapshot = renderSnapshot(row) || projectionBinding(board, row);
220
+ lines.push(alignedBoardRow({
221
+ prefix: `${projectionStatusIndicator(row.state)} ${identity}`,
222
+ title: snapshot,
223
+ titleTone: "normal",
224
+ facts: [...projectionFacts(row), ...pending],
225
+ width,
226
+ }));
227
+ }
228
+ }
229
+ if (board.projections.rows.length === 0) {
230
+ lines.push(includeRosterFooter ? "no akuma out there · full roster: keiyaku status --akuma" : "no akuma out there");
231
+ }
232
+ else if (includeRosterFooter) {
233
+ lines.push(tone("full roster: keiyaku status --akuma", "description"));
221
234
  }
222
- const folded = terminalSummary(board);
223
- if (folded)
224
- lines.push(tone(folded, "description"));
225
235
  return lines.join("\n");
226
236
  }
227
237
  function taskLabel(task) {
@@ -233,9 +243,9 @@ function renderTaskSection(tasks, width) {
233
243
  const lines = [`task ${tasks.total}`];
234
244
  for (const task of tasks.topTasks) {
235
245
  lines.push(alignedBoardRow({
236
- prefix: "▶",
246
+ prefix: `${taskStatusIndicator(task)} ${task.state}`,
237
247
  title: taskLabel(task),
238
- facts: [{ text: `${task.state === "on_hold" ? "on hold · updated" : "in_progress · active"} ${formatAgeMs(task.activityAgeMs) ?? "0s"}` }],
248
+ facts: [{ text: `last update ${formatAgeMs(task.activityAgeMs) ?? "0s"} ago` }],
239
249
  width,
240
250
  }));
241
251
  }
@@ -248,16 +258,43 @@ function renderTaskSection(tasks, width) {
248
258
  lines.push(tone(`+ ${folded.join(" · ")}`, "description"));
249
259
  return lines.join("\n");
250
260
  }
251
- export function renderKanshiBoard(board) {
261
+ export function renderKanshiBoard(board, beforeAkuma = []) {
252
262
  const width = Math.min(KANSHI_MAX_COLUMNS, resolveLineColumns());
253
263
  const left = "kanshi ";
254
264
  const head = shortHead(board.defaultHead);
255
265
  const right = head ? ` 現世 ${head}` : " 現世";
256
266
  const dashes = "─".repeat(Math.max(1, width - displayColumns(left) - displayColumns(right)));
257
267
  const sections = [
268
+ STATUS_INDICATOR_LEGEND,
258
269
  renderKeiyakuSection(board, width),
270
+ board.commissionFilter === undefined ? renderTaskSection(board.tasks, width) : undefined,
271
+ ...beforeAkuma,
259
272
  renderAkumaSection(board, width),
260
- renderTaskSection(board.tasks, width),
261
273
  ].filter((section) => section !== undefined);
262
- return `${[`${left}${dashes}${right}`, ...sections].join("\n\n")}\n`;
274
+ const header = `${left}${dashes}${right}`;
275
+ const rendered = [header, ...sections].join("\n\n");
276
+ if (board.commissionFilter !== undefined || rendered.split("\n").length <= KANSHI_MAX_LINES) {
277
+ return `${rendered}\n`;
278
+ }
279
+ const akuma = sections.at(-1);
280
+ const leading = sections.slice(0, -1).join("\n\n").split("\n");
281
+ const akumaLines = akuma.split("\n");
282
+ const leadingBudget = Math.max(0, KANSHI_MAX_LINES - 3 - akumaLines.length);
283
+ const visible = leading.slice(0, Math.max(0, leadingBudget - 1));
284
+ while (visible.at(-1) === "")
285
+ visible.pop();
286
+ const omitted = leading.length - visible.length;
287
+ if (omitted > 0 && leadingBudget > 0)
288
+ visible.push(tone(`+ ${omitted} board lines omitted`, "description"));
289
+ return `${[header, visible.join("\n"), akuma].filter(Boolean).join("\n\n")}\n`;
290
+ }
291
+ /** Akuma roster mouth: reuse the shared frame and row grammar without unrelated board sections. */
292
+ export function renderAkumaRosterBoard(board) {
293
+ const width = Math.min(KANSHI_MAX_COLUMNS, resolveLineColumns());
294
+ const left = "kanshi ";
295
+ const head = shortHead(board.defaultHead);
296
+ const right = head ? ` 現世 ${head}` : " 現世";
297
+ const dashes = "─".repeat(Math.max(1, width - displayColumns(left) - displayColumns(right)));
298
+ const akuma = renderAkumaSection(board, width, false) ?? "akuma 0\nno akuma out there";
299
+ return `${[`${left}${dashes}${right}`, STATUS_INDICATOR_LEGEND, akuma].join("\n\n")}\n`;
263
300
  }
@@ -31,7 +31,7 @@ function buildErrorText(input) {
31
31
  const errorSection = buildSection("Error", input.message);
32
32
  const conflictSection = input.facts?.kind === "renew_conflict_scratch"
33
33
  ? buildSection("Conflict scratch", [
34
- input.facts.scratchPath,
34
+ `${input.facts.scratchPath}/files`,
35
35
  "",
36
36
  "Conflicting paths:",
37
37
  ...input.facts.conflictPaths.map((filePath) => ` ${filePath}`),
@@ -52,7 +52,7 @@ function buildErrorText(input) {
52
52
  : undefined;
53
53
  const nextActionSection = input.facts?.kind === "renew_conflict_scratch" && renewAddress
54
54
  ? buildSection("Next action", [
55
- "Resolve files in the conflict scratch, then:",
55
+ "Resolve files in the linked conflict worktree, then:",
56
56
  `» keiyaku ${renewAddress} renew --continue`,
57
57
  "Or discard the conflict scratch:",
58
58
  `» keiyaku ${renewAddress} renew --abort`,
@@ -30,6 +30,15 @@ export function buildPetitionPreviewResponse(preview, json) {
30
30
  : [
31
31
  `contract ${commissionSlug(preview.contract)}`,
32
32
  `arc ${source}`,
33
+ ...(preview.scopeWarning
34
+ ? [
35
+ `Scope warning: ${preview.scopeWarning.violations.join(", ")}`,
36
+ ...preview.scopeWarning.evidence.map((evidence) => {
37
+ const patterns = evidence.patterns.length ? ` · ${evidence.patterns.map((pattern) => pattern.pattern).join(", ")}` : "";
38
+ return ` ${evidence.path} · ${evidence.outcome}${patterns}`;
39
+ }),
40
+ ]
41
+ : []),
33
42
  ...preview.gates.map((gate) => {
34
43
  if (gate.result === "not_evaluated")
35
44
  return `gate ${gate.name} · not evaluated`;
@@ -53,7 +62,13 @@ export function buildPetitionClaimResponse(result, input) {
53
62
  const summary = `Claimed contract${commitSuffix}.`;
54
63
  const diffSection = result.diff ? buildSection(DIFF_OVERVIEW_SECTION_TITLE, result.diff) : null;
55
64
  const ledgerSection = result.ledgerView ? buildSection("Ledger", result.ledgerView) : null;
56
- const warningSection = buildSection(WARNING_SECTION_TITLE, formatWarnings(result.meta?.warnings ?? []));
65
+ const scopeWarning = result.sealed?.scopeAudit.violations.length
66
+ ? [`Scope warning: ${result.sealed.scopeAudit.violations.join(", ")}`]
67
+ : [];
68
+ const warningSection = buildSection(WARNING_SECTION_TITLE, [
69
+ ...scopeWarning,
70
+ ...formatWarnings(result.meta?.warnings ?? []),
71
+ ]);
57
72
  const infoLines = [
58
73
  ...formatMaybe("Result", result.result, INFO_COMMIT_MAX_CHARS),
59
74
  ...formatMaybe("Title", input.title),
@@ -28,17 +28,30 @@ function runLines(run) {
28
28
  `activity: ${run.activityRetention} · ${run.activityCount} retained${run.activityRange ? ` · ${run.activityRange.first}-${run.activityRange.last}` : ""}`,
29
29
  ...(run.telemetry ? [`telemetry: ${run.telemetry.inputTokens} in · ${run.telemetry.outputTokens} out${run.telemetry.cachedInputTokens !== undefined ? ` · ${run.telemetry.cachedInputTokens} cached` : ""}${run.telemetry.costUsd !== undefined ? ` · $${run.telemetry.costUsd.toFixed(2)}` : ""}`] : []),
30
30
  ...(run.artifact ? [`artifact: ${fact(run.artifact.id)} · ${run.artifact.retention}${run.artifact.path ? ` · path: ${run.artifact.path}` : ""}`] : []),
31
+ ...(run.terminalAnswer ? [`answer: ${run.terminalAnswer.text}`] : []),
31
32
  ...consequenceLines(run),
32
33
  ...run.diagnostics.map((diagnostic) => `diagnostic: ${diagnostic}`),
33
34
  ];
34
35
  }
35
- export function renderProjectionHistoryList(runs) {
36
- return runs.flatMap((run, index) => index === 0 ? runLines(run) : ["", ...runLines(run)]).join("\n");
36
+ export function renderProjectionHistoryList(runs, pagination) {
37
+ const lines = runs.flatMap((run, index) => index === 0 ? runLines(run) : ["", ...runLines(run)]);
38
+ if (!pagination)
39
+ return lines.join("\n");
40
+ const range = runs.length === 0
41
+ ? "none"
42
+ : `${pagination.offset}-${pagination.offset + runs.length - 1}`;
43
+ return [...lines, ...(lines.length > 0 ? [""] : []), `entries: ${range} of ${pagination.total}${pagination.nextOffset === null ? "" : ` · next offset: ${pagination.nextOffset}`}`].join("\n");
37
44
  }
38
- export function renderProjectionHistoryDetail(detail) {
45
+ export function renderProjectionHistoryDetail(detail, entry) {
39
46
  const lines = runLines(detail);
40
- if (!detail.activity || detail.activity.retainedTimeline.length === 0)
47
+ if (entry) {
48
+ return [...lines, "", `entry: ${entry.index}`, `event: ${JSON.stringify(entry.event)}`,
49
+ ...(entry.raw ? [`raw: ${entry.raw.retention} · ${entry.raw.reason}`] : []),
50
+ ].join("\n");
51
+ }
52
+ if (!detail.activity || detail.activity.retainedTimeline.length === 0) {
41
53
  return lines.join("\n");
54
+ }
42
55
  const state = detail.outcome === "done" ? "returned"
43
56
  : detail.outcome === "out" ? "running"
44
57
  : detail.outcome === "failed" || detail.outcome === "dead" ? "dead"
@@ -192,11 +192,11 @@ export function formatCallCompletionHeading(projection) {
192
192
  default: return "no record of this akuma";
193
193
  }
194
194
  }
195
- /** Machine-generated durable revive command: artifactId + explicit repository coordinate. */
195
+ /** Machine-generated durable fork command: artifactId + explicit repository coordinate. */
196
196
  export function formatDurableReviveCommand(input) {
197
197
  return input.repositoryCoordinate
198
- ? `keiyaku revive ${input.artifactId} --repo ${shellQuote(input.repositoryCoordinate)}`
199
- : `keiyaku revive ${input.artifactId}`;
198
+ ? `keiyaku fork ${input.artifactId} --repo ${shellQuote(input.repositoryCoordinate)}`
199
+ : `keiyaku fork ${input.artifactId}`;
200
200
  }
201
201
  export function formatTellCommand(projectionId, body) {
202
202
  return `keiyaku tell ${projectionId} [--wait DURATION] ${body}`;
@@ -211,14 +211,14 @@ export function projectionRejoinHintLines(projectionId) {
211
211
  }
212
212
  export function formatCallNextAction(input) {
213
213
  if (input.projection?.phase === "active") {
214
- return projectionRejoinHintLines(input.projection.alias ?? input.projection.id).join("\n");
214
+ return projectionRejoinHintLines(input.projection.id).join("\n");
215
215
  }
216
216
  if (input.projection?.phase === "done") {
217
217
  return [
218
218
  "The akuma is back.",
219
219
  ...(input.artifactId ? [`record: ${input.artifactId}`] : []),
220
220
  "talk to it:",
221
- ` » ${formatTellCommand(input.projection.alias ?? input.projection.id, '"your words"')}`,
221
+ ` » ${formatTellCommand(input.projection.id, '"your words"')}`,
222
222
  ].join("\n");
223
223
  }
224
224
  return "» keiyaku status";
@@ -0,0 +1,47 @@
1
+ export const STATUS_INDICATOR = {
2
+ active: "●",
3
+ starting: "…",
4
+ waiting: "⧗",
5
+ ready: "○",
6
+ paused: "‖",
7
+ success: "✓",
8
+ stopped: "×",
9
+ failed: "!",
10
+ unknown: "?",
11
+ };
12
+ export const STATUS_INDICATOR_LEGEND = "marks ● active · … starting · ⧗ waiting · ○ ready · ‖ paused · ✓ success · × stopped · ! failed/broken · ? unknown";
13
+ export function projectionStatusIndicator(state) {
14
+ switch (state) {
15
+ case "out": return STATUS_INDICATOR.active;
16
+ case "minting": return STATUS_INDICATOR.starting;
17
+ case "done": return STATUS_INDICATOR.success;
18
+ case "killed":
19
+ case "dismissed": return STATUS_INDICATOR.stopped;
20
+ case "failed":
21
+ case "dead":
22
+ case "startup-timeout": return STATUS_INDICATOR.failed;
23
+ case "lost":
24
+ case "unknown":
25
+ case "incompatible": return STATUS_INDICATOR.unknown;
26
+ }
27
+ }
28
+ export function contractStatusIndicator(input) {
29
+ if (input.state === "corrupt" || input.broken)
30
+ return STATUS_INDICATOR.failed;
31
+ if (input.state === "claimed")
32
+ return STATUS_INDICATOR.success;
33
+ if (input.state === "forfeited")
34
+ return STATUS_INDICATOR.stopped;
35
+ if (input.state === "petitioned" || input.waiting)
36
+ return STATUS_INDICATOR.waiting;
37
+ return STATUS_INDICATOR.active;
38
+ }
39
+ export function taskStatusIndicator(input) {
40
+ if (input.state === "done")
41
+ return STATUS_INDICATOR.success;
42
+ if (input.state === "on_hold")
43
+ return STATUS_INDICATOR.paused;
44
+ if (input.state === "in_progress")
45
+ return STATUS_INDICATOR.active;
46
+ return input.blocked ? STATUS_INDICATOR.waiting : STATUS_INDICATOR.ready;
47
+ }