@astrosheep/keiyaku 2.8.5 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.md +35 -15
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
  4. package/build/agents/harness/control-types.js +1 -0
  5. package/build/agents/harness/execution-handle.js +23 -3
  6. package/build/agents/harness/index.js +6 -607
  7. package/build/agents/harness/outcome.js +141 -0
  8. package/build/agents/harness/projection.js +310 -0
  9. package/build/agents/harness/router.js +201 -0
  10. package/build/agents/harness/runtime.js +2 -1
  11. package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
  12. package/build/agents/launch-snapshot/resolve.js +72 -0
  13. package/build/agents/opencode-sdk.js +24 -3
  14. package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
  15. package/build/agents/providers/claude-agent-sdk/events.js +218 -0
  16. package/build/agents/providers/claude-agent-sdk/session.js +158 -0
  17. package/build/agents/providers/codex-app-server/adapter.js +347 -0
  18. package/build/agents/providers/codex-app-server/events.js +352 -0
  19. package/build/agents/providers/codex-app-server/session.js +266 -0
  20. package/build/agents/providers/codex-sdk.js +23 -5
  21. package/build/agents/providers/opencode-sdk/adapter.js +344 -0
  22. package/build/agents/providers/opencode-sdk/events.js +354 -0
  23. package/build/agents/providers/opencode-sdk/session.js +180 -0
  24. package/build/agents/providers/pi/adapter.js +269 -0
  25. package/build/agents/providers/pi/checkpoint.js +41 -0
  26. package/build/agents/providers/pi/events.js +282 -0
  27. package/build/agents/{selector_v2.js → selector.js} +8 -6
  28. package/build/cli/commands/akuma/akuma/handler.js +4 -0
  29. package/build/cli/commands/akuma/akuma/meta.js +16 -0
  30. package/build/cli/commands/akuma/catalog.js +8 -0
  31. package/build/cli/commands/akuma/list/handler.js +15 -0
  32. package/build/cli/commands/akuma/list/meta-ls.js +9 -0
  33. package/build/cli/commands/akuma/view/handler.js +34 -0
  34. package/build/cli/commands/akuma/view/meta.js +8 -0
  35. package/build/cli/commands/akuma.js +1 -1
  36. package/build/cli/commands/contract/amend/handler.js +10 -0
  37. package/build/cli/commands/contract/amend/meta.js +12 -0
  38. package/build/cli/commands/contract/arc/handler.js +9 -0
  39. package/build/cli/commands/contract/arc/meta.js +26 -0
  40. package/build/cli/commands/contract/bind/handler.js +23 -0
  41. package/build/cli/commands/contract/bind/meta.js +30 -0
  42. package/build/cli/commands/contract/catalog.js +16 -0
  43. package/build/cli/commands/contract/forfeit/handler.js +13 -0
  44. package/build/cli/commands/contract/forfeit/meta.js +12 -0
  45. package/build/cli/commands/contract/log/handler.js +12 -0
  46. package/build/cli/commands/contract/log/meta.js +12 -0
  47. package/build/cli/commands/contract/petition/handler.js +26 -0
  48. package/build/cli/commands/contract/petition/meta.js +23 -0
  49. package/build/cli/commands/contract/renew/handler.js +10 -0
  50. package/build/cli/commands/contract/renew/meta.js +17 -0
  51. package/build/cli/commands/projection/call/handler.js +42 -0
  52. package/build/cli/commands/projection/call/meta.js +9 -0
  53. package/build/cli/commands/projection/catalog.js +14 -0
  54. package/build/cli/commands/projection/kill/handler.js +37 -0
  55. package/build/cli/commands/projection/kill/meta.js +11 -0
  56. package/build/cli/commands/projection/revive/handler.js +56 -0
  57. package/build/cli/commands/projection/revive/meta.js +9 -0
  58. package/build/cli/commands/projection/status/handler.js +25 -0
  59. package/build/cli/commands/projection/status/meta.js +9 -0
  60. package/build/cli/commands/projection/tell/handler.js +36 -0
  61. package/build/cli/commands/projection/tell/meta.js +9 -0
  62. package/build/cli/commands/projection/wait/handler.js +23 -0
  63. package/build/cli/commands/projection/wait/meta.js +11 -0
  64. package/build/cli/commands/registry.js +100 -0
  65. package/build/cli/commands/shared.js +71 -0
  66. package/build/cli/commands/skills/catalog.js +6 -0
  67. package/build/cli/commands/skills/install/handler.js +10 -0
  68. package/build/cli/commands/skills/install/meta.js +9 -0
  69. package/build/cli/commands/skills/skills/handler.js +4 -0
  70. package/build/cli/commands/skills/skills/meta.js +10 -0
  71. package/build/cli/commands/system/catalog.js +8 -0
  72. package/build/cli/commands/system/completion/handler.js +10 -0
  73. package/build/cli/commands/system/completion/meta.js +9 -0
  74. package/build/cli/commands/system/dump-env/handler.js +3 -0
  75. package/build/cli/commands/system/dump-env/meta.js +10 -0
  76. package/build/cli/commands/system/guide/handler.js +4 -0
  77. package/build/cli/commands/system/guide/meta.js +9 -0
  78. package/build/cli/commands/task/add/handler.js +21 -0
  79. package/build/cli/commands/task/add/meta.js +8 -0
  80. package/build/cli/commands/task/catalog.js +22 -0
  81. package/build/cli/commands/task/doctor/handler.js +4 -0
  82. package/build/cli/commands/task/doctor/meta.js +8 -0
  83. package/build/cli/commands/task/done/handler.js +17 -0
  84. package/build/cli/commands/task/done/meta.js +8 -0
  85. package/build/cli/commands/task/drop/handler.js +6 -0
  86. package/build/cli/commands/task/drop/meta.js +8 -0
  87. package/build/cli/commands/task/ls/handler.js +13 -0
  88. package/build/cli/commands/task/ls/meta.js +8 -0
  89. package/build/cli/commands/task/shared.js +131 -0
  90. package/build/cli/commands/task/start/handler.js +6 -0
  91. package/build/cli/commands/task/start/meta.js +8 -0
  92. package/build/cli/commands/task/stop/handler.js +17 -0
  93. package/build/cli/commands/task/stop/meta.js +8 -0
  94. package/build/cli/commands/task/task/handler.js +5 -0
  95. package/build/cli/commands/task/task/meta.js +11 -0
  96. package/build/cli/commands/task/update/handler.js +18 -0
  97. package/build/cli/commands/task/update/meta.js +8 -0
  98. package/build/cli/commands/task/view/handler.js +14 -0
  99. package/build/cli/commands/task/view/meta.js +8 -0
  100. package/build/cli/completion.js +26 -27
  101. package/build/cli/flags.js +79 -2
  102. package/build/cli/help.js +27 -49
  103. package/build/cli/index.js +121 -374
  104. package/build/cli/output-stream-error-policy.js +17 -0
  105. package/build/cli/parse-flags.js +197 -0
  106. package/build/cli/parse-metadata.js +129 -0
  107. package/build/cli/parse-selectors.js +65 -0
  108. package/build/cli/parse.js +46 -313
  109. package/build/cli/projection-address.js +5 -0
  110. package/build/cli/render/arc.js +1 -1
  111. package/build/cli/render/errors.js +4 -3
  112. package/build/cli/render/format.js +14 -0
  113. package/build/cli/render/kanshi.js +106 -0
  114. package/build/cli/render/petition.js +24 -1
  115. package/build/cli/render/projection-activity.js +5 -1
  116. package/build/cli/render/shared.js +2 -2
  117. package/build/cli/render/status.js +79 -13
  118. package/build/cli/render/task.js +113 -0
  119. package/build/cli/render/wait.js +23 -3
  120. package/build/cli/types.js +1 -1
  121. package/build/config/{akuma-loader_v2.js → akuma-loader.js} +7 -4
  122. package/build/config/env.js +9 -4
  123. package/build/config/settings/disease.js +26 -0
  124. package/build/config/settings/knobs.js +8 -0
  125. package/build/config/settings/loader.js +244 -0
  126. package/build/config/settings/schema.js +276 -0
  127. package/build/core/addressing.js +1 -1
  128. package/build/core/amend.js +5 -8
  129. package/build/core/arc.js +7 -8
  130. package/build/core/bind-workspace.js +123 -0
  131. package/build/core/bind.js +75 -155
  132. package/build/core/call/call.js +229 -0
  133. package/build/core/call/context.js +251 -0
  134. package/build/core/call/execution.js +217 -0
  135. package/build/core/call/prompt.js +42 -0
  136. package/build/core/call/reference.js +24 -0
  137. package/build/core/call-persist.js +10 -3
  138. package/build/core/claim-delivery.js +247 -0
  139. package/build/core/claim.js +39 -277
  140. package/build/core/context.js +2 -1
  141. package/build/core/{render.js → contract-view.js} +12 -140
  142. package/build/core/draft.js +107 -9
  143. package/build/core/entry.js +9 -1
  144. package/build/core/execution-coordinate.js +4 -20
  145. package/build/core/execution-pact.js +16 -31
  146. package/build/core/forfeit.js +35 -22
  147. package/build/core/hints.js +2 -2
  148. package/build/core/log.js +2 -2
  149. package/build/core/path-coordinate.js +27 -0
  150. package/build/core/petition-claim-gates.js +8 -6
  151. package/build/core/petition-preview.js +97 -0
  152. package/build/core/petition-run.js +5 -7
  153. package/build/core/petition.js +39 -26
  154. package/build/core/projection/generation/database.js +306 -0
  155. package/build/core/projection/generation/identity.js +84 -0
  156. package/build/core/projection/generation/model.js +201 -0
  157. package/build/core/projection/generation/store.js +73 -0
  158. package/build/core/projection/generation/transitions.js +258 -0
  159. package/build/core/projection/heart.js +0 -307
  160. package/build/core/projection/tell/database.js +109 -0
  161. package/build/core/projection/tell/model.js +97 -0
  162. package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
  163. package/build/core/projection-activity.js +23 -2
  164. package/build/core/projection-coordinate.js +14 -2
  165. package/build/core/projection-core.js +2 -1
  166. package/build/core/projection-execution-observer.js +259 -0
  167. package/build/core/projection-generation-continuation.js +1 -1
  168. package/build/core/projection-generation-execution.js +90 -20
  169. package/build/core/projection-generation-launcher.js +1 -1
  170. package/build/core/projection-generation-runner.js +198 -4
  171. package/build/core/projection-identity.js +1 -1
  172. package/build/core/projection-kill.js +50 -17
  173. package/build/core/projection-life-observer.js +1 -1
  174. package/build/core/projection-life-protocol.js +10 -0
  175. package/build/core/projection-mint.js +1 -1
  176. package/build/core/projection-status.js +45 -32
  177. package/build/core/projection-wait.js +12 -2
  178. package/build/core/projection-wake.js +5 -2
  179. package/build/core/{queue_v2.js → queue.js} +2 -1
  180. package/build/core/registry.js +1 -1
  181. package/build/core/renew.js +9 -11
  182. package/build/core/response-artifact-catalog-sqlite.js +112 -0
  183. package/build/core/response-artifact-catalog.js +7 -0
  184. package/build/core/seal.js +44 -16
  185. package/build/core/status/board.js +289 -0
  186. package/build/core/status/drift.js +99 -0
  187. package/build/core/status/lifecycle.js +84 -0
  188. package/build/core/status/reconciliation.js +131 -0
  189. package/build/core/stored-agent-event.js +28 -4
  190. package/build/core/target-ref.js +10 -0
  191. package/build/core/task/board.js +175 -0
  192. package/build/core/task/commands.js +211 -0
  193. package/build/core/task/document.js +189 -0
  194. package/build/core/task/model.js +1 -0
  195. package/build/core/task/settlement-git.js +207 -0
  196. package/build/core/task/settlement-policy.js +82 -0
  197. package/build/core/task/source-board.js +84 -0
  198. package/build/core/task/source-model.js +1 -0
  199. package/build/core/task/validation.js +44 -0
  200. package/build/core/task-contract.js +237 -0
  201. package/build/core/task-doctor.js +14 -0
  202. package/build/core/task-git-actor.js +38 -0
  203. package/build/core/task-git-runtime.js +37 -0
  204. package/build/core/task-git-store.js +385 -0
  205. package/build/core/task-repository.js +1 -0
  206. package/build/core/task-store-repository.js +86 -0
  207. package/build/core/task-store.js +1 -0
  208. package/build/core/task-worktree.js +51 -0
  209. package/build/core/task.js +4 -0
  210. package/build/core/transcripts.js +138 -56
  211. package/build/core/validation.js +17 -0
  212. package/build/core/verdict.js +2 -2
  213. package/build/core/worktree-path.js +33 -8
  214. package/build/flow-error.js +5 -2
  215. package/build/generated/version.js +1 -1
  216. package/build/git/branches.js +33 -9
  217. package/build/git/commits.js +3 -0
  218. package/build/git/core.js +9 -0
  219. package/build/git/diff/parsers.js +0 -94
  220. package/build/index.js +2 -0
  221. package/build/keiyaku-constants.js +2 -0
  222. package/build/keiyaku.js +4 -3
  223. package/package.json +3 -2
  224. package/skills/keiyaku/SKILL.md +30 -13
  225. package/skills/keiyaku-akuma/SKILL.md +30 -57
  226. package/skills/keiyaku-task/SKILL.md +51 -0
  227. package/skills/keiyaku-workflow/SKILL.md +71 -0
  228. package/build/agents/harness/pump.js +0 -158
  229. package/build/agents/providers/codex-app-server.js +0 -864
  230. package/build/agents/providers/opencode-sdk.js +0 -363
  231. package/build/agents/providers/pi.js +0 -557
  232. package/build/config/settings.js +0 -533
  233. package/build/core/call.js +0 -686
  234. package/build/core/projection/generation.js +0 -412
  235. package/build/core/projection/identity.js +0 -81
  236. package/build/core/projection/mint.js +0 -174
  237. package/build/core/projection-generation-store.js +0 -707
  238. package/build/core/status.js +0 -539
@@ -1,276 +1,11 @@
1
1
  import { FlowError } from "../flow-error.js";
2
- import { agentNameSchema } from "../config/settings.js";
2
+ import { agentNameSchema } from "../config/settings/schema.js";
3
3
  import { isResponseArtifactId } from "../core/response-artifact-id.js";
4
- import { BOOLEAN_FLAGS, CONTROL_FLAGS, HELP_FLAGS, SHORT_FLAG_ALIASES, VALUE_FLAGS, } from "./flags.js";
5
- /** Commands that may carry an explicit commission selector (@ or --contract). */
6
- const COMMISSION_SELECTOR_COMMANDS = new Set([
7
- "arc",
8
- "amend",
9
- "call",
10
- "wait",
11
- "tell",
12
- "kill",
13
- "log",
14
- "renew",
15
- "petition",
16
- "forfeit",
17
- ]);
18
- const CLI_COMMAND_ORDER = [
19
- "bind",
20
- "arc",
21
- "call",
22
- "revive",
23
- "wait",
24
- "tell",
25
- "kill",
26
- "log",
27
- "akuma list",
28
- "akuma ls",
29
- "akuma show",
30
- "skills install",
31
- "skills",
32
- "akuma",
33
- "amend",
34
- "renew",
35
- "forfeit",
36
- "petition",
37
- "guide",
38
- "completion",
39
- "status",
40
- "dump-env",
41
- ];
42
- const COMMAND_FLAGS = {
43
- // contract is parseable on bind only so the mouth can reject it with bind-specific copy.
44
- bind: ["cwd", "repo", "contract", "after", "exclusive", "draft-only"],
45
- arc: ["cwd", "repo", "contract", "waive"],
46
- call: ["cwd", "repo", "contract", "akuma", "model", "effort", "incognito", "bare", "detach", "alias"],
47
- revive: ["cwd", "repo", "model", "effort"],
48
- wait: ["cwd", "repo", "contract", "timeout"],
49
- tell: ["cwd", "repo", "contract", "effort"],
50
- kill: ["cwd", "repo", "contract"],
51
- log: ["cwd", "repo", "contract"],
52
- akuma: [],
53
- "akuma ls": ["cwd", "repo"],
54
- "akuma list": ["cwd", "repo"],
55
- "akuma show": ["cwd", "repo"],
56
- skills: [],
57
- "skills install": ["force"],
58
- amend: ["cwd", "repo", "contract"],
59
- renew: ["cwd", "repo", "contract", "waive"],
60
- petition: ["cwd", "repo", "contract", "waive"],
61
- forfeit: ["cwd", "repo", "contract", "reason"],
62
- guide: [],
63
- completion: ["cwd", "repo", "shell", "word", "previous", "complete"],
64
- status: ["cwd", "repo", "target", "all"],
65
- "dump-env": [],
66
- };
67
- const STDIN_COMMANDS = new Set(["bind", "arc", "amend"]);
68
- export function normalizeContractAddress(raw) {
69
- const value = raw.startsWith("@") ? raw.slice(1) : raw;
70
- if (!value.trim()) {
71
- throw new FlowError("EMPTY_PARAM", "contract address cannot be empty");
72
- }
73
- return value.trim();
74
- }
75
- export function isCallCommand(command) {
76
- return command === "call";
77
- }
78
- export function commandUsesPromptInput(command) {
79
- return isCallCommand(command) || command === "revive";
80
- }
81
- export function parseWaitTimeout(value) {
82
- const matched = /^(?<amount>[1-9][0-9]*)(?<unit>[smh])$/.exec(value);
83
- if (!matched?.groups) {
84
- throw new FlowError("EMPTY_PARAM", "wait timeout must use <positive integer><s|m|h>, for example 45s, 5m, or 2h (maximum 24h)");
85
- }
86
- const amount = Number(matched.groups.amount);
87
- const multiplier = matched.groups.unit === "s" ? 1_000 : matched.groups.unit === "m" ? 60_000 : 3_600_000;
88
- const timeoutMs = amount * multiplier;
89
- if (!Number.isSafeInteger(timeoutMs) || timeoutMs > 24 * 3_600_000) {
90
- throw new FlowError("EMPTY_PARAM", "wait timeout must use <positive integer><s|m|h>, for example 45s, 5m, or 2h (maximum 24h)");
91
- }
92
- return timeoutMs;
93
- }
94
- export function commandPositionalRange(command) {
95
- if (command === "akuma show")
96
- return { min: 1, max: 1, label: "<name>" };
97
- if (command === "log")
98
- return { min: 0, max: 0, label: "" };
99
- if (command === "revive")
100
- return { min: 1, max: 1, label: "<artifact-id>" };
101
- if (command === "wait")
102
- return { min: 1, max: 1, label: "<projection-address>" };
103
- if (command === "tell")
104
- return { min: 2, max: 2, label: "<projection> <message>" };
105
- if (command === "kill")
106
- return { min: 1, max: 1, label: "<projection-address>" };
107
- if (isCallCommand(command))
108
- return { min: 0, max: 1 };
109
- return { min: 0, max: 0 };
110
- }
111
- function commandRequiresStdin(command) {
112
- return STDIN_COMMANDS.has(command);
113
- }
114
- function commandTokens(command) {
115
- return command.split(" ");
116
- }
117
- function parseFlagName(raw) {
118
- return raw.slice(2);
119
- }
120
- function assignFlag(flags, name, value) {
121
- switch (name) {
122
- case "cwd":
123
- flags.cwd = String(value);
124
- return;
125
- case "repo":
126
- flags.repo = String(value);
127
- return;
128
- case "contract":
129
- flags.contractId = normalizeContractAddress(String(value));
130
- flags.contractAddressSource = "explicit-flag";
131
- return;
132
- case "akuma":
133
- flags.akuma = String(value);
134
- return;
135
- case "projection":
136
- flags.projection = String(value);
137
- return;
138
- case "alias":
139
- flags.alias = String(value);
140
- return;
141
- case "timeout":
142
- flags.timeoutMs = parseWaitTimeout(String(value));
143
- return;
144
- case "model":
145
- flags.model = String(value);
146
- return;
147
- case "effort": {
148
- const effort = String(value);
149
- flags.effort = effort;
150
- return;
151
- }
152
- case "incognito":
153
- flags.incognito = Boolean(value);
154
- return;
155
- case "bare":
156
- flags.bare = Boolean(value);
157
- return;
158
- case "detach":
159
- flags.detach = Boolean(value);
160
- return;
161
- case "draft-only":
162
- flags.draftOnly = Boolean(value);
163
- return;
164
- case "exclusive":
165
- flags.exclusive = Boolean(value);
166
- return;
167
- case "after":
168
- flags.after = [...(flags.after ?? []), String(value)];
169
- return;
170
- case "force":
171
- flags.force = Boolean(value);
172
- return;
173
- case "reason":
174
- flags.reason = String(value);
175
- return;
176
- case "dry-run":
177
- flags.dryRun = Boolean(value);
178
- return;
179
- case "waive":
180
- flags.waivePaths = [...(flags.waivePaths ?? []), String(value)];
181
- return;
182
- case "shell":
183
- flags.shell = String(value);
184
- return;
185
- case "word":
186
- flags.word = String(value);
187
- return;
188
- case "previous":
189
- flags.previous = String(value);
190
- return;
191
- case "complete":
192
- flags.complete = Boolean(value);
193
- return;
194
- case "all":
195
- flags.all = Boolean(value);
196
- return;
197
- case "target":
198
- if (flags.target !== undefined) {
199
- throw new FlowError("EMPTY_PARAM", "option --target may only be specified once");
200
- }
201
- flags.target = String(value);
202
- return;
203
- default:
204
- throw new FlowError("EMPTY_PARAM", `unknown option: --${name}`);
205
- }
206
- }
207
- function assertAllowedFlag(command, name) {
208
- if (!COMMAND_FLAGS[command].includes(name)) {
209
- throw new FlowError("EMPTY_PARAM", `option --${name} is not valid for ${command}`);
210
- }
211
- }
212
- function resolveCommand(tokens) {
213
- if (tokens[0] === "petition" && (tokens[1] === "claim" || tokens[1] === "forfeit")) {
214
- throw new FlowError("UNKNOWN_COMMAND", `unknown command: petition ${tokens[1]}`);
215
- }
216
- for (const command of CLI_COMMAND_ORDER) {
217
- const parts = commandTokens(command);
218
- if (parts.every((part, index) => tokens[index] === part)) {
219
- return { command, rest: tokens.slice(parts.length) };
220
- }
221
- }
222
- const [head] = tokens;
223
- if (head === "skills") {
224
- return { command: "skills", rest: tokens.slice(1) };
225
- }
226
- if (!head)
227
- throw new FlowError("EMPTY_PARAM", "command cannot be empty");
228
- throw new FlowError("UNKNOWN_COMMAND", `unknown command: ${head ?? ""}`.trim());
229
- }
230
- function splitAtLiteralBoundary(tokens) {
231
- const boundary = tokens.indexOf("--");
232
- if (boundary === -1)
233
- return { head: tokens, payload: [] };
234
- return { head: tokens.slice(0, boundary), payload: tokens.slice(boundary + 1) };
235
- }
236
- function readValueFlag(name, token, eq, tokens, index) {
237
- // --target alone owns emptiness in core; empty remains a supplied value.
238
- // Other value flags keep the historical requires-a-value rejection.
239
- if (eq !== -1) {
240
- const value = token.slice(eq + 1);
241
- if (value === "" && name !== "target") {
242
- throw new FlowError("EMPTY_PARAM", `option --${name} requires a value`);
243
- }
244
- return { value, nextIndex: index };
245
- }
246
- const value = tokens[index + 1];
247
- if (value === undefined || value === "--" || value.startsWith("--")) {
248
- throw new FlowError("EMPTY_PARAM", `option --${name} requires a value`);
249
- }
250
- if (value === "" && name !== "target") {
251
- throw new FlowError("EMPTY_PARAM", `option --${name} requires a value`);
252
- }
253
- // Short-flag values may begin with @; they are flag values, not commission tokens.
254
- return { value, nextIndex: index + 1 };
255
- }
256
- function commissionConflictMessage(atForm, contractForm) {
257
- return `commission address supplied twice: ${atForm} and --contract ${contractForm}; use exactly one form`;
258
- }
259
- function formatSelectorList(items) {
260
- if (items.length <= 1)
261
- return items[0] ?? "";
262
- if (items.length === 2)
263
- return `${items[0]} and ${items[1]}`;
264
- return `${items.slice(0, -1).join(", ")}, and ${items[items.length - 1]}`;
265
- }
266
- function multiCommissionSelectorMessage(command, spellings) {
267
- return `${command} accepts one commission address; got ${formatSelectorList(spellings)}`;
268
- }
269
- function commissionSelectorSpelling(source, value, rawToken) {
270
- if (source === "at-address")
271
- return rawToken ?? `@${value}`;
272
- return `--contract ${rawToken ?? value}`;
273
- }
4
+ import { HELP_FLAGS } from "./flags.js";
5
+ import { assertAllowedFlag, assignFlag, BOOLEAN_FLAGS, CONTROL_FLAGS, parseFlagName, readValueFlag, SHORT_FLAG_ALIASES, VALUE_FLAGS, } from "./parse-flags.js";
6
+ import { commandPositionalRange, commandRequiresStdin, isCallCommand, resolveCommand, splitAtLiteralBoundary, TASK_SUBCOMMANDS, } from "./parse-metadata.js";
7
+ import { applyCommissionSelector, assertCommissionSelectorAllowed, assertProjectionSelectorPresent, } from "./parse-selectors.js";
8
+ export { commandPositionalRange, commandUsesPromptInput, isCallCommand, isPetitionDryRunInvocation, normalizeContractAddress, parseWaitTimeout, } from "./parse-metadata.js";
274
9
  export function parseCliArgs(tokens) {
275
10
  const { head, payload } = splitAtLiteralBoundary(tokens);
276
11
  const flags = {};
@@ -322,9 +57,6 @@ export function parseCliArgs(tokens) {
322
57
  }
323
58
  const eq = token.indexOf("=");
324
59
  const name = parseFlagName(eq === -1 ? token : token.slice(0, eq));
325
- if (name === "place") {
326
- throw new FlowError("EMPTY_PARAM", "unknown option --place; use @addr or --contract <addr>");
327
- }
328
60
  if (!CONTROL_FLAGS.has(name)) {
329
61
  throw new FlowError("EMPTY_PARAM", `unknown option: --${name}`);
330
62
  }
@@ -348,81 +80,82 @@ export function parseCliArgs(tokens) {
348
80
  }
349
81
  }
350
82
  const { command, rest } = resolveCommand(free);
351
- if (atTokens.length > 0 && contractFlagRaws.length > 0) {
352
- throw new FlowError("EMPTY_PARAM", commissionConflictMessage(atTokens[0], contractFlagRaws[0]));
353
- }
354
- if (atTokens.length > 1) {
355
- throw new FlowError("EMPTY_PARAM", multiCommissionSelectorMessage(command, atTokens));
356
- }
357
- if (contractFlagRaws.length > 1) {
358
- throw new FlowError("EMPTY_PARAM", multiCommissionSelectorMessage(command, contractFlagRaws.map((raw) => `--contract ${raw}`)));
359
- }
360
- if (atTokens.length === 1) {
361
- flags.contractId = normalizeContractAddress(atTokens[0]);
362
- flags.contractAddressSource = "at-address";
363
- }
364
- else if (contractFlagRaws.length === 1) {
365
- assignFlag(flags, "contract", contractFlagRaws[0]);
366
- }
83
+ applyCommissionSelector(command, flags, atTokens, contractFlagRaws);
367
84
  if (helpRequested) {
368
85
  return {
369
86
  command,
370
- flags: flags.contractId ? { contractId: flags.contractId, contractAddressSource: flags.contractAddressSource, ...(flags.cwd ? { cwd: flags.cwd } : {}), ...(flags.repo ? { repo: flags.repo } : {}) } : {
371
- ...(flags.cwd ? { cwd: flags.cwd } : {}),
372
- ...(flags.repo ? { repo: flags.repo } : {}),
373
- },
87
+ flags: flags.contractId
88
+ ? {
89
+ contractId: flags.contractId,
90
+ contractAddressSource: flags.contractAddressSource,
91
+ ...(flags.cwd ? { cwd: flags.cwd } : {}),
92
+ ...(flags.repo ? { repo: flags.repo } : {}),
93
+ }
94
+ : {
95
+ ...(flags.cwd ? { cwd: flags.cwd } : {}),
96
+ ...(flags.repo ? { repo: flags.repo } : {}),
97
+ },
374
98
  positional: [],
375
99
  helpRequested: true,
376
100
  };
377
101
  }
378
102
  if (command === "akuma") {
379
- throw new FlowError("EMPTY_PARAM", "akuma requires subcommand: list, ls, or show");
103
+ throw new FlowError("EMPTY_PARAM", "akuma requires subcommand: ls or view");
380
104
  }
381
105
  if (command === "skills") {
382
106
  throw new FlowError("EMPTY_PARAM", "skills requires subcommand: install");
383
107
  }
108
+ if (command === "task") {
109
+ throw new FlowError("EMPTY_PARAM", `task requires subcommand: ${TASK_SUBCOMMANDS.join(", ")}`);
110
+ }
111
+ if (command !== "bind" && seenFlagNames.has("place")) {
112
+ throw new FlowError("EMPTY_PARAM", "unknown option --place; use @addr or --contract <addr>");
113
+ }
384
114
  for (const name of seenFlagNames) {
385
115
  assertAllowedFlag(command, name);
386
116
  }
387
- if (flags.contractId !== undefined && !COMMISSION_SELECTOR_COMMANDS.has(command)) {
388
- throw new FlowError("EMPTY_PARAM", command === "bind"
389
- ? `bind creates a commission and does not accept @${flags.contractId}; use -C/--cwd to select the repository`
390
- : `contract address @${flags.contractId} is not valid for ${command}`);
117
+ if (command === "call" && flags.detach && flags.timeoutMs !== undefined) {
118
+ throw new FlowError("EMPTY_PARAM", "call cannot combine --detach and --wait");
391
119
  }
392
- if ((command === "wait" || command === "tell") && flags.contractId !== undefined) {
393
- const selectorSpelling = commissionSelectorSpelling(flags.contractAddressSource === "at-address" ? "at-address" : "explicit-flag", flags.contractId, flags.contractAddressSource === "at-address" ? atTokens[0] : contractFlagRaws[0]);
394
- const scopeOnlyMessage = `${command} requires a projection id or alias; ${selectorSpelling} only limits projection lookup, so add the projection address`;
395
- if (command === "wait" && rest.length + payload.length === 0) {
396
- throw new FlowError("EMPTY_PARAM", scopeOnlyMessage);
397
- }
398
- if (command === "tell" && rest.length === 0) {
399
- // Payload after -- is the message body, never the projection address.
400
- throw new FlowError("EMPTY_PARAM", scopeOnlyMessage);
401
- }
120
+ if (command === "task ls" && flags.all && flags.done) {
121
+ throw new FlowError("EMPTY_PARAM", "task ls cannot combine --all and --done");
122
+ }
123
+ if (command === "task update" && flags.taskParent !== undefined && flags.taskNoParent) {
124
+ throw new FlowError("EMPTY_PARAM", "task update cannot combine --parent and --no-parent");
125
+ }
126
+ if (command === "task update" && flags.taskTitle === undefined && flags.taskBody === undefined
127
+ && flags.taskPri === undefined && flags.taskNeeds === undefined && flags.taskDropNeeds === undefined
128
+ && flags.taskParent === undefined && !flags.taskNoParent && flags.taskFrom === undefined) {
129
+ throw new FlowError("EMPTY_PARAM", "task update requires at least one change");
130
+ }
131
+ if (command === "petition" && flags.json && !flags.dryRun) {
132
+ throw new FlowError("EMPTY_PARAM", "petition --json requires --dry-run");
402
133
  }
134
+ assertCommissionSelectorAllowed(command, flags);
135
+ assertProjectionSelectorPresent(command, flags, atTokens, contractFlagRaws, rest.length, payload.length);
403
136
  const positional = [...rest, ...payload];
404
137
  if (isCallCommand(command)) {
405
138
  if (flags.akuma) {
406
139
  if (positional.length > 1) {
407
- throw new FlowError("EMPTY_PARAM", `${command} accepts at most one prompt argument when --akuma is used`);
140
+ throw new FlowError("EMPTY_PARAM", `${command} accepts at most one <BODY|-> when --akuma is used`);
408
141
  }
409
142
  }
410
143
  else {
411
144
  const [name] = positional;
412
145
  if (!name) {
413
- throw new FlowError("EMPTY_PARAM", `${command} requires an agent name; use \`keiyaku ${command} NAME [prompt|-]\``);
146
+ throw new FlowError("EMPTY_PARAM", `${command} requires an agent name; use \`keiyaku ${command} NAME <BODY|->\``);
414
147
  }
415
148
  if (isResponseArtifactId(name)) {
416
149
  throw new FlowError("EMPTY_PARAM", `artifact ${name} is a response artifact; call expects an Akuma profile name`);
417
150
  }
418
151
  const parsedName = agentNameSchema.safeParse(name);
419
152
  if (!parsedName.success) {
420
- throw new FlowError("EMPTY_PARAM", `${command} requires a valid agent name before the optional prompt`);
153
+ throw new FlowError("EMPTY_PARAM", `${command} requires a valid agent name before <BODY|->`);
421
154
  }
422
155
  flags.akuma = parsedName.data;
423
156
  positional.shift();
424
157
  if (positional.length > 1) {
425
- throw new FlowError("EMPTY_PARAM", `${command} accepts at most one prompt argument after the agent name`);
158
+ throw new FlowError("EMPTY_PARAM", `${command} accepts at most one <BODY|-> after the agent name`);
426
159
  }
427
160
  }
428
161
  }
@@ -5,6 +5,7 @@ import { resolveProjectionCoordinate } from "../core/projection-coordinate.js";
5
5
  import { isProjectionId, projectionDir } from "../core/projection-core.js";
6
6
  import { isProjectionAlias, readProjectionAlias } from "../core/projection-alias.js";
7
7
  import { readProjectionIdentity } from "../core/projection-identity.js";
8
+ import { isProjectionGenerationSchemaV1Residue } from "../core/projection/generation/store.js";
8
9
  import { isResponseArtifactId } from "../core/response-artifact-id.js";
9
10
  import { isErrnoException } from "../errno.js";
10
11
  function isRealDirectory(directory) {
@@ -80,6 +81,10 @@ export async function resolveProjectionAddress(input) {
80
81
  const subject = alias ? `projection alias ${alias} points to missing projection ${id}` : `projection ${id}`;
81
82
  throw new AddressResolutionError("EMPTY_PARAM", `${subject} has no match ${suffix}`, attempt);
82
83
  }
84
+ if (isProjectionGenerationSchemaV1Residue(directory)) {
85
+ const subject = alias ? `projection alias ${alias} points to missing projection ${id}` : `projection ${id}`;
86
+ throw new AddressResolutionError("EMPTY_PARAM", `${subject} has no match ${suffix}`, attempt);
87
+ }
83
88
  let identity;
84
89
  try {
85
90
  identity = readProjectionIdentity(directory);
@@ -1,4 +1,4 @@
1
- import { shortCommitHash } from "../../core/render.js";
1
+ import { shortCommitHash } from "../../git/commits.js";
2
2
  import { assembleResponse, buildPayload, buildSection, formatHints, formatList, formatMaybe, formatWarnings, } from "./format.js";
3
3
  import { DIFF_OVERVIEW_SECTION_TITLE, RESPONSE_MARKERS, WARNING_SECTION_TITLE } from "./response-style.js";
4
4
  import { appendPersistenceSummary, BRANCH_LABEL, CONTENT_SECTION_TITLE, HINTS_LIST_MAX_ITEMS, HINTS_SECTION_TITLE, INFO_BRANCH_MAX_CHARS, INFO_COMMIT_MAX_CHARS, INFO_PLEA_MAX_CHARS, INFO_SECTION_TITLE, } from "./shared.js";
@@ -1,6 +1,7 @@
1
1
  import { asMessage, isFlowError, pickHintsFromError } from "../../flow-error.js";
2
- import { assertSettingsKnobUsable, loadKeiyakuSettings } from "../../config/settings.js";
3
- import { loadAkumaCatalogV2 } from "../../config/akuma-loader_v2.js";
2
+ import { assertSettingsKnobUsable } from "../../config/settings/disease.js";
3
+ import { loadKeiyakuSettings } from "../../config/settings/loader.js";
4
+ import { loadAkumaCatalog } from "../../config/akuma-loader.js";
4
5
  import { appendDebugLog } from "../../telemetry/debug-log.js";
5
6
  import { ACTOR_IDENTITY, TOOL_NAMES, BUILTIN_AGENT_NAMES } from "../../keiyaku.js";
6
7
  import { buildErrorResponse } from "./misc.js";
@@ -18,7 +19,7 @@ async function getAvailableActorNames(cwd, fallback) {
18
19
  try {
19
20
  const loaded = await loadKeiyakuSettings(cwd);
20
21
  assertSettingsKnobUsable(loaded, "agents");
21
- return Object.keys((await loadAkumaCatalogV2(cwd)).selected);
22
+ return Object.keys((await loadAkumaCatalog(cwd)).selected);
22
23
  }
23
24
  catch {
24
25
  return [...fallback];
@@ -6,6 +6,20 @@ export function shellQuote(value) {
6
6
  return value;
7
7
  return `'${value.replace(/'/g, "'\\''")}'`;
8
8
  }
9
+ export function formatAgeMs(ms) {
10
+ if (ms === undefined)
11
+ return undefined;
12
+ const seconds = Math.max(0, Math.floor(ms / 1_000));
13
+ if (seconds < 60)
14
+ return `${seconds}s`;
15
+ const minutes = Math.floor(seconds / 60);
16
+ if (minutes < 60)
17
+ return `${minutes}m`;
18
+ const hours = Math.floor(minutes / 60);
19
+ if (hours < 24)
20
+ return `${hours}h`;
21
+ return `${Math.floor(hours / 24)}d`;
22
+ }
9
23
  export const DISPLAY_TEXT_MAX_CHARS = 5000;
10
24
  export const FORMAT_MAYBE_MAX_CHARS = 1200;
11
25
  export const FORMAT_LIST_MAX_ITEMS = 20;
@@ -0,0 +1,106 @@
1
+ import { formatAgeMs } from "./format.js";
2
+ function shortHead(hash) {
3
+ if (!hash)
4
+ return "????????";
5
+ return hash.slice(0, 7);
6
+ }
7
+ function compactWhitespace(value) {
8
+ return value.replace(/\s+/g, " ").trim();
9
+ }
10
+ function arcSparkline(arcs) {
11
+ if (arcs <= 0)
12
+ return "";
13
+ return Array.from({ length: arcs }, () => "·").join("──");
14
+ }
15
+ function pendingAfterIds(contract) {
16
+ return contract.after.filter((item) => !item.terminal).map((item) => item.id);
17
+ }
18
+ function kanshiGlyph(contract) {
19
+ if (contract.state.state === "corrupt")
20
+ return "×";
21
+ if (pendingAfterIds(contract).length > 0)
22
+ return "○";
23
+ if (contract.state.state === "petitioned")
24
+ return "◎";
25
+ return "●";
26
+ }
27
+ function renderDriftMark(drift) {
28
+ if (drift.state === "drift")
29
+ return `▲${drift.behindBy}`;
30
+ if (drift.state === "orphaned")
31
+ return "▲orphaned";
32
+ return undefined;
33
+ }
34
+ export function renderKanshiBoard(status) {
35
+ const head = shortHead(status.defaultHead);
36
+ if (status.contracts.length === 0) {
37
+ if (status.targetFilter !== null) {
38
+ return `現世 ${head} · target ${status.targetFilter}\nno commissions on target ${status.targetFilter}\n`;
39
+ }
40
+ return `現世 ${head} 无在飞契约\n`;
41
+ }
42
+ const header = status.targetFilter !== null
43
+ ? `現世 ${head} · target ${status.targetFilter}`
44
+ : `現世 ${head}`;
45
+ const lines = [header, ""];
46
+ for (const contract of status.contracts) {
47
+ const glyph = kanshiGlyph(contract);
48
+ const name = contract.slug;
49
+ const spark = arcSparkline(contract.arcs);
50
+ const facts = [];
51
+ const lifecycle = contract.state.state;
52
+ if (lifecycle === "bound" || lifecycle === "active" || lifecycle === "petitioned") {
53
+ facts.push(lifecycle);
54
+ }
55
+ if (contract.place) {
56
+ facts.push(`@${contract.place}`);
57
+ }
58
+ const arcObjective = compactWhitespace(contract.currentArc.objective || "(no arc objective)");
59
+ const arcMark = contract.currentArc.state === "open"
60
+ ? `a${contract.currentArc.number}+`
61
+ : `a${contract.currentArc.number}`;
62
+ facts.push(`${arcMark} ${arcObjective}`);
63
+ facts.push(`next ${contract.nextStep.detail}`);
64
+ const age = formatAgeMs(contract.lastActiveMs);
65
+ if (age)
66
+ facts.push(age);
67
+ if (contract.queuePosition)
68
+ facts.push(`Q${contract.queuePosition}`);
69
+ const drift = renderDriftMark(contract.baseDrift);
70
+ if (drift)
71
+ facts.push(drift);
72
+ if (contract.nextStep.hint)
73
+ facts.push(contract.nextStep.hint);
74
+ const pending = pendingAfterIds(contract);
75
+ if (pending.length > 0) {
76
+ facts.push(`⧗ ${pending.map((id) => {
77
+ const dot = id.indexOf(".");
78
+ return dot > 0 ? id.slice(0, dot) : id;
79
+ }).join(",")}`);
80
+ }
81
+ if (contract.state.state === "corrupt") {
82
+ facts.push(`corrupt (${contract.state.reason ?? contract.corruptReason ?? "unknown"})`);
83
+ }
84
+ if (contract.queueHeadStalled) {
85
+ facts.push("朱 stall 去广场");
86
+ }
87
+ const sparkCol = spark.padEnd(14);
88
+ const factText = facts.join(" · ");
89
+ lines.push(`${glyph} ${name.padEnd(18)} ${sparkCol} ${factText}`.trimEnd());
90
+ if (contract.bootstrapDiagnostics.some((diagnostic) => diagnostic.kind === "plan-without-result")) {
91
+ lines.push(" ! bootstrap · no result recorded · forfeit and re-bind");
92
+ }
93
+ for (const diagnostic of contract.queueDiagnostics) {
94
+ if (diagnostic.kind === "legacy-petition") {
95
+ lines.push(" ! legacy petition · no seat · reject then re-petition");
96
+ continue;
97
+ }
98
+ if (diagnostic.kind === "duplicate-seat") {
99
+ lines.push(` ! seat ${diagnostic.seat} duplicated with ${diagnostic.with} · ordered by contract id`);
100
+ continue;
101
+ }
102
+ lines.push(` ! target mismatch · petitioned ${diagnostic.petitioned} · derived ${diagnostic.derived}`);
103
+ }
104
+ }
105
+ return `${lines.join("\n")}\n`;
106
+ }
@@ -1,8 +1,31 @@
1
- import { shortCommitHash } from "../../core/render.js";
1
+ import { shortCommitHash } from "../../git/commits.js";
2
2
  import { assembleResponse, buildPayload, buildSection, formatMaybe, formatWarnings, } from "./format.js";
3
3
  import { DIFF_OVERVIEW_SECTION_TITLE, RESPONSE_MARKERS, WARNING_SECTION_TITLE } from "./response-style.js";
4
4
  import { BRANCH_LABEL, INFO_BRANCH_MAX_CHARS, INFO_COMMIT_MAX_CHARS, INFO_PLEA_MAX_CHARS, } from "./shared.js";
5
5
  import { prependAddressReceipt } from "./address.js";
6
+ export function buildPetitionPreviewResponse(preview, json) {
7
+ const failed = preview.gates.filter((gate) => gate.result === "failed").length;
8
+ const text = json
9
+ ? JSON.stringify(preview)
10
+ : [
11
+ `contract ${preview.contract}`,
12
+ `target ${preview.target}`,
13
+ `arc ${preview.arc.source}`,
14
+ ...preview.gates.map((gate) => {
15
+ if (gate.result === "not_evaluated")
16
+ return `gate ${gate.name} · not evaluated`;
17
+ if (gate.result === "failed")
18
+ return `gate ${gate.name} · failed · ${gate.detail ?? "failed"}`;
19
+ return `gate ${gate.name} · pass${gate.detail ? ` · ${gate.detail}` : ""}`;
20
+ }),
21
+ failed === 0 ? "would succeed" : `would fail (${failed} gates failed)`,
22
+ ].join("\n");
23
+ return {
24
+ text,
25
+ payload: preview,
26
+ ...(failed > 0 ? { exitCode: 1 } : {}),
27
+ };
28
+ }
6
29
  export function buildPetitionClaimResponse(result, input) {
7
30
  const { status: _status, address: _address, ...resultData } = result;
8
31
  const renderedCommit = result.commit ? shortCommitHash(result.commit) : undefined;
@@ -41,6 +41,10 @@ function compactTokens(value) {
41
41
  }
42
42
  function warningText(row) {
43
43
  const warning = row.warning;
44
+ if (warning.reason === "retry") {
45
+ const status = warning.errorStatus === null ? "no response" : String(warning.errorStatus);
46
+ return `provider retrying ${warning.attempt}/${warning.maxRetries} · retry in ${formatTimelineDuration(warning.retryDelayMs)} · status ${status}${row.count > 1 ? ` (${row.count})` : ""}`;
47
+ }
44
48
  const modelRoute = warning.originalModel && warning.fallbackModel
45
49
  ? ` ${warning.originalModel}→${warning.fallbackModel}`
46
50
  : warning.direction
@@ -166,7 +170,7 @@ export function renderProjectionActivity(activity, input) {
166
170
  ? ` · ${compactTokens(row.inputTokens)}▸${compactTokens(row.outputTokens)} tok`
167
171
  : "";
168
172
  const cost = row.costUsd !== undefined ? ` · $${row.costUsd.toFixed(2)}` : "";
169
- lines.push(fitVariableLine(`${"".padStart(TIME_GUTTER_WIDTH)}├ `, `turn ${row.turn} sealed${usage}${cost}`, maxColumns));
173
+ lines.push(fitVariableLine(`${"".padStart(TIME_GUTTER_WIDTH)}├ `, `turn ${row.turn}${usage}${cost}`, maxColumns));
170
174
  }
171
175
  }
172
176
  for (const row of activity.pinned) {
@@ -128,7 +128,7 @@ export function formatDurableReviveCommand(input) {
128
128
  export function projectionRejoinHintLines(projectionId) {
129
129
  return [
130
130
  "Come back for the result:",
131
- ` » keiyaku wait ${projectionId}`,
131
+ ` » keiyaku wait ${projectionId} [--timeout DURATION]`,
132
132
  "Steer it while it works:",
133
133
  ` » keiyaku tell ${projectionId} "your words"`,
134
134
  ];
@@ -145,7 +145,7 @@ export function formatCallNextAction(input) {
145
145
  ` » keiyaku tell ${input.projection.alias ?? input.projection.id} "your words"`,
146
146
  ].join("\n");
147
147
  }
148
- return "⟶ keiyaku status";
148
+ return "» keiyaku status";
149
149
  }
150
150
  export function appendPersistenceSummary(base, responsePath) {
151
151
  const persistence = formatPersistenceSummary(responsePath);