@astrosheep/keiyaku 2.8.5 → 2.9.0

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 (228) 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 +39 -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 +35 -0
  55. package/build/cli/commands/projection/kill/meta.js +11 -0
  56. package/build/cli/commands/projection/revive/handler.js +53 -0
  57. package/build/cli/commands/projection/revive/meta.js +9 -0
  58. package/build/cli/commands/projection/status/handler.js +23 -0
  59. package/build/cli/commands/projection/status/meta.js +9 -0
  60. package/build/cli/commands/projection/tell/handler.js +34 -0
  61. package/build/cli/commands/projection/tell/meta.js +9 -0
  62. package/build/cli/commands/projection/wait/handler.js +21 -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.js +159 -72
  106. package/build/cli/projection-address.js +5 -0
  107. package/build/cli/render/arc.js +1 -1
  108. package/build/cli/render/errors.js +4 -3
  109. package/build/cli/render/format.js +14 -0
  110. package/build/cli/render/kanshi.js +106 -0
  111. package/build/cli/render/petition.js +24 -1
  112. package/build/cli/render/projection-activity.js +5 -1
  113. package/build/cli/render/shared.js +2 -2
  114. package/build/cli/render/status.js +79 -13
  115. package/build/cli/render/task.js +113 -0
  116. package/build/cli/render/wait.js +23 -3
  117. package/build/cli/types.js +1 -1
  118. package/build/config/{akuma-loader_v2.js → akuma-loader.js} +2 -2
  119. package/build/config/env.js +9 -4
  120. package/build/config/settings/disease.js +26 -0
  121. package/build/config/settings/knobs.js +8 -0
  122. package/build/config/settings/loader.js +244 -0
  123. package/build/config/settings/schema.js +276 -0
  124. package/build/core/addressing.js +1 -1
  125. package/build/core/amend.js +3 -3
  126. package/build/core/arc.js +5 -4
  127. package/build/core/bind-workspace.js +123 -0
  128. package/build/core/bind.js +75 -155
  129. package/build/core/call/call.js +224 -0
  130. package/build/core/call/context.js +238 -0
  131. package/build/core/call/execution.js +217 -0
  132. package/build/core/call/prompt.js +42 -0
  133. package/build/core/call/reference.js +24 -0
  134. package/build/core/call-persist.js +1 -1
  135. package/build/core/claim-delivery.js +247 -0
  136. package/build/core/claim.js +39 -277
  137. package/build/core/context.js +2 -1
  138. package/build/core/{render.js → contract-view.js} +12 -140
  139. package/build/core/draft.js +107 -9
  140. package/build/core/entry.js +9 -1
  141. package/build/core/execution-coordinate.js +4 -20
  142. package/build/core/execution-pact.js +16 -31
  143. package/build/core/forfeit.js +35 -22
  144. package/build/core/hints.js +2 -2
  145. package/build/core/log.js +2 -2
  146. package/build/core/petition-claim-gates.js +8 -6
  147. package/build/core/petition-preview.js +97 -0
  148. package/build/core/petition-run.js +3 -2
  149. package/build/core/petition.js +39 -26
  150. package/build/core/projection/generation/database.js +306 -0
  151. package/build/core/projection/generation/identity.js +84 -0
  152. package/build/core/projection/generation/model.js +201 -0
  153. package/build/core/projection/generation/store.js +73 -0
  154. package/build/core/projection/generation/transitions.js +258 -0
  155. package/build/core/projection/heart.js +0 -307
  156. package/build/core/projection/tell/database.js +109 -0
  157. package/build/core/projection/tell/model.js +97 -0
  158. package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
  159. package/build/core/projection-activity.js +23 -2
  160. package/build/core/projection-core.js +2 -1
  161. package/build/core/projection-execution-observer.js +259 -0
  162. package/build/core/projection-generation-continuation.js +1 -1
  163. package/build/core/projection-generation-execution.js +90 -20
  164. package/build/core/projection-generation-launcher.js +1 -1
  165. package/build/core/projection-generation-runner.js +198 -4
  166. package/build/core/projection-identity.js +1 -1
  167. package/build/core/projection-kill.js +50 -17
  168. package/build/core/projection-life-observer.js +1 -1
  169. package/build/core/projection-life-protocol.js +10 -0
  170. package/build/core/projection-mint.js +1 -1
  171. package/build/core/projection-status.js +45 -32
  172. package/build/core/projection-wait.js +12 -2
  173. package/build/core/projection-wake.js +5 -2
  174. package/build/core/{queue_v2.js → queue.js} +2 -1
  175. package/build/core/registry.js +1 -1
  176. package/build/core/renew.js +7 -7
  177. package/build/core/response-artifact-catalog-sqlite.js +112 -0
  178. package/build/core/response-artifact-catalog.js +7 -0
  179. package/build/core/seal.js +44 -16
  180. package/build/core/status/board.js +286 -0
  181. package/build/core/status/drift.js +99 -0
  182. package/build/core/status/lifecycle.js +84 -0
  183. package/build/core/status/reconciliation.js +131 -0
  184. package/build/core/stored-agent-event.js +28 -4
  185. package/build/core/target-ref.js +10 -0
  186. package/build/core/task/board.js +175 -0
  187. package/build/core/task/commands.js +211 -0
  188. package/build/core/task/document.js +189 -0
  189. package/build/core/task/model.js +1 -0
  190. package/build/core/task/settlement-git.js +207 -0
  191. package/build/core/task/settlement-policy.js +82 -0
  192. package/build/core/task/source-board.js +84 -0
  193. package/build/core/task/source-model.js +1 -0
  194. package/build/core/task/validation.js +44 -0
  195. package/build/core/task-contract.js +224 -0
  196. package/build/core/task-doctor.js +14 -0
  197. package/build/core/task-git-actor.js +38 -0
  198. package/build/core/task-git-runtime.js +34 -0
  199. package/build/core/task-git-store.js +375 -0
  200. package/build/core/task-repository.js +1 -0
  201. package/build/core/task-store-repository.js +86 -0
  202. package/build/core/task-store.js +1 -0
  203. package/build/core/task-worktree.js +51 -0
  204. package/build/core/task.js +4 -0
  205. package/build/core/transcripts.js +138 -56
  206. package/build/core/validation.js +17 -0
  207. package/build/core/verdict.js +2 -2
  208. package/build/core/worktree-path.js +24 -6
  209. package/build/flow-error.js +3 -2
  210. package/build/git/commits.js +3 -0
  211. package/build/git/diff/parsers.js +0 -94
  212. package/build/index.js +2 -0
  213. package/build/keiyaku-constants.js +2 -0
  214. package/build/keiyaku.js +4 -3
  215. package/package.json +3 -2
  216. package/skills/keiyaku/SKILL.md +1 -1
  217. package/skills/keiyaku-akuma/SKILL.md +11 -6
  218. package/build/agents/harness/pump.js +0 -158
  219. package/build/agents/providers/codex-app-server.js +0 -864
  220. package/build/agents/providers/opencode-sdk.js +0 -363
  221. package/build/agents/providers/pi.js +0 -557
  222. package/build/config/settings.js +0 -533
  223. package/build/core/call.js +0 -686
  224. package/build/core/projection/generation.js +0 -412
  225. package/build/core/projection/identity.js +0 -81
  226. package/build/core/projection/mint.js +0 -174
  227. package/build/core/projection-generation-store.js +0 -707
  228. package/build/core/status.js +0 -539
@@ -1,7 +1,9 @@
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
4
  import { BOOLEAN_FLAGS, CONTROL_FLAGS, HELP_FLAGS, SHORT_FLAG_ALIASES, VALUE_FLAGS, } from "./flags.js";
5
+ import { commandParseOrder, getCommandMetadata } from "./commands/registry.js";
6
+ import { TASK_SUBCOMMANDS } from "./types.js";
5
7
  /** Commands that may carry an explicit commission selector (@ or --contract). */
6
8
  const COMMISSION_SELECTOR_COMMANDS = new Set([
7
9
  "arc",
@@ -15,56 +17,11 @@ const COMMISSION_SELECTOR_COMMANDS = new Set([
15
17
  "petition",
16
18
  "forfeit",
17
19
  ]);
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"]);
20
+ /** Parse-time allowed flags; prefers meta.parseFlags when help flags omit a mouth-only flag. */
21
+ function allowedFlagsForParse(command) {
22
+ const meta = getCommandMetadata(command);
23
+ return meta.parseFlags ?? meta.flags;
24
+ }
68
25
  export function normalizeContractAddress(raw) {
69
26
  const value = raw.startsWith("@") ? raw.slice(1) : raw;
70
27
  if (!value.trim()) {
@@ -75,8 +32,35 @@ export function normalizeContractAddress(raw) {
75
32
  export function isCallCommand(command) {
76
33
  return command === "call";
77
34
  }
35
+ /** Identify petition --dry-run before parsing without mistaking flag values or literal payload. */
36
+ export function isPetitionDryRunInvocation(tokens) {
37
+ const boundary = tokens.indexOf("--");
38
+ const head = boundary === -1 ? tokens : tokens.slice(0, boundary);
39
+ if (!head.some((token) => token === "--dry-run" || token.startsWith("--dry-run=")))
40
+ return false;
41
+ for (let index = 0; index < head.length; index += 1) {
42
+ const token = head[index];
43
+ if (HELP_FLAGS.has(token) || token.startsWith("@"))
44
+ continue;
45
+ if (/^-[A-Za-z]$/.test(token)) {
46
+ const name = SHORT_FLAG_ALIASES[token.slice(1)];
47
+ if (name && VALUE_FLAGS.has(name))
48
+ index += 1;
49
+ continue;
50
+ }
51
+ if (token.startsWith("--")) {
52
+ const eq = token.indexOf("=");
53
+ const name = parseFlagName(eq === -1 ? token : token.slice(0, eq));
54
+ if (eq === -1 && VALUE_FLAGS.has(name))
55
+ index += 1;
56
+ continue;
57
+ }
58
+ return token === "petition";
59
+ }
60
+ return false;
61
+ }
78
62
  export function commandUsesPromptInput(command) {
79
- return isCallCommand(command) || command === "revive";
63
+ return isCallCommand(command) || command === "tell" || command === "revive";
80
64
  }
81
65
  export function parseWaitTimeout(value) {
82
66
  const matched = /^(?<amount>[1-9][0-9]*)(?<unit>[smh])$/.exec(value);
@@ -92,24 +76,34 @@ export function parseWaitTimeout(value) {
92
76
  return timeoutMs;
93
77
  }
94
78
  export function commandPositionalRange(command) {
95
- if (command === "akuma show")
79
+ if (command === "akuma view")
96
80
  return { min: 1, max: 1, label: "<name>" };
97
81
  if (command === "log")
98
82
  return { min: 0, max: 0, label: "" };
83
+ if (isCallCommand(command))
84
+ return { min: 1, max: 1, label: "<BODY|->" };
85
+ if (command === "tell")
86
+ return { min: 2, max: 2, label: "<PROJECTION> <BODY|->" };
99
87
  if (command === "revive")
100
- return { min: 1, max: 1, label: "<artifact-id>" };
88
+ return { min: 1, max: 2, label: "<ARTIFACT> [BODY|-]" };
101
89
  if (command === "wait")
102
90
  return { min: 1, max: 1, label: "<projection-address>" };
103
- if (command === "tell")
104
- return { min: 2, max: 2, label: "<projection> <message>" };
105
91
  if (command === "kill")
106
92
  return { min: 1, max: 1, label: "<projection-address>" };
107
- if (isCallCommand(command))
108
- return { min: 0, max: 1 };
93
+ if (command === "status")
94
+ return { min: 0, max: 1, label: "[projection-id]" };
95
+ if (command === "task add")
96
+ return { min: 1, max: 1, label: "<BODY|->" };
97
+ if (command === "task view" || command === "task start" || command === "task drop")
98
+ return { min: 1, max: 1, label: "<ID>" };
99
+ if (command === "task update")
100
+ return { min: 1, max: 1, label: "<ID>" };
101
+ if (command === "task stop" || command === "task done")
102
+ return { min: 0, max: 1, label: "[ID]" };
109
103
  return { min: 0, max: 0 };
110
104
  }
111
105
  function commandRequiresStdin(command) {
112
- return STDIN_COMMANDS.has(command);
106
+ return getCommandMetadata(command).stdin === "required";
113
107
  }
114
108
  function commandTokens(command) {
115
109
  return command.split(" ");
@@ -139,6 +133,7 @@ function assignFlag(flags, name, value) {
139
133
  flags.alias = String(value);
140
134
  return;
141
135
  case "timeout":
136
+ case "wait":
142
137
  flags.timeoutMs = parseWaitTimeout(String(value));
143
138
  return;
144
139
  case "model":
@@ -164,6 +159,35 @@ function assignFlag(flags, name, value) {
164
159
  case "exclusive":
165
160
  flags.exclusive = Boolean(value);
166
161
  return;
162
+ case "place":
163
+ if (flags.bindPlace !== undefined) {
164
+ throw new FlowError("EMPTY_PARAM", "option --place may only be specified once");
165
+ }
166
+ flags.bindPlace = String(value);
167
+ return;
168
+ case "objective":
169
+ if (flags.bindObjective !== undefined) {
170
+ throw new FlowError("EMPTY_PARAM", "option --objective may only be specified once");
171
+ }
172
+ flags.bindObjective = String(value);
173
+ return;
174
+ case "scope":
175
+ if (flags.bindScope !== undefined) {
176
+ throw new FlowError("EMPTY_PARAM", "option --scope may only be specified once");
177
+ }
178
+ flags.bindScope = String(value);
179
+ return;
180
+ case "checks":
181
+ if (flags.bindChecks !== undefined) {
182
+ throw new FlowError("EMPTY_PARAM", "option --checks may only be specified once");
183
+ }
184
+ flags.bindChecks = String(value);
185
+ return;
186
+ case "task":
187
+ if (flags.bindTaskId !== undefined)
188
+ throw new FlowError("EMPTY_PARAM", "option --task may only be specified once");
189
+ flags.bindTaskId = String(value);
190
+ return;
167
191
  case "after":
168
192
  flags.after = [...(flags.after ?? []), String(value)];
169
193
  return;
@@ -200,12 +224,54 @@ function assignFlag(flags, name, value) {
200
224
  }
201
225
  flags.target = String(value);
202
226
  return;
227
+ case "json":
228
+ flags.json = Boolean(value);
229
+ return;
230
+ case "done":
231
+ flags.done = Boolean(value);
232
+ return;
233
+ case "pri": {
234
+ const raw = String(value);
235
+ if (!/^[0-3]$/.test(raw))
236
+ throw new FlowError("EMPTY_PARAM", "task priority must be an integer from 0 through 3");
237
+ if (flags.taskPri !== undefined)
238
+ throw new FlowError("EMPTY_PARAM", "option --pri may only be specified once");
239
+ flags.taskPri = Number(raw);
240
+ return;
241
+ }
242
+ case "needs":
243
+ flags.taskNeeds = [...(flags.taskNeeds ?? []), String(value)];
244
+ return;
245
+ case "drop-needs":
246
+ flags.taskDropNeeds = [...(flags.taskDropNeeds ?? []), String(value)];
247
+ return;
248
+ case "from":
249
+ flags.taskFrom = [...(flags.taskFrom ?? []), String(value)];
250
+ return;
251
+ case "parent":
252
+ if (flags.taskParent !== undefined)
253
+ throw new FlowError("EMPTY_PARAM", "option --parent may only be specified once");
254
+ flags.taskParent = String(value);
255
+ return;
256
+ case "no-parent":
257
+ flags.taskNoParent = Boolean(value);
258
+ return;
259
+ case "title":
260
+ if (flags.taskTitle !== undefined)
261
+ throw new FlowError("EMPTY_PARAM", "option --title may only be specified once");
262
+ flags.taskTitle = String(value);
263
+ return;
264
+ case "body":
265
+ if (flags.taskBody !== undefined)
266
+ throw new FlowError("EMPTY_PARAM", "option --body may only be specified once");
267
+ flags.taskBody = String(value);
268
+ return;
203
269
  default:
204
270
  throw new FlowError("EMPTY_PARAM", `unknown option: --${name}`);
205
271
  }
206
272
  }
207
273
  function assertAllowedFlag(command, name) {
208
- if (!COMMAND_FLAGS[command].includes(name)) {
274
+ if (!allowedFlagsForParse(command).includes(name)) {
209
275
  throw new FlowError("EMPTY_PARAM", `option --${name} is not valid for ${command}`);
210
276
  }
211
277
  }
@@ -213,7 +279,7 @@ function resolveCommand(tokens) {
213
279
  if (tokens[0] === "petition" && (tokens[1] === "claim" || tokens[1] === "forfeit")) {
214
280
  throw new FlowError("UNKNOWN_COMMAND", `unknown command: petition ${tokens[1]}`);
215
281
  }
216
- for (const command of CLI_COMMAND_ORDER) {
282
+ for (const command of commandParseOrder()) {
217
283
  const parts = commandTokens(command);
218
284
  if (parts.every((part, index) => tokens[index] === part)) {
219
285
  return { command, rest: tokens.slice(parts.length) };
@@ -234,11 +300,11 @@ function splitAtLiteralBoundary(tokens) {
234
300
  return { head: tokens.slice(0, boundary), payload: tokens.slice(boundary + 1) };
235
301
  }
236
302
  function readValueFlag(name, token, eq, tokens, index) {
237
- // --target alone owns emptiness in core; empty remains a supplied value.
303
+ // --target and task --body own emptiness in core; empty remains supplied.
238
304
  // Other value flags keep the historical requires-a-value rejection.
239
305
  if (eq !== -1) {
240
306
  const value = token.slice(eq + 1);
241
- if (value === "" && name !== "target") {
307
+ if (value === "" && name !== "target" && name !== "body") {
242
308
  throw new FlowError("EMPTY_PARAM", `option --${name} requires a value`);
243
309
  }
244
310
  return { value, nextIndex: index };
@@ -247,7 +313,7 @@ function readValueFlag(name, token, eq, tokens, index) {
247
313
  if (value === undefined || value === "--" || value.startsWith("--")) {
248
314
  throw new FlowError("EMPTY_PARAM", `option --${name} requires a value`);
249
315
  }
250
- if (value === "" && name !== "target") {
316
+ if (value === "" && name !== "target" && name !== "body") {
251
317
  throw new FlowError("EMPTY_PARAM", `option --${name} requires a value`);
252
318
  }
253
319
  // Short-flag values may begin with @; they are flag values, not commission tokens.
@@ -322,9 +388,6 @@ export function parseCliArgs(tokens) {
322
388
  }
323
389
  const eq = token.indexOf("=");
324
390
  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
391
  if (!CONTROL_FLAGS.has(name)) {
329
392
  throw new FlowError("EMPTY_PARAM", `unknown option: --${name}`);
330
393
  }
@@ -376,14 +439,38 @@ export function parseCliArgs(tokens) {
376
439
  };
377
440
  }
378
441
  if (command === "akuma") {
379
- throw new FlowError("EMPTY_PARAM", "akuma requires subcommand: list, ls, or show");
442
+ throw new FlowError("EMPTY_PARAM", "akuma requires subcommand: ls or view");
380
443
  }
381
444
  if (command === "skills") {
382
445
  throw new FlowError("EMPTY_PARAM", "skills requires subcommand: install");
383
446
  }
447
+ if (command === "task") {
448
+ throw new FlowError("EMPTY_PARAM", `task requires subcommand: ${TASK_SUBCOMMANDS.join(", ")}`);
449
+ }
450
+ // --place is bind's H1 domain flag; every other command keeps the retired-selector mouth.
451
+ if (command !== "bind" && seenFlagNames.has("place")) {
452
+ throw new FlowError("EMPTY_PARAM", "unknown option --place; use @addr or --contract <addr>");
453
+ }
384
454
  for (const name of seenFlagNames) {
385
455
  assertAllowedFlag(command, name);
386
456
  }
457
+ if (command === "call" && flags.detach && flags.timeoutMs !== undefined) {
458
+ throw new FlowError("EMPTY_PARAM", "call cannot combine --detach and --wait");
459
+ }
460
+ if (command === "task ls" && flags.all && flags.done) {
461
+ throw new FlowError("EMPTY_PARAM", "task ls cannot combine --all and --done");
462
+ }
463
+ if (command === "task update" && flags.taskParent !== undefined && flags.taskNoParent) {
464
+ throw new FlowError("EMPTY_PARAM", "task update cannot combine --parent and --no-parent");
465
+ }
466
+ if (command === "task update" && flags.taskTitle === undefined && flags.taskBody === undefined
467
+ && flags.taskPri === undefined && flags.taskNeeds === undefined && flags.taskDropNeeds === undefined
468
+ && flags.taskParent === undefined && !flags.taskNoParent && flags.taskFrom === undefined) {
469
+ throw new FlowError("EMPTY_PARAM", "task update requires at least one change");
470
+ }
471
+ if (command === "petition" && flags.json && !flags.dryRun) {
472
+ throw new FlowError("EMPTY_PARAM", "petition --json requires --dry-run");
473
+ }
387
474
  if (flags.contractId !== undefined && !COMMISSION_SELECTOR_COMMANDS.has(command)) {
388
475
  throw new FlowError("EMPTY_PARAM", command === "bind"
389
476
  ? `bind creates a commission and does not accept @${flags.contractId}; use -C/--cwd to select the repository`
@@ -404,25 +491,25 @@ export function parseCliArgs(tokens) {
404
491
  if (isCallCommand(command)) {
405
492
  if (flags.akuma) {
406
493
  if (positional.length > 1) {
407
- throw new FlowError("EMPTY_PARAM", `${command} accepts at most one prompt argument when --akuma is used`);
494
+ throw new FlowError("EMPTY_PARAM", `${command} accepts at most one <BODY|-> when --akuma is used`);
408
495
  }
409
496
  }
410
497
  else {
411
498
  const [name] = positional;
412
499
  if (!name) {
413
- throw new FlowError("EMPTY_PARAM", `${command} requires an agent name; use \`keiyaku ${command} NAME [prompt|-]\``);
500
+ throw new FlowError("EMPTY_PARAM", `${command} requires an agent name; use \`keiyaku ${command} NAME <BODY|->\``);
414
501
  }
415
502
  if (isResponseArtifactId(name)) {
416
503
  throw new FlowError("EMPTY_PARAM", `artifact ${name} is a response artifact; call expects an Akuma profile name`);
417
504
  }
418
505
  const parsedName = agentNameSchema.safeParse(name);
419
506
  if (!parsedName.success) {
420
- throw new FlowError("EMPTY_PARAM", `${command} requires a valid agent name before the optional prompt`);
507
+ throw new FlowError("EMPTY_PARAM", `${command} requires a valid agent name before <BODY|->`);
421
508
  }
422
509
  flags.akuma = parsedName.data;
423
510
  positional.shift();
424
511
  if (positional.length > 1) {
425
- throw new FlowError("EMPTY_PARAM", `${command} accepts at most one prompt argument after the agent name`);
512
+ throw new FlowError("EMPTY_PARAM", `${command} accepts at most one <BODY|-> after the agent name`);
426
513
  }
427
514
  }
428
515
  }
@@ -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);