@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
@@ -0,0 +1,33 @@
1
+ import { TASK_MUTATION_ACTIONS } from "../task/mutation.js";
2
+ export const ALLOWED_ACTIONS = Object.freeze([
3
+ "akuma.call",
4
+ "akuma.kill",
5
+ "akuma.tell",
6
+ "contract.deliver",
7
+ "contract.review",
8
+ ...TASK_MUTATION_ACTIONS,
9
+ ]);
10
+ const ALLOWED_ACTION_SET = new Set(ALLOWED_ACTIONS);
11
+ export function isAllowedAction(value) {
12
+ return typeof value === "string" && ALLOWED_ACTION_SET.has(value);
13
+ }
14
+ export function decodeAllowedActions(value, label = "allowed") {
15
+ if (!Array.isArray(value))
16
+ throw new TypeError(`${label} must be an array`);
17
+ const seen = new Set();
18
+ for (const action of value) {
19
+ if (!isAllowedAction(action))
20
+ throw new TypeError(`${label} contains an unknown action: ${String(action)}`);
21
+ if (seen.has(action))
22
+ throw new TypeError(`${label} contains a duplicate action: ${action}`);
23
+ seen.add(action);
24
+ }
25
+ return Object.freeze([...seen].sort());
26
+ }
27
+ export function effectiveAllowedActions(value) {
28
+ return value === undefined ? ALLOWED_ACTIONS : decodeAllowedActions(value);
29
+ }
30
+ export function clipAllowedActions(requested, parent) {
31
+ const ceiling = new Set(parent);
32
+ return Object.freeze(requested.filter((action) => ceiling.has(action)));
33
+ }
@@ -1,12 +1,14 @@
1
1
  import type { Settings } from "../settings.js";
2
2
  import type { ProviderAdapter } from "./provider.js";
3
3
  import { type ProviderExecution, type ProviderOptions, type ReadonlyRestraint } from "./provider-recipe.js";
4
+ import { type AllowedActions } from "./allowed.js";
4
5
  type DecodedArchetype = Readonly<{
5
6
  name: string;
6
7
  path: string;
7
8
  provider: string;
8
9
  description?: string;
9
10
  options: ProviderOptions;
11
+ allowed: AllowedActions;
10
12
  }>;
11
13
  export type ArchetypeCatalogRow = Readonly<{
12
14
  name: string;
@@ -27,14 +29,15 @@ export declare class AkumaArchetypeError extends Error {
27
29
  readonly kind = "akuma-archetype";
28
30
  constructor(archetype: string, searched: readonly string[], reason: string, guidance?: string);
29
31
  }
30
- export declare function listArchetypes(input: Readonly<{
31
- settings: Settings;
32
+ export declare function listArchetypes(input?: Readonly<{
33
+ home?: string;
32
34
  }>): Promise<readonly string[]>;
33
- export declare function listArchetypeDefinitions(input: Readonly<{
34
- settings: Settings;
35
+ export declare function listArchetypeDefinitions(input?: Readonly<{
36
+ home?: string;
35
37
  }>): Promise<readonly ArchetypeCatalogRow[]>;
36
38
  export declare function loadArchetype(input: Readonly<{
37
39
  name: string;
40
+ home?: string;
38
41
  settings: Settings;
39
42
  }>): Promise<AdmittedArchetype>;
40
43
  export {};
@@ -1,9 +1,11 @@
1
1
  import { readFile, readdir } from "node:fs/promises";
2
- import { dirname, join } from "node:path";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
3
4
  import { parseDocument } from "yaml";
4
5
  import { archetypeName } from "./identity.js";
5
6
  import { decodeProviderOptions, decodeProviderRecipe, } from "./provider-recipe.js";
6
7
  import { resolveProviderExecution } from "./providers/index.js";
8
+ import { effectiveAllowedActions } from "./allowed.js";
7
9
  export class AkumaArchetypeError extends Error {
8
10
  archetype;
9
11
  searched;
@@ -17,14 +19,11 @@ export class AkumaArchetypeError extends Error {
17
19
  this.name = "AkumaArchetypeError";
18
20
  }
19
21
  }
20
- function archetypeDirectory(settings) {
21
- const userPath = settings.scopes.user.path;
22
- return userPath === undefined ? null : join(dirname(userPath), "akuma");
22
+ function archetypeDirectory(home) {
23
+ return join(home ?? join(homedir(), ".keiyaku"), "akuma");
23
24
  }
24
- async function archetypePaths(settings) {
25
- const directory = archetypeDirectory(settings);
26
- if (directory === null)
27
- return [];
25
+ async function archetypePaths(home) {
26
+ const directory = archetypeDirectory(home);
28
27
  try {
29
28
  return (await readdir(directory, { withFileTypes: true }))
30
29
  .flatMap((entry) => {
@@ -46,8 +45,8 @@ async function archetypePaths(settings) {
46
45
  throw error;
47
46
  }
48
47
  }
49
- export async function listArchetypes(input) {
50
- return (await archetypePaths(input.settings)).map(({ name }) => name);
48
+ export async function listArchetypes(input = {}) {
49
+ return (await archetypePaths(input.home)).map(({ name }) => name);
51
50
  }
52
51
  function archetypeField(values, key, required = false) {
53
52
  const value = values[key];
@@ -96,6 +95,7 @@ function decodeArchetype(name, path, markdown) {
96
95
  const readonly = archetypeReadonly(values);
97
96
  const network = archetypeEnum(values, "network", ["disabled", "enabled"]);
98
97
  const description = archetypeField(values, "description");
98
+ const allowed = effectiveAllowedActions(values.allowed);
99
99
  const systemPrompt = lines.slice(closing + 1).join("\n");
100
100
  return Object.freeze({
101
101
  name,
@@ -109,12 +109,13 @@ function decodeArchetype(name, path, markdown) {
109
109
  ...(network === undefined ? {} : { network }),
110
110
  ...(systemPrompt.length === 0 ? {} : { systemPrompt }),
111
111
  }),
112
+ allowed,
112
113
  });
113
114
  }
114
- export async function listArchetypeDefinitions(input) {
115
+ export async function listArchetypeDefinitions(input = {}) {
115
116
  // Reads still run concurrently, but the reported failure is the first invalid
116
117
  // definition in catalog byte order, not whichever read happened to finish first.
117
- const settled = await Promise.allSettled((await archetypePaths(input.settings)).map(async ({ name, path }) => {
118
+ const settled = await Promise.allSettled((await archetypePaths(input.home)).map(async ({ name, path }) => {
118
119
  try {
119
120
  const definition = decodeArchetype(name, path, await readFile(path, "utf8"));
120
121
  return Object.freeze({
@@ -209,11 +210,9 @@ function admitArchetype(archetype, settings) {
209
210
  }
210
211
  export async function loadArchetype(input) {
211
212
  const name = archetypeName(input.name);
212
- const directory = archetypeDirectory(input.settings);
213
- const missing = () => new AkumaArchetypeError(name, directory === null ? [] : [join(directory, `${name}.md`)], "was not found", "use `keiyaku ls aku/` to list available Akuma");
214
- if (directory === null)
215
- throw missing();
213
+ const directory = archetypeDirectory(input.home);
216
214
  const path = join(directory, `${name}.md`);
215
+ const missing = () => new AkumaArchetypeError(name, [path], "was not found", "use `keiyaku ls aku/` to list available Akuma");
217
216
  let markdown;
218
217
  try {
219
218
  markdown = await readFile(path, "utf8");
@@ -1,7 +1,7 @@
1
1
  import { type SessionFact, type Soul } from "./heart/index.js";
2
2
  import type { AkumaPaths } from "./identity.js";
3
3
  import { type ProviderAdapter } from "./provider.js";
4
- import { type RequestChildLaunch } from "./requests.js";
4
+ import { type UpstreamExecutionPort, type RequestChildLaunch } from "./request-serve.js";
5
5
  export declare const CONTROL_RESPONSE_MS = 1000;
6
6
  export type BodyLaunch = Readonly<{
7
7
  paths: AkumaPaths;
@@ -12,7 +12,12 @@ export type BodyLaunch = Readonly<{
12
12
  type BodyRuntime = Readonly<{
13
13
  now(): string;
14
14
  spawnChild?(launch: RequestChildLaunch): Promise<void>;
15
+ upstream?: UpstreamExecutionPort;
15
16
  }>;
16
17
  export declare function driveAkumaBody(launch: BodyLaunch, adapter?: ProviderAdapter, runtime?: BodyRuntime): Promise<void>;
17
18
  export declare function spawnAkumaBody(launch: BodyLaunch): Promise<void>;
19
+ export declare function runAkumaBody(upstreamFor: (launch: BodyLaunch, configuration: Readonly<{
20
+ home?: string;
21
+ gitPath?: string;
22
+ }>) => UpstreamExecutionPort): Promise<void>;
18
23
  export {};
@@ -3,7 +3,7 @@ import { abortableDelay } from "./abort.js";
3
3
  import { HeldAkumaLeash, appendActivity, beginTurn, breakBody, endTurn, finishBodyIfIdle, heartExists, isHeartAbsent, readHeart, recordSession, recordTellDeliveries, recordTellReceipt, } from "./heart/index.js";
4
4
  import { encodeAgentEvent, } from "./provider.js";
5
5
  import { resolveProviderExecution } from "./providers/index.js";
6
- import { BodyRequestPump, clearBodyRequestTransport, settleBodyRequests, } from "./requests.js";
6
+ import { BodyRequestPump, clearBodyRequestTransport, settleBodyRequests, } from "./request-serve.js";
7
7
  import { spawnDetachedProcess, } from "../runtime/proc/run.js";
8
8
  const LEASH_RETRY_MS = 25;
9
9
  const BODY_CONTROL_OBSERVATION_MS = 100;
@@ -178,23 +178,22 @@ async function startTurnDrive(input) {
178
178
  startedAt: input.now(),
179
179
  ...(input.call === undefined ? {} : { call: input.call }),
180
180
  });
181
- const requests = input.soul.confinement.kind === "declared"
182
- ? await BodyRequestPump.open({
183
- paths: input.paths,
184
- parent: input.soul,
185
- bodySequence: input.bodySequence,
186
- now: input.now,
187
- spawn: input.runtimeSpawn,
188
- signal: input.supervisor.signal,
189
- })
190
- : null;
181
+ const requests = await BodyRequestPump.open({
182
+ paths: input.paths,
183
+ parent: input.soul,
184
+ bodySequence: input.bodySequence,
185
+ now: input.now,
186
+ spawn: input.runtimeSpawn,
187
+ ...(input.upstream === undefined ? {} : { upstream: input.upstream }),
188
+ signal: input.supervisor.signal,
189
+ });
191
190
  const driveInput = {
192
191
  body: input.body,
193
192
  launchTells: input.launchTells.map((tell) => ({ id: tell.id, text: tell.body })),
194
193
  cwd,
195
194
  options,
196
195
  signal: input.supervisor.signal,
197
- ...(requests === null ? {} : { requests: { dir: requests.directory } }),
196
+ requests: { dir: requests.directory },
198
197
  };
199
198
  const setup = session === undefined
200
199
  ? input.adapter.start({ ...driveInput, session: { kind: "fresh" } })
@@ -203,7 +202,7 @@ async function startTurnDrive(input) {
203
202
  const selected = await setup;
204
203
  if (input.supervisor.signal.aborted) {
205
204
  await retireProviderCustody(input, turn.sequence, selected);
206
- await requests?.close();
205
+ await requests.close();
207
206
  return { kind: "stopped" };
208
207
  }
209
208
  if (input.launchTells.length > 0) {
@@ -215,13 +214,12 @@ async function startTurnDrive(input) {
215
214
  deliveredAt: input.now(),
216
215
  })));
217
216
  }
218
- if (requests !== null)
219
- void selected.completion.then(() => requests.stopAdmission());
217
+ void selected.completion.then(() => requests.stopAdmission());
220
218
  return { turnSequence: turn.sequence, drive: selected, requests, cwd, options,
221
219
  ...(session === undefined ? {} : { resume: session }) };
222
220
  }
223
221
  catch (error) {
224
- await requests?.close();
222
+ await requests.close();
225
223
  if (input.supervisor.signal.aborted) {
226
224
  if (input.supervisor.reason === "heart-gone")
227
225
  throw error;
@@ -310,7 +308,7 @@ async function submitPendingLiveTells(writers, pending, attempted, tellLive) {
310
308
  }
311
309
  async function stopActiveDrive(input, active) {
312
310
  await retireProviderCustody(input, active.turnSequence, active.drive);
313
- await active.requests?.close();
311
+ await active.requests.close();
314
312
  }
315
313
  function hasUnattemptedTell(liveTells, tellPump, pending, attempted) {
316
314
  return liveTells && tellPump === null && pending.some((tell) => !attempted.has(tell.id));
@@ -319,7 +317,7 @@ function persistProviderEvent(_input, _active, event) {
319
317
  return event.type === "session" ? event.coordinate : undefined;
320
318
  }
321
319
  async function settleCompletion(result, session, requests) {
322
- await requests?.close();
320
+ await requests.close();
323
321
  return result.kind === "answered" ? { ...result, ...(session === undefined ? {} : { session }) } : result;
324
322
  }
325
323
  async function consumeTurnDrive(input, active) {
@@ -359,7 +357,7 @@ async function consumeTurnDrive(input, active) {
359
357
  input.supervisor.next(heart).then((observation) => ({ kind: "heart", observation })),
360
358
  ...(tellObservation === null ? [] : [tellObservation]),
361
359
  receiptFailure,
362
- ...(requests === null ? [] : [requests.failure]),
360
+ requests.failure,
363
361
  ]);
364
362
  if (next.kind === "event" && !next.event.done) {
365
363
  await writeProviderEvent(input, active, next.event.value);
@@ -394,7 +392,7 @@ async function consumeTurnDrive(input, active) {
394
392
  }
395
393
  await retireProviderCustody(input, turnSequence, drive);
396
394
  try {
397
- await requests?.close();
395
+ await requests.close();
398
396
  }
399
397
  catch { /* preserve the first pump failure */ }
400
398
  return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error) };
@@ -423,7 +421,7 @@ async function driveTurn(input) {
423
421
  }
424
422
  catch (error) {
425
423
  if (await heartExists(input.paths)) {
426
- await active.requests?.close();
424
+ await active.requests.close();
427
425
  return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error),
428
426
  turnSequence: active.turnSequence };
429
427
  }
@@ -538,6 +536,7 @@ async function runBodyTurns(input) {
538
536
  body: initial ?? "",
539
537
  ...(initial === undefined ? {} : { call: initial }),
540
538
  launchTells,
539
+ ...(runtime.upstream === undefined ? {} : { upstream: runtime.upstream }),
541
540
  now: runtime.now,
542
541
  });
543
542
  if (result.kind === "stopped") {
@@ -601,20 +600,30 @@ export async function spawnAkumaBody(launch) {
601
600
  if (actorId === undefined)
602
601
  throw new Error("Akuma wake has no born soul");
603
602
  const owned = await spawnDetachedProcess({
604
- argv: [process.execPath, ...process.execArgv, fileURLToPath(import.meta.url), encoded],
603
+ argv: [process.execPath, ...process.execArgv, fileURLToPath(new URL("../akuma-body.js", import.meta.url)), encoded],
605
604
  cwd: await launchCwd(launch),
606
605
  env: { ...process.env, KEIYAKU_ACTOR_ID: actorId },
607
606
  log: launch.paths.log,
608
607
  });
609
608
  owned.release();
610
609
  }
611
- async function main() {
610
+ export async function runAkumaBody(upstreamFor) {
612
611
  const encoded = process.argv[2];
613
612
  if (encoded === undefined)
614
613
  throw new TypeError("Akuma body launch payload is missing");
615
614
  const launch = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
616
- await driveAkumaBody(launch);
617
- }
618
- if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
619
- await main();
615
+ const mappedHome = process.env.KEIYAKU_HOME?.trim();
616
+ const mappedGitPath = process.env.KEIYAKU_GIT_PATH;
617
+ if (mappedGitPath !== undefined && mappedGitPath.trim().length === 0) {
618
+ throw new TypeError("KEIYAKU_GIT_PATH requires a nonblank value");
619
+ }
620
+ const configuration = {
621
+ ...(mappedHome === undefined || mappedHome.length === 0 ? {} : { home: mappedHome }),
622
+ ...(mappedGitPath === undefined ? {} : { gitPath: mappedGitPath }),
623
+ };
624
+ await driveAkumaBody(launch, undefined, {
625
+ now: () => new Date().toISOString(),
626
+ spawnChild: spawnAkumaBody,
627
+ upstream: upstreamFor(launch, configuration),
628
+ });
620
629
  }
@@ -1,13 +1,9 @@
1
1
  import type { AkuId } from "../identity.js";
2
2
  import type { ResumeCoordinate } from "../coordinate.js";
3
3
  import type { ProviderExecution, ProviderOptions, ReadonlyRestraint } from "../provider-recipe.js";
4
+ import type { AllowedActions } from "../allowed.js";
5
+ import type { TaskMutationAction, TaskMutationRequest } from "../../task/mutation.js";
4
6
  export type { ResumeCoordinate } from "../coordinate.js";
5
- export type Confinement = Readonly<{
6
- kind: "unconfined";
7
- }> | Readonly<{
8
- kind: "declared";
9
- writableRoots: readonly string[];
10
- }>;
11
7
  export type AkumaOrigin = Readonly<{
12
8
  kind: "direct";
13
9
  }> | Readonly<{
@@ -28,10 +24,10 @@ export type Soul = Readonly<{
28
24
  readonly?: ReadonlyRestraint;
29
25
  cwd: string;
30
26
  origin: AkumaOrigin;
31
- confinement: Confinement;
27
+ allowed: AllowedActions;
32
28
  createdAt: string;
33
29
  }>;
34
- export type RequestRecipe = Pick<Soul, "description" | "provider" | "options" | "readonly" | "confinement">;
30
+ export type RequestRecipe = Pick<Soul, "description" | "provider" | "options" | "readonly" | "allowed">;
35
31
  export type BodyEnd = "exited" | "broke-off" | "put-down";
36
32
  export type BodyFact = Readonly<{
37
33
  sequence: number;
@@ -127,28 +123,100 @@ export type TellReceiptInput = Readonly<{
127
123
  turnSequence: number;
128
124
  fence: string;
129
125
  }>);
126
+ export type TaskRequestInput = Readonly<{
127
+ id: string;
128
+ action: TaskMutationAction;
129
+ world: string;
130
+ request: TaskMutationRequest;
131
+ }>;
130
132
  export type RequestInput = Readonly<{
131
133
  id: string;
134
+ action: "akuma.call";
132
135
  archetype: string;
133
136
  body: string;
134
137
  cwd?: string;
135
138
  world: string;
136
139
  recipe: RequestRecipe;
140
+ }> | Readonly<{
141
+ id: string;
142
+ action: "akuma.wait";
143
+ targets: readonly AkuId[];
144
+ completion: "any" | "all";
145
+ timeoutMs?: number;
146
+ }> | Readonly<{
147
+ id: string;
148
+ action: "akuma.tell";
149
+ target: AkuId;
150
+ body: string;
151
+ }> | Readonly<{
152
+ id: string;
153
+ action: "akuma.kill";
154
+ targets: readonly AkuId[];
155
+ }> | Readonly<{
156
+ id: string;
157
+ action: "contract.deliver";
158
+ repoRoot: string;
159
+ contractId: string;
160
+ message?: string;
161
+ includeDirty: boolean;
162
+ }> | Readonly<{
163
+ id: string;
164
+ action: "contract.review";
165
+ repoRoot: string;
166
+ contractId: string;
167
+ verdict: "satisfied" | "unsatisfied";
168
+ summary?: string;
169
+ }> | TaskRequestInput;
170
+ export type UpstreamRequestService = Readonly<{
171
+ action: "akuma.wait";
172
+ }> | Readonly<{
173
+ action: "akuma.tell";
174
+ target: AkuId;
175
+ tellId: string;
176
+ }> | Readonly<{
177
+ action: "akuma.kill";
178
+ results: readonly Readonly<{
179
+ id: AkuId;
180
+ evidence: KillEvidence;
181
+ }>[];
182
+ }> | Readonly<{
183
+ action: "contract.deliver";
184
+ repoRoot: string;
185
+ contractId: string;
186
+ deliveryFactId: string;
187
+ }> | Readonly<{
188
+ action: "contract.review";
189
+ repoRoot: string;
190
+ contractId: string;
191
+ reviewFactId: string;
192
+ }> | Readonly<{
193
+ action: TaskMutationRequest["action"];
137
194
  }>;
138
- export type RequestFact = RequestInput & Readonly<{
195
+ type AdmittedRequest = RequestInput & Readonly<{
196
+ requester: AkuId;
139
197
  admittedAt: string;
140
- }> & (Readonly<{
198
+ }>;
199
+ export type RequestFact = (AdmittedRequest & Readonly<{
141
200
  state: "admitted";
142
- }> | Readonly<{
201
+ }>) | (Extract<AdmittedRequest, {
202
+ action: "akuma.call";
203
+ }> & Readonly<{
143
204
  state: "reserved";
144
205
  child: AkuId;
145
- }> | Readonly<{
206
+ }>) | (Extract<AdmittedRequest, {
207
+ action: "akuma.call";
208
+ }> & Readonly<{
146
209
  state: "served";
147
210
  child: AkuId;
148
- }> | Readonly<{
211
+ }>) | (Exclude<AdmittedRequest, {
212
+ action: "akuma.call";
213
+ }> & Readonly<{
214
+ state: "served";
215
+ service: UpstreamRequestService;
216
+ }>) | (AdmittedRequest & Readonly<{
149
217
  state: "refused";
150
218
  diagnostic: string;
151
- }> | Readonly<{
219
+ }>) | (AdmittedRequest & Readonly<{
152
220
  state: "voided";
153
221
  evidence: string;
154
222
  }>);
@@ -1,11 +1,12 @@
1
- import type { AkuId, AkumaPaths } from "../identity.js";
2
- import type { BodyEnd, BodyFact, ForkPoint, HeartSnapshot, KillFact, RequestFact, RequestInput, SealFact, SessionFact, Soul, TellDeliveryInput, TellFact, TellReceiptInput, TurnEndFact, TurnFact, TurnOutcome, TurnStartFact } from "./facts.js";
1
+ import type { AkumaPaths } from "../identity.js";
2
+ import type { BodyEnd, BodyFact, ForkPoint, HeartSnapshot, KillFact, SealFact, SessionFact, Soul, TellDeliveryInput, TellFact, TellReceiptInput, TurnEndFact, TurnFact, TurnOutcome, TurnStartFact } from "./facts.js";
3
3
  export type { CallFact } from "./facts.js";
4
4
  import type { ActivityFact } from "./rows.js";
5
5
  import { type ActivityFactSlice } from "./timeline.js";
6
6
  export { HeartAbsentError, HeldAkumaLeash, initializeHeart, isHeartAbsent, probeLeash } from "./storage.js";
7
+ export { admitRequest, readNonterminalRequests, readRequest, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, voidRequest, } from "./request-authority.js";
7
8
  export { life, lifeAt } from "./facts.js";
8
- export type { AkumaLife, AkumaOrigin, BodyEnd, BodyFact, Confinement, HeartSnapshot, ForkPoint, KillEvidence, KillFact, LeashProbe, PauseFact, RequestFact, RequestInput, RequestRecipe, SealFact, SessionFact, Soul, StopFact, TellFact, TellDelivery, TellDeliveryInput, TellReceiptInput, TurnEndFact, TurnFact, TurnOutcome, TurnStartFact, } from "./facts.js";
9
+ export type { AkumaLife, AkumaOrigin, BodyEnd, BodyFact, HeartSnapshot, ForkPoint, KillEvidence, KillFact, LeashProbe, PauseFact, RequestFact, RequestInput, RequestRecipe, UpstreamRequestService, SealFact, SessionFact, Soul, StopFact, TellFact, TellDelivery, TellDeliveryInput, TellReceiptInput, TurnEndFact, TurnFact, TurnOutcome, TurnStartFact, } from "./facts.js";
9
10
  export type { ResumeCoordinate } from "../coordinate.js";
10
11
  export declare function readSoul(paths: AkumaPaths): Promise<Soul | null>;
11
12
  export declare function heartExists(paths: AkumaPaths): Promise<boolean>;
@@ -16,15 +17,10 @@ export declare function appendActivity(paths: AkumaPaths, input: Readonly<{
16
17
  event: unknown;
17
18
  at: string;
18
19
  }>): Promise<number>;
19
- export type ActivitySliceInput = Readonly<{
20
- before?: number;
21
- since?: number;
22
- limit?: number;
23
- }>;
24
20
  export type ActivitySlice = ActivityFactSlice;
25
21
  export type { ActivityFact };
26
22
  export type { TimelineFact } from "./timeline.js";
27
- export declare function activitySlice(paths: AkumaPaths, input?: ActivitySliceInput): Promise<ActivitySlice>;
23
+ export declare function activitySlice(paths: AkumaPaths): Promise<ActivitySlice>;
28
24
  export declare function recordTell(paths: AkumaPaths, tell: Omit<TellFact, "sequence" | "state" | "deliveries">): Promise<Readonly<{
29
25
  kind: "not-born";
30
26
  } | {
@@ -33,15 +29,6 @@ export declare function recordTell(paths: AkumaPaths, tell: Omit<TellFact, "sequ
33
29
  }>>;
34
30
  export declare function recordTellDeliveries(paths: AkumaPaths, inputs: readonly TellDeliveryInput[]): Promise<void>;
35
31
  export declare function recordTellReceipt(paths: AkumaPaths, input: TellReceiptInput): Promise<void>;
36
- export declare function admitRequest(paths: AkumaPaths, input: RequestInput & Readonly<{
37
- admittedAt: string;
38
- }>): Promise<RequestFact>;
39
- export declare function reserveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
40
- export declare function serveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
41
- export declare function refuseRequest(paths: AkumaPaths, id: string, diagnostic: string): Promise<RequestFact>;
42
- export declare function voidRequest(paths: AkumaPaths, id: string, evidence: string): Promise<RequestFact>;
43
- export declare function readRequest(paths: AkumaPaths, id: string): Promise<RequestFact | null>;
44
- export declare function readNonterminalRequests(paths: AkumaPaths): Promise<readonly RequestFact[]>;
45
32
  export declare function readKill(paths: AkumaPaths, bodySequence: number): Promise<KillFact | null>;
46
33
  export declare function requestStop(paths: AkumaPaths, at: string): Promise<Readonly<{
47
34
  kind: "requested";
@@ -1,9 +1,10 @@
1
- import { answeredTurnFact, endBodyFact, finishBodyFact, insertActivityFact, insertTurnEndFact, insertTurnStartFact, insertPauseControl, insertRequestFact, insertSessionFact, insertStopControl, killFactForBody, latestBodyFact, latestKillFact, latestSessionFact, lastAnsweredTurnFact, nonterminalRequestFacts, pauseFact, requestFact, sessionFactForCoordinate, stopFact, updateRequestRefused, updateRequestReserved, updateRequestServed, updateRequestVoided, } from "./rows.js";
1
+ import { answeredTurnFact, endBodyFact, finishBodyFact, insertActivityFact, insertTurnEndFact, insertTurnStartFact, insertPauseControl, insertSessionFact, insertStopControl, killFactForBody, latestBodyFact, latestKillFact, latestSessionFact, lastAnsweredTurnFact, pauseFact, sessionFactForCoordinate, stopFact, } from "./rows.js";
2
2
  import { insertTellDeliveryFact, insertTellFact, insertTellReceiptFact, pendingTellFacts, tellFact, tellIdsForFence, } from "./tells.js";
3
3
  import { activityFactSlice, pruneActivityFacts, } from "./timeline.js";
4
- import { isHeartAbsent, readSealFromLeash, transaction, withHeart } from "./storage.js";
4
+ import { isHeartAbsent, readSealFromLeash, readTransaction, transaction, withHeart } from "./storage.js";
5
5
  import { soulFact } from "./soul.js";
6
6
  export { HeartAbsentError, HeldAkumaLeash, initializeHeart, isHeartAbsent, probeLeash } from "./storage.js";
7
+ export { admitRequest, readNonterminalRequests, readRequest, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, voidRequest, } from "./request-authority.js";
7
8
  export { life, lifeAt } from "./facts.js";
8
9
  const ACTIVITY_LIMIT = 5_000;
9
10
  export async function readSoul(paths) {
@@ -46,14 +47,20 @@ export async function appendActivity(paths, input) {
46
47
  return sequence;
47
48
  }));
48
49
  }
49
- export async function activitySlice(paths, input = {}) {
50
- const limit = input.limit ?? ACTIVITY_LIMIT;
51
- return await withHeart(paths, (heart) => activityFactSlice(heart, { ...input, limit }));
50
+ export async function activitySlice(paths) {
51
+ return await withHeart(paths, (heart) => readTransaction(heart, () => activityFactSlice(heart)));
52
52
  }
53
53
  export async function recordTell(paths, tell) {
54
54
  return await withHeart(paths, (heart) => transaction(heart, () => {
55
55
  if (soulFact(heart) === null)
56
56
  return { kind: "not-born" };
57
+ const existing = tellFact(heart, tell.id);
58
+ if (existing !== null) {
59
+ if (existing.body !== tell.body || existing.recordedAt !== tell.recordedAt) {
60
+ throw new Error(`tell ${tell.id} reused different input`);
61
+ }
62
+ return { kind: "recorded", tell: existing };
63
+ }
57
64
  const sequence = insertTellFact(heart, tell);
58
65
  pruneActivityFacts(heart, ACTIVITY_LIMIT);
59
66
  return { kind: "recorded", tell: { sequence, ...tell, state: "pending", deliveries: [] } };
@@ -82,83 +89,6 @@ export async function recordTellReceipt(paths, input) {
82
89
  pruneActivityFacts(heart, ACTIVITY_LIMIT);
83
90
  }));
84
91
  }
85
- function sameRequestInput(fact, input) {
86
- return fact.id === input.id
87
- && fact.archetype === input.archetype
88
- && fact.body === input.body
89
- && fact.cwd === input.cwd
90
- && fact.world === input.world
91
- && JSON.stringify(fact.recipe) === JSON.stringify(input.recipe);
92
- }
93
- export async function admitRequest(paths, input) {
94
- return await withHeart(paths, (heart) => transaction(heart, () => {
95
- insertRequestFact(heart, input);
96
- const fact = requestFact(heart, input.id);
97
- if (fact === null)
98
- throw new Error(`Akuma request ${input.id} was not admitted`);
99
- if (!sameRequestInput(fact, input))
100
- throw new Error(`Akuma request ${input.id} reused different input`);
101
- return fact;
102
- }));
103
- }
104
- export async function reserveRequest(paths, id, child) {
105
- return await withHeart(paths, (heart) => transaction(heart, () => {
106
- const before = requestFact(heart, id);
107
- if (before === null)
108
- throw new Error(`unknown Akuma request ${id}`);
109
- if (before.state === "admitted")
110
- updateRequestReserved(heart, id, child);
111
- else if ((before.state !== "reserved" && before.state !== "served") || before.child !== child) {
112
- throw new Error(`Akuma request ${id} cannot reserve ${child}`);
113
- }
114
- return requestFact(heart, id);
115
- }));
116
- }
117
- export async function serveRequest(paths, id, child) {
118
- return await withHeart(paths, (heart) => transaction(heart, () => {
119
- const before = requestFact(heart, id);
120
- if (before === null)
121
- throw new Error(`unknown Akuma request ${id}`);
122
- if (before.state === "reserved" && before.child === child)
123
- updateRequestServed(heart, id, child);
124
- else if (before.state !== "served" || before.child !== child) {
125
- throw new Error(`Akuma request ${id} cannot serve ${child}`);
126
- }
127
- return requestFact(heart, id);
128
- }));
129
- }
130
- export async function refuseRequest(paths, id, diagnostic) {
131
- return await withHeart(paths, (heart) => transaction(heart, () => {
132
- const before = requestFact(heart, id);
133
- if (before === null)
134
- throw new Error(`unknown Akuma request ${id}`);
135
- if (before.state === "admitted")
136
- updateRequestRefused(heart, id, diagnostic);
137
- else if (before.state !== "refused" || before.diagnostic !== diagnostic) {
138
- throw new Error(`Akuma request ${id} cannot be refused`);
139
- }
140
- return requestFact(heart, id);
141
- }));
142
- }
143
- export async function voidRequest(paths, id, evidence) {
144
- return await withHeart(paths, (heart) => transaction(heart, () => {
145
- const before = requestFact(heart, id);
146
- if (before === null)
147
- throw new Error(`unknown Akuma request ${id}`);
148
- if (before.state === "admitted" || before.state === "reserved")
149
- updateRequestVoided(heart, id, evidence);
150
- else if (before.state !== "voided" || before.evidence !== evidence) {
151
- throw new Error(`Akuma request ${id} cannot be voided`);
152
- }
153
- return requestFact(heart, id);
154
- }));
155
- }
156
- export async function readRequest(paths, id) {
157
- return await withHeart(paths, (heart) => requestFact(heart, id));
158
- }
159
- export async function readNonterminalRequests(paths) {
160
- return await withHeart(paths, nonterminalRequestFacts);
161
- }
162
92
  export async function readKill(paths, bodySequence) {
163
93
  return await withHeart(paths, (heart) => killFactForBody(heart, bodySequence));
164
94
  }
@@ -234,7 +164,7 @@ export async function finishBodyIfIdle(paths, input) {
234
164
  }
235
165
  export async function readHeart(paths) {
236
166
  try {
237
- return await withHeart(paths, (heart) => ({
167
+ return await withHeart(paths, (heart) => readTransaction(heart, () => ({
238
168
  soul: soulFact(heart),
239
169
  latestBody: latestBodyFact(heart),
240
170
  latestSession: latestSessionFact(heart),
@@ -242,7 +172,7 @@ export async function readHeart(paths) {
242
172
  latestKill: latestKillFact(heart),
243
173
  stop: stopFact(heart),
244
174
  pause: pauseFact(heart),
245
- }));
175
+ })));
246
176
  }
247
177
  catch (error) {
248
178
  if (isHeartAbsent(error)) {
@@ -0,0 +1,12 @@
1
+ import type { AkuId, AkumaPaths } from "../identity.js";
2
+ import type { RequestFact, RequestInput, UpstreamRequestService } from "./facts.js";
3
+ export declare function admitRequest(paths: AkumaPaths, input: RequestInput & Readonly<{
4
+ admittedAt: string;
5
+ }>): Promise<RequestFact>;
6
+ export declare function reserveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
7
+ export declare function serveRequest(paths: AkumaPaths, id: string, child: AkuId): Promise<RequestFact>;
8
+ export declare function serveUpstreamRequest(paths: AkumaPaths, id: string, service: UpstreamRequestService): Promise<RequestFact>;
9
+ export declare function refuseRequest(paths: AkumaPaths, id: string, diagnostic: string): Promise<RequestFact>;
10
+ export declare function voidRequest(paths: AkumaPaths, id: string, evidence: string): Promise<RequestFact>;
11
+ export declare function readRequest(paths: AkumaPaths, id: string): Promise<RequestFact | null>;
12
+ export declare function readNonterminalRequests(paths: AkumaPaths): Promise<readonly RequestFact[]>;