@astrosheep/keiyaku 4.0.3 → 4.0.5

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/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 +1 -1
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +15 -1
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +3 -1
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +34 -13
  9. package/build/src/akuma/akuma.d.ts +34 -12
  10. package/build/src/akuma/akuma.js +118 -63
  11. package/build/src/akuma/allowed.d.ts +7 -0
  12. package/build/src/akuma/allowed.js +33 -0
  13. package/build/src/akuma/archetype.d.ts +7 -4
  14. package/build/src/akuma/archetype.js +15 -16
  15. package/build/src/akuma/body.d.ts +6 -1
  16. package/build/src/akuma/body.js +36 -27
  17. package/build/src/akuma/heart/facts.d.ts +82 -14
  18. package/build/src/akuma/heart/index.d.ts +5 -18
  19. package/build/src/akuma/heart/index.js +14 -84
  20. package/build/src/akuma/heart/request-authority.d.ts +12 -0
  21. package/build/src/akuma/heart/request-authority.js +119 -0
  22. package/build/src/akuma/heart/request-rows.d.ts +16 -0
  23. package/build/src/akuma/heart/request-rows.js +88 -0
  24. package/build/src/akuma/heart/rows.d.ts +1 -26
  25. package/build/src/akuma/heart/rows.js +0 -50
  26. package/build/src/akuma/heart/schema.d.ts +1 -1
  27. package/build/src/akuma/heart/schema.js +22 -10
  28. package/build/src/akuma/heart/soul.js +2 -36
  29. package/build/src/akuma/heart/storage.d.ts +1 -0
  30. package/build/src/akuma/heart/storage.js +15 -0
  31. package/build/src/akuma/heart/timeline.d.ts +1 -5
  32. package/build/src/akuma/heart/timeline.js +8 -17
  33. package/build/src/akuma/index.d.ts +5 -2
  34. package/build/src/akuma/index.js +1 -0
  35. package/build/src/akuma/projection.d.ts +17 -3
  36. package/build/src/akuma/projection.js +40 -3
  37. package/build/src/akuma/provider-recipe.js +1 -11
  38. package/build/src/akuma/provider.d.ts +2 -7
  39. package/build/src/akuma/provider.js +2 -1
  40. package/build/src/akuma/providers/acp/core.d.ts +3 -1
  41. package/build/src/akuma/providers/acp/core.js +10 -6
  42. package/build/src/akuma/providers/acp/events.d.ts +11 -3
  43. package/build/src/akuma/providers/acp/events.js +78 -4
  44. package/build/src/akuma/providers/acp/index.js +0 -1
  45. package/build/src/akuma/providers/claude/events.js +62 -3
  46. package/build/src/akuma/providers/claude/index.d.ts +0 -4
  47. package/build/src/akuma/providers/claude/index.js +7 -3
  48. package/build/src/akuma/providers/codex-app-server/events.js +1 -13
  49. package/build/src/akuma/providers/codex-app-server/index.d.ts +2 -27
  50. package/build/src/akuma/providers/codex-app-server/index.js +0 -2
  51. package/build/src/akuma/providers/grok-build/index.d.ts +2 -1
  52. package/build/src/akuma/providers/grok-build/index.js +72 -3
  53. package/build/src/akuma/providers/opencode-sdk/events.js +71 -6
  54. package/build/src/akuma/providers/opencode-sdk/index.d.ts +2 -28
  55. package/build/src/akuma/providers/opencode-sdk/index.js +8 -4
  56. package/build/src/akuma/providers/opencode-sdk/session.d.ts +1 -1
  57. package/build/src/akuma/providers/opencode-sdk/session.js +1 -1
  58. package/build/src/akuma/providers/pi/events.js +17 -3
  59. package/build/src/akuma/providers/pi/index.js +11 -4
  60. package/build/src/akuma/providers/unified-patch.d.ts +4 -0
  61. package/build/src/akuma/providers/unified-patch.js +14 -0
  62. package/build/src/akuma/publication.d.ts +1 -1
  63. package/build/src/akuma/publication.js +1 -1
  64. package/build/src/akuma/request-serve.d.ts +87 -0
  65. package/build/src/akuma/request-serve.js +484 -0
  66. package/build/src/akuma/request-wire.d.ts +124 -0
  67. package/build/src/akuma/request-wire.js +380 -0
  68. package/build/src/akuma/requests.d.ts +41 -41
  69. package/build/src/akuma/requests.js +75 -374
  70. package/build/src/akuma-body.d.ts +8 -0
  71. package/build/src/akuma-body.js +84 -0
  72. package/build/src/body/arc.js +4 -29
  73. package/build/src/body/decode.js +5 -39
  74. package/build/src/body/envelope.d.ts +7 -0
  75. package/build/src/body/envelope.js +37 -0
  76. package/build/src/cli/accepted.d.ts +4 -1
  77. package/build/src/cli/accepted.js +39 -9
  78. package/build/src/cli/commands/akuma-invoke.d.ts +8 -7
  79. package/build/src/cli/commands/akuma-invoke.js +18 -10
  80. package/build/src/cli/commands/akuma.d.ts +11 -2
  81. package/build/src/cli/commands/akuma.js +67 -28
  82. package/build/src/cli/commands/amend.d.ts +1 -1
  83. package/build/src/cli/commands/amend.js +1 -1
  84. package/build/src/cli/commands/contract.d.ts +8 -8
  85. package/build/src/cli/commands/contract.js +3 -3
  86. package/build/src/cli/commands/install.js +2 -2
  87. package/build/src/cli/commands/task-invoke.js +98 -9
  88. package/build/src/cli/commands/task-query.d.ts +1 -1
  89. package/build/src/cli/commands/task-query.js +11 -5
  90. package/build/src/cli/coordinates.d.ts +2 -0
  91. package/build/src/cli/coordinates.js +12 -5
  92. package/build/src/cli/invoke.d.ts +1 -0
  93. package/build/src/cli/invoke.js +116 -75
  94. package/build/src/cli/main.d.ts +2 -0
  95. package/build/src/cli/main.js +29 -4
  96. package/build/src/cli/parse.d.ts +3 -2
  97. package/build/src/cli/parse.js +25 -8
  98. package/build/src/cli/render/akuma.d.ts +2 -2
  99. package/build/src/cli/render/akuma.js +138 -24
  100. package/build/src/cli/render/audit.js +18 -8
  101. package/build/src/cli/render/contract.d.ts +2 -0
  102. package/build/src/cli/render/contract.js +243 -36
  103. package/build/src/cli/render/kanshi.js +64 -29
  104. package/build/src/cli/render/receipt.d.ts +2 -1
  105. package/build/src/cli/render/receipt.js +37 -2
  106. package/build/src/cli/render/terminal.d.ts +0 -2
  107. package/build/src/cli/render/terminal.js +0 -29
  108. package/build/src/cli/render/text.js +3 -1
  109. package/build/src/cli/result.d.ts +52 -9
  110. package/build/src/cli/selectors.d.ts +1 -0
  111. package/build/src/cli/selectors.js +9 -6
  112. package/build/src/contract-worktree.d.ts +1 -2
  113. package/build/src/contract-worktree.js +7 -9
  114. package/build/src/core/facts/codec.js +9 -0
  115. package/build/src/core/facts/fold.js +13 -1
  116. package/build/src/core/facts/types.d.ts +8 -1
  117. package/build/src/core/subject.js +4 -3
  118. package/build/src/core/verbs/placement.d.ts +9 -1
  119. package/build/src/core/verbs/placement.js +24 -6
  120. package/build/src/core/verbs/reintegrate.d.ts +13 -0
  121. package/build/src/core/verbs/reintegrate.js +24 -0
  122. package/build/src/dispatch/index.d.ts +1 -1
  123. package/build/src/dispatch/index.js +50 -39
  124. package/build/src/git/admission.d.ts +2 -1
  125. package/build/src/git/hooks.d.ts +0 -4
  126. package/build/src/git/hooks.js +0 -36
  127. package/build/src/git/integration.d.ts +7 -8
  128. package/build/src/git/integration.js +62 -9
  129. package/build/src/git/observe.d.ts +2 -1
  130. package/build/src/git/observe.js +6 -5
  131. package/build/src/git/process.d.ts +26 -0
  132. package/build/src/git/process.js +94 -0
  133. package/build/src/git/read-observation.d.ts +2 -1
  134. package/build/src/git/read-observation.js +3 -2
  135. package/build/src/git/reconcile.d.ts +8 -2
  136. package/build/src/git/reconcile.js +63 -14
  137. package/build/src/git/repository.d.ts +2 -29
  138. package/build/src/git/repository.js +4 -118
  139. package/build/src/git/scratch.d.ts +1 -1
  140. package/build/src/git/scratch.js +1 -1
  141. package/build/src/git/target-placement.d.ts +1 -1
  142. package/build/src/git/target-placement.js +9 -7
  143. package/build/src/git/tender.d.ts +20 -5
  144. package/build/src/git/tender.js +45 -13
  145. package/build/src/git/terminal-seal.d.ts +16 -2
  146. package/build/src/git/terminal-seal.js +15 -5
  147. package/build/src/git/workspace.d.ts +2 -1
  148. package/build/src/git/workspace.js +13 -5
  149. package/build/src/index.d.ts +1 -2
  150. package/build/src/index.js +1 -1
  151. package/build/src/kanshi/index.d.ts +1 -1
  152. package/build/src/kanshi/index.js +1 -1
  153. package/build/src/kanshi/read.d.ts +9 -1
  154. package/build/src/kanshi/read.js +91 -37
  155. package/build/src/kanshi/report.d.ts +1 -0
  156. package/build/src/library/address.d.ts +5 -14
  157. package/build/src/library/address.js +27 -23
  158. package/build/src/library/akuma-creation.d.ts +4 -2
  159. package/build/src/library/akuma-creation.js +43 -26
  160. package/build/src/library/audit.d.ts +2 -1
  161. package/build/src/library/audit.js +1 -1
  162. package/build/src/library/bind.d.ts +2 -1
  163. package/build/src/library/bind.js +4 -4
  164. package/build/src/library/catalog.d.ts +1 -2
  165. package/build/src/library/catalog.js +11 -6
  166. package/build/src/library/configuration.d.ts +5 -1
  167. package/build/src/library/configuration.js +71 -18
  168. package/build/src/library/contract.d.ts +70 -3
  169. package/build/src/library/contract.js +213 -27
  170. package/build/src/library/delivery.d.ts +1 -1
  171. package/build/src/library/fleet.d.ts +70 -12
  172. package/build/src/library/fleet.js +236 -56
  173. package/build/src/library/input.d.ts +0 -1
  174. package/build/src/library/input.js +1 -5
  175. package/build/src/library/keiyaku.d.ts +4 -4
  176. package/build/src/library/keiyaku.js +1 -2
  177. package/build/src/library/mutation.d.ts +2 -1
  178. package/build/src/library/reconcile.d.ts +2 -1
  179. package/build/src/library/reconcile.js +3 -1
  180. package/build/src/library/region.d.ts +1 -1
  181. package/build/src/library/repo.d.ts +3 -1
  182. package/build/src/library/repo.js +8 -4
  183. package/build/src/protocol/abandon.d.ts +9 -0
  184. package/build/src/protocol/abandon.js +15 -0
  185. package/build/src/protocol/amend.d.ts +16 -0
  186. package/build/src/protocol/amend.js +77 -0
  187. package/build/src/protocol/arc.d.ts +6 -0
  188. package/build/src/protocol/arc.js +12 -0
  189. package/build/src/protocol/attempt.d.ts +2 -1
  190. package/build/src/protocol/audit.d.ts +53 -0
  191. package/build/src/protocol/audit.js +140 -0
  192. package/build/src/protocol/bind.d.ts +2 -3
  193. package/build/src/protocol/bind.js +2 -16
  194. package/build/src/protocol/completion.d.ts +32 -0
  195. package/build/src/protocol/completion.js +130 -0
  196. package/build/src/protocol/deliver.d.ts +37 -0
  197. package/build/src/protocol/deliver.js +160 -0
  198. package/build/src/protocol/intent.d.ts +1 -1
  199. package/build/src/protocol/intent.js +1 -1
  200. package/build/src/protocol/operations.d.ts +65 -198
  201. package/build/src/protocol/operations.js +21 -634
  202. package/build/src/protocol/placement.d.ts +4 -13
  203. package/build/src/protocol/placement.js +3 -15
  204. package/build/src/protocol/read/status.d.ts +4 -2
  205. package/build/src/protocol/read/status.js +27 -15
  206. package/build/src/protocol/reconcile.d.ts +35 -0
  207. package/build/src/protocol/reconcile.js +41 -0
  208. package/build/src/protocol/reintegrate.d.ts +31 -0
  209. package/build/src/protocol/reintegrate.js +74 -0
  210. package/build/src/protocol/review.d.ts +33 -0
  211. package/build/src/protocol/review.js +148 -0
  212. package/build/src/protocol/run.d.ts +1 -1
  213. package/build/src/runtime/proc/run.d.ts +1 -0
  214. package/build/src/runtime/proc/run.js +9 -2
  215. package/build/src/settlement/fence.d.ts +1 -1
  216. package/build/src/settlement/holder.d.ts +1 -1
  217. package/build/src/settlement/settle.d.ts +2 -1
  218. package/build/src/settlement/settle.js +4 -1
  219. package/build/src/task/board.d.ts +18 -4
  220. package/build/src/task/board.js +73 -29
  221. package/build/src/task/compose.d.ts +1 -1
  222. package/build/src/task/compose.js +11 -4
  223. package/build/src/task/index.d.ts +4 -4
  224. package/build/src/task/index.js +8 -131
  225. package/build/src/task/input.d.ts +18 -0
  226. package/build/src/task/input.js +189 -0
  227. package/build/src/task/mutation.d.ts +39 -0
  228. package/build/src/task/mutation.js +85 -0
  229. package/build/src/task/operations.d.ts +4 -19
  230. package/build/src/task/operations.js +64 -18
  231. package/build/src/task/query.d.ts +9 -2
  232. package/build/src/task/query.js +32 -64
  233. package/build/src/task/store.js +0 -2
  234. package/build/src/verification/execution.d.ts +1 -1
  235. package/build/src/verification/execution.js +2 -1
  236. package/build/src/workspace-place.d.ts +1 -4
  237. package/build/src/workspace-place.js +0 -15
  238. package/package.json +5 -3
@@ -1,5 +1,5 @@
1
- import { AkumaWorldScopeError, gatesFrom, Keiyaku, requireBranchesToBeUpToDateFrom, settings, SettingsError, worktreeHooksFrom } from "../index.js";
2
- import { kanshi, selectKanshi, selectRegion } from "../kanshi/index.js";
1
+ import { AkumaWorldScopeError, gatesFrom, Keiyaku, KeiyakuRefused, requireBranchesToBeUpToDateFrom, settings, SettingsError, worktreeHooksFrom, } from "../index.js";
2
+ import { kanshi, observeKanshi, selectKanshi, selectRegion, } from "../kanshi/index.js";
3
3
  import { resolveActor } from "./actor.js";
4
4
  import { acceptedAbandon, acceptedAmend, acceptedArc, acceptedAudit, acceptedBind, acceptedDeliver, acceptedReview, resultFromMutationCall, } from "./accepted.js";
5
5
  import { amendFromCommand } from "./commands/amend.js";
@@ -10,8 +10,10 @@ import { installHarnesses } from "./commands/install.js";
10
10
  import { invokeTask } from "./commands/task-invoke.js";
11
11
  import { CliUsageError, renderCommandUsage } from "./parse.js";
12
12
  import { isBlankInput } from "./usage.js";
13
- import { contractFromInput, resolveContextualContract, resolveKanshiContract } from "./selectors.js";
13
+ import { canonicalContractSelector, contractFromInput, resolveContextualContract, resolveKanshiContract, } from "./selectors.js";
14
14
  import { resolveNamedAddress } from "../library/address.js";
15
+ import { injectedBodyRequests } from "../akuma/requests.js";
16
+ import { EMPTY_WORKTREE_HOOKS } from "../library/configuration.js";
15
17
  import { assertExplicitRepoUse, resolveCliCoordinates } from "./coordinates.js";
16
18
  import { BindDraftError, preserveBindDraft } from "./draft.js";
17
19
  async function readStdin() {
@@ -23,9 +25,10 @@ async function readStdin() {
23
25
  function selectedStdinDiagnostic(command) {
24
26
  switch (command.command) {
25
27
  case "bind":
26
- case "amend":
27
28
  case "arc":
28
29
  return `${command.command} requires a nonblank stdin document`;
30
+ case "amend":
31
+ return command.stdin === true ? "amend requires a nonblank stdin document" : undefined;
29
32
  case "review":
30
33
  return command.summaryFromStdin === true ? "review requires a nonblank summary" : undefined;
31
34
  case "call":
@@ -53,13 +56,12 @@ async function withAcquiredStdin(command, runtime) {
53
56
  throw new CliUsageError(diagnostic);
54
57
  return { ...runtime, readStdin: async () => bytes };
55
58
  }
56
- function settingsAt(root, environment) {
57
- const home = environment.KEIYAKU_HOME?.trim();
58
- return settings({ ...(root === undefined ? {} : { root }), ...(home === undefined || home.length === 0 ? {} : { home }) });
59
+ function settingsAt(root, home) {
60
+ return settings({ ...(root === undefined ? {} : { root }), ...(home === undefined ? {} : { home }) });
59
61
  }
60
- function selectedGates(value, name) {
62
+ function consumeSettings(run) {
61
63
  try {
62
- return gatesFrom({ settings: value, ...(name === undefined ? {} : { name }) });
64
+ return run();
63
65
  }
64
66
  catch (error) {
65
67
  if (error instanceof SettingsError)
@@ -67,25 +69,11 @@ function selectedGates(value, name) {
67
69
  throw error;
68
70
  }
69
71
  }
70
- function selectedHooks(value) {
71
- try {
72
- return worktreeHooksFrom({ settings: value });
73
- }
74
- catch (error) {
75
- if (error instanceof SettingsError)
76
- throw new CliUsageError(error.message);
77
- throw error;
78
- }
72
+ function selectedGates(value, names) {
73
+ return consumeSettings(() => gatesFrom({ settings: value, ...(names === undefined ? {} : { names }) }));
79
74
  }
80
75
  function selectedGitPolicy(value) {
81
- try {
82
- return requireBranchesToBeUpToDateFrom({ settings: value });
83
- }
84
- catch (error) {
85
- if (error instanceof SettingsError)
86
- throw new CliUsageError(error.message);
87
- throw error;
88
- }
76
+ return consumeSettings(() => requireBranchesToBeUpToDateFrom({ settings: value }));
89
77
  }
90
78
  function actorFromEdge(actor, environment) {
91
79
  let resolved;
@@ -97,6 +85,14 @@ function actorFromEdge(actor, environment) {
97
85
  }
98
86
  return resolved;
99
87
  }
88
+ function gitPathFromEdge(environment) {
89
+ const value = environment.KEIYAKU_GIT_PATH;
90
+ if (value === undefined)
91
+ return undefined;
92
+ if (value.trim().length === 0)
93
+ throw new CliUsageError("KEIYAKU_GIT_PATH requires a nonblank value");
94
+ return value;
95
+ }
100
96
  async function selectContract(repo, selector, scope) {
101
97
  if (selector !== undefined && !selector.startsWith("@"))
102
98
  return contractFromInput(repo, selector);
@@ -127,7 +123,7 @@ async function invokeBind({ parsed, repo, edge, configuration, hooks, establishW
127
123
  const bound = accepted.facts.find((fact) => fact.kind === "bind");
128
124
  if (bound === undefined || bound.kind !== "bind")
129
125
  throw new Error("accepted bind is missing its bind fact");
130
- return acceptedBind(accepted, bound.data.coordinates.target ?? null);
126
+ return acceptedBind(accepted, bound.data.coordinates);
131
127
  });
132
128
  if (result.kind !== "refused")
133
129
  return result;
@@ -176,17 +172,30 @@ async function invokeAudit(parsed, seat, requireBranchesToBeUpToDate) {
176
172
  hooks: seat.hooks,
177
173
  }), (result) => acceptedAudit(result, seat.id), { coordinate: seat.id });
178
174
  }
179
- async function invokeExisting({ parsed, repo, edge, scope, configuration, hooks }) {
175
+ async function existingSeat({ parsed, repo, edge, scope, hooks }) {
180
176
  const { id, contract } = await selectContract(repo, parsed.contract, scope);
181
177
  const actor = actorFromEdge(parsed.actor, edge.environment);
182
- const seat = { contract, id, ...(actor === undefined ? {} : { actor }), hooks };
178
+ return { contract, id, ...(actor === undefined ? {} : { actor }), hooks };
179
+ }
180
+ async function invokeExisting(input) {
181
+ const { parsed, repo, edge, configuration, hooks } = input;
182
+ const seat = await existingSeat(input);
183
+ const { id, contract, actor } = seat;
183
184
  switch (parsed.command) {
184
185
  case "amend": {
185
- const markdown = await edge.readStdin();
186
+ const markdown = parsed.stdin === true ? await edge.readStdin() : undefined;
186
187
  const gates = parsed.gates === undefined
187
188
  ? undefined
188
189
  : selectedGates(configuration, parsed.gates);
189
- return resultFromMutationCall("amend", () => amendFromCommand({ command: parsed, repo, contract, markdown, gates, ...(actor === undefined ? {} : { actor }), hooks }), (result) => acceptedAmend(result, id), { coordinate: id });
190
+ return resultFromMutationCall("amend", () => amendFromCommand({
191
+ command: parsed,
192
+ repo,
193
+ contract,
194
+ ...(markdown === undefined ? {} : { markdown }),
195
+ gates,
196
+ ...(actor === undefined ? {} : { actor }),
197
+ hooks,
198
+ }), (result) => acceptedAmend(result, id), { coordinate: id });
190
199
  }
191
200
  case "deliver":
192
201
  return invokeDeliver(parsed, seat, selectedGitPolicy(configuration));
@@ -212,32 +221,23 @@ async function invokeExisting({ parsed, repo, edge, scope, configuration, hooks
212
221
  return parsed;
213
222
  }
214
223
  }
215
- async function invokeAkumaCommand(parsed, input) {
216
- const { path, executionCwd, repo, configuration, edge } = input;
217
- if (parsed.command === "call" && parsed.contract !== undefined) {
218
- if (repo === undefined)
224
+ async function invokeAkumaFromEdge(parsed, input) {
225
+ try {
226
+ const { path, statedCwd, repo, home, configuration, edge } = input;
227
+ if (parsed.command === "call" && parsed.contract !== undefined && repo === undefined) {
219
228
  throw new Error("call with Contract requires a resolved Repo");
220
- const selected = contractFromInput(repo, parsed.contract);
229
+ }
221
230
  return await invokeAkuma(parsed, {
222
231
  path,
223
- ...(executionCwd === undefined ? {} : { executionCwd }),
224
- settings: configuration,
225
- contract: selected.contract,
232
+ ...(statedCwd === undefined ? {} : { statedCwd }),
233
+ ...(home === undefined ? {} : { home }),
234
+ ...(configuration === undefined ? {} : { settings: configuration }),
235
+ ...(parsed.command === "call" && parsed.contract !== undefined
236
+ ? { contract: contractFromInput(repo, parsed.contract).contract }
237
+ : repo === undefined ? {} : { repo }),
226
238
  readStdin: edge.readStdin,
227
239
  });
228
240
  }
229
- return await invokeAkuma(parsed, {
230
- path,
231
- ...(executionCwd === undefined ? {} : { executionCwd }),
232
- settings: configuration,
233
- ...(repo === undefined ? {} : { repo }),
234
- readStdin: edge.readStdin,
235
- });
236
- }
237
- async function invokeAkumaFromEdge(parsed, input) {
238
- try {
239
- return await invokeAkumaCommand(parsed, input);
240
- }
241
241
  catch (error) {
242
242
  if (error instanceof AkumaWorldScopeError)
243
243
  throw error;
@@ -252,7 +252,7 @@ async function akumaWorldFor(parsed, located, candidate, establish) {
252
252
  throw new CliUsageError("no Keiyaku world contains the invocation cwd");
253
253
  return world;
254
254
  }
255
- async function invokeCatalog(parsed, world, repo, edge) {
255
+ async function invokeCatalog(parsed, world, repo, home) {
256
256
  try {
257
257
  if (parsed.query.kind === "contracts") {
258
258
  if (repo === undefined)
@@ -262,7 +262,7 @@ async function invokeCatalog(parsed, world, repo, edge) {
262
262
  if (parsed.query.kind === "archetypes") {
263
263
  return {
264
264
  kind: "catalog",
265
- catalog: await Keiyaku.ls({ query: parsed.query, settings: await settingsAt(undefined, edge.environment) }),
265
+ catalog: await Keiyaku.ls({ query: parsed.query, ...(home === undefined ? {} : { home }) }),
266
266
  };
267
267
  }
268
268
  if (world === null)
@@ -278,12 +278,11 @@ async function invokeCatalog(parsed, world, repo, edge) {
278
278
  throw error;
279
279
  }
280
280
  }
281
- async function invokeStatus(parsed, world, repo, edge) {
282
- const configuration = await settingsAt(world ?? undefined, edge.environment);
281
+ async function invokeStatus(parsed, world, repo) {
283
282
  if (parsed.akuma === true) {
284
283
  if (world === null)
285
284
  throw new CliUsageError("no Keiyaku world contains the invocation cwd");
286
- return invokeAkumaStatus(world, parsed.contract, configuration, undefined, repo);
285
+ return invokeAkumaStatus(world, parsed.contract, undefined, repo);
287
286
  }
288
287
  if (parsed.contract === undefined) {
289
288
  const report = await kanshi({ world, ...(repo === undefined ? {} : { repo }) });
@@ -291,18 +290,18 @@ async function invokeStatus(parsed, world, repo, edge) {
291
290
  }
292
291
  if (parsed.contract.startsWith("@")) {
293
292
  try {
294
- const address = await resolveNamedAddress({
295
- path: world,
293
+ const observation = await observeKanshi({ world, ...(repo === undefined ? {} : { repo }) });
294
+ const address = resolveNamedAddress({
296
295
  selector: parsed.contract,
297
- contracts: repo === undefined ? [] : (await Keiyaku.list({ repo })).rows,
296
+ report: observation.report,
297
+ aliases: observation.aliases,
298
298
  });
299
299
  if (address.kind === "akuma") {
300
300
  if (world === null)
301
301
  throw new CliUsageError("no Keiyaku world contains the invocation cwd");
302
- return invokeAkumaStatus(world, address.id, configuration, parsed.contract, repo);
302
+ return invokeAkumaStatus(world, address.id, parsed.contract, repo);
303
303
  }
304
- const report = await kanshi({ world, ...(repo === undefined ? {} : { repo }) });
305
- return { kind: "status", report: selectKanshi({ report, contract: address.id }), selection: "contract" };
304
+ return { kind: "status", report: selectKanshi({ report: observation.report, contract: address.id }), selection: "contract" };
306
305
  }
307
306
  catch (error) {
308
307
  if (error instanceof TypeError)
@@ -310,6 +309,16 @@ async function invokeStatus(parsed, world, repo, edge) {
310
309
  throw error;
311
310
  }
312
311
  }
312
+ if (parsed.contract.startsWith("kei/")) {
313
+ if (repo === undefined)
314
+ throw new CliUsageError("cannot select a contract while the Contract world is absent");
315
+ const contract = canonicalContractSelector(parsed.contract);
316
+ return {
317
+ kind: "status",
318
+ report: await kanshi({ world, repo, contract }),
319
+ selection: "contract",
320
+ };
321
+ }
313
322
  const report = await kanshi({ world, ...(repo === undefined ? {} : { repo }) });
314
323
  const contract = resolveKanshiContract(report, parsed.contract);
315
324
  return { kind: "status", report: selectKanshi({ report, contract }), selection: "contract" };
@@ -343,22 +352,43 @@ async function invokeRegion(parsed, world, repo) {
343
352
  const selection = parsed.overlap ? { kind: "overlap", contract } : { kind: "contract", contract };
344
353
  return { kind: "region", region: { kind: "present", value: selectRegion({ declarations: report.region.value.declarations, selection }) } };
345
354
  }
355
+ async function invokeContractHistory(repo, contract) {
356
+ if (repo === undefined)
357
+ throw new Error("history kei/... requires a resolved Repo");
358
+ const selected = contractFromInput(repo, contract);
359
+ try {
360
+ return { kind: "contract-history", history: await selected.contract.history() };
361
+ }
362
+ catch (error) {
363
+ if (error instanceof TypeError)
364
+ throw new CliUsageError(error.message);
365
+ if (error instanceof KeiyakuRefused) {
366
+ return { kind: "refused", verb: "history", contract: selected.id, refusal: error.refusal };
367
+ }
368
+ throw error;
369
+ }
370
+ }
346
371
  // eslint-disable-next-line complexity -- command dispatch keeps the CLI's existing boundary in one place.
347
372
  async function invokeParsed(invocation, runtime) {
373
+ const environment = runtime.environment ?? process.env;
374
+ const gitPath = gitPathFromEdge(environment);
348
375
  const coordinates = await resolveCliCoordinates({
349
376
  ...(runtime.cwd === undefined ? {} : { processCwd: runtime.cwd }),
350
377
  ...(invocation.cwd === undefined ? {} : { cwd: invocation.cwd }),
351
378
  ...(invocation.repo === undefined ? {} : { repo: invocation.repo }),
379
+ ...(gitPath === undefined ? {} : { gitPath }),
352
380
  command: invocation.command,
353
381
  });
354
- const { cwd, repo, world, candidateWorld, establishWorld } = coordinates;
382
+ const { cwd, cwdSource, repo, world, candidateWorld, establishWorld } = coordinates;
355
383
  const edge = {
356
384
  environment: runtime.environment ?? process.env,
357
385
  readStdin: runtime.readStdin ?? readStdin,
358
386
  };
359
387
  const parsed = invocation.command;
388
+ const mapped = edge.environment.KEIYAKU_HOME?.trim();
389
+ const home = mapped === undefined || mapped.length === 0 ? undefined : mapped;
360
390
  if (parsed.command === "settings") {
361
- return { kind: "settings", value: await settingsAt(world ?? undefined, edge.environment) };
391
+ return { kind: "settings", value: await settingsAt(world ?? undefined, home) };
362
392
  }
363
393
  if (parsed.command === "task") {
364
394
  try {
@@ -375,30 +405,37 @@ async function invokeParsed(invocation, runtime) {
375
405
  throw error;
376
406
  }
377
407
  }
408
+ if (parsed.command === "history" && "contract" in parsed)
409
+ return await invokeContractHistory(repo, parsed.contract);
378
410
  if (isParsedAkumaCommand(parsed)) {
379
411
  const akumaWorld = await akumaWorldFor(parsed, world, candidateWorld, coordinates.establishWorld);
380
- const configuration = await settingsAt(akumaWorld, edge.environment);
412
+ const configuration = parsed.command === "call" ? await settingsAt(akumaWorld, home) : undefined;
381
413
  return await invokeAkumaFromEdge(parsed, {
382
414
  path: akumaWorld,
383
- ...(parsed.command === "call" && parsed.contract !== undefined && invocation.cwd === undefined
384
- ? {}
385
- : { executionCwd: cwd }),
415
+ ...(cwdSource === "input" ? { statedCwd: cwd } : {}),
386
416
  ...(repo === undefined ? {} : { repo }),
387
- configuration,
417
+ ...(parsed.command === "call" && home !== undefined ? { home } : {}),
418
+ ...(configuration === undefined ? {} : { configuration }),
388
419
  edge,
389
420
  });
390
421
  }
391
422
  if (parsed.command === "ls")
392
- return await invokeCatalog(parsed, world, repo, edge);
423
+ return await invokeCatalog(parsed, world, repo, home);
393
424
  if (parsed.command === "status")
394
- return await invokeStatus(parsed, world, repo, edge);
425
+ return await invokeStatus(parsed, world, repo);
395
426
  if (repo === undefined)
396
427
  throw new Error(`${parsed.command} requires a resolved Repo`);
397
428
  if (parsed.command === "region")
398
429
  return invokeRegion(parsed, world, repo);
399
430
  const scope = cwd;
400
- const configuration = await settingsAt(world ?? undefined, edge.environment);
401
- const hooks = selectedHooks(configuration);
431
+ if ((parsed.command === "deliver" || parsed.command === "review") && injectedBodyRequests() !== null) {
432
+ const seat = await existingSeat({ parsed, repo, edge, scope, hooks: EMPTY_WORKTREE_HOOKS });
433
+ return parsed.command === "deliver"
434
+ ? await invokeDeliver(parsed, seat, false)
435
+ : await invokeReview(parsed, seat, edge.readStdin);
436
+ }
437
+ const configuration = await settingsAt(world ?? undefined, home);
438
+ const hooks = consumeSettings(() => worktreeHooksFrom({ settings: configuration }));
402
439
  if (parsed.command === "show") {
403
440
  const selected = await selectContract(repo, parsed.contract, scope);
404
441
  return { kind: "guidance", contract: selected.id, guidance: await selected.contract.guidance() };
@@ -427,13 +464,17 @@ export async function invoke(invocation, runtime = {}) {
427
464
  try {
428
465
  const command = invocation.command;
429
466
  assertExplicitRepoUse(command, invocation.repo);
430
- if (command.command === "install")
467
+ if (command.command === "install") {
468
+ runtime.onOperationStart?.();
431
469
  return installHarnesses(command.harnesses, runtime.environment ?? process.env);
470
+ }
471
+ const acquiredRuntime = await withAcquiredStdin(command, withResolvedTaskActor(command, runtime));
472
+ runtime.onOperationStart?.();
432
473
  return await invokeParsed({
433
474
  ...(invocation.cwd === undefined ? {} : { cwd: invocation.cwd }),
434
475
  ...(invocation.repo === undefined ? {} : { repo: invocation.repo }),
435
476
  command,
436
- }, await withAcquiredStdin(command, withResolvedTaskActor(command, runtime)));
477
+ }, acquiredRuntime);
437
478
  }
438
479
  catch (error) {
439
480
  if (error instanceof CliUsageError && error.projection === undefined) {
@@ -1 +1,3 @@
1
+ import { type ParsedCommand } from "./parse.js";
2
+ export declare function invocationStart(command: ParsedCommand): string | undefined;
1
3
  export declare function main(argv?: readonly string[]): Promise<number>;
@@ -28,7 +28,7 @@ function writeTask(command, result) {
28
28
  return taskExitCode(result);
29
29
  }
30
30
  function writeAkuma(command, result) {
31
- const output = command.output === "json" ? renderAkumaJson(command, result) : renderAkumaText(command, result, {
31
+ const output = command.output === "json" ? renderAkumaJson(result) : renderAkumaText(command, result, {
32
32
  columns: process.stdout.isTTY === true && Number.isInteger(process.stdout.columns) ? process.stdout.columns : 80,
33
33
  color: process.stdout.isTTY === true && process.env.NO_COLOR === undefined,
34
34
  });
@@ -46,6 +46,18 @@ function renderHelp(coordinate) {
46
46
  case "akuma": return renderAkumaHelp(coordinate.action);
47
47
  }
48
48
  }
49
+ export function invocationStart(command) {
50
+ if (command.output === "json")
51
+ return undefined;
52
+ switch (command.command) {
53
+ case "bind": return "⧖ preparing keiyaku";
54
+ case "deliver": return "⧖ delivering";
55
+ case "audit": return "⧖ auditing";
56
+ case "reconcile": return "⧖ reconciling";
57
+ case "install": return "⧖ installing skills";
58
+ default: return undefined;
59
+ }
60
+ }
49
61
  function writeGuidance(command, result) {
50
62
  if (command.output === "json")
51
63
  process.stdout.write(`${JSON.stringify({ contract: result.contract, guidance: result.guidance })}\n`);
@@ -71,8 +83,17 @@ function writeResult(command, result) {
71
83
  process.stdout.write(`${command.output === "json" ? JSON.stringify(settingsJsonValue(value)) : renderSettingsText(value)}\n`);
72
84
  return 0;
73
85
  }
74
- if (isParsedAkumaCommand(command)
75
- || (typeof result === "object" && result !== null && "kind" in result && result.kind === "akuma")) {
86
+ if (typeof result === "object" && result !== null && "kind" in result && result.kind === "contract-history") {
87
+ const history = result.history;
88
+ const output = command.output === "json" ? JSON.stringify(history) : renderText(result);
89
+ process.stdout.write(`${output}\n`);
90
+ return 0;
91
+ }
92
+ const akumaResult = typeof result === "object" && result !== null && "kind" in result && result.kind === "akuma";
93
+ if (isParsedAkumaCommand(command)) {
94
+ return writeAkuma(command, result);
95
+ }
96
+ if (akumaResult && command.command === "status") {
76
97
  return writeAkuma(command, result);
77
98
  }
78
99
  const contractResult = result;
@@ -111,7 +132,11 @@ export async function main(argv = process.argv.slice(2)) {
111
132
  }
112
133
  output = parsed.command.output;
113
134
  const { invoke } = await import("./invoke.js");
114
- const result = await invoke(parsed, { cwd: process.cwd() });
135
+ const start = invocationStart(parsed.command);
136
+ const result = await invoke(parsed, {
137
+ cwd: process.cwd(),
138
+ ...(start === undefined ? {} : { onOperationStart: () => { process.stderr.write(`${start}\n`); } }),
139
+ });
115
140
  return writeResult(parsed.command, result);
116
141
  }
117
142
  catch (error) {
@@ -20,14 +20,15 @@ export type ParsedBind = Output & Actor & Readonly<{
20
20
  target?: string;
21
21
  workspace?: "here";
22
22
  after?: readonly string[];
23
- gates?: string;
23
+ gates?: readonly string[];
24
24
  }>;
25
25
  export type ParsedAmend = Output & Actor & Readonly<{
26
26
  command: "amend";
27
27
  contract?: string;
28
28
  after?: readonly string[];
29
29
  clearAfter?: true;
30
- gates?: string;
30
+ gates?: readonly string[];
31
+ stdin?: true;
31
32
  }>;
32
33
  export type ParsedDeliver = Output & Actor & Readonly<{
33
34
  command: "deliver";
@@ -1,7 +1,7 @@
1
1
  import { isTaskAction, parseTaskCommand, renderTaskUsage, } from "./commands/task.js";
2
2
  import { isAkumaAction, parseAkumaCatalogPath, parseAkumaCommand, 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";
4
+ import { AMEND_MINIMAL_STDIN_HELP, CONTRACT_COMMAND_SPECS, } from "./commands/contract.js";
5
5
  import { CliUsageError, isBlankInput, usageLine, withJsonAutomationHelp } 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 ...] [-]";
@@ -69,9 +69,12 @@ function scanOption(command, argv, state, index) {
69
69
  return index;
70
70
  }
71
71
  const value = argv[index + 1];
72
- if (value === undefined || value === "-" || value.startsWith("--"))
72
+ if (value === undefined)
73
73
  refuse(command, `${token} requires a value`);
74
- if (isBlankInput(value))
74
+ if (kind !== "raw-value" && (value === "-" || value.startsWith("--"))) {
75
+ refuse(command, `${token} requires a value`);
76
+ }
77
+ if (kind !== "raw-value" && isBlankInput(value))
75
78
  refuse(command, `${token} requires a nonblank value`);
76
79
  if (kind === "repeat-value") {
77
80
  const values = state.flags[name];
@@ -121,7 +124,7 @@ function parseBind(parts) {
121
124
  const task = optionalFlag(parts.flags, "task");
122
125
  const target = optionalFlag(parts.flags, "target");
123
126
  const after = parts.flags.after === undefined ? [] : Array.isArray(parts.flags.after) ? parts.flags.after : [parts.flags.after];
124
- const gates = optionalFlag(parts.flags, "gates");
127
+ const gates = parseGateBundleNames(parts, "bind");
125
128
  return {
126
129
  command: "bind",
127
130
  ...(task === undefined ? {} : { task }),
@@ -138,7 +141,10 @@ function parseAmend(parts) {
138
141
  const after = parts.flags.after === undefined ? [] : Array.isArray(parts.flags.after) ? parts.flags.after : [parts.flags.after];
139
142
  if (parts.flags["clear-after"] === true && after.length > 0)
140
143
  refuse("amend", "--clear-after and --after are mutually exclusive");
141
- const gates = optionalFlag(parts.flags, "gates");
144
+ const gates = parseGateBundleNames(parts, "amend");
145
+ if (!parts.stdin && parts.flags.after === undefined && parts.flags["clear-after"] !== true && gates === undefined) {
146
+ refuse("amend", "amend requires stdin or --after, --clear-after, or --gates");
147
+ }
142
148
  return {
143
149
  command: "amend",
144
150
  ...(contract === undefined ? {} : { contract }),
@@ -146,9 +152,20 @@ function parseAmend(parts) {
146
152
  ...(parts.flags["clear-after"] === true ? { clearAfter: true } : {}),
147
153
  ...(gates === undefined ? {} : { gates }),
148
154
  ...(parts.actor === undefined ? {} : { actor: parts.actor }),
155
+ ...(parts.stdin ? { stdin: true } : {}),
149
156
  output: parts.output,
150
157
  };
151
158
  }
159
+ function parseGateBundleNames(parts, command) {
160
+ const value = optionalFlag(parts.flags, "gates");
161
+ if (value === undefined)
162
+ return undefined;
163
+ const names = value.split(",");
164
+ if (names.some((name) => name.length === 0)) {
165
+ refuse(command, "--gates requires nonempty comma-separated names");
166
+ }
167
+ return names;
168
+ }
152
169
  function parseDeliver(parts) {
153
170
  const contract = parts.positionals[0];
154
171
  const message = optionalFlag(parts.flags, "message");
@@ -236,14 +253,14 @@ function parseRegion(parts) {
236
253
  }
237
254
  function parseLs(parts) {
238
255
  const path = parts.positionals[0];
239
- if (path === "task/")
256
+ if (path === "task" || path === "task/")
240
257
  return { command: "ls", query: { kind: "tasks" }, output: parts.output };
241
- if (path === "kei/")
258
+ if (path === "kei" || path === "kei/")
242
259
  return { command: "ls", query: { kind: "contracts" }, output: parts.output };
243
260
  try {
244
261
  const query = parseAkumaCatalogPath(path);
245
262
  if (query === null)
246
- refuse("ls", "ls requires an identity directory with a trailing slash");
263
+ refuse("ls", "ls requires a supported identity directory selector");
247
264
  return { command: "ls", query, output: parts.output };
248
265
  }
249
266
  catch (error) {
@@ -4,5 +4,5 @@ import { type TextRenderContext } from "./terminal.js";
4
4
  export declare function akumaRawAnswer(result: AkumaInvocationResult): string | undefined;
5
5
  export declare function renderAkumaText(command: ParsedCommand, result: AkumaInvocationResult, context?: TextRenderContext): string;
6
6
  export declare function akumaExitCode(result: AkumaInvocationResult): number;
7
- export declare function akumaJsonValue(command: ParsedCommand, result: AkumaInvocationResult): unknown;
8
- export declare function renderAkumaJson(command: ParsedCommand, result: AkumaInvocationResult): string;
7
+ export declare function akumaJsonValue(result: AkumaInvocationResult): unknown;
8
+ export declare function renderAkumaJson(result: AkumaInvocationResult): string;