@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,6 +1,6 @@
1
1
  {
2
2
  "name": "keiyaku",
3
- "version": "0.1.0+codex.20260815181541",
3
+ "version": "0.1.0+codex.20260819092206",
4
4
  "description": "Use the Keiyaku contract, task, and Akuma CLI.",
5
5
  "author": { "name": "Keiyaku" },
6
6
  "skills": "./skills/"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keiyaku",
3
- "version": "0.1.0+codex.20260815181541",
3
+ "version": "0.1.0+codex.20260819092206",
4
4
  "description": "Use the Keiyaku contract, task, and Akuma CLI.",
5
5
  "author": {
6
6
  "name": "Keiyaku"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keiyaku-harness",
3
- "version": "0.1.0+codex.20260815181541",
3
+ "version": "0.1.0+codex.20260819092206",
4
4
  "type": "module",
5
5
  "main": "./opencode.js",
6
6
  "keywords": ["pi-package"],
@@ -15,9 +15,9 @@ read `<command> --help` before using flags.
15
15
  then `keiyaku-workflow` for the remaining lifecycle.
16
16
  - An Akuma is a callable worker; see `keiyaku-akuma`.
17
17
 
18
- Settings owns named gate sets. Omitting `--gates` selects `gates.default`, or
19
- freezes an empty gate list when that entry is absent. `--gates <name>` selects
20
- one configured set; it does not add a literal gate word.
18
+ Settings owns named gate bundles. Omitting `--gates` selects `gates.default`,
19
+ or freezes `["reviewed"]` when that entry is absent. `--gates <name,...>`
20
+ selects configured bundles in order; it does not add literal gate words.
21
21
 
22
22
  ## Quick Start
23
23
 
@@ -31,7 +31,7 @@ keiyaku -C <repo> review [<contract>|@<contract>] --satisfied
31
31
  ```
32
32
 
33
33
  ```bash
34
- keiyaku -C <cwd> call <akuma-name> [--contract <kei/...>] [--alias @name] [--wait <duration> | -d | --detach] [--json] (<prompt> | -)
34
+ keiyaku -C <cwd> call <akuma-name> [--contract <kei/...>] [--alias @name] [--allowed <product.action>]... [--wait <duration> | -d | --detach] [--json] (<prompt> | -)
35
35
  keiyaku -C <repo> wait <akuma-selector>... [--any | --all]
36
36
  keiyaku -C <repo> tell <aku/...|@alias> (<prompt> | -)
37
37
  ```
@@ -13,7 +13,7 @@ is accepted; the identity underneath never changes.
13
13
  ## Start One
14
14
 
15
15
  ```bash
16
- keiyaku -C <cwd> call <akuma-name> [--alias @name] [--wait <duration> | -d | --detach] [--json] (<prompt> | -)
16
+ keiyaku -C <cwd> call <akuma-name> [--alias @name] [--allowed <product.action>]... [--wait <duration> | -d | --detach] [--json] (<prompt> | -)
17
17
  ```
18
18
 
19
19
  Give the worker's initial prompt as one argument (quote it when it contains
@@ -31,6 +31,14 @@ Bind is the last step of an investigation, never the first step of an idea.
31
31
  now. Cannot draft means unresolved design — "the worker will sort out the
32
32
  docs" is a design gap in disguise.
33
33
 
34
+ Split complex work wherever independently acceptable delivery boundaries
35
+ exist. When a complex Keiyaku cannot be split without breaking one acceptance
36
+ boundary, bind one Contract and plan its fulfillment as explicit arcs. Treat
37
+ each arc as a chapter as in a work of literature, not as a task sequence.
38
+ Commission one current chapter at a time; never hand the whole undifferentiated
39
+ Contract to one Deliverer and trust it to finish everything in one pass.
40
+ Continue with `keiyaku-workflow` for the arc document and command.
41
+
34
42
  Two tests close the gate:
35
43
 
36
44
  - **Substitution.** Two workers who never met each deliver test-green from
@@ -59,7 +67,8 @@ Design read the same without a sentence here, delete it.>
59
67
 
60
68
  ## Objective
61
69
  <One observable end-state, judged done/not-done without reading Design.
62
- If you need "and", bind two Contracts.>
70
+ If "and" joins independently acceptable outcomes, bind two Contracts. A
71
+ single outcome may still require several arcs during fulfillment.>
63
72
 
64
73
  ## Design
65
74
  <The closed decisions. A statement belongs here exactly when a test-green
@@ -93,6 +102,11 @@ Decidable without consulting you.>
93
102
  KEIYAKU
94
103
  ~~~~
95
104
 
105
+ Use separate fences for checks that need separate timeouts or results. Fences
106
+ run top-to-bottom, and later fences may use earlier outputs. Put setup/build
107
+ before its consumers; use `&&` in one fence only when the consumer must stop
108
+ if setup fails.
109
+
96
110
  Each declaration may set an individual timeout in its fence info string, using
97
111
  an explicit duration unit such as `bash timeout=5m`. Omit it for an unbounded
98
112
  declaration; there is no Verification-wide timeout.
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: keiyaku-task
3
- description: "Use when planning work in a Keiyaku v4 repo: add tasks, wire dependencies, inspect readiness, and track lifecycle."
3
+ description: >-
4
+ Use when recording, decomposing, or tracking a complex task, typically
5
+ involving three or more steps.
4
6
  ---
5
7
 
6
8
  # Keiyaku Task
@@ -94,6 +94,12 @@ frontmatter names `Contract`, then reads the listed owner documents and source
94
94
  files before acting. Do not substitute a generic repository tour for the files
95
95
  that actually govern the assignment.
96
96
 
97
+ Contract association, available forwarded actions, and the brief are
98
+ independent inputs. When a Reviewer should record its own verdict, include
99
+ `--allowed contract.review` and say in the brief to record `--satisfied` on
100
+ pass or `--unsatisfied` on failure. When a Deliverer should tender its completed
101
+ candidate, include `--allowed contract.deliver` and say so in the brief.
102
+
97
103
  A `Deliverer` implements and verifies the terms in `Worktree`. Commission a
98
104
  `Reviewer` after delivery. The reviewer inspects the complete current Contract
99
105
  worktree snapshot, not a worker report or named candidate commit, and does not
@@ -121,11 +127,17 @@ the test. Give each resulting Contract coherent terms. Connect them with
121
127
  `--after` only when one must proceed from another's settled result or their
122
128
  intended work is unsafe to run concurrently.
123
129
 
124
- When one acceptance boundary still spans several coherent chapters,
125
- organize them as arcs. An arc is a chapter of the delivery's
126
- story, not a task list: its title names the chapter, Objective is the
127
- chapter's aim, Brief opens the next chapter. When an Arc is active, stay
128
- within that current chapter. `.keiyaku/KEIYAKU.md` renders the current Arc.
130
+ When a complex Keiyaku cannot be split without breaking one acceptance
131
+ boundary, organize its fulfillment into arcs. Do not hand the whole
132
+ undifferentiated Contract to one Deliverer and trust one pass to finish it.
133
+ Record and work one current chapter at a time.
134
+
135
+ An arc is a chapter as in a work of literature: one named part of the
136
+ delivery's story, not a task list, progress slice, or claim that the work is
137
+ mechanically sequential. Its title names the chapter, Objective states that
138
+ chapter's aim, and Brief commissions work for that chapter. When an Arc is
139
+ active, stay within that current chapter. `.keiyaku/KEIYAKU.md` renders the
140
+ current Arc.
129
141
  Record the next chapter before entering it:
130
142
 
131
143
  ```bash
@@ -159,22 +171,28 @@ old Contract onto a different delivery.
159
171
 
160
172
  ## Audit Before Delivery
161
173
 
162
- Audit is how you see a delivery before it exists:
174
+ Audit is an evidence window for a prospective delivery:
163
175
 
164
176
  ```bash
165
177
  keiyaku audit <contract> --diff
166
178
  ```
167
179
 
168
- Audit answers three already-adjudicated questions: candidate, Verification,
169
- and target. It uses the same candidate preparation as deliver, shows the
170
- prospective identity and optional requested diff, and runs declared
171
- Verification against that candidate. A terminal run records ordinary
172
- subject-bound `verified` testimony; it does not record a delivery or request
173
- placement. Read those three answers instead of trusting a worker's completion
174
- report.
180
+ It aggregates facts from the same candidate preparation used by `deliver`:
181
+ the prospective candidate and integration identities, the requested diff, the
182
+ declared Verification commands and their observed results, and the target
183
+ placement observation. A terminal run may record subject-bound `verified`
184
+ testimony for those observed commands; it does not deliver, request placement,
185
+ satisfy a review gate, or decide whether the candidate should land. The
186
+ coordinator judges the returned facts; a worker's completion report is not a
187
+ substitute for them.
175
188
 
176
189
  ## Deliver
177
190
 
191
+ When the brief assigns delivery to the Deliverer, include `--allowed
192
+ contract.deliver`; require it to run the command below after verification and
193
+ return the receipt. Otherwise the coordinator runs it after accepting the
194
+ candidate.
195
+
178
196
  Deliver when the worktree content is the candidate you intend to land:
179
197
 
180
198
  ```bash
@@ -210,6 +228,9 @@ keiyaku review <contract> --unsatisfied --summary "<finding>"
210
228
  ```
211
229
 
212
230
  Have an independent reviewer inspect the delivered Contract worktree snapshot.
231
+ If it should record the verdict itself, dispatch it with `--allowed
232
+ contract.review` and state both verdicts in the brief. Otherwise its answer is
233
+ review input for the coordinator to record.
213
234
  The `review` command records the verdict. `--satisfied` requests placement; if
214
235
  the other gates are current, the receipt shows `claimed`.
215
236
 
@@ -3,13 +3,13 @@ import { type AkuId } from "./identity.js";
3
3
  import { type ActivityHistory, type ActivitySnapshot } from "./projection.js";
4
4
  import { type Settings } from "../settings.js";
5
5
  import type { WorldRoot } from "../world.js";
6
+ import { type AllowedAction } from "./allowed.js";
6
7
  export type AkumaListRow = Readonly<{
7
8
  id: AkuId;
8
9
  archetype: string;
9
10
  description?: string;
10
11
  life: AkumaLife;
11
12
  lifeAt: string | null;
12
- confinement: Soul["confinement"];
13
13
  pending: readonly string[];
14
14
  }>;
15
15
  export type AkumaStatus = Readonly<{
@@ -36,6 +36,22 @@ export type AkumaList = Readonly<{
36
36
  export type AkumaListInput = Readonly<{
37
37
  archetype?: string;
38
38
  }>;
39
+ export type AkumaCallExecution = Readonly<{
40
+ cwd: string;
41
+ source: "input" | "caller" | "process" | "world";
42
+ }>;
43
+ declare const CALL_EXECUTION: unique symbol;
44
+ declare const CALL_WITH_CONTEXT: unique symbol;
45
+ export type AkumaCallInput = Readonly<{
46
+ archetype: string;
47
+ body: string;
48
+ cwd?: string;
49
+ allowed?: readonly AllowedAction[];
50
+ }>;
51
+ type AkumaCallContext = Readonly<{
52
+ initiatorCwd?: string;
53
+ cwdCanonical?: true;
54
+ }>;
39
55
  export type TellResult = Readonly<{
40
56
  admission: Readonly<{
41
57
  tellId: string;
@@ -76,8 +92,7 @@ export declare class AkumaNotBornError extends Error {
76
92
  readonly kind = "akuma-not-born";
77
93
  constructor(id: AkuId);
78
94
  }
79
- /** Package-internal action observation; it uses the same snapshot selector as status. */
80
- export declare function readActionFeedbackStatus(worldPath: WorldRoot, id: AkuId): Promise<AkumaStatus>;
95
+ export declare function tellAkumaWithId(worldPath: WorldRoot, id: AkuId, body: string, tellId: string, recordedAt?: string): Promise<TellResult>;
81
96
  export type BudgetedStatusObservation = Readonly<{
82
97
  status: AkumaStatus;
83
98
  ordinarySelected: number;
@@ -86,10 +101,13 @@ export type BudgetedStatusObservation = Readonly<{
86
101
  export declare function readBudgetedStatus(worldPath: WorldRoot, id: AkuId, input: Readonly<{
87
102
  ordinaryBudget: number;
88
103
  }>): Promise<BudgetedStatusObservation>;
104
+ /** Package-internal birth projection used by the composed Library call result. */
105
+ export declare function readAkumaBirthCwd(worldPath: WorldRoot, id: AkuId): Promise<string>;
89
106
  export declare class AkumaHandle {
90
107
  readonly id: AkuId;
91
108
  private readonly worldPath;
92
- constructor(id: AkuId, worldPath: WorldRoot);
109
+ readonly [CALL_EXECUTION]?: AkumaCallExecution;
110
+ constructor(id: AkuId, worldPath: WorldRoot, execution?: AkumaCallExecution);
93
111
  private get paths();
94
112
  status(): Promise<AkumaStatus>;
95
113
  history(input?: Readonly<{
@@ -108,26 +126,30 @@ export declare class AkumaHandle {
108
126
  kill(): Promise<KillEvidence>;
109
127
  lastAnswer(): Promise<LastAnswer>;
110
128
  }
129
+ /** Package-internal provenance retained only by the handle returned from call. */
130
+ export declare function akumaCallExecution(handle: AkumaHandle): AkumaCallExecution | undefined;
111
131
  export type LastAnswer = Readonly<{
112
132
  kind: "answer";
113
133
  answer: string;
114
134
  }> | Readonly<{
115
135
  kind: "no-answer";
116
136
  }>;
137
+ type AkumaConfiguration = Readonly<{
138
+ home?: string;
139
+ settings?: Settings;
140
+ }>;
117
141
  export declare class Akuma {
118
142
  private readonly path;
119
- private readonly configuredSettings?;
143
+ private readonly configuration;
120
144
  private constructor();
121
- static of(root: WorldRoot, settings?: Settings): Akuma;
122
- private settings;
145
+ static of(root: WorldRoot, input?: AkumaConfiguration): Akuma;
123
146
  of(input: Readonly<{
124
147
  id: string;
125
148
  }>): AkumaHandle;
126
149
  listArchetypes(): Promise<readonly string[]>;
127
- call(input: Readonly<{
128
- archetype: string;
129
- body: string;
130
- cwd?: string;
131
- }>): Promise<AkumaHandle>;
150
+ call(input: AkumaCallInput): Promise<AkumaHandle>;
151
+ [CALL_WITH_CONTEXT](input: AkumaCallInput, context: AkumaCallContext): Promise<AkumaHandle>;
132
152
  list(input?: AkumaListInput): Promise<AkumaList>;
133
153
  }
154
+ /** Package-internal call path for a composition owner that already canonicalized cwd. */
155
+ export declare function callAkumaWithContext(akuma: Akuma, input: AkumaCallInput, context: AkumaCallContext): Promise<AkumaHandle>;
@@ -1,8 +1,8 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { readdir } from "node:fs/promises";
2
+ import { readdir, realpath, stat } from "node:fs/promises";
3
3
  import { resolve } from "node:path";
4
4
  import { CONTROL_RESPONSE_MS, spawnAkumaBody } from "./body.js";
5
- import { HeldAkumaLeash, activitySlice, life, lifeAt, probeLeash, readHeart, readLastAnsweredTurn, readForkPoint, readKill, readSeal, readSoul, recordTell, requestPause, requestStop, } from "./heart/index.js";
5
+ import { HeldAkumaLeash, activitySlice, isHeartAbsent, life, lifeAt, probeLeash, readHeart, readLastAnsweredTurn, readForkPoint, readKill, readSeal, readSoul, recordTell, requestPause, requestStop, } from "./heart/index.js";
6
6
  import { akuIdFromDirectoryName, akumaPaths, akumaRunRoot, parseAkuId, pathsForAkuId, archetypeName, } from "./identity.js";
7
7
  import { ordinarySelectedCount, ordinarySnapshotBudget, projectTurns, selectActivitySnapshot, selectHistory, selectSnapshot, } from "./projection.js";
8
8
  import { listArchetypes as readArchetypes, loadArchetype } from "./archetype.js";
@@ -10,7 +10,22 @@ import { publishAkuma } from "./publication.js";
10
10
  import { resolveProviderExecution } from "./providers/index.js";
11
11
  import { injectedBodyRequests, requestBodyCall } from "./requests.js";
12
12
  import { settings as readSettings } from "../settings.js";
13
+ import { decodeAllowedActions, } from "./allowed.js";
13
14
  const POLL_MS = 25;
15
+ async function canonicalBirthCwd(input) {
16
+ const selected = resolve(input);
17
+ try {
18
+ const canonical = await realpath(selected);
19
+ if (!(await stat(canonical)).isDirectory())
20
+ throw new Error("not a directory");
21
+ return canonical;
22
+ }
23
+ catch {
24
+ throw new Error(`cwd is not an existing directory: ${input}`);
25
+ }
26
+ }
27
+ const CALL_EXECUTION = Symbol("akuma-call-execution");
28
+ const CALL_WITH_CONTEXT = Symbol("akuma-call-with-context");
14
29
  export class AkumaNotBornError extends Error {
15
30
  id;
16
31
  kind = "akuma-not-born";
@@ -33,9 +48,8 @@ async function takeLeashUntil(paths, deadline) {
33
48
  await wait(POLL_MS);
34
49
  }
35
50
  }
36
- async function recordTellBody(paths, akuma, body) {
37
- const id = randomUUID();
38
- const admitted = await recordTell(paths, { kind: "tell", id, body, recordedAt: new Date().toISOString() });
51
+ async function recordTellBody(paths, akuma, body, id = randomUUID(), recordedAt = new Date().toISOString()) {
52
+ const admitted = await recordTell(paths, { kind: "tell", id, body, recordedAt });
39
53
  if (admitted.kind === "not-born")
40
54
  throw new AkumaNotBornError(akuma);
41
55
  return { kind: "recorded", tellId: admitted.tell.id };
@@ -48,10 +62,34 @@ async function wakeTell(paths, tellId) {
48
62
  catch (error) {
49
63
  return {
50
64
  admission: { tellId, fact: "recorded" },
51
- wake: { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error) },
65
+ wake: { kind: "failed", diagnostic: diagnostic(error) },
52
66
  };
53
67
  }
54
68
  }
69
+ export async function tellAkumaWithId(worldPath, id, body, tellId, recordedAt = new Date().toISOString()) {
70
+ const paths = pathsForAkuId(worldPath, id);
71
+ const recorded = await recordTellBody(paths, id, body, tellId, recordedAt);
72
+ return await wakeTell(paths, recorded.tellId);
73
+ }
74
+ function diagnostic(error) {
75
+ return error instanceof Error ? error.message : String(error);
76
+ }
77
+ async function fleetListRow(paths, expected) {
78
+ const snapshot = await readHeart(paths);
79
+ if (snapshot.soul !== null)
80
+ return await bornListRow(paths, expected, snapshot);
81
+ try {
82
+ if (await probeLeash(paths) === "held")
83
+ return { id: expected, life: "unborn" };
84
+ const seal = await readSeal(paths);
85
+ return seal === null ? { id: expected, life: "unborn" } : { id: expected, life: "stillborn", seal };
86
+ }
87
+ catch (error) {
88
+ if (isHeartAbsent(error))
89
+ return { id: expected, life: "unborn" };
90
+ throw error;
91
+ }
92
+ }
55
93
  async function bornListRow(paths, expected, snapshot) {
56
94
  snapshot ??= await readHeart(paths);
57
95
  if (snapshot.soul === null)
@@ -69,7 +107,6 @@ async function bornListRow(paths, expected, snapshot) {
69
107
  ...(snapshot.soul.description === undefined ? {} : { description: snapshot.soul.description }),
70
108
  life: currentLife,
71
109
  lifeAt: lifeAt(currentLife, snapshot.latestBody, snapshot.latestKill, snapshot.soul.createdAt),
72
- confinement: snapshot.soul.confinement,
73
110
  pending: snapshot.pending.map((tell) => tell.id),
74
111
  };
75
112
  }
@@ -81,7 +118,7 @@ async function bornStatus(paths, expected, budget) {
81
118
  const resumeUnsupported = current.life === "stranded"
82
119
  && snapshot.latestSession?.provider === snapshot.soul.provider.name
83
120
  && resolveProviderExecution(snapshot.soul.provider).adapter.resume === undefined;
84
- const slice = await activitySlice(paths, { limit: Number.MAX_SAFE_INTEGER });
121
+ const slice = await activitySlice(paths);
85
122
  return {
86
123
  id: current.id,
87
124
  life: current.life,
@@ -92,10 +129,6 @@ async function bornStatus(paths, expected, budget) {
92
129
  : selectSnapshot(projectTurns(slice.rows), budget),
93
130
  };
94
131
  }
95
- /** Package-internal action observation; it uses the same snapshot selector as status. */
96
- export async function readActionFeedbackStatus(worldPath, id) {
97
- return await bornStatus(pathsForAkuId(worldPath, id), id);
98
- }
99
132
  /** Package-internal budgeted observation; Fleet allocates, Akuma still selects. */
100
133
  export async function readBudgetedStatus(worldPath, id, input) {
101
134
  if (!Number.isSafeInteger(input.ordinaryBudget) || input.ordinaryBudget < 0) {
@@ -104,15 +137,22 @@ export async function readBudgetedStatus(worldPath, id, input) {
104
137
  const status = await bornStatus(pathsForAkuId(worldPath, id), id, ordinarySnapshotBudget(input.ordinaryBudget));
105
138
  return { status, ordinarySelected: ordinarySelectedCount(status.timeline) };
106
139
  }
107
- function diagnostic(error) {
108
- return error instanceof Error ? error.message : String(error);
140
+ /** Package-internal birth projection used by the composed Library call result. */
141
+ export async function readAkumaBirthCwd(worldPath, id) {
142
+ const soul = await readSoul(pathsForAkuId(worldPath, id));
143
+ if (soul === null)
144
+ throw new AkumaNotBornError(id);
145
+ return soul.cwd;
109
146
  }
110
147
  export class AkumaHandle {
111
148
  id;
112
149
  worldPath;
113
- constructor(id, worldPath) {
150
+ [CALL_EXECUTION];
151
+ constructor(id, worldPath, execution) {
114
152
  this.id = id;
115
153
  this.worldPath = worldPath;
154
+ if (execution !== undefined)
155
+ this[CALL_EXECUTION] = execution;
116
156
  }
117
157
  get paths() {
118
158
  return pathsForAkuId(this.worldPath, this.id);
@@ -133,11 +173,7 @@ export class AkumaHandle {
133
173
  if (!Number.isSafeInteger(limit) || limit <= 0 || limit > 5_000) {
134
174
  throw new TypeError("Akuma history limit must be a positive safe integer no greater than 5000");
135
175
  }
136
- const slice = await activitySlice(this.paths, {
137
- ...(input.before === undefined ? {} : { before: input.before }),
138
- ...(input.since === undefined ? {} : { since: input.since }),
139
- limit: 5_000,
140
- });
176
+ const slice = await activitySlice(this.paths);
141
177
  return selectHistory(projectTurns(slice.rows, {
142
178
  lowestRetained: slice.lowestRetained,
143
179
  highest: slice.highest,
@@ -254,9 +290,9 @@ export class AkumaHandle {
254
290
  provider: source.provider,
255
291
  options: source.options,
256
292
  ...(source.readonly === undefined ? {} : { readonly: source.readonly }),
293
+ allowed: source.allowed,
257
294
  cwd: source.cwd,
258
295
  origin: { kind: "fork", parent: this.id, at: input.at },
259
- confinement: source.confinement,
260
296
  },
261
297
  birthSession,
262
298
  }),
@@ -264,7 +300,11 @@ export class AkumaHandle {
264
300
  return { kind: "forked", child: child.id };
265
301
  }
266
302
  catch (error) {
267
- return { kind: "upstream-forked", childSession, diagnostic: diagnostic(error) };
303
+ return {
304
+ kind: "upstream-forked",
305
+ childSession,
306
+ diagnostic: diagnostic(error),
307
+ };
268
308
  }
269
309
  }
270
310
  async kill() {
@@ -309,52 +349,72 @@ export class AkumaHandle {
309
349
  : { kind: "no-answer" };
310
350
  }
311
351
  }
352
+ /** Package-internal provenance retained only by the handle returned from call. */
353
+ export function akumaCallExecution(handle) {
354
+ return handle[CALL_EXECUTION];
355
+ }
312
356
  export class Akuma {
313
357
  path;
314
- configuredSettings;
315
- constructor(path, configuredSettings) {
358
+ configuration;
359
+ constructor(path, configuration) {
316
360
  this.path = path;
317
- this.configuredSettings = configuredSettings;
361
+ this.configuration = configuration;
318
362
  }
319
- static of(root, settings) {
363
+ static of(root, input = {}) {
320
364
  if (typeof root !== "string")
321
365
  throw new TypeError("Akuma.of root must be a WorldRoot");
322
- return new Akuma(root, settings);
323
- }
324
- async settings() {
325
- return this.configuredSettings ?? await readSettings({ root: this.path });
366
+ return new Akuma(root, input);
326
367
  }
327
368
  of(input) {
328
369
  return new AkumaHandle(parseAkuId(input.id).id, this.path);
329
370
  }
330
371
  async listArchetypes() {
331
- return readArchetypes({ settings: await this.settings() });
372
+ return readArchetypes(this.configuration.home === undefined ? {} : { home: this.configuration.home });
332
373
  }
333
374
  async call(input) {
375
+ return await this[CALL_WITH_CONTEXT](input, { initiatorCwd: process.cwd() });
376
+ }
377
+ async [CALL_WITH_CONTEXT](input, context) {
334
378
  const name = archetypeName(input.archetype);
335
- const archetype = await loadArchetype({ name, settings: await this.settings() });
336
- const provider = archetype.adapter;
337
- const cwd = resolve(input.cwd ?? this.path);
338
- const recipe = Object.freeze({
379
+ const home = this.configuration.home === undefined ? {} : { home: this.configuration.home };
380
+ const settings = this.configuration.settings ?? await readSettings({ root: this.path, ...home });
381
+ const archetype = await loadArchetype({ name, ...home, settings });
382
+ const allowed = input.allowed === undefined
383
+ ? archetype.allowed
384
+ : decodeAllowedActions(input.allowed, "Akuma call allowed");
385
+ const requests = injectedBodyRequests();
386
+ const requestRecipe = Object.freeze({
339
387
  ...(archetype.description === undefined ? {} : { description: archetype.description }),
340
388
  provider: archetype.provider,
341
389
  options: archetype.options,
342
390
  ...(archetype.readonly === undefined ? {} : { readonly: archetype.readonly }),
343
- confinement: provider.confinement({ cwd, options: archetype.options }),
391
+ allowed,
344
392
  });
345
- const requests = injectedBodyRequests();
346
393
  if (requests !== null) {
394
+ const cwd = input.cwd === undefined
395
+ ? undefined
396
+ : context?.cwdCanonical === true ? input.cwd : await canonicalBirthCwd(input.cwd);
347
397
  const child = await requestBodyCall({
348
398
  directory: requests,
349
399
  id: randomUUID(),
350
400
  world: this.path,
351
401
  archetype: name,
352
402
  body: input.body,
353
- cwd,
354
- recipe,
403
+ ...(cwd === undefined ? {} : { cwd }),
404
+ recipe: requestRecipe,
405
+ });
406
+ const bornCwd = await readAkumaBirthCwd(this.path, child);
407
+ return new AkumaHandle(child, this.path, {
408
+ cwd: bornCwd,
409
+ source: cwd === undefined ? "caller" : "input",
355
410
  });
356
- return new AkumaHandle(child, this.path);
357
411
  }
412
+ const initiatorCwd = context.initiatorCwd;
413
+ const selectedCwd = input.cwd ?? initiatorCwd ?? this.path;
414
+ const cwd = input.cwd !== undefined && context?.cwdCanonical === true
415
+ ? input.cwd
416
+ : await canonicalBirthCwd(selectedCwd);
417
+ const recipe = requestRecipe;
358
418
  const published = await publishAkuma({
359
419
  worldPath: this.path,
360
420
  archetype: archetype.name,
@@ -363,18 +423,17 @@ export class Akuma {
363
423
  seed: {
364
424
  id: allocated.id,
365
425
  archetype: allocated.archetype,
366
- ...(archetype.description === undefined ? {} : { description: archetype.description }),
367
- provider: archetype.provider,
368
- options: archetype.options,
369
- ...(archetype.readonly === undefined ? {} : { readonly: archetype.readonly }),
426
+ ...recipe,
370
427
  cwd,
371
428
  origin: { kind: "direct" },
372
- confinement: recipe.confinement,
373
429
  },
374
430
  initialBody: input.body,
375
431
  }),
376
432
  });
377
- return new AkumaHandle(published.id, this.path);
433
+ return new AkumaHandle(published.id, this.path, {
434
+ cwd,
435
+ source: input.cwd !== undefined ? "input" : initiatorCwd === undefined ? "world" : "process",
436
+ });
378
437
  }
379
438
  async list(input = {}) {
380
439
  if (typeof input !== "object" || input === null || Array.isArray(input)) {
@@ -399,28 +458,20 @@ export class Akuma {
399
458
  }
400
459
  const rows = [];
401
460
  for (const name of names) {
461
+ let physical;
402
462
  try {
403
- const physical = akuIdFromDirectoryName(name);
404
- if (selected !== undefined && physical.archetype !== selected)
405
- continue;
406
- const paths = akumaPaths({ runRoot, archetype: physical.archetype, suffix: physical.suffix });
407
- const snapshot = await readHeart(paths);
408
- if (snapshot.soul !== null) {
409
- rows.push(await bornListRow(paths, physical.id, snapshot));
410
- continue;
411
- }
412
- if (await probeLeash(paths) === "held") {
413
- rows.push({ id: physical.id, life: "unborn" });
414
- continue;
415
- }
416
- const seal = await readSeal(paths);
417
- rows.push(seal === null
418
- ? { id: physical.id, life: "unborn" }
419
- : { id: physical.id, life: "stillborn", seal });
463
+ physical = akuIdFromDirectoryName(name);
420
464
  }
421
465
  catch {
422
466
  continue;
423
467
  }
468
+ if (selected !== undefined && physical.archetype !== selected)
469
+ continue;
470
+ const paths = akumaPaths({ runRoot, archetype: physical.archetype, suffix: physical.suffix });
471
+ try {
472
+ rows.push(await fleetListRow(paths, physical.id));
473
+ }
474
+ catch { }
424
475
  }
425
476
  return {
426
477
  rows,
@@ -428,3 +479,7 @@ export class Akuma {
428
479
  };
429
480
  }
430
481
  }
482
+ /** Package-internal call path for a composition owner that already canonicalized cwd. */
483
+ export async function callAkumaWithContext(akuma, input, context) {
484
+ return await akuma[CALL_WITH_CONTEXT](input, context);
485
+ }
@@ -0,0 +1,7 @@
1
+ export declare const ALLOWED_ACTIONS: readonly ["akuma.call", "akuma.kill", "akuma.tell", "contract.deliver", "contract.review", "task.add", "task.addDocument", "task.compose", "task.done", "task.drop", "task.hold", "task.resume", "task.start", "task.stop", "task.update"];
2
+ export type AllowedAction = (typeof ALLOWED_ACTIONS)[number];
3
+ export type AllowedActions = readonly AllowedAction[];
4
+ export declare function isAllowedAction(value: unknown): value is AllowedAction;
5
+ export declare function decodeAllowedActions(value: unknown, label?: string): AllowedActions;
6
+ export declare function effectiveAllowedActions(value: unknown): AllowedActions;
7
+ export declare function clipAllowedActions(requested: AllowedActions, parent: AllowedActions): AllowedActions;