@astrosheep/keiyaku 2.9.12 → 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 (212) hide show
  1. package/README.md +22 -18
  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 +2 -2
  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/petition/handler.js +2 -1
  17. package/build/cli/commands/contract/petition/meta.js +2 -2
  18. package/build/cli/commands/contract/renew/handler.js +44 -3
  19. package/build/cli/commands/contract/renew/meta.js +5 -4
  20. package/build/cli/commands/metadata.js +12 -9
  21. package/build/cli/commands/projection/call/handler.js +1 -1
  22. package/build/cli/commands/projection/call/meta.js +1 -1
  23. package/build/cli/commands/projection/catalog.js +2 -2
  24. package/build/cli/commands/projection/{revive → fork}/handler.js +10 -5
  25. package/build/cli/commands/projection/fork/meta.js +12 -0
  26. package/build/cli/commands/projection/history/handler.js +46 -2
  27. package/build/cli/commands/projection/history/meta.js +3 -3
  28. package/build/cli/commands/projection/kill/meta.js +2 -2
  29. package/build/cli/commands/projection/status/handler.js +29 -13
  30. package/build/cli/commands/projection/status/meta.js +14 -3
  31. package/build/cli/commands/projection/tell/handler.js +8 -4
  32. package/build/cli/commands/projection/tell/meta.js +1 -1
  33. package/build/cli/commands/projection/wait/handler.js +45 -20
  34. package/build/cli/commands/projection/wait/meta.js +1 -1
  35. package/build/cli/commands/shared.js +1 -1
  36. package/build/cli/commands/system/catalog.js +2 -0
  37. package/build/cli/commands/task/add/handler.js +28 -12
  38. package/build/cli/commands/task/add/meta.js +18 -6
  39. package/build/cli/commands/task/catalog.js +2 -0
  40. package/build/cli/commands/task/compose/handler.js +2 -2
  41. package/build/cli/commands/task/compose/meta.js +2 -2
  42. package/build/cli/commands/task/doctor/handler.js +2 -3
  43. package/build/cli/commands/task/doctor/meta.js +2 -2
  44. package/build/cli/commands/task/done/meta.js +2 -2
  45. package/build/cli/commands/task/drop/handler.js +7 -2
  46. package/build/cli/commands/task/drop/meta.js +6 -3
  47. package/build/cli/commands/task/hold/meta.js +2 -2
  48. package/build/cli/commands/task/log/meta.js +2 -2
  49. package/build/cli/commands/task/ls/meta.js +2 -2
  50. package/build/cli/commands/task/note/handler.js +6 -0
  51. package/build/cli/commands/task/note/meta.js +11 -0
  52. package/build/cli/commands/task/resume/meta.js +2 -2
  53. package/build/cli/commands/task/shared.js +29 -15
  54. package/build/cli/commands/task/show/meta.js +2 -2
  55. package/build/cli/commands/task/start/meta.js +2 -2
  56. package/build/cli/commands/task/stop/meta.js +2 -2
  57. package/build/cli/commands/task/update/meta.js +3 -2
  58. package/build/cli/commands/verification/handler.js +43 -0
  59. package/build/cli/commands/verification/meta.js +13 -0
  60. package/build/cli/completion.js +16 -13
  61. package/build/cli/flags.js +43 -11
  62. package/build/cli/help.js +29 -30
  63. package/build/cli/index.js +6 -5
  64. package/build/cli/parse-flags.js +39 -0
  65. package/build/cli/parse-metadata.js +5 -2
  66. package/build/cli/parse-selectors.js +18 -0
  67. package/build/cli/parse.js +21 -8
  68. package/build/cli/render/arc.js +12 -3
  69. package/build/cli/render/audit.js +2 -2
  70. package/build/cli/render/call.js +4 -4
  71. package/build/cli/render/kanshi.js +122 -85
  72. package/build/cli/render/misc.js +2 -2
  73. package/build/cli/render/petition.js +16 -1
  74. package/build/cli/render/projection-history.js +17 -4
  75. package/build/cli/render/shared.js +5 -5
  76. package/build/cli/render/status-indicator.js +47 -0
  77. package/build/cli/render/status.js +106 -76
  78. package/build/cli/render/success-response.js +20 -5
  79. package/build/cli/render/task.js +6 -5
  80. package/build/cli/render/tell.js +10 -4
  81. package/build/cli/render/tool-command-normalization.js +137 -0
  82. package/build/cli/render/tool-presentation.js +2 -1
  83. package/build/cli/render/verification.js +23 -0
  84. package/build/cli/render/wait.js +101 -33
  85. package/build/cli/types.js +2 -1
  86. package/build/config/akuma-loader.js +21 -1
  87. package/build/config/settings/knobs.js +7 -1
  88. package/build/config/settings/schema.js +10 -5
  89. package/build/core/amend.js +102 -17
  90. package/build/core/arc.js +4 -4
  91. package/build/core/audit/candidate.js +10 -18
  92. package/build/core/audit/coordinates.js +12 -17
  93. package/build/core/audit/evidence.js +6 -4
  94. package/build/core/audit/facade.js +3 -3
  95. package/build/core/audit/report.js +1 -1
  96. package/build/core/bind-reconciliation.js +42 -23
  97. package/build/core/bind.js +182 -81
  98. package/build/core/call/call.js +6 -7
  99. package/build/core/call/context.js +43 -30
  100. package/build/core/call/execution.js +21 -6
  101. package/build/core/call/prompt.js +11 -42
  102. package/build/core/contract-carrier-runtime.js +209 -105
  103. package/build/core/contract-carrier.js +156 -73
  104. package/build/core/contract-view.js +42 -5
  105. package/build/core/contract.js +2 -1
  106. package/build/core/derived-replay.js +168 -35
  107. package/build/core/draft.js +9 -5
  108. package/build/core/forfeit.js +1 -1
  109. package/build/core/lifecycle-history.js +13 -0
  110. package/build/core/lifecycle-recovery.js +32 -27
  111. package/build/core/lifecycle-runner.js +14 -14
  112. package/build/core/log.js +1 -1
  113. package/build/core/outcome-base.js +2 -2
  114. package/build/core/projection/akuma-name.js +43 -0
  115. package/build/core/projection/generation/database.js +141 -79
  116. package/build/core/projection/generation/ledger.js +91 -0
  117. package/build/core/projection/generation/model.js +18 -13
  118. package/build/core/projection/generation/projection-generation-continuation.js +1 -1
  119. package/build/core/projection/generation/projection-generation-doorbell.js +88 -0
  120. package/build/core/projection/generation/projection-generation-execution.js +24 -0
  121. package/build/core/projection/generation/projection-generation-identity.js +4 -0
  122. package/build/core/projection/generation/projection-generation-launcher.js +72 -138
  123. package/build/core/projection/generation/projection-generation-process.js +16 -15
  124. package/build/core/projection/generation/projection-generation-runner.js +125 -79
  125. package/build/core/projection/generation/projection-generation-runtime.js +10 -61
  126. package/build/core/projection/generation/protocol.js +68 -0
  127. package/build/core/projection/generation/store.js +17 -7
  128. package/build/core/projection/generation/transitions.js +14 -14
  129. package/build/core/projection/index.js +5 -5
  130. package/build/core/projection/projection-core.js +6 -2
  131. package/build/core/projection/projection-execution-observer.js +1 -1
  132. package/build/core/projection/projection-history.js +7 -7
  133. package/build/core/projection/projection-kill.js +15 -6
  134. package/build/core/projection/projection-life-observer.js +8 -8
  135. package/build/core/projection/projection-mint.js +6 -8
  136. package/build/core/projection/projection-status-observation.js +77 -8
  137. package/build/core/projection/projection-status.js +151 -4
  138. package/build/core/projection/projection-wait.js +46 -27
  139. package/build/core/projection/projection-wake.js +27 -89
  140. package/build/core/projection/tell/launch-store.js +1 -1
  141. package/build/core/projection/tell/store.js +1 -1
  142. package/build/core/renew-build.js +204 -74
  143. package/build/core/renew-plan.js +34 -9
  144. package/build/core/renew-rewrite.js +56 -15
  145. package/build/core/renew.js +39 -35
  146. package/build/core/repository-ledger/accepted-fold-read.js +6 -3
  147. package/build/core/repository-ledger/codec.js +11 -5
  148. package/build/core/repository-ledger/current-state-store.js +13 -16
  149. package/build/core/repository-ledger/fold-repository.js +5 -6
  150. package/build/core/repository-ledger/identity.js +60 -0
  151. package/build/core/repository-ledger/inventory.js +3 -3
  152. package/build/core/repository-ledger/read-model.js +54 -6
  153. package/build/core/repository-ledger/write-transaction.js +9 -4
  154. package/build/core/run-control/connection-bound-close.js +41 -0
  155. package/build/core/run-control/detached-lease-bootstrap.js +208 -0
  156. package/build/core/run-control/detached-process.js +14 -0
  157. package/build/core/run-control/index.js +6 -0
  158. package/build/core/{process-group.js → run-control/process-tree.js} +1 -1
  159. package/build/core/run-control/runner-lease.js +172 -0
  160. package/build/core/{sqlite-process-lifetime-lock.js → run-control/sqlite-process-lifetime-lock.js} +4 -24
  161. package/build/core/seal.js +44 -32
  162. package/build/core/settlement/claim-delivery.js +22 -9
  163. package/build/core/settlement/claim.js +8 -6
  164. package/build/core/settlement/petition-claim-gates.js +9 -8
  165. package/build/core/settlement/petition-head-guard.js +5 -6
  166. package/build/core/settlement/petition-preview.js +21 -5
  167. package/build/core/settlement/petition.js +51 -17
  168. package/build/core/settlement/settlement.js +20 -15
  169. package/build/core/settlement/verdict.js +2 -2
  170. package/build/core/settlement/verification.js +492 -364
  171. package/build/core/status/board.js +184 -75
  172. package/build/core/status/drift.js +8 -10
  173. package/build/core/task/board.js +1 -0
  174. package/build/core/task/commands.js +25 -0
  175. package/build/core/task/compose.js +3 -2
  176. package/build/core/task/document.js +102 -39
  177. package/build/core/task/index.js +3 -3
  178. package/build/core/task/settlement-git.js +1 -4
  179. package/build/core/task/settlement-policy.js +27 -14
  180. package/build/core/task/source-board.js +1 -0
  181. package/build/core/task/task-bind-preparation.js +59 -9
  182. package/build/core/task/task-contract.js +2 -2
  183. package/build/core/task/task-store-repository.js +1 -0
  184. package/build/core/task/task.js +2 -2
  185. package/build/core/transcripts.js +4 -4
  186. package/build/core/verification-declaration.js +95 -0
  187. package/build/core/worktree-bootstrap.js +1 -1
  188. package/build/core/worktree-path.js +7 -11
  189. package/build/flow-error.js +9 -1
  190. package/build/generated/version.js +2 -2
  191. package/build/git/branches.js +41 -70
  192. package/build/git/commits.js +92 -21
  193. package/build/git/core.js +9 -161
  194. package/build/git/diff/preview.js +4 -4
  195. package/build/git/diff/read.js +4 -4
  196. package/build/git/diff/structured.js +5 -5
  197. package/build/git/process.js +229 -0
  198. package/build/git/refs.js +30 -5
  199. package/build/git/staging.js +39 -115
  200. package/build/git/streaming-batch.js +9 -16
  201. package/build/git/worktree.js +104 -91
  202. package/build/index.js +7 -0
  203. package/package.json +1 -1
  204. package/skills/keiyaku-akuma/SKILL.md +21 -20
  205. package/skills/keiyaku-task/SKILL.md +38 -4
  206. package/skills/keiyaku-workflow/SKILL.md +51 -11
  207. package/build/cli/commands/projection/revive/meta.js +0 -12
  208. package/build/core/projection/projection-life-protocol.js +0 -115
  209. package/build/core/projection/projection-runner-lock.js +0 -211
  210. package/build/core/projection/tell/database.js +0 -127
  211. package/build/core/settlement/verification-coordination.js +0 -305
  212. package/build/core/settlement/verification-supervisor.js +0 -275
@@ -1,33 +1,13 @@
1
1
  import { formatSettingsDiseases } from "../../config/settings/disease.js";
2
2
  import { shortCommitHash } from "../../git/commits.js";
3
3
  import { formatAgeMs } from "./format.js";
4
- import { renderKanshiBoard } from "./kanshi.js";
4
+ import { renderAkumaRosterBoard, renderKanshiBoard } from "./kanshi.js";
5
5
  import { renderProjectionActivitySummary, } from "./projection-activity.js";
6
- import { renderTerminalFailureFace, terminalFailureCodeSuffix } from "./terminal-failure.js";
6
+ import { terminalFailureCodeSuffix } from "./terminal-failure.js";
7
7
  import { formatTellCommand } from "./shared.js";
8
+ import { projectionStatusIndicator } from "./status-indicator.js";
8
9
  export const STATUS_DISEASES_SECTION_TITLE = "Diseases";
9
10
  export const STATUS_PROJECTION_SECTION_TITLE = "akuma";
10
- function projectionGlyph(state) {
11
- switch (state) {
12
- case "out":
13
- return "●";
14
- case "lost":
15
- return "○";
16
- case "done":
17
- return "◎";
18
- case "dismissed":
19
- return "×";
20
- case "dead":
21
- return "✕";
22
- case "minting":
23
- return "…";
24
- case "startup-timeout":
25
- return "!";
26
- case "unknown":
27
- case "incompatible":
28
- return "?";
29
- }
30
- }
31
11
  export function renderSettingsDiseasesSection(diseases, taskDiseases = []) {
32
12
  if (diseases.length === 0 && taskDiseases.length === 0)
33
13
  return "";
@@ -72,7 +52,7 @@ function terminalFailureSuffix(row) {
72
52
  function renderProjectionOmission(board) {
73
53
  if (!board.omitted)
74
54
  return undefined;
75
- const counts = ["failed", "dead", "done", "killed", "dismissed"]
55
+ const counts = ["failed", "dead", "done", "killed", "dismissed", "incompatible"]
76
56
  .flatMap((state) => {
77
57
  const count = board.omitted?.byState[state] ?? 0;
78
58
  return count > 0 ? [`${count} ${state}`] : [];
@@ -80,26 +60,15 @@ function renderProjectionOmission(board) {
80
60
  return counts.length > 0 ? `+ ${counts.join(" · ")}` : undefined;
81
61
  }
82
62
  function renderProjectionAge(row) {
83
- const duration = formatAgeMs(row.durationMs) ?? "?";
84
- const activity = formatAgeMs(row.activityAgeMs) ?? "?";
85
- const facts = `dur ${duration} · active ${activity}`;
86
- if (row.state === "done")
87
- return `done · ${facts}`;
88
- if (row.state === "killed")
89
- return `killed · ${facts}`;
90
- if (row.state === "dismissed")
91
- return `dismissed · ${facts}`;
92
- if (row.state === "failed")
93
- return `failed · ${facts}`;
94
- if (row.state === "dead")
95
- return `dead · ${facts}`;
96
- if (row.state === "startup-timeout")
97
- return `startup timed out · ${facts}`;
98
- if (row.state === "unknown")
99
- return `unknown · ${facts}`;
100
- if (row.state === "incompatible")
101
- return "incompatible history";
102
- return facts;
63
+ const duration = formatAgeMs(row.durationMs);
64
+ const activity = formatAgeMs(row.activityAgeMs);
65
+ const terminalAge = formatAgeMs(row.terminalAgeMs);
66
+ const facts = [
67
+ ...(terminalAge ? [`terminal ${terminalAge} ago`] : []),
68
+ ...(duration ? [`${isTerminalProjectionStatus(row) ? "ran" : "observed for"} ${duration}`] : []),
69
+ ...(activity ? [`last activity ${activity} ago`] : []),
70
+ ];
71
+ return [row.state, ...facts].join(" · ");
103
72
  }
104
73
  function renderProjectionTellCounts(row) {
105
74
  const { inbox, inflight, submitted, seen, consumed } = row.tellCounts;
@@ -131,30 +100,24 @@ function renderProjectionActivityLine(row) {
131
100
  ...(row.workspaceRoot ? { workspaceRoot: row.workspaceRoot } : {}),
132
101
  });
133
102
  }
134
- function renderProjectionRow(row) {
135
- const glyph = row.state === "killed"
136
- ? "×"
137
- : projectionGlyph(row.state === "failed"
138
- ? "lost"
139
- : row.state === "startup-timeout"
140
- ? "minting"
141
- : row.state);
103
+ function renderProjectionRow(row, includeDrillDown = true, includeIdentity = true) {
142
104
  const identity = row.alias ? `${row.id} (${row.alias})` : row.id;
105
+ const prefix = includeIdentity
106
+ ? `${projectionStatusIndicator(row.state)} ${identity} · `
107
+ : `${projectionStatusIndicator(row.state)} `;
143
108
  let heading;
144
109
  if (row.state === "startup-timeout" || row.state === "unknown" || row.state === "incompatible") {
145
- const akuma = (row.akuma ?? "(unknown)").padEnd(18);
146
- heading = ` ${glyph} ${identity} ${akuma} ${renderProjectionAge(row)}${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
110
+ heading = ` ${prefix}${renderProjectionAge(row)}${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
147
111
  }
148
112
  else if (row.state === "minting") {
149
- heading = ` ${glyph} ${identity.padEnd(18)} (minting) · ${renderProjectionAge(row)}${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
113
+ heading = ` ${prefix}${renderProjectionAge(row)}${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
150
114
  }
151
115
  else {
152
116
  const age = renderProjectionAge(row);
153
- const akuma = (row.akuma ?? "(unknown)").padEnd(18);
154
- heading = ` ${glyph} ${identity} ${akuma} ${age}${renderProjectionTellCounts(row)}${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
117
+ heading = ` ${prefix}${age}${renderProjectionTellCounts(row)}${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
155
118
  }
156
119
  const activity = renderProjectionActivityLine(row);
157
- const drillDown = row.terminalFailure ? [` » keiyaku wait ${row.alias ?? row.id}`] : [];
120
+ const drillDown = includeDrillDown && row.terminalFailure ? [` » keiyaku wait ${row.id}`] : [];
158
121
  return activity ? [heading, activity, ...drillDown] : [heading, ...drillDown];
159
122
  }
160
123
  function isTerminalProjectionStatus(row) {
@@ -167,47 +130,114 @@ function isTerminalProjectionStatus(row) {
167
130
  }
168
131
  export function renderProjectionFilteredStatus(board, projectionId) {
169
132
  const head = board.defaultHead ? shortCommitHash(board.defaultHead) : "(no HEAD)";
170
- const heading = `現世 ${head} · projection ${projectionId}`;
171
- const row = board.projections?.rows.find((candidate) => candidate.id === projectionId);
133
+ const row = board.projections?.rows[0];
172
134
  if (!row)
173
- return `${heading}\nno projections on projection ${projectionId}\n`;
174
- if (row.state === "failed" || row.terminalFailure) {
175
- const lines = [...renderTerminalFailureFace(projectionId, row.terminalFailure), "", keiyaku wait ${projectionId}`];
176
- return lines.join("\n");
177
- }
178
- const lines = [heading, "", ...renderProjectionRow(row), ""];
135
+ return `現世 ${head} · projection ${projectionId}\nunknown projection ${projectionId}\n`;
136
+ const identity = row.alias ? `${row.identity.canonicalId} (${row.alias})` : row.identity.canonicalId;
137
+ const heading = `現世 ${head} · projection ${identity}`;
138
+ const moved = row.addressedBy?.aliasMovedTo
139
+ ? [`${row.addressedBy.token} has since moved to ${row.addressedBy.aliasMovedTo}`]
140
+ : [];
141
+ const lines = [heading, "", ...renderProjectionRow(row, false, false), ""];
142
+ lines.push(...moved);
179
143
  if (row.observation.compatibility === "incompatible") {
180
144
  return `${lines.join("\n")}\n`;
181
145
  }
182
146
  if (isTerminalProjectionStatus(row)) {
183
- lines.push(`» keiyaku wait ${projectionId}`);
184
- return lines.join("\n");
147
+ if (row.terminalAnswer?.text) {
148
+ if (row.responseArtifact?.state === "none") {
149
+ lines.push("nothing written to disk", row.terminalAnswer.text);
150
+ }
151
+ else {
152
+ const answer = row.terminalAnswer.text.split("\n");
153
+ lines.push(...answer.slice(0, 4));
154
+ if (answer.length > 4) {
155
+ lines.push(row.responseArtifact?.state === "retained"
156
+ ? `… answer continues in ${row.responseArtifact.path}`
157
+ : `… +${answer.length - 4} more lines`);
158
+ }
159
+ else if (row.responseArtifact?.state === "retained") {
160
+ lines.push(`response: ${row.responseArtifact.path}`);
161
+ }
162
+ }
163
+ }
164
+ else if (row.responseArtifact?.state === "retained") {
165
+ lines.push(`response: ${row.responseArtifact.path}`);
166
+ }
167
+ return `${lines.join("\n")}\n`;
185
168
  }
186
- lines.push(`» ${formatTellCommand(projectionId, '"..."')}`);
187
- lines.push(`» keiyaku wait ${projectionId}`);
169
+ const commandAddress = row.addressedBy?.kind === "alias" && !row.addressedBy.aliasMovedTo
170
+ ? row.addressedBy.token
171
+ : row.identity.canonicalId;
172
+ lines.push(`» ${formatTellCommand(commandAddress, '"..."')}`);
173
+ lines.push(`» keiyaku wait ${commandAddress}`);
188
174
  return `${lines.join("\n")}\n`;
189
175
  }
190
176
  export function renderProjectionStatusSection(board) {
191
177
  if (!board || (board.rows.length === 0 && !board.omitted))
192
178
  return "";
193
- const lines = board.rows.flatMap(renderProjectionRow);
179
+ const lines = board.rows.flatMap((row) => renderProjectionRow(row));
194
180
  const omission = renderProjectionOmission(board);
195
181
  if (omission)
196
182
  lines.push(omission);
197
- return `${STATUS_PROJECTION_SECTION_TITLE}\n${lines.join("\n")}\n`;
183
+ const total = board.rows.length + (board.omitted?.total ?? 0);
184
+ return `${STATUS_PROJECTION_SECTION_TITLE} ${board.rows.length}/${total}\n${lines.join("\n")}\n`;
198
185
  }
199
186
  /**
200
187
  * Status mouth: kanshi board plus optional diseases section.
201
188
  * Healthy boards (no diseases) are byte-identical to renderKanshiBoard alone.
202
189
  */
203
190
  export function renderStatusBoard(board) {
204
- const boardText = renderKanshiBoard(board);
205
191
  const taskDiseaseText = [
206
192
  ...(board.tasks?.diseases ?? []).map((disease) => disease.message),
207
193
  ...(board.tasks?.diagnostic ? [board.tasks.diagnostic] : []),
208
194
  ];
209
195
  const diseasesText = renderSettingsDiseasesSection(board.diseases, taskDiseaseText);
210
- if (diseasesText === "")
211
- return boardText;
212
- return `${[boardText.trimEnd(), diseasesText.trimEnd()].join("\n\n")}\n`;
196
+ return renderKanshiBoard(board, diseasesText === "" ? [] : [diseasesText.trimEnd()]);
197
+ }
198
+ export function renderAkumaRosterStatus(board) {
199
+ return renderAkumaRosterBoard(board);
200
+ }
201
+ function statusJsonValue(value) {
202
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
203
+ return value;
204
+ }
205
+ if (typeof value === "number") {
206
+ if (!Number.isFinite(value))
207
+ throw new TypeError("Status payload numbers must be finite");
208
+ return value;
209
+ }
210
+ if (Array.isArray(value))
211
+ return value.map(statusJsonValue);
212
+ if (value instanceof Map || value instanceof Set) {
213
+ throw new TypeError("Status payload collections must be converted explicitly");
214
+ }
215
+ if (typeof value === "object") {
216
+ const entries = [];
217
+ for (const [key, item] of Object.entries(value)) {
218
+ if (item !== undefined)
219
+ entries.push([key, statusJsonValue(item)]);
220
+ }
221
+ return Object.fromEntries(entries);
222
+ }
223
+ throw new TypeError(`Status payload contains unsupported ${typeof value}`);
224
+ }
225
+ /** One JSON-safe status DTO shared by human and JSON command responses. */
226
+ export function buildStatusPayload(board) {
227
+ return {
228
+ contracts: statusJsonValue(board.contracts),
229
+ contractsObservable: board.contractsObservable,
230
+ commissionPlaces: statusJsonValue(Object.fromEntries(board.commissionPlaces)),
231
+ projections: statusJsonValue(board.projections),
232
+ queueLength: board.queueLength,
233
+ ...(board.defaultBranch === undefined ? {} : { defaultBranch: board.defaultBranch }),
234
+ ...(board.defaultHead === undefined ? {} : { defaultHead: board.defaultHead }),
235
+ diseases: statusJsonValue(board.diseases),
236
+ targetFilter: board.targetFilter,
237
+ ...(board.commissionFilter === undefined ? {} : { commissionFilter: board.commissionFilter }),
238
+ ...(board.tasks === undefined ? {} : { tasks: statusJsonValue(board.tasks) }),
239
+ };
240
+ }
241
+ export function renderStatusJson(payload) {
242
+ return `${JSON.stringify(payload)}\n`;
213
243
  }
@@ -11,6 +11,12 @@ function responseData(response) {
11
11
  return {};
12
12
  return payload;
13
13
  }
14
+ const AKUMA_JSON_COMMANDS = new Set(["call", "tell", "wait", "fork"]);
15
+ export function serializeAkumaSuccessResponse(command, flags, response) {
16
+ return flags.json && AKUMA_JSON_COMMANDS.has(command)
17
+ ? `${JSON.stringify(responseData(response))}\n`
18
+ : undefined;
19
+ }
14
20
  function isCallProjectionFacts(value) {
15
21
  if (value === null || typeof value !== "object" || Array.isArray(value))
16
22
  return false;
@@ -25,10 +31,17 @@ function conversationalFooter(response) {
25
31
  if (response.address) {
26
32
  const projection = data.projection;
27
33
  const projectionFacts = isCallProjectionFacts(projection) ? projection : undefined;
28
- const receiptArtifactId = typeof data.revivedArtifactId === "string"
29
- ? data.revivedArtifactId
34
+ const receiptArtifactId = typeof data.sourceArtifactId === "string"
35
+ ? data.sourceArtifactId
30
36
  : typeof data.artifactId === "string" ? data.artifactId : undefined;
31
37
  lines.push(renderResolvedAddressReceipt(response.address, { artifactId: receiptArtifactId, projectionId: projectionFacts?.id }));
38
+ if (typeof data.sourceArtifactId === "string" && typeof data.artifactId === "string") {
39
+ lines.push([
40
+ typeof data.sourceProjectionId === "string" ? `source projection ${data.sourceProjectionId}` : undefined,
41
+ "conversation continued",
42
+ `response artifact ${data.artifactId}`,
43
+ ].filter((part) => part !== undefined).join(" · "));
44
+ }
32
45
  }
33
46
  const responsePath = typeof data.responsePath === "string" ? data.responsePath : undefined;
34
47
  const agent = typeof data.agent === "string" ? data.agent : undefined;
@@ -56,9 +69,11 @@ function conversationalFooter(response) {
56
69
  return lines.join("\n");
57
70
  }
58
71
  export async function writeSuccessResponse(command, flags, response) {
59
- // Plain tell is always silent; tell --wait owns the ordinary wait response.
60
- if (command === "tell" && flags.timeoutMs === undefined)
72
+ const json = serializeAkumaSuccessResponse(command, flags, response);
73
+ if (json !== undefined) {
74
+ await writeCliOutput(process.stdout, json);
61
75
  return;
76
+ }
62
77
  if (command === "bind" && flags.dryRun) {
63
78
  // Canonical Markdown already ends with exactly one newline.
64
79
  await writeCliOutput(process.stdout, responseText(response));
@@ -66,7 +81,7 @@ export async function writeSuccessResponse(command, flags, response) {
66
81
  await writeCliOutput(process.stderr, `${response.stderr}\n`);
67
82
  return;
68
83
  }
69
- if (command !== "revive") {
84
+ if (command !== "fork") {
70
85
  await writeCliOutput(process.stdout, `${responseText(response)}\n`);
71
86
  return;
72
87
  }
@@ -7,14 +7,14 @@ export function deriveTaskDisplay(task) {
7
7
  const display = deriveStructuredTaskDisplay(task);
8
8
  return display === "bound" ? `bound(${shortContractId(task.contractId)})` : display;
9
9
  }
10
- function renderTaskRowWithId(task, id) {
11
- return `${id} · ${task.namespace ?? "hub"} · P${task.pri} · ${deriveTaskDisplay(task)} · ${task.title}`;
10
+ function renderTaskRowWithCoordinate(task, coordinate) {
11
+ return `${coordinate} · P${task.pri} · ${deriveTaskDisplay(task)} · ${task.title}`;
12
12
  }
13
13
  export function renderTaskListRow(task) {
14
- return renderTaskRowWithId(task, task.coordinate);
14
+ return renderTaskRowWithCoordinate(task, task.coordinate);
15
15
  }
16
16
  export function renderTaskMutationRow(task) {
17
- return renderTaskRowWithId(task, task.coordinate);
17
+ return renderTaskRowWithCoordinate(task, task.coordinate);
18
18
  }
19
19
  export function renderTaskUpdate(result) {
20
20
  const lines = [renderTaskMutationRow(result.task)];
@@ -75,7 +75,6 @@ function renderTaskDetails(task) {
75
75
  const released = new Set(task.releasedNeeds);
76
76
  return [
77
77
  `${task.coordinate} · ${task.title}`,
78
- `namespace: ${task.namespace ?? "(hub)"}`,
79
78
  `state: ${deriveTaskDisplay(task)}`,
80
79
  `priority: ${task.pri}`,
81
80
  ...(task.needs.length === 0 ? [] : [`needs: ${task.needs.map((id) => `${id}${released.has(id) ? " (dropped)" : ""}`).join(", ")}`]),
@@ -88,6 +87,7 @@ function renderTaskDetails(task) {
88
87
  `created: ${task.createdAt} by ${task.creator}`,
89
88
  "",
90
89
  task.body,
90
+ ...task.notes.flatMap((note) => ["", `${note.timestamp} · ${note.actor}`, note.text]),
91
91
  ];
92
92
  }
93
93
  function renderTreeNode(node, prefix, last) {
@@ -147,6 +147,7 @@ export function taskJson(task) {
147
147
  createdAt: task.createdAt,
148
148
  updatedAt: task.updatedAt ?? task.createdAt,
149
149
  creator: task.creator,
150
+ notes: task.notes.map((note) => ({ ...note })),
150
151
  };
151
152
  }
152
153
  function taskTreeNodeJson(node) {
@@ -1,5 +1,11 @@
1
- import { textResponse } from "./shared.js";
2
- /** Accepted plain tell: zero stdout/stderr bytes. */
3
- export function buildSilentTellResponse() {
4
- return textResponse("");
1
+ import { coreTextResponse } from "./shared.js";
2
+ /** Tell returns after mailbox acceptance; it never claims consumption. */
3
+ export function buildTellAcceptedResponse(projectionId, inputToken, alias) {
4
+ const payload = {
5
+ state: "accepted",
6
+ canonicalId: projectionId,
7
+ inputToken,
8
+ ...(alias ? { alias } : {}),
9
+ };
10
+ return coreTextResponse(`${projectionId}${alias ? ` (${alias})` : ""} heard.`, payload);
5
11
  }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Unwrap only complete provider transport launchers. This is deliberately not
3
+ * a shell parser: uncertainty preserves the persisted command's presentation.
4
+ */
5
+ const HORIZONTAL_WHITESPACE = new Set([" ", "\t"]);
6
+ const UNSUPPORTED_UNQUOTED = new Set(["$", "`", "|", "&", ";", "<", ">", "(", ")"]);
7
+ const POWERSHELL_OPTION_FLAGS = new Set(["-nologo", "-noprofile"]);
8
+ const POWERSHELL_COMMAND_FLAGS = new Set(["-command", "-c"]);
9
+ function isAbsoluteExecutable(value) {
10
+ return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value);
11
+ }
12
+ function executableName(value) {
13
+ const segments = value.split(/[\\/]/);
14
+ return segments[segments.length - 1].toLowerCase();
15
+ }
16
+ function isBashOrZsh(value) {
17
+ const name = executableName(value);
18
+ return (value === "bash" || value === "zsh" || isAbsoluteExecutable(value))
19
+ && (name === "bash" || name === "zsh");
20
+ }
21
+ function isPowerShell(value) {
22
+ const name = executableName(value);
23
+ return (value.toLowerCase() === "powershell" || value.toLowerCase() === "pwsh" || isAbsoluteExecutable(value))
24
+ && (name === "powershell" || name === "powershell.exe" || name === "pwsh" || name === "pwsh.exe");
25
+ }
26
+ /**
27
+ * Read only a conservative argv-shaped command line. Newlines are supported
28
+ * inside a quoted argument but not as outer command syntax.
29
+ */
30
+ function parseTransportArgv(command) {
31
+ const argv = [];
32
+ let index = 0;
33
+ while (index < command.length) {
34
+ while (HORIZONTAL_WHITESPACE.has(command[index]))
35
+ index += 1;
36
+ if (index === command.length)
37
+ break;
38
+ if (command[index] === "\n" || command[index] === "\r")
39
+ return undefined;
40
+ let value = "";
41
+ let consumed = false;
42
+ while (index < command.length && !HORIZONTAL_WHITESPACE.has(command[index])) {
43
+ const character = command[index];
44
+ if (character === "\n" || character === "\r" || UNSUPPORTED_UNQUOTED.has(character))
45
+ return undefined;
46
+ if (character === "'") {
47
+ const end = command.indexOf("'", index + 1);
48
+ if (end < 0)
49
+ return undefined;
50
+ value += command.slice(index + 1, end);
51
+ index = end + 1;
52
+ consumed = true;
53
+ continue;
54
+ }
55
+ if (character === '"') {
56
+ index += 1;
57
+ consumed = true;
58
+ let closed = false;
59
+ while (index < command.length) {
60
+ const quoted = command[index];
61
+ if (quoted === '"') {
62
+ index += 1;
63
+ closed = true;
64
+ break;
65
+ }
66
+ if (quoted === "$")
67
+ return undefined;
68
+ if (quoted === "`")
69
+ return undefined;
70
+ if (quoted === "\\") {
71
+ const next = command[index + 1];
72
+ if (next === undefined || next === "\n" || next === "\r")
73
+ return undefined;
74
+ if (next === '"' || next === "\\" || next === "$" || next === "`") {
75
+ value += next;
76
+ }
77
+ else {
78
+ value += `\\${next}`;
79
+ }
80
+ index += 2;
81
+ continue;
82
+ }
83
+ value += quoted;
84
+ index += 1;
85
+ }
86
+ if (!closed)
87
+ return undefined;
88
+ continue;
89
+ }
90
+ if (character === "\\") {
91
+ const next = command[index + 1];
92
+ if (next === undefined || next === "\n" || next === "\r")
93
+ return undefined;
94
+ value += next;
95
+ index += 2;
96
+ consumed = true;
97
+ continue;
98
+ }
99
+ value += character;
100
+ index += 1;
101
+ consumed = true;
102
+ }
103
+ if (!consumed)
104
+ return undefined;
105
+ argv.push(value);
106
+ }
107
+ return argv;
108
+ }
109
+ function unwrapBashOrZsh(argv) {
110
+ const [shell, flag, script] = argv;
111
+ if (argv.length !== 3 || !shell || !script || !isBashOrZsh(shell))
112
+ return undefined;
113
+ return flag === "-c" || flag === "-lc" ? script : undefined;
114
+ }
115
+ function unwrapPowerShell(argv) {
116
+ const [shell, ...arguments_] = argv;
117
+ if (!shell || !isPowerShell(shell) || arguments_.length < 2)
118
+ return undefined;
119
+ const options = new Set();
120
+ for (let index = 0; index < arguments_.length - 1; index += 1) {
121
+ const flag = arguments_[index].toLowerCase();
122
+ if (POWERSHELL_COMMAND_FLAGS.has(flag)) {
123
+ return index === arguments_.length - 2 && arguments_[index + 1] ? arguments_[index + 1] : undefined;
124
+ }
125
+ if (!POWERSHELL_OPTION_FLAGS.has(flag) || options.has(flag))
126
+ return undefined;
127
+ options.add(flag);
128
+ }
129
+ return undefined;
130
+ }
131
+ /** Return a display subject only when the full transport shape is unambiguous. */
132
+ export function normalizeToolCommand(command) {
133
+ const argv = parseTransportArgv(command);
134
+ if (!argv)
135
+ return command;
136
+ return unwrapBashOrZsh(argv) ?? unwrapPowerShell(argv) ?? command;
137
+ }
@@ -1,4 +1,5 @@
1
1
  import { compactText } from "./compact-text.js";
2
+ import { normalizeToolCommand } from "./tool-command-normalization.js";
2
3
  export function activitySemanticClass(call) {
3
4
  switch (call.kind) {
4
5
  case "run": return "run";
@@ -24,7 +25,7 @@ function rangeText(call) {
24
25
  }
25
26
  function subject(call, presentPath) {
26
27
  switch (call.kind) {
27
- case "run": return compactText(call.description ?? `$ ${call.command}`);
28
+ case "run": return compactText(call.description ?? `$ ${normalizeToolCommand(call.command)}`);
28
29
  case "read": return presentPath(call.path);
29
30
  case "search": return `“${compactText(call.query)}”`;
30
31
  case "other": return compactText(call.display);
@@ -0,0 +1,23 @@
1
+ import { buildPayload } from "./format.js";
2
+ import { coreTextResponse } from "./shared.js";
3
+ function humanLines(model) {
4
+ return `${model.runId}\n${model.phase}`;
5
+ }
6
+ /** Canonical Verification CLI renderer: one model drives human text and JSON. */
7
+ export function renderVerificationCli(model, json) {
8
+ const payload = buildPayload(model);
9
+ const output = coreTextResponse(json ? JSON.stringify(payload) : humanLines(model), payload);
10
+ return model.operation === "wait" && model.phase === "timeout" ? { ...output, exitCode: 124 } : output;
11
+ }
12
+ export function verificationStatusModel(run) {
13
+ return { operation: "status", runId: run.id, phase: run.terminal?.status ?? "running", run };
14
+ }
15
+ export function verificationWaitModel(runId, terminal) {
16
+ return { operation: "wait", runId, phase: terminal.status, terminal };
17
+ }
18
+ export function verificationWaitTimeoutModel(runId) {
19
+ return { operation: "wait", runId, phase: "timeout" };
20
+ }
21
+ export function verificationCancelModel(runId, accepted) {
22
+ return { operation: "cancel", runId, phase: accepted ? "accepted" : "already-terminal-or-missing", accepted };
23
+ }