@astrosheep/keiyaku 4.0.5 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) 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 +1 -1
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +15 -7
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -3
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +10 -4
  8. package/build/src/akuma/akuma.d.ts +2 -0
  9. package/build/src/akuma/akuma.js +26 -3
  10. package/build/src/akuma/archetype.d.ts +3 -1
  11. package/build/src/akuma/archetype.js +19 -7
  12. package/build/src/akuma/body-turn.d.ts +64 -0
  13. package/build/src/akuma/body-turn.js +449 -0
  14. package/build/src/akuma/body.d.ts +3 -7
  15. package/build/src/akuma/body.js +9 -420
  16. package/build/src/akuma/heart/facts.d.ts +2 -0
  17. package/build/src/akuma/heart/facts.js +3 -1
  18. package/build/src/akuma/heart/index.js +12 -2
  19. package/build/src/akuma/heart/rows.js +4 -1
  20. package/build/src/akuma/heart/schema.d.ts +1 -1
  21. package/build/src/akuma/heart/schema.js +3 -2
  22. package/build/src/akuma/heart/timeline.d.ts +1 -0
  23. package/build/src/akuma/heart/timeline.js +19 -0
  24. package/build/src/akuma/nuke.d.ts +2 -0
  25. package/build/src/akuma/nuke.js +152 -0
  26. package/build/src/akuma/provider-recipe.d.ts +2 -0
  27. package/build/src/akuma/provider-recipe.js +10 -0
  28. package/build/src/akuma/provider.d.ts +3 -1
  29. package/build/src/akuma/providers/acp/config.d.ts +10 -0
  30. package/build/src/akuma/providers/acp/config.js +45 -0
  31. package/build/src/akuma/providers/acp/core.d.ts +5 -2
  32. package/build/src/akuma/providers/acp/core.js +35 -16
  33. package/build/src/akuma/providers/acp/index.d.ts +1 -8
  34. package/build/src/akuma/providers/acp/index.js +10 -39
  35. package/build/src/akuma/providers/claude/index.d.ts +1 -1
  36. package/build/src/akuma/providers/claude/index.js +14 -5
  37. package/build/src/akuma/providers/codex-app-server/index.js +9 -1
  38. package/build/src/akuma/providers/grok-build/index.js +16 -2
  39. package/build/src/akuma/providers/index.d.ts +3 -2
  40. package/build/src/akuma/providers/index.js +37 -37
  41. package/build/src/akuma/providers/opencode-sdk/index.js +9 -0
  42. package/build/src/akuma/providers/opencode-sdk/session.d.ts +1 -1
  43. package/build/src/akuma/providers/opencode-sdk/session.js +1 -1
  44. package/build/src/akuma/providers/pi/index.d.ts +1 -1
  45. package/build/src/akuma/providers/pi/index.js +30 -12
  46. package/build/src/akuma/request-serve.d.ts +1 -0
  47. package/build/src/akuma/request-serve.js +31 -31
  48. package/build/src/akuma/request-wire.d.ts +3 -2
  49. package/build/src/akuma/request-wire.js +5 -2
  50. package/build/src/akuma-body.js +15 -1
  51. package/build/src/alias/index.d.ts +1 -0
  52. package/build/src/alias/index.js +34 -1
  53. package/build/src/body/amend.js +0 -9
  54. package/build/src/body/region.js +2 -2
  55. package/build/src/cli/accepted.js +6 -0
  56. package/build/src/cli/commands/akuma-invoke.js +1 -0
  57. package/build/src/cli/commands/akuma.d.ts +1 -0
  58. package/build/src/cli/commands/akuma.js +11 -8
  59. package/build/src/cli/commands/contract.d.ts +28 -15
  60. package/build/src/cli/commands/contract.js +34 -18
  61. package/build/src/cli/commands/install.d.ts +2 -2
  62. package/build/src/cli/commands/install.js +6 -6
  63. package/build/src/cli/commands/nuke.d.ts +10 -0
  64. package/build/src/cli/commands/nuke.js +20 -0
  65. package/build/src/cli/commands/task-invoke.d.ts +19 -1
  66. package/build/src/cli/commands/task-invoke.js +63 -29
  67. package/build/src/cli/commands/task-query.d.ts +2 -2
  68. package/build/src/cli/commands/task-query.js +1 -2
  69. package/build/src/cli/commands/task.js +30 -22
  70. package/build/src/cli/coordinates.d.ts +5 -2
  71. package/build/src/cli/coordinates.js +5 -52
  72. package/build/src/cli/invoke.d.ts +5 -4
  73. package/build/src/cli/invoke.js +89 -59
  74. package/build/src/cli/main.d.ts +0 -2
  75. package/build/src/cli/main.js +4 -140
  76. package/build/src/cli/parse.d.ts +15 -2
  77. package/build/src/cli/parse.js +73 -8
  78. package/build/src/cli/render/akuma.js +95 -49
  79. package/build/src/cli/render/catalog.js +5 -1
  80. package/build/src/cli/render/contract.js +72 -49
  81. package/build/src/cli/render/kanshi.js +157 -99
  82. package/build/src/cli/render/nuke.d.ts +3 -0
  83. package/build/src/cli/render/nuke.js +8 -0
  84. package/build/src/cli/render/receipt.d.ts +1 -0
  85. package/build/src/cli/render/receipt.js +18 -14
  86. package/build/src/cli/render/refusal.d.ts +2 -1
  87. package/build/src/cli/render/refusal.js +37 -0
  88. package/build/src/cli/render/task.js +63 -11
  89. package/build/src/cli/render/text.js +6 -1
  90. package/build/src/cli/result.d.ts +28 -2
  91. package/build/src/cli/runtime.d.ts +2 -0
  92. package/build/src/cli/runtime.js +140 -0
  93. package/build/src/cli/usage.d.ts +0 -2
  94. package/build/src/cli/usage.js +0 -4
  95. package/build/src/contract-worktree.d.ts +26 -12
  96. package/build/src/contract-worktree.js +119 -64
  97. package/build/src/git/hooks.d.ts +2 -0
  98. package/build/src/git/hooks.js +34 -1
  99. package/build/src/git/integration.d.ts +4 -0
  100. package/build/src/git/integration.js +38 -0
  101. package/build/src/git/nuke.d.ts +2 -0
  102. package/build/src/git/nuke.js +92 -0
  103. package/build/src/git/process.d.ts +2 -0
  104. package/build/src/git/repository.js +4 -1
  105. package/build/src/git/target-placement.d.ts +2 -1
  106. package/build/src/git/target-placement.js +6 -7
  107. package/build/src/git/tender.d.ts +14 -2
  108. package/build/src/git/tender.js +45 -6
  109. package/build/src/git/workspace.d.ts +3 -0
  110. package/build/src/kanshi/read.js +37 -13
  111. package/build/src/kanshi/report.d.ts +2 -1
  112. package/build/src/library/akuma-creation.d.ts +1 -0
  113. package/build/src/library/akuma-creation.js +8 -1
  114. package/build/src/library/audit.d.ts +1 -0
  115. package/build/src/library/audit.js +1 -0
  116. package/build/src/library/continuation.d.ts +26 -0
  117. package/build/src/library/continuation.js +78 -0
  118. package/build/src/library/contract.d.ts +14 -8
  119. package/build/src/library/contract.js +82 -35
  120. package/build/src/library/delivery.d.ts +18 -11
  121. package/build/src/library/keiyaku.d.ts +5 -1
  122. package/build/src/library/keiyaku.js +2 -0
  123. package/build/src/library/mutation.d.ts +1 -0
  124. package/build/src/library/mutation.js +14 -4
  125. package/build/src/library/nuke.d.ts +14 -0
  126. package/build/src/library/nuke.js +54 -0
  127. package/build/src/library/reconcile.js +5 -2
  128. package/build/src/library/refusal.d.ts +10 -1
  129. package/build/src/library/repo.d.ts +1 -0
  130. package/build/src/library/repo.js +2 -0
  131. package/build/src/protocol/audit.js +12 -5
  132. package/build/src/protocol/completion.d.ts +11 -1
  133. package/build/src/protocol/completion.js +68 -15
  134. package/build/src/protocol/deliver.d.ts +25 -3
  135. package/build/src/protocol/deliver.js +148 -14
  136. package/build/src/protocol/intent.d.ts +1 -0
  137. package/build/src/protocol/intent.js +7 -1
  138. package/build/src/protocol/operations.d.ts +36 -4
  139. package/build/src/protocol/operations.js +2 -2
  140. package/build/src/protocol/placement.d.ts +9 -1
  141. package/build/src/protocol/placement.js +5 -4
  142. package/build/src/protocol/read/status.d.ts +16 -4
  143. package/build/src/protocol/read/status.js +54 -12
  144. package/build/src/protocol/review.d.ts +1 -0
  145. package/build/src/protocol/review.js +8 -0
  146. package/build/src/runtime/proc/run.js +9 -5
  147. package/build/src/settlement/settle.js +1 -2
  148. package/build/src/task/board.d.ts +21 -2
  149. package/build/src/task/board.js +25 -12
  150. package/build/src/task/compose.d.ts +1 -1
  151. package/build/src/task/compose.js +2 -7
  152. package/build/src/task/context.d.ts +14 -2
  153. package/build/src/task/context.js +30 -7
  154. package/build/src/task/identity.js +14 -4
  155. package/build/src/task/index.d.ts +7 -5
  156. package/build/src/task/index.js +21 -18
  157. package/build/src/task/mutation.d.ts +7 -2
  158. package/build/src/task/mutation.js +14 -6
  159. package/build/src/task/operations.d.ts +14 -7
  160. package/build/src/task/operations.js +37 -50
  161. package/build/src/task/query.js +2 -2
  162. package/build/src/task/store.d.ts +3 -0
  163. package/build/src/task/store.js +21 -2
  164. package/build/src/workspace-place.d.ts +2 -0
  165. package/build/src/workspace-place.js +27 -1
  166. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keiyaku",
3
- "version": "0.1.0+codex.20260819092206",
3
+ "version": "0.1.0+codex.20260819155641",
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.20260819092206",
3
+ "version": "0.1.0+codex.20260819155641",
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.20260819092206",
3
+ "version": "0.1.0+codex.20260819155641",
4
4
  "type": "module",
5
5
  "main": "./opencode.js",
6
6
  "keywords": ["pi-package"],
@@ -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] [--allowed <product.action>]... [--wait <duration> | -d | --detach] [--json] (<prompt> | -)
34
+ keiyaku -C <cwd> call <akuma-name> [--contract <kei/...>] [--alias @name] [--readonly] [--allowed <product.action>]... [--wait <duration> | -d | --detach] (<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] [--allowed <product.action>]... [--wait <duration> | -d | --detach] [--json] (<prompt> | -)
16
+ keiyaku -C <cwd> call <akuma-name> [--alias @name] [--readonly] [--allowed <product.action>]... [--wait <duration> | -d | --detach] (<prompt> | -)
17
17
  ```
18
18
 
19
19
  Give the worker's initial prompt as one argument (quote it when it contains
@@ -44,14 +44,22 @@ outgrows its Archetype mid-life.
44
44
  keiyaku status # deep fleet observation
45
45
  keiyaku status <aku/...|@alias> # one worker's snapshot
46
46
  keiyaku ls aku/ # shallow catalog; also aku/<archetype>/ and "aku/*/*"
47
- keiyaku wait <selector>... [--any | --all] [--timeout <duration>] [--json]
47
+ keiyaku wait <selector>... [--any | --all] [--timeout <duration>]
48
48
  ```
49
49
 
50
- `wait` accepts complete ids, aliases, and Akuma globs, resolved once into a
51
- stable deduplicated set. One member needs no mode; two or more require exactly
52
- one of `--any` or `--all`. A timeout returns the current real snapshot — never
53
- a fabricated timeout state — and `--any` leaves the unfinished members
54
- running.
50
+ `wait` accepts complete ids, aliases, and Akuma globs. Wait on one Akuma without
51
+ a mode. When observing multiple Akuma, prefer one plural wait over separate
52
+ waits and choose exactly one mode:
53
+
54
+ ```bash
55
+ keiyaku -C <cwd> wait @worker-a --timeout 5m
56
+ keiyaku -C <cwd> wait @worker-a @worker-b --all --timeout 5m
57
+ keiyaku -C <cwd> wait @worker-a @worker-b --any --timeout 5m
58
+ ```
59
+
60
+ `--all` waits until every selected Akuma stops running. `--any` returns when the
61
+ first one stops and leaves the others alone. When the timeout expires, `wait`
62
+ returns their current status without stopping them.
55
63
 
56
64
  ## Steer
57
65
 
@@ -66,9 +66,11 @@ reader would otherwise re-derive wrongly. Never narrative. If Objective and
66
66
  Design read the same without a sentence here, delete it.>
67
67
 
68
68
  ## Objective
69
- <One observable end-state, judged done/not-done without reading Design.
70
- If "and" joins independently acceptable outcomes, bind two Contracts. A
71
- single outcome may still require several arcs during fulfillment.>
69
+ <One end-state you could watch happen, named at the level of intent and goal
70
+ — above implementation detail, above spec recital. If "and" joins two
71
+ outcomes that would each stand alone, bind two Contracts. Even an outcome
72
+ that cannot split into two may still need arcs to organize its
73
+ fulfillment.>
72
74
 
73
75
  ## Design
74
76
  <The closed decisions. A statement belongs here exactly when a test-green
@@ -85,7 +85,8 @@ Read first:
85
85
  - <owner documents governing this delivery>
86
86
  - <source files named or selected from the Contract Region for this work>
87
87
  Objective:
88
- <bounded assignment>
88
+ <the assignment's high-level intent and goal — not implementation detail,
89
+ not a restatement of the Contract terms>
89
90
  ```
90
91
 
91
92
  Every `Read first` path is relative to `Worktree` unless it is absolute. The
@@ -196,11 +197,16 @@ candidate.
196
197
  Deliver when the worktree content is the candidate you intend to land:
197
198
 
198
199
  ```bash
199
- keiyaku deliver <contract>
200
+ keiyaku deliver <contract> --include-dirty
200
201
  ```
201
202
 
202
- `deliver` freshly tenders the clean `HEAD`, records the candidate, and requests
203
- placement. When a current audit attestation names the identical integration
203
+ This example includes all non-ignored staged, unstaged, and untracked bytes in
204
+ the candidate. Use `--include-dirty` only when the complete current workspace
205
+ is the intended delivery; otherwise commit the intended bytes and run
206
+ `keiyaku deliver <contract>`.
207
+
208
+ `deliver` freshly tenders the candidate, records it, and requests placement.
209
+ When a current audit attestation names the identical integration
204
210
  snapshot and Verification segment, deliver reuses it; otherwise it runs the
205
211
  declarations. Worktree, target, policy, document, Verification, or
206
212
  snapshot-producing option changes prevent reuse. If the workspace is dirty, the refusal
@@ -10,6 +10,7 @@ export type AkumaListRow = Readonly<{
10
10
  description?: string;
11
11
  life: AkumaLife;
12
12
  lifeAt: string | null;
13
+ lastActivityAt: string | null;
13
14
  pending: readonly string[];
14
15
  }>;
15
16
  export type AkumaStatus = Readonly<{
@@ -46,6 +47,7 @@ export type AkumaCallInput = Readonly<{
46
47
  archetype: string;
47
48
  body: string;
48
49
  cwd?: string;
50
+ readonly?: true;
49
51
  allowed?: readonly AllowedAction[];
50
52
  }>;
51
53
  type AkumaCallContext = Readonly<{
@@ -24,6 +24,13 @@ async function canonicalBirthCwd(input) {
24
24
  throw new Error(`cwd is not an existing directory: ${input}`);
25
25
  }
26
26
  }
27
+ function callReadonly(value) {
28
+ if (value === undefined)
29
+ return {};
30
+ if (value !== true)
31
+ throw new TypeError("Akuma call readonly must be true");
32
+ return { readonly: true };
33
+ }
27
34
  const CALL_EXECUTION = Symbol("akuma-call-execution");
28
35
  const CALL_WITH_CONTEXT = Symbol("akuma-call-with-context");
29
36
  export class AkumaNotBornError extends Error {
@@ -107,6 +114,7 @@ async function bornListRow(paths, expected, snapshot) {
107
114
  ...(snapshot.soul.description === undefined ? {} : { description: snapshot.soul.description }),
108
115
  life: currentLife,
109
116
  lifeAt: lifeAt(currentLife, snapshot.latestBody, snapshot.latestKill, snapshot.soul.createdAt),
117
+ lastActivityAt: snapshot.lastActivityAt,
110
118
  pending: snapshot.pending.map((tell) => tell.id),
111
119
  };
112
120
  }
@@ -117,7 +125,7 @@ async function bornStatus(paths, expected, budget) {
117
125
  const current = await bornListRow(paths, expected, snapshot);
118
126
  const resumeUnsupported = current.life === "stranded"
119
127
  && snapshot.latestSession?.provider === snapshot.soul.provider.name
120
- && resolveProviderExecution(snapshot.soul.provider).adapter.resume === undefined;
128
+ && (await resolveProviderExecution(snapshot.soul.provider)).adapter.resume === undefined;
121
129
  const slice = await activitySlice(paths);
122
130
  return {
123
131
  id: current.id,
@@ -218,6 +226,15 @@ export class AkumaHandle {
218
226
  : "unavailable" };
219
227
  }
220
228
  const settledBody = (await readHeart(this.paths)).latestBody;
229
+ if (settledBody?.sequence === request.body.sequence && settledBody.hung !== undefined) {
230
+ try {
231
+ await leash.clearPause(this.paths);
232
+ }
233
+ finally {
234
+ leash.release();
235
+ }
236
+ return { kind: "unavailable", evidence: "hung" };
237
+ }
221
238
  if (settledBody?.sequence !== request.body.sequence || settledBody.end === undefined) {
222
239
  try {
223
240
  await leash.clearPause(this.paths);
@@ -253,7 +270,7 @@ export class AkumaHandle {
253
270
  throw new AkumaNotBornError(this.id);
254
271
  if (source.id !== this.id)
255
272
  throw new Error("Akuma soul does not match its coordinate");
256
- const adapter = resolveProviderExecution(source.provider).adapter;
273
+ const adapter = (await resolveProviderExecution(source.provider)).adapter;
257
274
  if (adapter.fork === undefined)
258
275
  return { kind: "provider-cannot-fork", provider: source.provider.name };
259
276
  const point = await readForkPoint(this.paths, input.at);
@@ -375,10 +392,16 @@ export class Akuma {
375
392
  return await this[CALL_WITH_CONTEXT](input, { initiatorCwd: process.cwd() });
376
393
  }
377
394
  async [CALL_WITH_CONTEXT](input, context) {
395
+ const readonly = callReadonly(input.readonly);
378
396
  const name = archetypeName(input.archetype);
379
397
  const home = this.configuration.home === undefined ? {} : { home: this.configuration.home };
380
398
  const settings = this.configuration.settings ?? await readSettings({ root: this.path, ...home });
381
- const archetype = await loadArchetype({ name, ...home, settings });
399
+ const archetype = await loadArchetype({
400
+ name,
401
+ ...home,
402
+ settings,
403
+ ...readonly,
404
+ });
382
405
  const allowed = input.allowed === undefined
383
406
  ? archetype.allowed
384
407
  : decodeAllowedActions(input.allowed, "Akuma call allowed");
@@ -8,6 +8,7 @@ type DecodedArchetype = Readonly<{
8
8
  provider: string;
9
9
  description?: string;
10
10
  options: ProviderOptions;
11
+ readonly?: true;
11
12
  allowed: AllowedActions;
12
13
  }>;
13
14
  export type ArchetypeCatalogRow = Readonly<{
@@ -18,7 +19,7 @@ export type ArchetypeCatalogRow = Readonly<{
18
19
  type ArchetypeDefinition = DecodedArchetype & Readonly<{
19
20
  adapter: ProviderAdapter;
20
21
  }>;
21
- type AdmittedArchetype = Omit<ArchetypeDefinition, "provider"> & Readonly<{
22
+ type AdmittedArchetype = Omit<ArchetypeDefinition, "provider" | "readonly"> & Readonly<{
22
23
  provider: ProviderExecution;
23
24
  readonly?: ReadonlyRestraint;
24
25
  }>;
@@ -39,5 +40,6 @@ export declare function loadArchetype(input: Readonly<{
39
40
  name: string;
40
41
  home?: string;
41
42
  settings: Settings;
43
+ readonly?: true;
42
44
  }>): Promise<AdmittedArchetype>;
43
45
  export {};
@@ -96,7 +96,11 @@ function decodeArchetype(name, path, markdown) {
96
96
  const network = archetypeEnum(values, "network", ["disabled", "enabled"]);
97
97
  const description = archetypeField(values, "description");
98
98
  const allowed = effectiveAllowedActions(values.allowed);
99
+ const systemPromptMode = archetypeEnum(values, "systemPromptMode", ["append", "replace"]);
99
100
  const systemPrompt = lines.slice(closing + 1).join("\n");
101
+ if (systemPromptMode !== undefined && systemPrompt.length === 0) {
102
+ throw new TypeError("Akuma systemPromptMode requires a nonempty Markdown body");
103
+ }
100
104
  return Object.freeze({
101
105
  name,
102
106
  path,
@@ -105,10 +109,13 @@ function decodeArchetype(name, path, markdown) {
105
109
  options: decodeProviderOptions({
106
110
  ...(model === undefined ? {} : { model }),
107
111
  ...(effort === undefined ? {} : { effort }),
108
- ...(readonly === undefined ? {} : { readonly }),
109
112
  ...(network === undefined ? {} : { network }),
110
- ...(systemPrompt.length === 0 ? {} : { systemPrompt }),
113
+ ...(systemPrompt.length === 0 ? {} : {
114
+ systemPrompt,
115
+ systemPromptMode: systemPromptMode ?? "append",
116
+ }),
111
117
  }),
118
+ ...(readonly === undefined ? {} : { readonly }),
112
119
  allowed,
113
120
  });
114
121
  }
@@ -184,10 +191,10 @@ function providerExecution(settings, name) {
184
191
  return decodeProviderRecipe({ name, ...builtin });
185
192
  throw new TypeError(`unknown provider ${name}`);
186
193
  }
187
- function admitArchetype(archetype, settings) {
194
+ async function admitArchetype(archetype, settings, callReadonly) {
188
195
  let selected;
189
196
  try {
190
- selected = resolveProviderExecution(providerExecution(settings, archetype.provider));
197
+ selected = await resolveProviderExecution(providerExecution(settings, archetype.provider));
191
198
  }
192
199
  catch (error) {
193
200
  if (error instanceof TypeError)
@@ -196,12 +203,17 @@ function admitArchetype(archetype, settings) {
196
203
  }
197
204
  const execution = selected.execution;
198
205
  const adapter = selected.adapter;
199
- const admission = adapter.admitOptions(archetype.options);
206
+ const effectiveReadonly = archetype.readonly === true || callReadonly === true;
207
+ const admission = adapter.admitOptions({
208
+ ...archetype.options,
209
+ ...(effectiveReadonly ? { readonly: true } : {}),
210
+ });
200
211
  if (admission.kind === "refused") {
201
212
  throw new AkumaArchetypeError(archetype.name, [archetype.path], `is unsupported: ${admission.diagnostic}`);
202
213
  }
214
+ const { readonly: _readonly, ...definition } = archetype;
203
215
  return Object.freeze({
204
- ...archetype,
216
+ ...definition,
205
217
  provider: execution,
206
218
  adapter,
207
219
  options: admission.options,
@@ -223,7 +235,7 @@ export async function loadArchetype(input) {
223
235
  throw new AkumaArchetypeError(name, [path], `could not be read: ${error instanceof Error ? error.message : String(error)}`);
224
236
  }
225
237
  try {
226
- return admitArchetype(decodeArchetype(name, path, markdown), input.settings);
238
+ return await admitArchetype(decodeArchetype(name, path, markdown), input.settings, input.readonly);
227
239
  }
228
240
  catch (error) {
229
241
  if (error instanceof AkumaArchetypeError)
@@ -0,0 +1,64 @@
1
+ import { type HeartSnapshot, type HeldAkumaLeash, type ResumeCoordinate, type Soul, type TellFact } from "./heart/index.js";
2
+ import type { AkumaPaths } from "./identity.js";
3
+ import { type ProviderAdapter, type TurnResult } from "./provider.js";
4
+ import { type RequestChildLaunch, type UpstreamExecutionPort } from "./request-serve.js";
5
+ export declare const CONTROL_RESPONSE_MS = 1000;
6
+ export declare class BodySupervisor {
7
+ private readonly paths;
8
+ private readonly bodySequence;
9
+ private readonly leash;
10
+ readonly signal: AbortSignal;
11
+ private readonly controller;
12
+ private readonly finished;
13
+ private readonly observer;
14
+ private waiter;
15
+ private observation;
16
+ private stopping?;
17
+ private constructor();
18
+ static open(paths: AkumaPaths, bodySequence: number, leash: HeldAkumaLeash): Promise<BodySupervisor>;
19
+ get reason(): "control" | "heart-gone" | undefined;
20
+ current(): HeartSnapshot;
21
+ recordHung(diagnostic: string, at: string): Promise<void>;
22
+ refresh(): Promise<HeartSnapshot>;
23
+ next(after: HeartSnapshot): Promise<HeartSnapshot>;
24
+ cancel(reason: "control" | "heart-gone"): void;
25
+ close(): Promise<void>;
26
+ private publish;
27
+ private observe;
28
+ }
29
+ export declare function turnRecipe(paths: AkumaPaths, soul: Soul): Promise<Readonly<{
30
+ cwd: string;
31
+ options: Soul["options"];
32
+ session?: ResumeCoordinate;
33
+ }>>;
34
+ export type DrivenTurn = (Extract<TurnResult, {
35
+ kind: "answered";
36
+ }> & Readonly<{
37
+ session?: ResumeCoordinate;
38
+ }>) | Extract<TurnResult, {
39
+ kind: "failed";
40
+ }>;
41
+ export type DriveTurnInput = Readonly<{
42
+ paths: AkumaPaths;
43
+ soul: Soul;
44
+ adapter: ProviderAdapter;
45
+ bodySequence: number;
46
+ body: string;
47
+ call?: string;
48
+ launchTells: readonly TellFact[];
49
+ supervisor: BodySupervisor;
50
+ runtimeSpawn(launch: RequestChildLaunch): Promise<void>;
51
+ upstream?: UpstreamExecutionPort;
52
+ now(): string;
53
+ }>;
54
+ export declare function driveTurn(input: DriveTurnInput): Promise<(DrivenTurn & Readonly<{
55
+ turnSequence: number;
56
+ }>) | Readonly<{
57
+ kind: "stopped";
58
+ }> | Readonly<{
59
+ kind: "hung";
60
+ }> | Readonly<{
61
+ kind: "handoff";
62
+ }> | Readonly<{
63
+ kind: "resume-unsupported";
64
+ }>>;