@astrosheep/keiyaku 4.0.0 → 4.0.2

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 (308) hide show
  1. package/README.md +133 -8
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +2 -2
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +4 -4
  4. package/build/integrations/marketplace/plugins/keiyaku/opencode.js +2 -2
  5. package/build/integrations/marketplace/plugins/keiyaku/package.json +2 -2
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +13 -5
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -32
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +134 -0
  9. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/agents/openai.yaml +4 -0
  10. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +41 -6
  11. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +262 -46
  12. package/build/src/akuma/abort.d.ts +2 -0
  13. package/build/src/akuma/abort.js +50 -0
  14. package/build/src/akuma/akuma.d.ts +50 -33
  15. package/build/src/akuma/akuma.js +175 -127
  16. package/build/src/akuma/archetype.d.ts +14 -5
  17. package/build/src/akuma/archetype.js +85 -39
  18. package/build/src/akuma/body.d.ts +3 -5
  19. package/build/src/akuma/body.js +490 -183
  20. package/build/src/akuma/coordinate.d.ts +9 -0
  21. package/build/src/akuma/coordinate.js +22 -0
  22. package/build/src/akuma/heart/facts.d.ts +88 -45
  23. package/build/src/akuma/heart/facts.js +19 -8
  24. package/build/src/akuma/heart/index.d.ts +64 -55
  25. package/build/src/akuma/heart/index.js +172 -252
  26. package/build/src/akuma/heart/rows.d.ts +38 -83
  27. package/build/src/akuma/heart/rows.js +117 -155
  28. package/build/src/akuma/heart/schema.d.ts +1 -1
  29. package/build/src/akuma/heart/schema.js +61 -22
  30. package/build/src/akuma/heart/soul.d.ts +8 -0
  31. package/build/src/akuma/heart/soul.js +136 -0
  32. package/build/src/akuma/heart/storage.d.ts +47 -0
  33. package/build/src/akuma/heart/storage.js +224 -0
  34. package/build/src/akuma/heart/tells.d.ts +12 -0
  35. package/build/src/akuma/heart/tells.js +79 -0
  36. package/build/src/akuma/heart/timeline.d.ts +15 -0
  37. package/build/src/akuma/heart/timeline.js +86 -0
  38. package/build/src/akuma/identity.d.ts +2 -2
  39. package/build/src/akuma/identity.js +9 -9
  40. package/build/src/akuma/index.d.ts +10 -3
  41. package/build/src/akuma/index.js +7 -1
  42. package/build/src/akuma/projection.d.ts +176 -0
  43. package/build/src/akuma/projection.js +256 -0
  44. package/build/src/akuma/provider-recipe.d.ts +24 -0
  45. package/build/src/akuma/provider-recipe.js +100 -0
  46. package/build/src/akuma/provider.d.ts +67 -13
  47. package/build/src/akuma/provider.js +172 -105
  48. package/build/src/akuma/providers/acp/core.d.ts +19 -0
  49. package/build/src/akuma/providers/acp/core.js +159 -0
  50. package/build/src/akuma/providers/acp/events.d.ts +20 -0
  51. package/build/src/akuma/providers/acp/events.js +73 -0
  52. package/build/src/akuma/providers/acp/index.d.ts +12 -0
  53. package/build/src/akuma/providers/acp/index.js +94 -0
  54. package/build/src/akuma/providers/{claude.d.ts → claude/events.d.ts} +9 -41
  55. package/build/src/akuma/providers/claude/events.js +238 -0
  56. package/build/src/akuma/providers/claude/index.d.ts +47 -0
  57. package/build/src/akuma/providers/claude/index.js +279 -0
  58. package/build/src/akuma/providers/claude/input.d.ts +13 -0
  59. package/build/src/akuma/providers/claude/input.js +109 -0
  60. package/build/src/akuma/providers/codex-app-server/events.d.ts +1 -1
  61. package/build/src/akuma/providers/codex-app-server/events.js +15 -12
  62. package/build/src/akuma/providers/codex-app-server/index.d.ts +15 -13
  63. package/build/src/akuma/providers/codex-app-server/index.js +77 -33
  64. package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
  65. package/build/src/akuma/providers/grok-build/index.js +70 -0
  66. package/build/src/akuma/providers/index.d.ts +5 -3
  67. package/build/src/akuma/providers/index.js +35 -56
  68. package/build/src/akuma/providers/opencode-sdk/events.d.ts +54 -0
  69. package/build/src/akuma/providers/opencode-sdk/events.js +235 -0
  70. package/build/src/akuma/providers/opencode-sdk/index.d.ts +33 -0
  71. package/build/src/akuma/providers/opencode-sdk/index.js +308 -0
  72. package/build/src/akuma/providers/opencode-sdk/session.d.ts +26 -0
  73. package/build/src/akuma/providers/opencode-sdk/session.js +63 -0
  74. package/build/src/akuma/providers/pi/events.d.ts +33 -0
  75. package/build/src/akuma/providers/pi/events.js +166 -0
  76. package/build/src/akuma/providers/pi/index.d.ts +11 -0
  77. package/build/src/akuma/providers/pi/index.js +191 -0
  78. package/build/src/akuma/publication.d.ts +3 -3
  79. package/build/src/akuma/publication.js +28 -40
  80. package/build/src/akuma/requests.d.ts +9 -6
  81. package/build/src/akuma/requests.js +95 -65
  82. package/build/src/alias/index.d.ts +4 -3
  83. package/build/src/alias/index.js +12 -13
  84. package/build/src/body/decode.js +7 -1
  85. package/build/src/body/region.d.ts +2 -0
  86. package/build/src/body/region.js +77 -7
  87. package/build/src/body/render.js +2 -1
  88. package/build/src/body/shape.js +7 -1
  89. package/build/src/body/verification.js +19 -4
  90. package/build/src/cli/accepted.d.ts +18 -12
  91. package/build/src/cli/accepted.js +73 -34
  92. package/build/src/cli/actor.js +3 -3
  93. package/build/src/cli/commands/akuma-invoke.d.ts +44 -19
  94. package/build/src/cli/commands/akuma-invoke.js +101 -52
  95. package/build/src/cli/commands/akuma.d.ts +27 -9
  96. package/build/src/cli/commands/akuma.js +151 -80
  97. package/build/src/cli/commands/contract.d.ts +155 -0
  98. package/build/src/cli/commands/contract.js +20 -0
  99. package/build/src/cli/commands/install.js +2 -0
  100. package/build/src/cli/commands/task-invoke.d.ts +19 -4
  101. package/build/src/cli/commands/task-invoke.js +65 -17
  102. package/build/src/cli/commands/task-query.d.ts +5 -0
  103. package/build/src/cli/commands/task-query.js +247 -0
  104. package/build/src/cli/commands/task.d.ts +3 -1
  105. package/build/src/cli/commands/task.js +52 -14
  106. package/build/src/cli/coordinates.d.ts +18 -0
  107. package/build/src/cli/coordinates.js +120 -0
  108. package/build/src/cli/draft.d.ts +8 -0
  109. package/build/src/cli/draft.js +96 -0
  110. package/build/src/cli/invoke.d.ts +9 -3
  111. package/build/src/cli/invoke.js +287 -108
  112. package/build/src/cli/main.js +54 -7
  113. package/build/src/cli/parse.d.ts +21 -117
  114. package/build/src/cli/parse.js +79 -84
  115. package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
  116. package/build/src/cli/render/akuma-tool-command.js +144 -0
  117. package/build/src/cli/render/akuma-tool.d.ts +4 -2
  118. package/build/src/cli/render/akuma-tool.js +35 -5
  119. package/build/src/cli/render/akuma.d.ts +3 -1
  120. package/build/src/cli/render/akuma.js +247 -212
  121. package/build/src/cli/render/audit.d.ts +3 -0
  122. package/build/src/cli/render/audit.js +104 -0
  123. package/build/src/cli/render/catalog.d.ts +2 -0
  124. package/build/src/cli/render/catalog.js +16 -0
  125. package/build/src/cli/render/contract.d.ts +3 -3
  126. package/build/src/cli/render/contract.js +200 -54
  127. package/build/src/cli/render/kanshi.js +272 -129
  128. package/build/src/cli/render/receipt.d.ts +19 -0
  129. package/build/src/cli/render/receipt.js +106 -0
  130. package/build/src/cli/render/refusal.d.ts +16 -2
  131. package/build/src/cli/render/refusal.js +88 -3
  132. package/build/src/cli/render/region.d.ts +2 -0
  133. package/build/src/cli/render/region.js +17 -0
  134. package/build/src/cli/render/task.d.ts +2 -1
  135. package/build/src/cli/render/task.js +223 -60
  136. package/build/src/cli/render/terminal.d.ts +20 -0
  137. package/build/src/cli/render/terminal.js +121 -0
  138. package/build/src/cli/render/text.js +11 -3
  139. package/build/src/cli/result.d.ts +126 -19
  140. package/build/src/cli/usage.d.ts +1 -0
  141. package/build/src/cli/usage.js +3 -0
  142. package/build/src/contract-worktree.d.ts +44 -0
  143. package/build/src/contract-worktree.js +251 -0
  144. package/build/src/coordination/durable-file.d.ts +5 -1
  145. package/build/src/coordination/durable-file.js +57 -10
  146. package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
  147. package/build/src/coordination/sqlite-transaction-lock.js +22 -5
  148. package/build/src/core/facts/codec.js +23 -4
  149. package/build/src/core/facts/eligibility.d.ts +1 -10
  150. package/build/src/core/facts/eligibility.js +0 -49
  151. package/build/src/core/facts/fold.js +1 -6
  152. package/build/src/core/facts/gate.d.ts +1 -0
  153. package/build/src/core/facts/gate.js +1 -0
  154. package/build/src/core/facts/observation.d.ts +3 -0
  155. package/build/src/core/facts/observation.js +12 -0
  156. package/build/src/core/facts/types.d.ts +10 -3
  157. package/build/src/core/subject.js +2 -2
  158. package/build/src/core/verbs/amend.d.ts +1 -1
  159. package/build/src/core/verbs/amend.js +3 -18
  160. package/build/src/core/verbs/bind.js +2 -16
  161. package/build/src/core/verbs/deliver.d.ts +1 -1
  162. package/build/src/core/verbs/deliver.js +14 -4
  163. package/build/src/core/verbs/placement.d.ts +1 -1
  164. package/build/src/core/verbs/placement.js +7 -9
  165. package/build/src/dispatch/index.d.ts +5 -3
  166. package/build/src/dispatch/index.js +30 -21
  167. package/build/src/duration.d.ts +10 -0
  168. package/build/src/duration.js +22 -0
  169. package/build/src/git/admission.d.ts +2 -2
  170. package/build/src/git/admission.js +33 -23
  171. package/build/src/git/hooks.d.ts +15 -0
  172. package/build/src/git/hooks.js +70 -18
  173. package/build/src/git/identity.d.ts +5 -1
  174. package/build/src/git/identity.js +23 -4
  175. package/build/src/git/integration.d.ts +48 -0
  176. package/build/src/git/integration.js +250 -0
  177. package/build/src/git/observe.d.ts +29 -15
  178. package/build/src/git/observe.js +185 -76
  179. package/build/src/git/read-observation.d.ts +41 -0
  180. package/build/src/git/read-observation.js +361 -0
  181. package/build/src/git/reconcile.d.ts +17 -5
  182. package/build/src/git/reconcile.js +305 -109
  183. package/build/src/git/repository.d.ts +41 -18
  184. package/build/src/git/repository.js +220 -114
  185. package/build/src/git/scratch.d.ts +17 -0
  186. package/build/src/git/scratch.js +73 -0
  187. package/build/src/git/target-placement.d.ts +92 -0
  188. package/build/src/git/target-placement.js +375 -0
  189. package/build/src/git/tender.d.ts +49 -0
  190. package/build/src/git/tender.js +63 -0
  191. package/build/src/git/terminal-seal.d.ts +24 -0
  192. package/build/src/git/terminal-seal.js +89 -0
  193. package/build/src/git/tree.d.ts +2 -2
  194. package/build/src/git/tree.js +4 -0
  195. package/build/src/git/workspace.d.ts +53 -0
  196. package/build/src/git/workspace.js +139 -0
  197. package/build/src/identity/selector.d.ts +6 -0
  198. package/build/src/identity/selector.js +19 -0
  199. package/build/src/index.d.ts +4 -2
  200. package/build/src/index.js +2 -1
  201. package/build/src/kanshi/index.d.ts +2 -2
  202. package/build/src/kanshi/index.js +1 -1
  203. package/build/src/kanshi/read.d.ts +7 -3
  204. package/build/src/kanshi/read.js +245 -45
  205. package/build/src/kanshi/report.d.ts +81 -6
  206. package/build/src/kanshi/select.d.ts +5 -0
  207. package/build/src/kanshi/select.js +33 -1
  208. package/build/src/library/address.d.ts +57 -0
  209. package/build/src/library/address.js +165 -0
  210. package/build/src/library/akuma-creation.d.ts +16 -7
  211. package/build/src/library/akuma-creation.js +96 -22
  212. package/build/src/library/audit.d.ts +18 -0
  213. package/build/src/library/audit.js +44 -0
  214. package/build/src/library/bind.d.ts +21 -0
  215. package/build/src/library/bind.js +56 -0
  216. package/build/src/library/catalog.d.ts +58 -0
  217. package/build/src/library/catalog.js +69 -0
  218. package/build/src/library/configuration.d.ts +6 -15
  219. package/build/src/library/configuration.js +14 -17
  220. package/build/src/library/contract.d.ts +23 -49
  221. package/build/src/library/contract.js +171 -185
  222. package/build/src/library/delivery.d.ts +24 -0
  223. package/build/src/library/delivery.js +21 -0
  224. package/build/src/library/fleet.d.ts +65 -0
  225. package/build/src/library/fleet.js +153 -0
  226. package/build/src/library/input.d.ts +3 -0
  227. package/build/src/library/input.js +19 -0
  228. package/build/src/library/keiyaku.d.ts +18 -3
  229. package/build/src/library/keiyaku.js +12 -1
  230. package/build/src/library/mutation.d.ts +39 -0
  231. package/build/src/library/mutation.js +37 -0
  232. package/build/src/library/reconcile.d.ts +29 -0
  233. package/build/src/library/reconcile.js +179 -0
  234. package/build/src/library/refusal.d.ts +21 -0
  235. package/build/src/library/refusal.js +29 -0
  236. package/build/src/library/region.d.ts +14 -1
  237. package/build/src/library/region.js +18 -4
  238. package/build/src/library/repo.d.ts +4 -13
  239. package/build/src/library/repo.js +14 -24
  240. package/build/src/protocol/attempt.d.ts +16 -3
  241. package/build/src/protocol/attempt.js +41 -10
  242. package/build/src/protocol/bind.d.ts +9 -2
  243. package/build/src/protocol/bind.js +48 -40
  244. package/build/src/protocol/intent.d.ts +57 -20
  245. package/build/src/protocol/intent.js +55 -79
  246. package/build/src/protocol/operations.d.ts +152 -43
  247. package/build/src/protocol/operations.js +482 -166
  248. package/build/src/protocol/outcome.d.ts +14 -3
  249. package/build/src/protocol/outcome.js +11 -3
  250. package/build/src/protocol/placement.d.ts +41 -0
  251. package/build/src/protocol/placement.js +147 -0
  252. package/build/src/protocol/read/documents.d.ts +2 -2
  253. package/build/src/protocol/read/documents.js +4 -4
  254. package/build/src/protocol/read/status.d.ts +18 -5
  255. package/build/src/protocol/read/status.js +73 -13
  256. package/build/src/protocol/run.d.ts +49 -7
  257. package/build/src/protocol/run.js +53 -25
  258. package/build/src/runtime/proc/line-rpc.d.ts +4 -8
  259. package/build/src/runtime/proc/line-rpc.js +22 -28
  260. package/build/src/runtime/proc/run.d.ts +23 -21
  261. package/build/src/runtime/proc/run.js +123 -89
  262. package/build/src/runtime/proc/stdio.d.ts +18 -0
  263. package/build/src/runtime/proc/stdio.js +58 -0
  264. package/build/src/settings.d.ts +7 -1
  265. package/build/src/settings.js +32 -17
  266. package/build/src/settlement/fence.d.ts +5 -0
  267. package/build/src/settlement/fence.js +14 -0
  268. package/build/src/settlement/holder.d.ts +35 -4
  269. package/build/src/settlement/holder.js +127 -28
  270. package/build/src/settlement/settle.d.ts +9 -1
  271. package/build/src/settlement/settle.js +74 -37
  272. package/build/src/task/board.d.ts +23 -5
  273. package/build/src/task/board.js +17 -10
  274. package/build/src/task/compose.d.ts +2 -2
  275. package/build/src/task/compose.js +18 -10
  276. package/build/src/task/context.d.ts +3 -3
  277. package/build/src/task/context.js +15 -20
  278. package/build/src/task/document.d.ts +2 -1
  279. package/build/src/task/document.js +15 -5
  280. package/build/src/task/index.d.ts +27 -15
  281. package/build/src/task/index.js +57 -35
  282. package/build/src/task/operations.d.ts +38 -13
  283. package/build/src/task/operations.js +80 -46
  284. package/build/src/task/query.d.ts +67 -0
  285. package/build/src/task/query.js +279 -0
  286. package/build/src/task/store.d.ts +5 -7
  287. package/build/src/task/store.js +43 -28
  288. package/build/src/verification/declaration.d.ts +1 -0
  289. package/build/src/verification/execution.d.ts +51 -0
  290. package/build/src/verification/execution.js +108 -0
  291. package/build/src/workspace-place.d.ts +41 -0
  292. package/build/src/workspace-place.js +386 -0
  293. package/build/src/world.d.ts +24 -0
  294. package/build/src/world.js +136 -0
  295. package/package.json +8 -4
  296. package/build/src/akuma/activity.d.ts +0 -66
  297. package/build/src/akuma/activity.js +0 -139
  298. package/build/src/akuma/providers/claude.js +0 -305
  299. package/build/src/context-root.d.ts +0 -4
  300. package/build/src/context-root.js +0 -15
  301. package/build/src/git/delivery.d.ts +0 -20
  302. package/build/src/git/delivery.js +0 -109
  303. package/build/src/git/verification.d.ts +0 -14
  304. package/build/src/git/verification.js +0 -56
  305. package/build/src/protocol/read/audit.d.ts +0 -25
  306. package/build/src/protocol/read/audit.js +0 -39
  307. package/build/src/verification/producer.d.ts +0 -23
  308. package/build/src/verification/producer.js +0 -54
@@ -0,0 +1,165 @@
1
+ import { readAliases } from "../alias/index.js";
2
+ import { Akuma } from "../akuma/akuma.js";
3
+ import { probeBornAkuma } from "../akuma/index.js";
4
+ import { parseAkuId } from "../akuma/identity.js";
5
+ import { contractId } from "../core/facts/types.js";
6
+ import { readDispatches } from "../dispatch/index.js";
7
+ import { matchesAkumaGlob, parseAkumaAlias, parseAkumaGlob, } from "../identity/selector.js";
8
+ import { requireInput } from "./input.js";
9
+ import { scopeForRepo } from "./repo.js";
10
+ export class AkumaWorldScopeError extends TypeError {
11
+ refusal;
12
+ constructor(refusal) {
13
+ super(`akuma-not-in-world ${refusal.world} ${refusal.ids.join(" ")}`);
14
+ this.name = "AkumaWorldScopeError";
15
+ this.refusal = refusal;
16
+ }
17
+ }
18
+ function nonblank(value, label) {
19
+ if (typeof value !== "string" || value.trim().length === 0)
20
+ throw new TypeError(`${label} must be a nonblank string`);
21
+ return value;
22
+ }
23
+ function settingsOption(value) {
24
+ if (value === undefined)
25
+ return undefined;
26
+ if (typeof value !== "object" || value === null || typeof value.namespace !== "function") {
27
+ throw new TypeError("settings must be a Settings");
28
+ }
29
+ return value;
30
+ }
31
+ function world(path, settings) {
32
+ return Akuma.of(path, settings);
33
+ }
34
+ async function directId(path, selector) {
35
+ if (selector.startsWith("@")) {
36
+ const alias = parseAkumaAlias(selector);
37
+ const resolved = (await readAliases(path)).find((binding) => binding.alias === alias)?.akuId ?? null;
38
+ if (resolved === null)
39
+ throw new TypeError(`unknown Akuma alias: ${alias}`);
40
+ return resolved;
41
+ }
42
+ return parseAkuId(selector).id;
43
+ }
44
+ export async function resolveNamedAddress(input) {
45
+ const selector = nonblank(input.selector, "selector");
46
+ if (selector.startsWith("kei/"))
47
+ return { kind: "contract", id: contractId(selector) };
48
+ if (selector.startsWith("aku/"))
49
+ return { kind: "akuma", id: parseAkuId(selector).id };
50
+ const alias = parseAkumaAlias(selector);
51
+ const contractMatches = input.contracts.filter((row) => row.disposition === "active"
52
+ && row.workspace === "worktree" && row.worktreePath !== null
53
+ && `@${row.id.slice("kei/".length)}` === alias);
54
+ const aliasId = input.path === null
55
+ ? null
56
+ : (await readAliases(input.path)).find((binding) => binding.alias === alias)?.akuId ?? null;
57
+ if (contractMatches.length > 0 && aliasId !== null)
58
+ throw new TypeError(`ambiguous selector matches Contract and Akuma: ${selector}`);
59
+ if (contractMatches.length === 1)
60
+ return { kind: "contract", id: contractMatches[0].id };
61
+ if (contractMatches.length > 1)
62
+ throw new TypeError(`ambiguous Contract selector: ${selector}`);
63
+ if (aliasId !== null)
64
+ return { kind: "akuma", id: aliasId };
65
+ throw new TypeError(`unknown selector: ${selector}`);
66
+ }
67
+ export async function addressAkuma(input) {
68
+ const values = requireInput(input, "Akuma address input");
69
+ for (const key of Object.keys(values)) {
70
+ if (!["path", "akuma", "settings", "repo"].includes(key))
71
+ throw new TypeError(`Akuma address input has unknown field: ${key}`);
72
+ }
73
+ if (values.repo !== undefined)
74
+ scopeForRepo(values.repo);
75
+ const path = nonblank(values.path, "path");
76
+ const settings = settingsOption(values.settings);
77
+ return { path, id: await directId(path, nonblank(values.akuma, "akuma")), ...(settings === undefined ? {} : { settings }) };
78
+ }
79
+ function idsFromFleet(fleet) {
80
+ return fleet.rows.map((row) => row.id);
81
+ }
82
+ function parseSetSelector(raw) {
83
+ const selector = nonblank(raw, "akuma selector");
84
+ if (selector.startsWith("kei/"))
85
+ return { kind: "contract", value: contractId(selector) };
86
+ if (selector.includes("*"))
87
+ return { kind: "glob", value: parseAkumaGlob(selector) };
88
+ if (selector.startsWith("@"))
89
+ return { kind: "alias", value: parseAkumaAlias(selector) };
90
+ return { kind: "direct", value: parseAkuId(selector).id };
91
+ }
92
+ function hasSelectorKind(selectors, kind) {
93
+ return selectors.some((selector) => selector.kind === kind);
94
+ }
95
+ function addSelectorIds(selector, sources, selected, contractMembers) {
96
+ if (selector.kind === "contract") {
97
+ for (const dispatch of sources.dispatches) {
98
+ if (dispatch.contractId !== selector.value)
99
+ continue;
100
+ selected.add(dispatch.akuId);
101
+ contractMembers.add(dispatch.akuId);
102
+ }
103
+ return;
104
+ }
105
+ if (selector.kind === "glob") {
106
+ for (const id of sources.fleetIds)
107
+ if (matchesAkumaGlob(selector.value, id))
108
+ selected.add(id);
109
+ return;
110
+ }
111
+ if (selector.kind === "alias") {
112
+ const id = sources.aliases.get(selector.value);
113
+ if (id === undefined)
114
+ throw new TypeError(`unknown Akuma alias: ${selector.value}`);
115
+ selected.add(id);
116
+ return;
117
+ }
118
+ selected.add(selector.value);
119
+ }
120
+ async function contractMemberInWorld(path, id) {
121
+ return await probeBornAkuma(path, id);
122
+ }
123
+ async function refuseForeignContractMembers(path, ids, contractMembers) {
124
+ const foreign = [];
125
+ for (const id of ids) {
126
+ if (contractMembers.has(id) && !await contractMemberInWorld(path, id))
127
+ foreign.push(id);
128
+ }
129
+ if (foreign.length > 0)
130
+ throw new AkumaWorldScopeError({ kind: "akuma-not-in-world", ids: foreign, world: path });
131
+ }
132
+ export async function addressAkumaSet(input) {
133
+ const values = requireInput(input, "Akuma set address input");
134
+ for (const key of Object.keys(values)) {
135
+ if (!["path", "akuma", "settings", "repo"].includes(key))
136
+ throw new TypeError(`Akuma set address input has unknown field: ${key}`);
137
+ }
138
+ if (!Array.isArray(values.akuma) || values.akuma.length === 0)
139
+ throw new TypeError("akuma must be a nonempty selector array");
140
+ const path = nonblank(values.path, "path");
141
+ const settings = settingsOption(values.settings);
142
+ const selectors = values.akuma.map(parseSetSelector);
143
+ if (hasSelectorKind(selectors, "contract") && values.repo === undefined) {
144
+ throw new TypeError("Contract Akuma selector requires repo");
145
+ }
146
+ const fleetIds = hasSelectorKind(selectors, "glob")
147
+ ? idsFromFleet(await world(path, settings).list())
148
+ : [];
149
+ const aliases = hasSelectorKind(selectors, "alias")
150
+ ? new Map((await readAliases(path)).map((binding) => [binding.alias, binding.akuId]))
151
+ : new Map();
152
+ const dispatches = hasSelectorKind(selectors, "contract")
153
+ ? await readDispatches(scopeForRepo(values.repo))
154
+ : [];
155
+ const selected = new Set();
156
+ const contractMembers = new Set();
157
+ const sources = { fleetIds, aliases, dispatches };
158
+ for (const selector of selectors)
159
+ addSelectorIds(selector, sources, selected, contractMembers);
160
+ const ids = [...selected].sort((left, right) => Buffer.compare(Buffer.from(left), Buffer.from(right)));
161
+ if (ids.length === 0)
162
+ throw new TypeError("Akuma selector snapshot is empty");
163
+ await refuseForeignContractMembers(path, ids, contractMembers);
164
+ return { path, ids, ...(settings === undefined ? {} : { settings }) };
165
+ }
@@ -1,9 +1,10 @@
1
1
  import { type AliasBinding } from "../alias/index.js";
2
- import { type AkumaStatus, type ForkReceipt } from "../akuma/akuma.js";
3
- import { type AkuId } from "../akuma/identity.js";
2
+ import { type AkumaStatus, type ForkReceipt, type ReadonlyRestraint } from "../akuma/akuma.js";
3
+ import type { AkuId } from "../akuma/identity.js";
4
4
  import { type Dispatch, type DispatchFailure } from "../dispatch/index.js";
5
5
  import { type AkumaAlias } from "../identity/selector.js";
6
6
  import type { Settings } from "../settings.js";
7
+ import type { WorldRoot } from "../world.js";
7
8
  import { type Keiyaku } from "./contract.js";
8
9
  import { type Repo } from "./repo.js";
9
10
  export type { AkumaStatus } from "../akuma/akuma.js";
@@ -34,7 +35,7 @@ export type AliasStage = Readonly<{
34
35
  failure: IntegrationFailure;
35
36
  }>;
36
37
  export type CallInput = Readonly<{
37
- path: string;
38
+ path: WorldRoot;
38
39
  archetype: string;
39
40
  body: string;
40
41
  cwd?: string;
@@ -56,24 +57,32 @@ export type CallObservation = Readonly<{
56
57
  export type CallResult = Readonly<{
57
58
  kind: "called";
58
59
  akuma: AkuId;
60
+ readonly?: ReadonlyRestraint;
61
+ execution: Readonly<{
62
+ cwd: string;
63
+ source: "input" | "world" | "contract-worktree";
64
+ }>;
59
65
  dispatch: DispatchStage;
60
66
  alias: AliasStage;
61
67
  observation: CallObservation;
62
68
  }>;
63
69
  export type ForkInput = Readonly<{
64
- path: string;
65
- akuma: AkuId;
70
+ path: WorldRoot;
71
+ akuma: string;
66
72
  at: string;
67
73
  settings?: Settings;
68
74
  repo?: Repo;
69
75
  }>;
70
76
  export type ForkResult = Readonly<{
71
77
  kind: "forked";
78
+ parent: AkuId;
72
79
  child: AkuId;
73
80
  dispatch: DispatchStage;
74
- }> | Exclude<ForkReceipt, Readonly<{
81
+ }> | (Exclude<ForkReceipt, Readonly<{
75
82
  kind: "forked";
76
83
  child: AkuId;
77
- }>>;
84
+ }>> & Readonly<{
85
+ parent: AkuId;
86
+ }>);
78
87
  export declare function callKeiyaku(input: CallInput): Promise<CallResult>;
79
88
  export declare function forkKeiyaku(input: ForkInput): Promise<ForkResult>;
@@ -1,12 +1,13 @@
1
- import { resolve } from "node:path";
1
+ import { realpath, stat } from "node:fs/promises";
2
2
  import { moveAlias } from "../alias/index.js";
3
- import { Akuma } from "../akuma/akuma.js";
4
- import { parseAkuId } from "../akuma/identity.js";
3
+ import { Akuma, } from "../akuma/akuma.js";
5
4
  import { AuthorityCorruptionError } from "../core/facts/errors.js";
6
5
  import { publishDispatch, readDispatch, } from "../dispatch/index.js";
7
6
  import { parseAkumaAlias } from "../identity/selector.js";
7
+ import { readManagedWorktreeAppointment } from "../workspace-place.js";
8
8
  import { requireInput } from "./input.js";
9
- import { seatForKeiyaku } from "./contract.js";
9
+ import { addressAkuma } from "./address.js";
10
+ import { KeiyakuRefused, seatForKeiyaku } from "./contract.js";
10
11
  import { scopeForRepo } from "./repo.js";
11
12
  function nonblank(value, label) {
12
13
  if (typeof value !== "string" || value.trim().length === 0) {
@@ -68,9 +69,9 @@ async function observeCall(handle, mode, timeoutMs) {
68
69
  return { kind: "failed", failure: integrationFailure(error) };
69
70
  }
70
71
  }
71
- function dispatchStage(input) {
72
+ async function dispatchStage(input) {
72
73
  try {
73
- const published = publishDispatch(input);
74
+ const published = await publishDispatch(input);
74
75
  return published.kind === "dispatched"
75
76
  ? { kind: "dispatched", dispatch: published.dispatch }
76
77
  : { kind: "failed", failure: published.failure };
@@ -79,21 +80,78 @@ function dispatchStage(input) {
79
80
  return { kind: "failed", failure: integrationFailure(error) };
80
81
  }
81
82
  }
82
- function forkDispatchStage(input) {
83
+ async function forkDispatchStage(input) {
83
84
  try {
84
- const parent = readDispatch(input.repository, input.parent);
85
+ const parent = await readDispatch(input.repository, input.parent);
85
86
  return parent === null
86
87
  ? { kind: "none" }
87
- : dispatchStage({ repository: input.repository, akuId: input.child, contractId: parent.contractId });
88
+ : await dispatchStage({ repository: input.repository, akuId: input.child, contractId: parent.contractId });
88
89
  }
89
90
  catch (error) {
90
91
  return { kind: "failed", failure: integrationFailure(error) };
91
92
  }
92
93
  }
94
+ async function canonicalizeExistingDirectory(path, diagnostic) {
95
+ try {
96
+ const real = await realpath(path);
97
+ if (!(await stat(real)).isDirectory())
98
+ throw new Error(diagnostic);
99
+ return real;
100
+ }
101
+ catch (error) {
102
+ if (error instanceof Error && error.message === diagnostic)
103
+ throw error;
104
+ throw new Error(diagnostic);
105
+ }
106
+ }
107
+ function unavailableWorkspace(contractId, detail) {
108
+ return new Error(`Contract workspace is unavailable: ${contractId} ${detail}`);
109
+ }
110
+ async function currentManagedContract(contract, contractId) {
111
+ let state;
112
+ try {
113
+ state = await contract.state();
114
+ }
115
+ catch (error) {
116
+ if (error instanceof Error && error.message === `contract does not exist: ${contractId}`) {
117
+ throw new KeiyakuRefused({ kind: "contract-missing", contractId });
118
+ }
119
+ throw error;
120
+ }
121
+ if (state.terminal !== null)
122
+ throw new KeiyakuRefused({ kind: "terminal", contractId: state.id });
123
+ if (state.coordinates.workspace !== "worktree") {
124
+ throw unavailableWorkspace(state.id, "is here");
125
+ }
126
+ return state;
127
+ }
128
+ async function resolveCallExecution(input) {
129
+ if (input.cwd !== undefined) {
130
+ return {
131
+ cwd: await canonicalizeExistingDirectory(input.cwd, `cwd is not an existing directory: ${input.cwd}`),
132
+ source: "input",
133
+ };
134
+ }
135
+ if (input.contract === undefined)
136
+ return { cwd: input.path, source: "world" };
137
+ const seat = seatForKeiyaku(input.contract);
138
+ const state = await currentManagedContract(input.contract, seat.id);
139
+ const appointment = await readManagedWorktreeAppointment(seat.scope, state.id);
140
+ if (appointment.kind === "unappointed") {
141
+ throw unavailableWorkspace(state.id, "is unappointed; use reconcile");
142
+ }
143
+ if (appointment.kind === "failed") {
144
+ throw new Error(`${appointment.diagnostic}; use reconcile`);
145
+ }
146
+ return {
147
+ cwd: await canonicalizeExistingDirectory(appointment.path, `Contract workspace is unavailable: ${appointment.path}`),
148
+ source: "contract-worktree",
149
+ };
150
+ }
93
151
  export async function callKeiyaku(input) {
94
152
  const values = requireInput(input, "Keiyaku.call input");
95
153
  onlyKeys(values, ["path", "archetype", "body", "cwd", "mode", "timeoutMs", "settings", "contract", "alias"], "Keiyaku.call input");
96
- const path = resolve(nonblank(values.path, "path"));
154
+ const path = nonblank(values.path, "path");
97
155
  const archetype = nonblank(values.archetype, "archetype");
98
156
  const body = text(values.body, "body");
99
157
  const cwd = values.cwd === undefined ? undefined : nonblank(values.cwd, "cwd");
@@ -104,14 +162,20 @@ export async function callKeiyaku(input) {
104
162
  ? undefined
105
163
  : parseAkumaAlias(nonblank(values.alias, "alias"));
106
164
  const seat = values.contract === undefined ? undefined : seatForKeiyaku(values.contract);
107
- const handle = await Akuma.at({ path, ...(settings === undefined ? {} : { settings }) }).call({
165
+ const execution = await resolveCallExecution({
166
+ path,
167
+ ...(cwd === undefined ? {} : { cwd }),
168
+ ...(seat === undefined ? {} : { contract: values.contract }),
169
+ });
170
+ const handle = await Akuma.of(path, settings).call({
108
171
  archetype,
109
172
  body,
110
- ...(cwd === undefined ? {} : { cwd }),
173
+ cwd: execution.cwd,
111
174
  });
175
+ const readonly = (await handle.status()).readonly;
112
176
  const dispatch = seat === undefined
113
177
  ? { kind: "none" }
114
- : dispatchStage({ repository: seat.scope, akuId: handle.id, contractId: seat.id });
178
+ : await dispatchStage({ repository: seat.scope, akuId: handle.id, contractId: seat.id });
115
179
  let aliasStage = { kind: "none" };
116
180
  if (alias !== undefined) {
117
181
  if (dispatch.kind === "failed")
@@ -127,25 +191,35 @@ export async function callKeiyaku(input) {
127
191
  }
128
192
  }
129
193
  const observation = await observeCall(handle, mode, timeoutMs);
130
- return { kind: "called", akuma: handle.id, dispatch, alias: aliasStage, observation };
194
+ return {
195
+ kind: "called",
196
+ akuma: handle.id,
197
+ ...(readonly === undefined ? {} : { readonly }),
198
+ execution,
199
+ dispatch,
200
+ alias: aliasStage,
201
+ observation,
202
+ };
131
203
  }
132
204
  export async function forkKeiyaku(input) {
133
205
  const values = requireInput(input, "Keiyaku.fork input");
134
206
  onlyKeys(values, ["path", "akuma", "at", "settings", "repo"], "Keiyaku.fork input");
135
- const path = resolve(nonblank(values.path, "path"));
136
- if (typeof values.akuma !== "string")
137
- throw new TypeError("akuma must be an AkuId");
138
- const akuma = parseAkuId(values.akuma).id;
207
+ const path = nonblank(values.path, "path");
139
208
  const at = nonblank(values.at, "at");
140
209
  const settings = settingsOption(values.settings);
210
+ const akuma = (await addressAkuma({
211
+ path,
212
+ akuma: nonblank(values.akuma, "akuma"),
213
+ ...(settings === undefined ? {} : { settings }),
214
+ })).id;
141
215
  const repository = values.repo === undefined ? undefined : scopeForRepo(values.repo);
142
- const receipt = await Akuma.at({ path, ...(settings === undefined ? {} : { settings }) })
216
+ const receipt = await Akuma.of(path, settings)
143
217
  .of({ id: akuma })
144
218
  .fork({ at });
145
219
  if (receipt.kind !== "forked")
146
- return receipt;
220
+ return { ...receipt, parent: akuma };
147
221
  const dispatch = repository === undefined
148
222
  ? { kind: "none" }
149
- : forkDispatchStage({ repository, parent: akuma, child: receipt.child });
150
- return { kind: "forked", child: receipt.child, dispatch };
223
+ : await forkDispatchStage({ repository, parent: akuma, child: receipt.child });
224
+ return { kind: "forked", parent: akuma, child: receipt.child, dispatch };
151
225
  }
@@ -0,0 +1,18 @@
1
+ import type { ContractId } from "../core/facts/types.js";
2
+ import { type AuditReport, type RepositoryScope } from "../protocol/operations.js";
3
+ import { type WorktreeHooks } from "./configuration.js";
4
+ import { type MutationResult } from "./mutation.js";
5
+ export type AuditInput = Readonly<{
6
+ actor?: string;
7
+ hooks?: WorktreeHooks;
8
+ includeDirty?: boolean;
9
+ showDiff?: boolean;
10
+ requireBranchesToBeUpToDate?: boolean;
11
+ signal?: AbortSignal;
12
+ }>;
13
+ /** Normalize public audit input and project the protocol audit operation. */
14
+ export declare function auditContract(input: Readonly<{
15
+ scope: RepositoryScope;
16
+ contractId: ContractId;
17
+ input?: AuditInput;
18
+ }>): Promise<MutationResult<AuditReport>>;
@@ -0,0 +1,44 @@
1
+ import { decodeContractDocument } from "../body/decode.js";
2
+ import { withGitDecodeChannel } from "../git/read-observation.js";
3
+ import { auditOperation, } from "../protocol/operations.js";
4
+ import { worktreeHooksOption } from "./configuration.js";
5
+ import { actorOption, documentDerivation, optionalBoolean, optionalSignal, requireInput, } from "./input.js";
6
+ import { completeMutation } from "./mutation.js";
7
+ import { requireAccepted } from "./refusal.js";
8
+ function normalizeAuditInput(input) {
9
+ const values = input === undefined ? undefined : requireInput(input, "audit input");
10
+ const signal = optionalSignal(values?.signal);
11
+ return {
12
+ hooks: worktreeHooksOption(values?.hooks),
13
+ ...actorOption(values?.actor),
14
+ includeDirty: optionalBoolean(values?.includeDirty, "includeDirty") ?? false,
15
+ showDiff: optionalBoolean(values?.showDiff, "showDiff") ?? false,
16
+ requireBranchesToBeUpToDate: optionalBoolean(values?.requireBranchesToBeUpToDate, "requireBranchesToBeUpToDate") ?? false,
17
+ ...(signal === undefined ? {} : { signal }),
18
+ };
19
+ }
20
+ /** Normalize public audit input and project the protocol audit operation. */
21
+ export async function auditContract(input) {
22
+ const normalized = normalizeAuditInput(input.input);
23
+ return withGitDecodeChannel(input.scope, async (channel) => {
24
+ const accepted = requireAccepted(await auditOperation({
25
+ scope: input.scope,
26
+ channel,
27
+ contractId: input.contractId,
28
+ deriveDocument: (state) => documentDerivation(decodeContractDocument(state.terms.document.bytes), state.terms.gates, state.id),
29
+ includeDirty: normalized.includeDirty,
30
+ showDiff: normalized.showDiff,
31
+ requireBranchesToBeUpToDate: normalized.requireBranchesToBeUpToDate,
32
+ ...(normalized.signal === undefined ? {} : { signal: normalized.signal }),
33
+ ...(normalized.actor === undefined ? {} : { actor: normalized.actor }),
34
+ }));
35
+ return completeMutation({
36
+ scope: input.scope,
37
+ channel,
38
+ contractId: input.contractId,
39
+ accepted,
40
+ value: (report) => report,
41
+ hooks: normalized.hooks,
42
+ });
43
+ });
44
+ }
@@ -0,0 +1,21 @@
1
+ import { type ActorId, type ContractId } from "../core/facts/types.js";
2
+ import type { GitDecodeChannel } from "../git/read-observation.js";
3
+ import { bindOperation, type IntentOutcome, type RepositoryScope } from "../protocol/operations.js";
4
+ import type { TaskId } from "../task/identity.js";
5
+ import type { VerificationDeclarationPreparation } from "../verification/declaration.js";
6
+ import type { KeiyakuRefusal } from "./refusal.js";
7
+ type BindAttemptInput = Readonly<{
8
+ scope: RepositoryScope;
9
+ channel: GitDecodeChannel;
10
+ title: string;
11
+ terms: Parameters<typeof bindOperation>[0]["terms"];
12
+ verification: VerificationDeclarationPreparation;
13
+ workspace: "worktree" | "here";
14
+ target?: string;
15
+ task?: TaskId;
16
+ actor?: ActorId;
17
+ }>;
18
+ export declare function admitBindWithAppointment(input: BindAttemptInput): Promise<IntentOutcome<Readonly<{
19
+ contractId: ContractId;
20
+ }>, KeiyakuRefusal>>;
21
+ export {};
@@ -0,0 +1,56 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { releaseContractWorktree, reserveContractWorktree, withContractWorktreeAppointment, } from "../contract-worktree.js";
3
+ import { contractIdFromSegment } from "../core/facts/types.js";
4
+ import { fitIdentityStem, normalizeIdentityStem } from "../identity/normalize.js";
5
+ import { bindOperation } from "../protocol/operations.js";
6
+ import { claimTaskHolder } from "../settlement/holder.js";
7
+ function candidateId(title, collision) {
8
+ const stem = fitIdentityStem({ stem: normalizeIdentityStem({ source: title }) || "contract", maxBytes: 48 });
9
+ const suffix = collision === 0 ? "" : `-${randomBytes(8).toString("hex")}`;
10
+ return contractIdFromSegment(`${stem}${suffix}`);
11
+ }
12
+ async function attempt(input, id) {
13
+ return bindOperation({
14
+ scope: input.scope,
15
+ channel: input.channel,
16
+ title: input.title,
17
+ terms: input.terms,
18
+ verification: input.verification,
19
+ workspace: input.workspace,
20
+ contractId: id,
21
+ ...(input.target === undefined ? {} : { target: input.target }),
22
+ ...(input.task === undefined ? {} : {
23
+ decorateOffer: ({ contractId: owner }) => [claimTaskHolder(input.task, owner)],
24
+ }),
25
+ ...(input.actor === undefined ? {} : { actor: input.actor }),
26
+ });
27
+ }
28
+ async function attemptCandidates(input) {
29
+ for (let collision = 0; collision <= 3; collision += 1) {
30
+ const id = candidateId(input.title, collision);
31
+ let reserved = false;
32
+ if (input.workspace === "here") {
33
+ const reservation = await reserveContractWorktree(input.scope, id);
34
+ if (reservation.kind !== "reserved") {
35
+ return { kind: "refused", refusal: {
36
+ kind: "here-worktree-appointed",
37
+ path: reservation.path,
38
+ ...(reservation.kind === "appointed" ? { contract: reservation.contract } : {}),
39
+ } };
40
+ }
41
+ reserved = true;
42
+ }
43
+ const result = await attempt(input, id);
44
+ if (result.kind === "accepted")
45
+ return result;
46
+ if (reserved)
47
+ await releaseContractWorktree(input.scope, id);
48
+ if (result.kind !== "refused" || result.refusal.kind !== "contract-exists")
49
+ return result;
50
+ }
51
+ throw new Error("contract identity collision attempts exhausted");
52
+ }
53
+ export async function admitBindWithAppointment(input) {
54
+ const action = () => attemptCandidates(input);
55
+ return input.workspace === "here" ? await withContractWorktreeAppointment(input.scope, action) : action();
56
+ }
@@ -0,0 +1,58 @@
1
+ import { type AkumaList } from "../akuma/akuma.js";
2
+ import { type ArchetypeCatalogRow } from "../akuma/archetype.js";
3
+ import type { Settings } from "../settings.js";
4
+ import type { TaskRow } from "../task/index.js";
5
+ import { type ContractBoard } from "./contract.js";
6
+ import { Repo } from "./repo.js";
7
+ import type { WorldRoot } from "../world.js";
8
+ export type CatalogQuery = Readonly<{
9
+ kind: "tasks";
10
+ }> | Readonly<{
11
+ kind: "contracts";
12
+ }> | Readonly<{
13
+ kind: "archetypes";
14
+ }> | Readonly<{
15
+ kind: "akuma";
16
+ archetype?: string;
17
+ }>;
18
+ export type CatalogInput = Readonly<{
19
+ query: Extract<CatalogQuery, {
20
+ kind: "tasks";
21
+ }>;
22
+ path: WorldRoot;
23
+ }> | Readonly<{
24
+ query: Extract<CatalogQuery, {
25
+ kind: "contracts";
26
+ }>;
27
+ repo: Repo;
28
+ }> | Readonly<{
29
+ query: Extract<CatalogQuery, {
30
+ kind: "archetypes";
31
+ }>;
32
+ settings: Settings;
33
+ }> | Readonly<{
34
+ query: Extract<CatalogQuery, {
35
+ kind: "akuma";
36
+ }>;
37
+ path: WorldRoot;
38
+ }>;
39
+ export type Catalog = Readonly<{
40
+ kind: "tasks";
41
+ root: WorldRoot;
42
+ rows: readonly TaskRow[];
43
+ }> | Readonly<{
44
+ kind: "contracts";
45
+ root: string;
46
+ state: string | null;
47
+ rows: ContractBoard["rows"];
48
+ }> | Readonly<{
49
+ kind: "archetypes";
50
+ rows: readonly ArchetypeCatalogRow[];
51
+ }> | Readonly<{
52
+ kind: "akuma";
53
+ root: WorldRoot;
54
+ archetype: string | null;
55
+ rows: AkumaList["rows"];
56
+ searched: readonly string[];
57
+ }>;
58
+ export declare function listCatalog(input: CatalogInput): Promise<Catalog>;
@@ -0,0 +1,69 @@
1
+ import { Akuma } from "../akuma/akuma.js";
2
+ import { listArchetypeDefinitions } from "../akuma/archetype.js";
3
+ import { observeTaskCatalogRows } from "../task/operations.js";
4
+ import { listKeiyaku } from "./contract.js";
5
+ import { requireInput } from "./input.js";
6
+ import { Repo } from "./repo.js";
7
+ function settingsValue(value) {
8
+ if (typeof value !== "object" || value === null
9
+ || typeof value.namespace !== "function") {
10
+ throw new TypeError("settings must be a Settings");
11
+ }
12
+ return value;
13
+ }
14
+ function worldRoot(value) {
15
+ if (typeof value !== "string" || value.trim().length === 0)
16
+ throw new TypeError("path must be a WorldRoot");
17
+ return value;
18
+ }
19
+ function queryValue(value) {
20
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
21
+ throw new TypeError("Keiyaku.ls query must be an object");
22
+ }
23
+ const query = value;
24
+ if (query.kind !== "tasks" && query.kind !== "contracts" && query.kind !== "archetypes" && query.kind !== "akuma") {
25
+ throw new TypeError("Keiyaku.ls query kind is invalid");
26
+ }
27
+ for (const key of Object.keys(query)) {
28
+ if (key !== "kind" && !(query.kind === "akuma" && key === "archetype")) {
29
+ throw new TypeError(`Keiyaku.ls query has unknown field: ${key}`);
30
+ }
31
+ }
32
+ if (query.kind !== "akuma")
33
+ return { kind: query.kind };
34
+ if (query.archetype !== undefined && typeof query.archetype !== "string") {
35
+ throw new TypeError("Keiyaku.ls Akuma name must be a string");
36
+ }
37
+ return { kind: "akuma", ...(query.archetype === undefined ? {} : { archetype: query.archetype }) };
38
+ }
39
+ export async function listCatalog(input) {
40
+ const values = requireInput(input, "Keiyaku.ls input");
41
+ const query = queryValue(values.query);
42
+ const allowed = query.kind === "contracts" ? ["query", "repo"]
43
+ : query.kind === "archetypes" ? ["query", "settings"] : ["query", "path"];
44
+ for (const key of Object.keys(values)) {
45
+ if (!allowed.includes(key))
46
+ throw new TypeError(`Keiyaku.ls input has unknown field: ${key}`);
47
+ }
48
+ if (query.kind === "contracts") {
49
+ if (!(values.repo instanceof Repo))
50
+ throw new TypeError("repo must be a Repo");
51
+ const board = await listKeiyaku({ repo: values.repo });
52
+ return { kind: "contracts", root: board.root, state: board.state, rows: board.rows };
53
+ }
54
+ if (query.kind === "archetypes") {
55
+ return { kind: "archetypes", rows: await listArchetypeDefinitions({ settings: settingsValue(values.settings) }) };
56
+ }
57
+ const path = worldRoot(values.path);
58
+ if (query.kind === "tasks") {
59
+ return { kind: "tasks", root: path, rows: await observeTaskCatalogRows(path) };
60
+ }
61
+ const listed = await Akuma.of(path).list(query.archetype === undefined ? undefined : { archetype: query.archetype });
62
+ return {
63
+ kind: "akuma",
64
+ root: path,
65
+ archetype: query.archetype ?? null,
66
+ rows: listed.rows,
67
+ searched: listed.searched,
68
+ };
69
+ }