@astrosheep/keiyaku 4.0.4 → 4.0.6

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 (233) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +4 -4
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +15 -7
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -3
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +24 -4
  8. package/build/src/akuma/akuma.d.ts +2 -1
  9. package/build/src/akuma/akuma.js +27 -9
  10. package/build/src/akuma/allowed.d.ts +1 -1
  11. package/build/src/akuma/allowed.js +3 -10
  12. package/build/src/akuma/archetype.d.ts +3 -1
  13. package/build/src/akuma/archetype.js +11 -6
  14. package/build/src/akuma/body-turn.d.ts +64 -0
  15. package/build/src/akuma/body-turn.js +449 -0
  16. package/build/src/akuma/body.d.ts +4 -5
  17. package/build/src/akuma/body.js +9 -414
  18. package/build/src/akuma/heart/facts.d.ts +37 -9
  19. package/build/src/akuma/heart/facts.js +3 -1
  20. package/build/src/akuma/heart/index.d.ts +4 -13
  21. package/build/src/akuma/heart/index.js +14 -135
  22. package/build/src/akuma/heart/request-authority.d.ts +12 -0
  23. package/build/src/akuma/heart/request-authority.js +119 -0
  24. package/build/src/akuma/heart/request-rows.d.ts +16 -0
  25. package/build/src/akuma/heart/request-rows.js +88 -0
  26. package/build/src/akuma/heart/rows.d.ts +1 -28
  27. package/build/src/akuma/heart/rows.js +4 -138
  28. package/build/src/akuma/heart/schema.d.ts +1 -1
  29. package/build/src/akuma/heart/schema.js +11 -3
  30. package/build/src/akuma/heart/soul.js +0 -36
  31. package/build/src/akuma/heart/timeline.d.ts +1 -0
  32. package/build/src/akuma/heart/timeline.js +19 -0
  33. package/build/src/akuma/index.d.ts +1 -1
  34. package/build/src/akuma/nuke.d.ts +2 -0
  35. package/build/src/akuma/nuke.js +152 -0
  36. package/build/src/akuma/provider-recipe.js +1 -11
  37. package/build/src/akuma/provider.d.ts +4 -7
  38. package/build/src/akuma/providers/acp/config.d.ts +8 -0
  39. package/build/src/akuma/providers/acp/config.js +37 -0
  40. package/build/src/akuma/providers/acp/core.js +12 -2
  41. package/build/src/akuma/providers/acp/index.d.ts +1 -8
  42. package/build/src/akuma/providers/acp/index.js +2 -38
  43. package/build/src/akuma/providers/claude/index.d.ts +0 -4
  44. package/build/src/akuma/providers/claude/index.js +12 -3
  45. package/build/src/akuma/providers/codex-app-server/index.d.ts +2 -27
  46. package/build/src/akuma/providers/codex-app-server/index.js +5 -2
  47. package/build/src/akuma/providers/grok-build/index.js +1 -2
  48. package/build/src/akuma/providers/index.d.ts +3 -2
  49. package/build/src/akuma/providers/index.js +36 -36
  50. package/build/src/akuma/providers/opencode-sdk/index.d.ts +2 -28
  51. package/build/src/akuma/providers/opencode-sdk/index.js +14 -4
  52. package/build/src/akuma/providers/opencode-sdk/session.d.ts +2 -2
  53. package/build/src/akuma/providers/opencode-sdk/session.js +2 -2
  54. package/build/src/akuma/providers/pi/index.d.ts +1 -1
  55. package/build/src/akuma/providers/pi/index.js +29 -6
  56. package/build/src/akuma/request-serve.d.ts +88 -0
  57. package/build/src/akuma/request-serve.js +484 -0
  58. package/build/src/akuma/request-wire.d.ts +125 -0
  59. package/build/src/akuma/request-wire.js +383 -0
  60. package/build/src/akuma/requests.d.ts +28 -94
  61. package/build/src/akuma/requests.js +52 -562
  62. package/build/src/akuma-body.d.ts +7 -0
  63. package/build/src/akuma-body.js +69 -2
  64. package/build/src/alias/index.d.ts +1 -0
  65. package/build/src/alias/index.js +34 -1
  66. package/build/src/body/arc.js +4 -29
  67. package/build/src/body/decode.js +5 -39
  68. package/build/src/body/envelope.d.ts +7 -0
  69. package/build/src/body/envelope.js +37 -0
  70. package/build/src/cli/accepted.js +21 -9
  71. package/build/src/cli/commands/akuma-invoke.js +1 -0
  72. package/build/src/cli/commands/akuma.d.ts +1 -0
  73. package/build/src/cli/commands/akuma.js +13 -10
  74. package/build/src/cli/commands/contract.d.ts +28 -17
  75. package/build/src/cli/commands/contract.js +23 -17
  76. package/build/src/cli/commands/install.d.ts +2 -2
  77. package/build/src/cli/commands/install.js +6 -6
  78. package/build/src/cli/commands/nuke.d.ts +10 -0
  79. package/build/src/cli/commands/nuke.js +20 -0
  80. package/build/src/cli/commands/task-invoke.d.ts +15 -0
  81. package/build/src/cli/commands/task-invoke.js +144 -24
  82. package/build/src/cli/commands/task-query.d.ts +2 -2
  83. package/build/src/cli/commands/task-query.js +1 -2
  84. package/build/src/cli/commands/task.js +22 -22
  85. package/build/src/cli/coordinates.d.ts +6 -2
  86. package/build/src/cli/coordinates.js +12 -56
  87. package/build/src/cli/invoke.d.ts +5 -4
  88. package/build/src/cli/invoke.js +112 -58
  89. package/build/src/cli/main.d.ts +0 -2
  90. package/build/src/cli/main.js +4 -140
  91. package/build/src/cli/parse.d.ts +17 -4
  92. package/build/src/cli/parse.js +93 -15
  93. package/build/src/cli/render/akuma.js +111 -53
  94. package/build/src/cli/render/audit.js +2 -6
  95. package/build/src/cli/render/contract.js +61 -20
  96. package/build/src/cli/render/kanshi.js +15 -5
  97. package/build/src/cli/render/nuke.d.ts +3 -0
  98. package/build/src/cli/render/nuke.js +8 -0
  99. package/build/src/cli/render/receipt.js +28 -1
  100. package/build/src/cli/render/refusal.d.ts +2 -1
  101. package/build/src/cli/render/refusal.js +31 -0
  102. package/build/src/cli/render/terminal.d.ts +0 -2
  103. package/build/src/cli/render/terminal.js +0 -29
  104. package/build/src/cli/render/text.js +6 -1
  105. package/build/src/cli/result.d.ts +36 -9
  106. package/build/src/cli/runtime.d.ts +2 -0
  107. package/build/src/cli/runtime.js +140 -0
  108. package/build/src/cli/usage.d.ts +0 -2
  109. package/build/src/cli/usage.js +0 -4
  110. package/build/src/contract-worktree.d.ts +29 -14
  111. package/build/src/contract-worktree.js +131 -70
  112. package/build/src/core/facts/codec.js +9 -0
  113. package/build/src/core/facts/fold.js +13 -1
  114. package/build/src/core/facts/types.d.ts +8 -1
  115. package/build/src/core/subject.js +4 -3
  116. package/build/src/core/verbs/placement.d.ts +9 -1
  117. package/build/src/core/verbs/placement.js +24 -6
  118. package/build/src/core/verbs/reintegrate.d.ts +13 -0
  119. package/build/src/core/verbs/reintegrate.js +24 -0
  120. package/build/src/dispatch/index.d.ts +1 -1
  121. package/build/src/git/admission.d.ts +2 -1
  122. package/build/src/git/hooks.d.ts +2 -0
  123. package/build/src/git/hooks.js +34 -1
  124. package/build/src/git/integration.d.ts +9 -2
  125. package/build/src/git/integration.js +92 -1
  126. package/build/src/git/nuke.d.ts +2 -0
  127. package/build/src/git/nuke.js +97 -0
  128. package/build/src/git/observe.d.ts +2 -1
  129. package/build/src/git/observe.js +6 -5
  130. package/build/src/git/process.d.ts +28 -0
  131. package/build/src/git/process.js +94 -0
  132. package/build/src/git/read-observation.d.ts +2 -1
  133. package/build/src/git/read-observation.js +3 -2
  134. package/build/src/git/reconcile.d.ts +4 -1
  135. package/build/src/git/reconcile.js +42 -8
  136. package/build/src/git/repository.d.ts +2 -29
  137. package/build/src/git/repository.js +7 -118
  138. package/build/src/git/scratch.d.ts +1 -1
  139. package/build/src/git/scratch.js +1 -1
  140. package/build/src/git/target-placement.d.ts +3 -2
  141. package/build/src/git/target-placement.js +15 -14
  142. package/build/src/git/tender.d.ts +2 -1
  143. package/build/src/git/tender.js +4 -3
  144. package/build/src/git/terminal-seal.d.ts +2 -2
  145. package/build/src/git/terminal-seal.js +3 -6
  146. package/build/src/git/workspace.d.ts +4 -1
  147. package/build/src/git/workspace.js +1 -1
  148. package/build/src/index.d.ts +1 -2
  149. package/build/src/index.js +1 -1
  150. package/build/src/kanshi/read.js +5 -1
  151. package/build/src/library/address.js +7 -1
  152. package/build/src/library/akuma-creation.d.ts +1 -0
  153. package/build/src/library/akuma-creation.js +8 -1
  154. package/build/src/library/audit.d.ts +3 -1
  155. package/build/src/library/audit.js +2 -1
  156. package/build/src/library/bind.d.ts +2 -1
  157. package/build/src/library/bind.js +1 -1
  158. package/build/src/library/configuration.d.ts +1 -1
  159. package/build/src/library/configuration.js +52 -18
  160. package/build/src/library/contract.d.ts +59 -4
  161. package/build/src/library/contract.js +195 -34
  162. package/build/src/library/delivery.d.ts +4 -2
  163. package/build/src/library/fleet.d.ts +27 -7
  164. package/build/src/library/fleet.js +79 -39
  165. package/build/src/library/input.d.ts +0 -1
  166. package/build/src/library/input.js +0 -5
  167. package/build/src/library/keiyaku.d.ts +6 -2
  168. package/build/src/library/keiyaku.js +2 -0
  169. package/build/src/library/mutation.d.ts +3 -1
  170. package/build/src/library/mutation.js +3 -0
  171. package/build/src/library/nuke.d.ts +14 -0
  172. package/build/src/library/nuke.js +54 -0
  173. package/build/src/library/reconcile.d.ts +2 -1
  174. package/build/src/library/reconcile.js +8 -3
  175. package/build/src/library/refusal.d.ts +10 -1
  176. package/build/src/library/region.d.ts +1 -1
  177. package/build/src/library/repo.d.ts +4 -1
  178. package/build/src/library/repo.js +10 -4
  179. package/build/src/protocol/abandon.d.ts +9 -0
  180. package/build/src/protocol/abandon.js +15 -0
  181. package/build/src/protocol/amend.d.ts +16 -0
  182. package/build/src/protocol/amend.js +77 -0
  183. package/build/src/protocol/arc.d.ts +6 -0
  184. package/build/src/protocol/arc.js +12 -0
  185. package/build/src/protocol/attempt.d.ts +2 -1
  186. package/build/src/protocol/audit.d.ts +53 -0
  187. package/build/src/protocol/audit.js +147 -0
  188. package/build/src/protocol/bind.d.ts +1 -1
  189. package/build/src/protocol/completion.d.ts +42 -0
  190. package/build/src/protocol/completion.js +183 -0
  191. package/build/src/protocol/deliver.d.ts +49 -0
  192. package/build/src/protocol/deliver.js +261 -0
  193. package/build/src/protocol/intent.d.ts +2 -1
  194. package/build/src/protocol/intent.js +8 -2
  195. package/build/src/protocol/operations.d.ts +93 -202
  196. package/build/src/protocol/operations.js +23 -642
  197. package/build/src/protocol/placement.d.ts +12 -13
  198. package/build/src/protocol/placement.js +8 -19
  199. package/build/src/protocol/read/status.d.ts +17 -5
  200. package/build/src/protocol/read/status.js +57 -13
  201. package/build/src/protocol/reconcile.d.ts +35 -0
  202. package/build/src/protocol/reconcile.js +41 -0
  203. package/build/src/protocol/reintegrate.d.ts +31 -0
  204. package/build/src/protocol/reintegrate.js +74 -0
  205. package/build/src/protocol/review.d.ts +34 -0
  206. package/build/src/protocol/review.js +156 -0
  207. package/build/src/protocol/run.d.ts +1 -1
  208. package/build/src/runtime/proc/run.js +9 -5
  209. package/build/src/settlement/fence.d.ts +3 -1
  210. package/build/src/settlement/fence.js +24 -0
  211. package/build/src/settlement/holder.d.ts +1 -1
  212. package/build/src/settlement/settle.d.ts +1 -1
  213. package/build/src/settlement/settle.js +1 -2
  214. package/build/src/task/board.d.ts +0 -1
  215. package/build/src/task/board.js +0 -3
  216. package/build/src/task/compose.d.ts +2 -2
  217. package/build/src/task/compose.js +13 -11
  218. package/build/src/task/context.d.ts +14 -2
  219. package/build/src/task/context.js +30 -7
  220. package/build/src/task/index.d.ts +7 -6
  221. package/build/src/task/index.js +17 -145
  222. package/build/src/task/input.d.ts +18 -0
  223. package/build/src/task/input.js +189 -0
  224. package/build/src/task/mutation.d.ts +44 -0
  225. package/build/src/task/mutation.js +93 -0
  226. package/build/src/task/operations.d.ts +14 -6
  227. package/build/src/task/operations.js +57 -57
  228. package/build/src/task/store.d.ts +1 -0
  229. package/build/src/task/store.js +91 -3
  230. package/build/src/verification/execution.d.ts +1 -1
  231. package/build/src/workspace-place.d.ts +3 -4
  232. package/build/src/workspace-place.js +26 -15
  233. package/package.json +3 -3
@@ -1,12 +1,12 @@
1
- import { isTaskAction, parseTaskCommand, renderTaskUsage, } from "./commands/task.js";
2
- import { isAkumaAction, parseAkumaCatalogPath, parseAkumaCommand, renderAkumaRootRows, renderAkumaUsage, } from "./commands/akuma.js";
1
+ import { isTaskAction, parseTaskCommand, renderTaskHelp, renderTaskUsage, } from "./commands/task.js";
2
+ import { isAkumaAction, parseAkumaCatalogPath, parseAkumaCommand, renderAkumaHelp, renderAkumaRootRows, renderAkumaUsage, } from "./commands/akuma.js";
3
3
  import { INSTALL_USAGE, parseInstallCommand, renderInstallHelp } from "./commands/install.js";
4
- import { AMEND_MINIMAL_STDIN_HELP, CONTRACT_COMMAND_SPECS } from "./commands/contract.js";
5
- import { CliUsageError, isBlankInput, usageLine, withJsonAutomationHelp } from "./usage.js";
4
+ import { AMEND_OPERATIONS_HELP, CONTRACT_COMMAND_SPECS, } from "./commands/contract.js";
5
+ import { CliUsageError, isBlankInput, usageLine } from "./usage.js";
6
6
  export { CliUsageError } from "./usage.js";
7
7
  const ROOT_USAGE = "usage: keiyaku [-C <path>] [--repo <path>] <command> [<contract>|@<contract>] [--flag ...] [-]";
8
8
  export function renderRootHelp() {
9
- return withJsonAutomationHelp([
9
+ return [
10
10
  ROOT_USAGE,
11
11
  "",
12
12
  "global options:",
@@ -20,12 +20,12 @@ export function renderRootHelp() {
20
20
  " task ...",
21
21
  " Task coordination; see `keiyaku task --help`.",
22
22
  ...renderAkumaRootRows(),
23
- ].join("\n"));
23
+ ].join("\n");
24
24
  }
25
25
  export function renderContractHelp(command) {
26
26
  const spec = CONTRACT_COMMAND_SPECS[command];
27
27
  const help = `${spec.purpose}\n\n${usageLine(spec.usage)}`;
28
- return withJsonAutomationHelp(command === "amend" ? `${help}\n\n${AMEND_MINIMAL_STDIN_HELP}` : help);
28
+ return command === "amend" ? `${help}\n\n${AMEND_OPERATIONS_HELP}` : help;
29
29
  }
30
30
  function contractUsage(command) {
31
31
  return usageLine(CONTRACT_COMMAND_SPECS[command].usage);
@@ -39,6 +39,65 @@ export function renderCommandUsage(command) {
39
39
  return renderAkumaUsage(command.command);
40
40
  return contractUsage(command.command);
41
41
  }
42
+ export function renderHelp(coordinate) {
43
+ switch (coordinate.kind) {
44
+ case "root": return renderRootHelp();
45
+ case "contract": return renderContractHelp(coordinate.command);
46
+ case "task": return renderTaskHelp(coordinate.action);
47
+ case "install": return renderInstallHelp();
48
+ case "akuma": return renderAkumaHelp(coordinate.action);
49
+ }
50
+ }
51
+ export function commandRepoPolicy(command) {
52
+ switch (command.command) {
53
+ case "bind":
54
+ case "amend":
55
+ case "deliver":
56
+ case "review":
57
+ case "arc":
58
+ case "abandon":
59
+ case "audit":
60
+ case "reconcile":
61
+ case "show":
62
+ case "region":
63
+ return { use: "required", acceptsExplicit: true };
64
+ case "ls":
65
+ return { use: command.query.kind === "contracts" ? "required" : "none", acceptsExplicit: false };
66
+ case "status":
67
+ case "tell":
68
+ return { use: "optional", acceptsExplicit: false };
69
+ case "history":
70
+ return "contract" in command
71
+ ? { use: "required", acceptsExplicit: true }
72
+ : { use: "optional", acceptsExplicit: false };
73
+ case "fork":
74
+ return { use: "optional", acceptsExplicit: true };
75
+ case "wait":
76
+ case "kill": {
77
+ const contractSelector = command.akuma.some((selector) => selector.startsWith("kei/"));
78
+ return { use: contractSelector ? "required" : "optional", acceptsExplicit: contractSelector };
79
+ }
80
+ case "call":
81
+ return {
82
+ use: command.contract === undefined ? "none" : "required",
83
+ acceptsExplicit: command.contract !== undefined,
84
+ };
85
+ case "settings":
86
+ case "nuke":
87
+ case "task":
88
+ case "install":
89
+ return { use: "none", acceptsExplicit: false };
90
+ }
91
+ }
92
+ function refuseUnusedRepo(command) {
93
+ if (command.command === "call")
94
+ throw new CliUsageError("--repo has no consumer without --contract");
95
+ throw new CliUsageError(`--repo has no consumer for ${command.command}`);
96
+ }
97
+ export function assertExplicitRepoUse(command, repo) {
98
+ if (repo !== undefined && !commandRepoPolicy(command).acceptsExplicit)
99
+ refuseUnusedRepo(command);
100
+ }
42
101
  function optionalFlag(flags, name) {
43
102
  const value = flags[name];
44
103
  return typeof value === "string" ? value : undefined;
@@ -69,9 +128,12 @@ function scanOption(command, argv, state, index) {
69
128
  return index;
70
129
  }
71
130
  const value = argv[index + 1];
72
- if (value === undefined || value === "-" || value.startsWith("--"))
131
+ if (value === undefined)
132
+ refuse(command, `${token} requires a value`);
133
+ if (kind !== "raw-value" && (value === "-" || value.startsWith("--"))) {
73
134
  refuse(command, `${token} requires a value`);
74
- if (isBlankInput(value))
135
+ }
136
+ if (kind !== "raw-value" && isBlankInput(value))
75
137
  refuse(command, `${token} requires a nonblank value`);
76
138
  if (kind === "repeat-value") {
77
139
  const values = state.flags[name];
@@ -121,7 +183,7 @@ function parseBind(parts) {
121
183
  const task = optionalFlag(parts.flags, "task");
122
184
  const target = optionalFlag(parts.flags, "target");
123
185
  const after = parts.flags.after === undefined ? [] : Array.isArray(parts.flags.after) ? parts.flags.after : [parts.flags.after];
124
- const gates = optionalFlag(parts.flags, "gates");
186
+ const gates = parseGateBundleNames(parts, "bind");
125
187
  return {
126
188
  command: "bind",
127
189
  ...(task === undefined ? {} : { task }),
@@ -138,7 +200,7 @@ function parseAmend(parts) {
138
200
  const after = parts.flags.after === undefined ? [] : Array.isArray(parts.flags.after) ? parts.flags.after : [parts.flags.after];
139
201
  if (parts.flags["clear-after"] === true && after.length > 0)
140
202
  refuse("amend", "--clear-after and --after are mutually exclusive");
141
- const gates = optionalFlag(parts.flags, "gates");
203
+ const gates = parseGateBundleNames(parts, "amend");
142
204
  if (!parts.stdin && parts.flags.after === undefined && parts.flags["clear-after"] !== true && gates === undefined) {
143
205
  refuse("amend", "amend requires stdin or --after, --clear-after, or --gates");
144
206
  }
@@ -153,6 +215,16 @@ function parseAmend(parts) {
153
215
  output: parts.output,
154
216
  };
155
217
  }
218
+ function parseGateBundleNames(parts, command) {
219
+ const value = optionalFlag(parts.flags, "gates");
220
+ if (value === undefined)
221
+ return undefined;
222
+ const names = value.split(",");
223
+ if (names.some((name) => name.length === 0)) {
224
+ refuse(command, "--gates requires nonempty comma-separated names");
225
+ }
226
+ return names;
227
+ }
156
228
  function parseDeliver(parts) {
157
229
  const contract = parts.positionals[0];
158
230
  const message = optionalFlag(parts.flags, "message");
@@ -162,6 +234,7 @@ function parseDeliver(parts) {
162
234
  ...(parts.actor === undefined ? {} : { actor: parts.actor }),
163
235
  ...(message === undefined ? {} : { message }),
164
236
  includeDirty: parts.flags["include-dirty"] === true,
237
+ materializeConflict: parts.flags["materialize-conflict"] === true,
165
238
  output: parts.output,
166
239
  };
167
240
  }
@@ -240,14 +313,14 @@ function parseRegion(parts) {
240
313
  }
241
314
  function parseLs(parts) {
242
315
  const path = parts.positionals[0];
243
- if (path === "task/")
316
+ if (path === "task" || path === "task/")
244
317
  return { command: "ls", query: { kind: "tasks" }, output: parts.output };
245
- if (path === "kei/")
318
+ if (path === "kei" || path === "kei/")
246
319
  return { command: "ls", query: { kind: "contracts" }, output: parts.output };
247
320
  try {
248
321
  const query = parseAkumaCatalogPath(path);
249
322
  if (query === null)
250
- refuse("ls", "ls requires an identity directory with a trailing slash");
323
+ refuse("ls", "ls requires a supported identity directory selector");
251
324
  return { command: "ls", query, output: parts.output };
252
325
  }
253
326
  catch (error) {
@@ -343,6 +416,10 @@ function parseCommand(parts) {
343
416
  output: parts.output,
344
417
  };
345
418
  }
419
+ case "nuke": {
420
+ const confirm = optionalFlag(parts.flags, "confirm");
421
+ return { command: "nuke", ...(confirm === undefined ? {} : { confirm }), output: parts.output };
422
+ }
346
423
  case "settings": return { command: "settings", output: parts.output };
347
424
  case "region": return parseRegion(parts);
348
425
  }
@@ -366,9 +443,10 @@ export function parseArgv(argv) {
366
443
  const akuma = isAkumaAction(invocation.commandArgv[0])
367
444
  ? parseAkumaCommand(invocation.commandArgv)
368
445
  : undefined;
369
- return {
446
+ const parsed = {
370
447
  ...(invocation.cwd === undefined ? {} : { cwd: invocation.cwd }),
371
448
  ...(invocation.repo === undefined ? {} : { repo: invocation.repo }),
372
449
  command: task ?? akuma ?? install ?? parseCommand(scanArgv(invocation.commandArgv)),
373
450
  };
451
+ return parsed;
374
452
  }
@@ -1,5 +1,5 @@
1
1
  import { toolRepr } from "./akuma-tool.js";
2
- import { displayColumns, renderBoundedTextBlock, renderTextBlock, safeText, truncateMiddleDisplayText, } from "./terminal.js";
2
+ import { displayColumns, renderBoundedTextBlock, safeText, truncateMiddleDisplayText, } from "./terminal.js";
3
3
  const DEFAULT_CONTEXT = { columns: 80, color: false };
4
4
  const OPENING_STROKE = "─────";
5
5
  const TIME_WIDTH = 5;
@@ -7,19 +7,30 @@ const VERB_WIDTH = 6;
7
7
  function identity(id, alias) {
8
8
  return `${id}${alias === undefined ? "" : ` (${alias})`}`;
9
9
  }
10
- function associatedIdentity(id, alias, contractId) {
10
+ function associatedContractId(contract) {
11
+ return contract.kind === "associated" ? contract.contractId : undefined;
12
+ }
13
+ function associatedIdentity(id, alias, contract) {
14
+ const contractId = contract === undefined ? undefined : associatedContractId(contract);
11
15
  return `${identity(id, alias)}${contractId === undefined ? "" : ` [${contractId}]`}`;
12
16
  }
13
- function snapshotHeading(id, alias, contractId) {
17
+ function snapshotHeading(id, alias, contract) {
18
+ const contractId = contract === undefined ? undefined : associatedContractId(contract);
14
19
  return [
15
20
  OPENING_STROKE,
16
21
  identity(id, alias),
17
22
  ...(contractId === undefined ? [] : [`└─ ${contractId}`]),
18
23
  ];
19
24
  }
25
+ function contractFacts(contract) {
26
+ return contract.kind === "failed" ? [`! contract failed ${safeText(contract.diagnostic)}`] : [];
27
+ }
28
+ function unobservedText(id, diagnostic) {
29
+ return `! ${id} unobserved: ${safeText(diagnostic)}`;
30
+ }
20
31
  function lifeLabel(life) {
21
32
  if (life === "running")
22
- return "● running";
33
+ return "● STILL RUNNING";
23
34
  if (life === "asleep")
24
35
  return "○ asleep";
25
36
  if (life === "killed")
@@ -59,7 +70,7 @@ function mark(row) {
59
70
  return "?";
60
71
  return row.state.status === "ok" ? "✓" : "!";
61
72
  }
62
- return "·";
73
+ return "│";
63
74
  }
64
75
  function rowText(row) {
65
76
  if (row.kind === "said" || row.kind === "thought" || row.kind === "note" || row.kind === "call" || row.kind === "tell") {
@@ -149,47 +160,59 @@ function taskDispositionMark(disposition) {
149
160
  return "●";
150
161
  return disposition === "blocked" ? "‖" : "○";
151
162
  }
152
- function taskScanLine(row, indent = "") {
153
- return `${indent}${taskDispositionMark(row.disposition)} ${row.id} · P${row.priority} ${row.disposition}`;
154
- }
155
- function changeOp(op) {
156
- return op === "add" ? "write" : op === "delete" ? "delete" : "edit";
157
- }
158
- function renderReportedChangeLines(snapshot, columns) {
159
- const lines = [` changes ${snapshot.reportedChanges.length + snapshot.reportedChangesOmitted}`];
160
- for (const change of snapshot.reportedChanges) {
161
- const scan = ` ${changeOp(change.op)}`;
162
- const path = safeText(change.path);
163
- const stat = change.diffstat === undefined
164
- ? ""
165
- : ` — +${change.diffstat.added} -${change.diffstat.removed}`;
166
- const inline = `${scan} ${path}${stat}`;
167
- if (displayColumns(inline) <= columns)
168
- lines.push(inline);
169
- else
170
- lines.push(`${scan}`, ...renderTextBlock(`${path}${stat}`, " ", columns));
163
+ function changeStat(group) {
164
+ let added = 0;
165
+ let removed = 0;
166
+ for (const change of group) {
167
+ if (change.diffstat === undefined)
168
+ return "+? -?";
169
+ added += change.diffstat.added;
170
+ removed += change.diffstat.removed;
171
171
  }
172
- if (snapshot.reportedChangesOmitted > 0) {
173
- lines.push(` ⋮ ${snapshot.reportedChangesOmitted} earlier changes`);
172
+ return `+${added} -${removed}`;
173
+ }
174
+ function groupedChangeRows(changes) {
175
+ const groups = [];
176
+ const seen = new Map();
177
+ for (const change of changes) {
178
+ const index = seen.get(change.path);
179
+ if (index === undefined) {
180
+ seen.set(change.path, groups.length);
181
+ groups.push([change]);
182
+ }
183
+ else
184
+ groups[index].push(change);
174
185
  }
175
- return lines;
186
+ return groups.map((group) => ({ path: group[0].path, stat: changeStat(group) }));
187
+ }
188
+ function renderReportedChangeLines(snapshot) {
189
+ const rows = groupedChangeRows(snapshot.reportedChanges);
190
+ const width = rows.reduce((max, row) => Math.max(max, row.stat.length), 0);
191
+ return [
192
+ `changes ${snapshot.reportedChanges.length + snapshot.reportedChangesOmitted}`,
193
+ ...rows.map((row) => ` ${row.stat.padEnd(width)} ${safeText(row.path)}`),
194
+ ...(snapshot.reportedChangesOmitted > 0 ? [` ⋮ ${snapshot.reportedChangesOmitted} earlier changes`] : []),
195
+ ];
196
+ }
197
+ function renderTaskRow(row, columns) {
198
+ const prefix = ` ${taskDispositionMark(row.disposition)} ${row.id} · `;
199
+ const body = `${safeText(row.title)} · ${row.disposition} · P${row.priority}`;
200
+ const inline = `${prefix}${body}`;
201
+ if (displayColumns(inline) <= columns)
202
+ return [inline];
203
+ return renderBoundedTextBlock(body, {
204
+ first: prefix,
205
+ continuation: " ",
206
+ columns,
207
+ lines: Number.MAX_SAFE_INTEGER,
208
+ });
176
209
  }
177
210
  function renderTaskContextLines(created, columns) {
178
211
  if (created === undefined)
179
212
  return [];
180
213
  if (created.kind === "failed")
181
214
  return [`! tasks failed ${safeText(created.diagnostic)}`];
182
- const lines = [` tasks ${created.rows.length}`];
183
- for (const row of created.rows) {
184
- const scan = ` ${taskScanLine(row)}`;
185
- const title = safeText(row.title);
186
- const inline = `${scan} — ${title}`;
187
- if (displayColumns(inline) <= columns)
188
- lines.push(inline);
189
- else
190
- lines.push(`${scan} —`, ...renderTextBlock(title, " ", columns));
191
- }
192
- return lines;
215
+ return [`tasks ${created.rows.length}`, ...created.rows.flatMap((row) => renderTaskRow(row, columns))];
193
216
  }
194
217
  function snapshotText(view, context, options = {}) {
195
218
  const snapshot = view.status.timeline;
@@ -201,29 +224,46 @@ function snapshotText(view, context, options = {}) {
201
224
  : groupedEntries(snapshot.entries, context);
202
225
  const facts = [
203
226
  ...(view.status.readonly?.enforcement === "none" ? [`! ${safeText(view.status.readonly.diagnostic)}`] : []),
227
+ ...contractFacts(view.contract),
204
228
  ...(options.facts ?? []),
205
229
  ];
206
- const footer = options.showLife === false ? [] : [` ${lifeLabel(view.status.life)}`];
230
+ const footer = options.showLife === false ? [] : ["", lifeLabel(view.status.life)];
207
231
  return [
208
- ...snapshotHeading(view.status.id, options.alias, view.contractId),
232
+ ...snapshotHeading(view.status.id, options.alias, view.contract),
209
233
  ...facts,
210
234
  ...activity,
211
- ...footer,
212
- ...renderReportedChangeLines(snapshot, context.columns),
213
235
  ...renderTaskContextLines(view.createdTasks, context.columns),
236
+ ...renderReportedChangeLines(snapshot),
237
+ ...footer,
214
238
  ].join("\n");
215
239
  }
240
+ function observationStageText(id, observation, context, options = {}) {
241
+ if (observation.kind === "unobserved")
242
+ return unobservedText(id, observation.diagnostic);
243
+ return snapshotText(observation, context, options);
244
+ }
245
+ function waitText(result, context) {
246
+ const alias = result.alias;
247
+ const blocks = [
248
+ ...result.result.observations.map((observation) => snapshotText(observation, context, { ...(alias === undefined ? {} : { alias }) })),
249
+ ...result.result.unobserved.map((member) => unobservedText(member.id, member.diagnostic)),
250
+ ];
251
+ return blocks.join("\n\n");
252
+ }
216
253
  function historyText(command, result, context) {
217
254
  if (command.last)
218
255
  return result.mode === "last" ? result.answer : "no answer retained";
219
256
  if (result.mode !== "page")
220
257
  throw new Error("history result lacks page");
221
- const contractId = result.historyResult.contractId;
222
- return [...snapshotHeading(result.akuma, result.alias, contractId), ...groupedRows(result.history.rows, context, true)].join("\n");
258
+ return [...snapshotHeading(result.akuma, result.alias, result.historyResult.contract), ...groupedRows(result.history.rows, context, true)].join("\n");
223
259
  }
224
260
  function tellText(result, context) {
225
261
  const facts = typeof result.result.tell.wake === "string" ? [] : [`! error ${safeText(result.result.tell.wake.diagnostic)}`];
226
- return snapshotText(result.result.observation, context, { ...(result.alias === undefined ? {} : { alias: result.alias }), facts, showLife: false });
262
+ return observationStageText(result.result.akuma, result.result.observation, context, {
263
+ ...(result.alias === undefined ? {} : { alias: result.alias }),
264
+ facts,
265
+ showLife: false,
266
+ });
227
267
  }
228
268
  function dispatchLines(stage) {
229
269
  if (stage.kind === "none" || stage.kind === "dispatched")
@@ -263,6 +303,9 @@ export function akumaRawAnswer(result) {
263
303
  function executionCwdLine(result) {
264
304
  return result.execution.source === "contract-worktree" ? [`cwd ${result.execution.cwd}`] : [];
265
305
  }
306
+ function posixShellArgument(value) {
307
+ return `'${value.replace(/'/g, `'\"'\"'`)}'`;
308
+ }
266
309
  function callText(result, context) {
267
310
  const alias = result.result.alias.kind === "aliased" ? result.result.alias.alias.alias : undefined;
268
311
  const contractId = result.result.dispatch.kind === "dispatched" ? result.result.dispatch.dispatch.contractId : undefined;
@@ -272,17 +315,24 @@ function callText(result, context) {
272
315
  facts.push(`alias failed ${result.result.alias.failure.kind} ${safeText(result.result.alias.failure.diagnostic)}`);
273
316
  const cwd = executionCwdLine(result.result);
274
317
  if (result.result.observation.kind === "detached") {
275
- const lines = [...snapshotHeading(result.result.akuma, alias, contractId), ...cwd, ...restraint, ...facts];
318
+ const lines = [...snapshotHeading(result.result.akuma, alias, contractId === undefined
319
+ ? { kind: "none" }
320
+ : { kind: "associated", contractId }), ...cwd, ...restraint, ...facts];
276
321
  if (!callFailed(result.result)) {
277
322
  const selector = result.result.alias.kind === "aliased" ? result.result.alias.alias.alias : result.result.akuma;
278
- lines.push(`$ keiyaku -C ${result.world} wait ${selector} --timeout 5m`);
323
+ lines.push(`$ keiyaku -C ${posixShellArgument(result.world)} wait ${selector} --timeout 5m`);
279
324
  }
280
325
  return lines.join("\n");
281
326
  }
282
327
  if (result.result.observation.kind === "failed") {
283
- return [...snapshotHeading(result.result.akuma, alias, contractId), ...cwd, ...restraint, ...facts, `! error ${safeText(result.result.observation.failure.diagnostic)}`].join("\n");
328
+ return [...snapshotHeading(result.result.akuma, alias, contractId === undefined
329
+ ? { kind: "none" }
330
+ : { kind: "associated", contractId }), ...cwd, ...restraint, ...facts, `! error ${safeText(result.result.observation.failure.diagnostic)}`].join("\n");
284
331
  }
285
- return snapshotText({ status: result.result.observation.status, ...(contractId === undefined ? {} : { contractId }) }, context, {
332
+ return snapshotText({
333
+ status: result.result.observation.status,
334
+ contract: contractId === undefined ? { kind: "none" } : { kind: "associated", contractId },
335
+ }, context, {
286
336
  ...(alias === undefined ? {} : { alias }),
287
337
  facts: [...cwd, ...facts],
288
338
  });
@@ -299,17 +349,25 @@ export function renderAkumaText(command, result, context = DEFAULT_CONTEXT) {
299
349
  case "call": return callText(result, context);
300
350
  case "status": return snapshotText(result.status, context, { ...(result.alias === undefined ? {} : { alias: result.alias }) });
301
351
  case "wait":
302
- return result.result.observations.map((observation) => snapshotText(observation, context, { ...(result.alias === undefined ? {} : { alias: result.alias }) })).join("\n\n");
303
- case "tell": return result.mode === "ordinary" ? tellText(result, context) : snapshotText(result.result.observation, context, { ...(result.alias === undefined ? {} : { alias: result.alias }), showLife: false });
352
+ return waitText(result, context);
353
+ case "tell":
354
+ return result.mode === "ordinary"
355
+ ? tellText(result, context)
356
+ : observationStageText(result.result.id, result.result.observation, context, {
357
+ ...(result.alias === undefined ? {} : { alias: result.alias }),
358
+ showLife: false,
359
+ });
304
360
  case "history":
305
361
  return historyText(command, result, context);
306
362
  case "fork": {
307
363
  if (result.receipt.kind !== "forked")
308
364
  return result.receipt.kind === "unknown-history" ? `${result.receipt.at} has no matching retained answered turn` : result.receipt.kind === "provider-cannot-fork" ? `${result.receipt.provider} cannot fork` : result.receipt.diagnostic;
309
365
  const contractId = result.receipt.dispatch.kind === "dispatched" ? result.receipt.dispatch.dispatch.contractId : undefined;
310
- return associatedIdentity(result.receipt.child, undefined, contractId);
366
+ return associatedIdentity(result.receipt.child, undefined, contractId === undefined
367
+ ? { kind: "none" }
368
+ : { kind: "associated", contractId });
311
369
  }
312
- case "kill": return result.result.results.map((member) => snapshotText(member.observation, context, { facts: [`kill ${member.evidence}`], ...(result.alias === undefined ? {} : { alias: result.alias }) })).join("\n\n");
370
+ case "kill": return result.result.results.map((member) => observationStageText(member.id, member.observation, context, { facts: [`kill ${member.evidence}`], ...(result.alias === undefined ? {} : { alias: result.alias }) })).join("\n\n");
313
371
  }
314
372
  }
315
373
  function callExitCode(result) {
@@ -1,6 +1,6 @@
1
1
  import { cleanupLines, leakLines, receiptPayload, receiptRow, stopLines, titleLines, } from "./receipt.js";
2
2
  import { renderRefusalFacts } from "./refusal.js";
3
- import { gitShortStat, renderBoundedTextBlock, renderOpaqueBlock, } from "./terminal.js";
3
+ import { gitShortStat, renderOpaqueBlock, } from "./terminal.js";
4
4
  const CHILD = " ";
5
5
  function workspaceEvidence(workspace, columns) {
6
6
  return renderOpaqueBlock(`workspace ${workspace.kind} ${workspace.path}`, CHILD, columns);
@@ -46,11 +46,7 @@ function verificationLines(verification, columns, addressed) {
46
46
  { text: `${verification.passed} of ${verification.total}` },
47
47
  ], columns);
48
48
  if (verification.summary !== undefined) {
49
- lines.push(...renderBoundedTextBlock(verification.summary, {
50
- first: `${CHILD}summary `,
51
- continuation: CHILD,
52
- columns,
53
- }));
49
+ receiptPayload(lines, "summary", verification.summary);
54
50
  }
55
51
  return lines;
56
52
  }
@@ -113,11 +113,20 @@ function acceptedRecord(result, columns) {
113
113
  const record = [];
114
114
  for (const fact of result.facts) {
115
115
  const contract = fact.contract === result.contract ? [] : [{ text: fact.contract, opaque: true }];
116
- receiptRow(record, " ", "journal", [
117
- ...contract,
118
- { text: fact.entry, opaque: true },
119
- { text: `· ${fact.kind}` },
120
- ], columns);
116
+ receiptRow(record, " ", "journal", fact.kind === "reintegrated"
117
+ ? [
118
+ ...contract,
119
+ { text: fact.entry, opaque: true },
120
+ { text: "· reintegrated" },
121
+ { text: fact.data.predecessor, opaque: true },
122
+ { text: "->" },
123
+ { text: fact.data.snapshot, opaque: true },
124
+ ]
125
+ : [
126
+ ...contract,
127
+ { text: fact.entry, opaque: true },
128
+ { text: `· ${fact.kind}` },
129
+ ], columns);
121
130
  }
122
131
  receiptRow(record, " ", "head", [{ text: result.head, opaque: true }], columns);
123
132
  if (result.verb === "deliver") {
@@ -176,11 +185,36 @@ function recordBlock(result, columns) {
176
185
  const rows = [...acceptedRecord(result, columns), ...acceptedLagRows(result, columns)];
177
186
  return [" record", ...indentRecord(rows)];
178
187
  }
179
- function verificationVerdictLine(verdict, columns) {
188
+ function completionLines(result, columns) {
180
189
  const lines = [];
181
- receiptRow(lines, verdict === "satisfied" ? "✓" : "!", "verification", [
182
- { text: verdict === "satisfied" ? "passed" : "failed" },
190
+ const completion = result.completion;
191
+ if (completion === undefined)
192
+ return lines;
193
+ const verification = completion.verification;
194
+ receiptRow(lines, " ", "target", [
195
+ { text: "->" },
196
+ { text: completion.integration, opaque: true },
197
+ ...(verification?.verdict === "satisfied"
198
+ ? [{ text: `· verified (${verification.mode})` }]
199
+ : []),
183
200
  ], columns);
201
+ if (verification?.verdict === "unsatisfied") {
202
+ receiptRow(lines, "!", "verification", [
203
+ { text: "unsatisfied" },
204
+ { text: `(${verification.mode})` },
205
+ ], columns);
206
+ if (result.verificationSummary !== undefined) {
207
+ receiptPayload(lines, " summary", result.verificationSummary);
208
+ }
209
+ }
210
+ return lines;
211
+ }
212
+ function movementLines(result, columns) {
213
+ const count = result.facts.filter((fact) => fact.kind === "reintegrated").length;
214
+ if (count === 0)
215
+ return [];
216
+ const lines = [];
217
+ receiptRow(lines, "~", "target", [{ text: `moved · re-integrated x${count}` }], columns);
184
218
  return lines;
185
219
  }
186
220
  function renderAcceptedBind(result, columns) {
@@ -202,23 +236,18 @@ function renderAcceptedAmend(result, columns) {
202
236
  return lines.join("\n");
203
237
  }
204
238
  function renderAcceptedDeliver(result, columns) {
205
- const complete = result.facts.some((fact) => fact.kind === "claimed");
239
+ const complete = result.completion !== undefined;
206
240
  const title = complete ? "delivered" : "deliver — not complete";
207
241
  const lines = titleLines("✓", title, result.contract, columns);
242
+ lines.push(...movementLines(result, columns), ...completionLines(result, columns));
208
243
  if (!complete)
209
244
  receiptRow(lines, " ", "candidate", [{ text: "kept" }], columns);
210
245
  if (result.verification !== undefined) {
211
246
  lines.push(...stopLines("verification", result.verification, columns, result.contract));
212
247
  }
213
- else if (result.verificationVerdict !== undefined) {
214
- lines.push(...verificationVerdictLine(result.verificationVerdict, columns));
215
- }
216
248
  if (!complete && result.placement !== undefined) {
217
249
  lines.push(...stopLines("completion", result.placement, columns, result.contract));
218
250
  }
219
- else if (!complete && (result.verification !== undefined || result.verificationVerdict === "unsatisfied")) {
220
- receiptRow(lines, "·", "completion", [{ text: "not attempted" }], columns);
221
- }
222
251
  if (result.cleanup !== undefined)
223
252
  pushBlock(lines, cleanupLines(result.cleanup, columns));
224
253
  if (result.leak !== undefined)
@@ -227,14 +256,21 @@ function renderAcceptedDeliver(result, columns) {
227
256
  return lines.join("\n");
228
257
  }
229
258
  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);
259
+ const complete = result.completion !== undefined;
260
+ const lines = titleLines("✓", `review ${result.verdict} — ${complete ? "complete" : "not complete"}`, result.contract, columns);
261
+ lines.push(...movementLines(result, columns), ...completionLines(result, columns));
262
+ if (!complete)
263
+ receiptRow(lines, " ", "candidate", [{ text: "kept" }], columns);
235
264
  if (result.placement !== undefined) {
236
265
  lines.push(...stopLines("completion", result.placement, columns, result.contract));
237
266
  }
267
+ if (result.verification !== undefined) {
268
+ lines.push(...stopLines("verification", result.verification, columns, result.contract));
269
+ }
270
+ if (result.cleanup !== undefined)
271
+ pushBlock(lines, cleanupLines(result.cleanup, columns));
272
+ if (result.leak !== undefined)
273
+ pushBlock(lines, leakLines(result.leak, columns));
238
274
  lines.push(...acceptedDeviations(result, columns), ...recordBlock(result, columns));
239
275
  return lines.join("\n");
240
276
  }
@@ -338,6 +374,11 @@ function journalBody(fact) {
338
374
  ` require-branches-to-be-up-to-date ${String(policy.requireBranchesToBeUpToDate)}`,
339
375
  ];
340
376
  }
377
+ case "reintegrated":
378
+ return [
379
+ ` predecessor ${fact.data.predecessor}`,
380
+ ` snapshot ${fact.data.snapshot}`,
381
+ ];
341
382
  case "attestation": {
342
383
  const lines = [
343
384
  ` gate ${fact.data.gate}`,