@astrosheep/keiyaku 4.5.19 → 4.5.21

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 (197) hide show
  1. package/README.md +4 -4
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +14 -7
  3. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +53 -20
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +237 -0
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +6 -7
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +2 -4
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -3
  8. package/build/src/akuma/akuma-handle.d.ts +5 -1
  9. package/build/src/akuma/akuma-handle.js +4 -1
  10. package/build/src/akuma/akuma-instance.d.ts +7 -2
  11. package/build/src/akuma/akuma-instance.js +14 -7
  12. package/build/src/akuma/akuma-observe.d.ts +11 -0
  13. package/build/src/akuma/akuma-observe.js +23 -0
  14. package/build/src/akuma/akuma-product.d.ts +2 -0
  15. package/build/src/akuma/akuma-product.js +6 -0
  16. package/build/src/akuma/akuma.d.ts +20 -1
  17. package/build/src/akuma/akuma.js +2 -0
  18. package/build/src/akuma/allowed.d.ts +20 -0
  19. package/build/src/akuma/allowed.js +11 -0
  20. package/build/src/akuma/archetype.js +3 -0
  21. package/build/src/akuma/body.d.ts +25 -5
  22. package/build/src/akuma/body.js +70 -31
  23. package/build/src/akuma/call-request.d.ts +5 -0
  24. package/build/src/akuma/call-request.js +14 -4
  25. package/build/src/akuma/fleet-execution.d.ts +28 -0
  26. package/build/src/akuma/fleet-execution.js +36 -4
  27. package/build/src/akuma/fleet-observation.d.ts +54 -0
  28. package/build/src/akuma/fleet-request.d.ts +10 -0
  29. package/build/src/akuma/fleet-request.js +13 -3
  30. package/build/src/akuma/heart/facts.d.ts +2 -0
  31. package/build/src/akuma/heart/index.d.ts +1 -0
  32. package/build/src/akuma/heart/index.js +4 -1
  33. package/build/src/akuma/heart/rows.d.ts +2 -0
  34. package/build/src/akuma/heart/rows.js +7 -5
  35. package/build/src/akuma/heart/schema.d.ts +1 -1
  36. package/build/src/akuma/heart/schema.js +3 -1
  37. package/build/src/akuma/heart/tells.js +6 -5
  38. package/build/src/akuma/heart/timeline.js +1 -1
  39. package/build/src/akuma/provider-recipe.d.ts +1 -0
  40. package/build/src/akuma/provider-recipe.js +5 -0
  41. package/build/src/akuma/provider.d.ts +1 -1
  42. package/build/src/akuma/provider.js +1 -1
  43. package/build/src/akuma/providers/acp/core.js +3 -6
  44. package/build/src/akuma/providers/acp/index.js +3 -0
  45. package/build/src/akuma/providers/claude/index.js +10 -10
  46. package/build/src/akuma/providers/codex-app-server/index.js +12 -11
  47. package/build/src/akuma/providers/execution-environment.d.ts +6 -0
  48. package/build/src/akuma/providers/execution-environment.js +24 -0
  49. package/build/src/akuma/providers/grok-build/index.js +3 -0
  50. package/build/src/akuma/providers/opencode-sdk/index.js +32 -23
  51. package/build/src/akuma/providers/opencode-sdk/session.d.ts +8 -1
  52. package/build/src/akuma/providers/opencode-sdk/session.js +6 -5
  53. package/build/src/akuma/providers/pi/events.js +7 -2
  54. package/build/src/akuma/providers/pi/index.js +5 -2
  55. package/build/src/akuma/request-observation.d.ts +45 -0
  56. package/build/src/akuma/request-observation.js +162 -0
  57. package/build/src/akuma/request-rendezvous.d.ts +6 -3
  58. package/build/src/akuma/request-rendezvous.js +80 -14
  59. package/build/src/akuma/request-serve.js +27 -4
  60. package/build/src/akuma/request-wire.d.ts +5 -0
  61. package/build/src/akuma/request-wire.js +2 -0
  62. package/build/src/akuma/turn-drive.d.ts +1 -0
  63. package/build/src/akuma/turn-drive.js +2 -0
  64. package/build/src/akuma-body.js +5 -0
  65. package/build/src/body/amend.js +6 -4
  66. package/build/src/body/decode.d.ts +3 -1
  67. package/build/src/body/decode.js +53 -17
  68. package/build/src/body/region.d.ts +9 -1
  69. package/build/src/body/region.js +87 -12
  70. package/build/src/body/render.js +1 -1
  71. package/build/src/body/verification.d.ts +3 -1
  72. package/build/src/body/verification.js +4 -1
  73. package/build/src/cli/accepted.js +19 -2
  74. package/build/src/cli/commands/akuma-invoke.d.ts +3 -1
  75. package/build/src/cli/commands/akuma-invoke.js +134 -14
  76. package/build/src/cli/commands/akuma.js +24 -12
  77. package/build/src/cli/commands/contract-help.d.ts +15 -15
  78. package/build/src/cli/commands/contract-help.js +45 -19
  79. package/build/src/cli/commands/contract-invoke.d.ts +3 -0
  80. package/build/src/cli/commands/contract-invoke.js +25 -11
  81. package/build/src/cli/commands/contract.js +6 -4
  82. package/build/src/cli/commands/install.d.ts +1 -1
  83. package/build/src/cli/commands/install.js +1 -1
  84. package/build/src/cli/commands/status-set.js +15 -24
  85. package/build/src/cli/commands/task.js +18 -18
  86. package/build/src/cli/invoke.d.ts +3 -0
  87. package/build/src/cli/invoke.js +58 -23
  88. package/build/src/cli/main.js +5 -0
  89. package/build/src/cli/parse.d.ts +3 -0
  90. package/build/src/cli/parse.js +26 -4
  91. package/build/src/cli/render/akuma-activity.d.ts +100 -2
  92. package/build/src/cli/render/akuma-activity.js +485 -40
  93. package/build/src/cli/render/akuma.d.ts +10 -0
  94. package/build/src/cli/render/akuma.js +31 -21
  95. package/build/src/cli/render/audit.js +1 -1
  96. package/build/src/cli/render/board.js +1 -1
  97. package/build/src/cli/render/catalog.js +16 -13
  98. package/build/src/cli/render/contract-history.js +39 -10
  99. package/build/src/cli/render/contract-observation.js +10 -6
  100. package/build/src/cli/render/contract.js +109 -106
  101. package/build/src/cli/render/execution-progress.d.ts +26 -0
  102. package/build/src/cli/render/execution-progress.js +178 -0
  103. package/build/src/cli/render/kanshi-akuma.js +27 -39
  104. package/build/src/cli/render/kanshi.js +33 -26
  105. package/build/src/cli/render/nuke.js +1 -1
  106. package/build/src/cli/render/receipt.d.ts +1 -1
  107. package/build/src/cli/render/receipt.js +6 -6
  108. package/build/src/cli/render/refusal.js +10 -7
  109. package/build/src/cli/render/region.js +1 -1
  110. package/build/src/cli/render/settings.js +12 -2
  111. package/build/src/cli/render/status-line.d.ts +30 -0
  112. package/build/src/cli/render/status-line.js +58 -0
  113. package/build/src/cli/render/status-set.js +1 -1
  114. package/build/src/cli/render/task.d.ts +2 -0
  115. package/build/src/cli/render/task.js +11 -7
  116. package/build/src/cli/render/terminal.d.ts +0 -1
  117. package/build/src/cli/render/terminal.js +47 -15
  118. package/build/src/cli/result.d.ts +1 -0
  119. package/build/src/cli/runtime.d.ts +2 -0
  120. package/build/src/cli/runtime.js +36 -4
  121. package/build/src/cli/usage.js +2 -2
  122. package/build/src/cli/version.d.ts +1 -0
  123. package/build/src/cli/version.js +25 -0
  124. package/build/src/git/hooks.d.ts +13 -1
  125. package/build/src/git/hooks.js +2 -1
  126. package/build/src/git/workspace.d.ts +1 -1
  127. package/build/src/git/workspace.js +1 -1
  128. package/build/src/identity/mint.d.ts +13 -0
  129. package/build/src/identity/mint.js +26 -0
  130. package/build/src/identity/normalize.d.ts +4 -0
  131. package/build/src/identity/normalize.js +30 -0
  132. package/build/src/index.d.ts +2 -0
  133. package/build/src/index.js +1 -0
  134. package/build/src/kanshi/read.js +17 -4
  135. package/build/src/kanshi/report.d.ts +1 -0
  136. package/build/src/library/akuma-creation.d.ts +2 -0
  137. package/build/src/library/akuma-creation.js +34 -18
  138. package/build/src/library/audit.d.ts +2 -0
  139. package/build/src/library/audit.js +1 -0
  140. package/build/src/library/bind.js +18 -16
  141. package/build/src/library/composition.d.ts +1 -0
  142. package/build/src/library/contract-bind.d.ts +3 -1
  143. package/build/src/library/contract-bind.js +5 -3
  144. package/build/src/library/contract-execution.d.ts +2 -0
  145. package/build/src/library/contract-execution.js +15 -1
  146. package/build/src/library/contract-forwarding.d.ts +4 -0
  147. package/build/src/library/contract-forwarding.js +3 -0
  148. package/build/src/library/contract-handle.d.ts +7 -0
  149. package/build/src/library/contract-handle.js +25 -0
  150. package/build/src/library/contract-operations.d.ts +7 -2
  151. package/build/src/library/contract-operations.js +21 -1
  152. package/build/src/library/contract-types.d.ts +1 -0
  153. package/build/src/library/execution-result.d.ts +2 -2
  154. package/build/src/library/execution.d.ts +8 -0
  155. package/build/src/library/execution.js +102 -0
  156. package/build/src/library/fleet.d.ts +4 -1
  157. package/build/src/library/fleet.js +32 -8
  158. package/build/src/library/keiyaku.d.ts +2 -0
  159. package/build/src/library/mutation.js +15 -7
  160. package/build/src/plugin/akuma-signals.d.ts +6 -0
  161. package/build/src/plugin/akuma-signals.js +9 -1
  162. package/build/src/plugin/public.d.ts +6 -2
  163. package/build/src/plugin/runtime.d.ts +1 -3
  164. package/build/src/plugin/runtime.js +95 -103
  165. package/build/src/protocol/amend.js +4 -3
  166. package/build/src/protocol/attempt.d.ts +2 -0
  167. package/build/src/protocol/bind.js +41 -14
  168. package/build/src/protocol/completion.d.ts +3 -0
  169. package/build/src/protocol/completion.js +35 -11
  170. package/build/src/protocol/deliver.js +165 -92
  171. package/build/src/protocol/execution-observation.d.ts +181 -0
  172. package/build/src/protocol/execution-observation.js +45 -0
  173. package/build/src/protocol/intent.d.ts +18 -22
  174. package/build/src/protocol/intent.js +63 -41
  175. package/build/src/protocol/operations.d.ts +2 -0
  176. package/build/src/protocol/placement.js +5 -1
  177. package/build/src/protocol/progress.d.ts +5 -1
  178. package/build/src/protocol/progress.js +10 -1
  179. package/build/src/protocol/read/status.d.ts +1 -0
  180. package/build/src/protocol/read/status.js +10 -2
  181. package/build/src/protocol/reintegrate.d.ts +1 -1
  182. package/build/src/protocol/reintegrate.js +70 -43
  183. package/build/src/protocol/result-codec.js +27 -11
  184. package/build/src/protocol/review.js +53 -30
  185. package/build/src/protocol/run.d.ts +83 -36
  186. package/build/src/protocol/run.js +90 -75
  187. package/build/src/runtime/proc/run.d.ts +16 -4
  188. package/build/src/runtime/proc/run.js +64 -22
  189. package/build/src/runtime/proc/windows-launch.exe +0 -0
  190. package/build/src/settings.js +5 -14
  191. package/build/src/task/document.d.ts +5 -1
  192. package/build/src/task/document.js +6 -1
  193. package/build/src/verification/execution.d.ts +10 -2
  194. package/build/src/verification/execution.js +143 -42
  195. package/build/src/verification/observation.d.ts +41 -0
  196. package/build/src/verification/observation.js +29 -0
  197. package/package.json +3 -1
@@ -10,6 +10,24 @@ declare const akumaObservationSchema: z.ZodObject<{
10
10
  asleep: "asleep";
11
11
  stranded: "stranded";
12
12
  }>;
13
+ allowed: z.ZodPipe<z.ZodArray<z.ZodEnum<{
14
+ "task.add": "task.add";
15
+ "task.addDocument": "task.addDocument";
16
+ "task.compose": "task.compose";
17
+ "task.done": "task.done";
18
+ "task.drop": "task.drop";
19
+ "task.hold": "task.hold";
20
+ "task.resume": "task.resume";
21
+ "task.start": "task.start";
22
+ "task.stop": "task.stop";
23
+ "task.update": "task.update";
24
+ "akuma.call": "akuma.call";
25
+ "akuma.kill": "akuma.kill";
26
+ "akuma.tell": "akuma.tell";
27
+ "contract.audit": "contract.audit";
28
+ "contract.deliver": "contract.deliver";
29
+ "contract.review": "contract.review";
30
+ }>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("task.add" | "task.addDocument" | "task.compose" | "task.done" | "task.drop" | "task.hold" | "task.resume" | "task.start" | "task.stop" | "task.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
13
31
  readonly: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
14
32
  enforcement: z.ZodLiteral<"native">;
15
33
  }, z.core.$strict>, z.ZodObject<{
@@ -446,6 +464,24 @@ declare const akumaWaitResultSchema: z.ZodObject<{
446
464
  asleep: "asleep";
447
465
  stranded: "stranded";
448
466
  }>;
467
+ allowed: z.ZodPipe<z.ZodArray<z.ZodEnum<{
468
+ "task.add": "task.add";
469
+ "task.addDocument": "task.addDocument";
470
+ "task.compose": "task.compose";
471
+ "task.done": "task.done";
472
+ "task.drop": "task.drop";
473
+ "task.hold": "task.hold";
474
+ "task.resume": "task.resume";
475
+ "task.start": "task.start";
476
+ "task.stop": "task.stop";
477
+ "task.update": "task.update";
478
+ "akuma.call": "akuma.call";
479
+ "akuma.kill": "akuma.kill";
480
+ "akuma.tell": "akuma.tell";
481
+ "contract.audit": "contract.audit";
482
+ "contract.deliver": "contract.deliver";
483
+ "contract.review": "contract.review";
484
+ }>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("task.add" | "task.addDocument" | "task.compose" | "task.done" | "task.drop" | "task.hold" | "task.resume" | "task.start" | "task.stop" | "task.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
449
485
  readonly: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
450
486
  enforcement: z.ZodLiteral<"native">;
451
487
  }, z.core.$strict>, z.ZodObject<{
@@ -1001,6 +1037,24 @@ export declare const fleetResultSchemas: {
1001
1037
  asleep: "asleep";
1002
1038
  stranded: "stranded";
1003
1039
  }>;
1040
+ allowed: z.ZodPipe<z.ZodArray<z.ZodEnum<{
1041
+ "task.add": "task.add";
1042
+ "task.addDocument": "task.addDocument";
1043
+ "task.compose": "task.compose";
1044
+ "task.done": "task.done";
1045
+ "task.drop": "task.drop";
1046
+ "task.hold": "task.hold";
1047
+ "task.resume": "task.resume";
1048
+ "task.start": "task.start";
1049
+ "task.stop": "task.stop";
1050
+ "task.update": "task.update";
1051
+ "akuma.call": "akuma.call";
1052
+ "akuma.kill": "akuma.kill";
1053
+ "akuma.tell": "akuma.tell";
1054
+ "contract.audit": "contract.audit";
1055
+ "contract.deliver": "contract.deliver";
1056
+ "contract.review": "contract.review";
1057
+ }>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("task.add" | "task.addDocument" | "task.compose" | "task.done" | "task.drop" | "task.hold" | "task.resume" | "task.start" | "task.stop" | "task.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
1004
1058
  readonly: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
1005
1059
  enforcement: z.ZodLiteral<"native">;
1006
1060
  }, z.core.$strict>, z.ZodObject<{
@@ -24,29 +24,35 @@ declare const waitRequestSchema: z.ZodPipe<z.ZodObject<{
24
24
  declare const tellRequestSchema: z.ZodPipe<z.ZodObject<{
25
25
  target: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
26
26
  body: z.ZodString;
27
+ initiator: z.ZodOptional<z.ZodString>;
27
28
  }, z.core.$strict>, z.ZodTransform<{
28
29
  target: import("./identity.js").AkuId;
29
30
  body: string;
31
+ initiator?: string | undefined;
30
32
  action: "akuma.tell";
31
33
  }, {
32
34
  target: import("./identity.js").AkuId;
33
35
  body: string;
36
+ initiator?: string | undefined;
34
37
  }>>;
35
38
  declare const tellAnswerRequestSchema: z.ZodPipe<z.ZodObject<{
36
39
  target: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
37
40
  body: z.ZodString;
38
41
  schemaJson: z.ZodString;
42
+ initiator: z.ZodOptional<z.ZodString>;
39
43
  interrupt: z.ZodOptional<z.ZodBoolean>;
40
44
  }, z.core.$strict>, z.ZodTransform<{
41
45
  target: import("./identity.js").AkuId;
42
46
  body: string;
43
47
  schemaJson: string;
48
+ initiator?: string | undefined;
44
49
  interrupt?: boolean | undefined;
45
50
  action: "akuma.tell-answer";
46
51
  }, {
47
52
  target: import("./identity.js").AkuId;
48
53
  body: string;
49
54
  schemaJson: string;
55
+ initiator?: string | undefined;
50
56
  interrupt?: boolean | undefined;
51
57
  }>>;
52
58
  declare const killRequestSchema: z.ZodPipe<z.ZodObject<{
@@ -102,12 +108,14 @@ export type FleetRequestPort = Readonly<{
102
108
  body: string;
103
109
  tellId: string;
104
110
  recordedAt: string;
111
+ initiator?: string;
105
112
  signal: AbortSignal;
106
113
  }>): Promise<AkumaTellResult>;
107
114
  tellAnswer?(input: Readonly<{
108
115
  target: AkumaStatus["id"];
109
116
  body: string;
110
117
  schemaJson: string;
118
+ initiator?: string;
111
119
  interrupt?: boolean;
112
120
  signal: AbortSignal;
113
121
  }>): Promise<unknown>;
@@ -131,6 +139,7 @@ export declare function requestForwardedFleetTellAnswer(input: Readonly<{
131
139
  target: AkumaStatus["id"];
132
140
  body: string;
133
141
  schema: Schema<unknown>;
142
+ initiator?: string;
134
143
  interrupt?: boolean;
135
144
  signal?: AbortSignal;
136
145
  }>): Promise<unknown>;
@@ -145,6 +154,7 @@ export declare function requestForwardedFleetTell(input: Readonly<{
145
154
  directory: string;
146
155
  target: AkumaStatus["id"];
147
156
  body: string;
157
+ initiator?: string;
148
158
  signal?: AbortSignal;
149
159
  }>): Promise<AkumaTellResult>;
150
160
  export declare function requestForwardedFleetKill(input: Readonly<{
@@ -26,7 +26,7 @@ const waitRequestSchema = z
26
26
  ...(timeoutMs === undefined ? {} : { timeoutMs }),
27
27
  }));
28
28
  const tellRequestSchema = z
29
- .object({ target: akumaIdSchema, body: z.string() })
29
+ .object({ target: akumaIdSchema, body: z.string(), initiator: nonblankTextSchema.optional() })
30
30
  .strict()
31
31
  .transform((request) => ({ action: "akuma.tell", ...request }));
32
32
  const tellAnswerRequestSchema = z
@@ -34,6 +34,7 @@ const tellAnswerRequestSchema = z
34
34
  target: akumaIdSchema,
35
35
  body: z.string(),
36
36
  schemaJson: nonblankTextSchema,
37
+ initiator: nonblankTextSchema.optional(),
37
38
  interrupt: z.boolean().optional(),
38
39
  })
39
40
  .strict()
@@ -100,7 +101,8 @@ export function fleetRequestProtocol(action) {
100
101
  decodeResult: (result) => decodedFleetResult(action, result),
101
102
  decodeReference: (reference) => decodeFleetService(action, reference),
102
103
  isPermitted: (allowed) => action === "akuma.wait" ||
103
- ((action === "akuma.tell" || action === "akuma.tell-answer") && allowed.includes("akuma.tell")),
104
+ ((action === "akuma.tell" || action === "akuma.tell-answer") && allowed.includes("akuma.tell")) ||
105
+ (action === "akuma.kill" && allowed.includes("akuma.kill")),
104
106
  };
105
107
  }
106
108
  export function fleetRequestCommand(action, port) {
@@ -123,6 +125,7 @@ export function fleetRequestCommand(action, port) {
123
125
  target: request.target,
124
126
  body: request.body,
125
127
  tellId: facts.id,
128
+ ...(request.initiator === undefined ? {} : { initiator: request.initiator }),
126
129
  recordedAt: facts.admittedAt,
127
130
  signal: facts.signal,
128
131
  }),
@@ -137,6 +140,7 @@ export function fleetRequestCommand(action, port) {
137
140
  target: request.target,
138
141
  body: request.body,
139
142
  schemaJson: request.schemaJson,
143
+ ...(request.initiator === undefined ? {} : { initiator: request.initiator }),
140
144
  ...(request.interrupt === undefined ? {} : { interrupt: request.interrupt }),
141
145
  signal: facts.signal,
142
146
  }),
@@ -170,6 +174,7 @@ export async function requestForwardedFleetTellAnswer(input) {
170
174
  target: input.target,
171
175
  body: input.body,
172
176
  schemaJson: schemaJsonText(input.schema),
177
+ ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
173
178
  ...(input.interrupt === undefined ? {} : { interrupt: input.interrupt }),
174
179
  },
175
180
  ...(input.signal === undefined ? {} : { signal: input.signal }),
@@ -213,7 +218,12 @@ export async function requestForwardedFleetTell(input) {
213
218
  const response = await requestBodyCommand({
214
219
  directory: input.directory,
215
220
  command: fleetRequestProtocol("akuma.tell"),
216
- value: { action: "akuma.tell", target: input.target, body: input.body },
221
+ value: {
222
+ action: "akuma.tell",
223
+ target: input.target,
224
+ body: input.body,
225
+ ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
226
+ },
217
227
  ...(input.signal === undefined ? {} : { signal: input.signal }),
218
228
  });
219
229
  return forwardedFleetCommandResult(response, "akuma.tell");
@@ -77,6 +77,7 @@ export type TurnStartFact = Readonly<{
77
77
  sequence: number;
78
78
  bodySequence: number;
79
79
  startedAt: string;
80
+ initiator?: string;
80
81
  schemaJson?: string;
81
82
  }>;
82
83
  export type TurnEndFact = Readonly<{
@@ -111,6 +112,7 @@ export type TellFact = Readonly<{
111
112
  sequence: number;
112
113
  id: string;
113
114
  body: string;
115
+ initiator?: string;
114
116
  schemaJson?: string;
115
117
  recordedAt: string;
116
118
  state: "pending" | "told";
@@ -77,6 +77,7 @@ export declare function beginTurn(paths: AkumaPaths, input: Readonly<{
77
77
  startedAt: string;
78
78
  call?: string;
79
79
  schemaJson?: string;
80
+ initiator?: string;
80
81
  }>): Promise<TurnStartFact>;
81
82
  export declare function bindTellsToTurn(paths: AkumaPaths, input: Readonly<{
82
83
  turnSequence: number;
@@ -74,7 +74,10 @@ export async function readLifeSnapshot(paths) {
74
74
  }
75
75
  }
76
76
  function sameTellInput(existing, tell) {
77
- return (existing.body === tell.body && existing.recordedAt === tell.recordedAt && existing.schemaJson === tell.schemaJson);
77
+ return (existing.body === tell.body &&
78
+ existing.recordedAt === tell.recordedAt &&
79
+ existing.schemaJson === tell.schemaJson &&
80
+ existing.initiator === tell.initiator);
78
81
  }
79
82
  export async function recordTell(paths, tell, options = {}) {
80
83
  return await withHeartTransaction(paths, (heart) => {
@@ -31,6 +31,7 @@ export type TurnRow = Readonly<{
31
31
  answer: string | null;
32
32
  answer_json: string | null;
33
33
  schema_json: string | null;
34
+ initiator: string | null;
34
35
  diagnostic: string | null;
35
36
  completed_at: string | null;
36
37
  }>;
@@ -107,6 +108,7 @@ export declare function insertTurnStartFact(database: DatabaseSync, input: Reado
107
108
  startedAt: string;
108
109
  call?: string;
109
110
  schemaJson?: string;
111
+ initiator?: string;
110
112
  }>): TurnStartFact;
111
113
  export declare function insertTurnEndFact(database: DatabaseSync, input: Omit<TurnEndFact, "sequence">): TurnEndFact;
112
114
  export declare function finishBodyFact(database: DatabaseSync, input: Readonly<{
@@ -72,6 +72,7 @@ export function decodeTurnRow(row) {
72
72
  bodySequence: row.body_sequence,
73
73
  startedAt: row.started_at,
74
74
  ...(row.schema_json === null || row.schema_json === undefined ? {} : { schemaJson: row.schema_json }),
75
+ ...(row.initiator == null ? {} : { initiator: row.initiator }),
75
76
  };
76
77
  if (row.outcome === null)
77
78
  return start;
@@ -192,8 +193,8 @@ export function markBodyHung(database, input) {
192
193
  export function insertTurnStartFact(database, input) {
193
194
  const sequence = Number(database.prepare("INSERT INTO timeline(kind) VALUES ('turn-start')").run().lastInsertRowid);
194
195
  database
195
- .prepare("INSERT INTO turns(sequence, body_sequence, started_at, schema_json) VALUES (?, ?, ?, ?)")
196
- .run(sequence, input.bodySequence, input.startedAt, input.schemaJson ?? null);
196
+ .prepare("INSERT INTO turns(sequence, body_sequence, started_at, schema_json, initiator) VALUES (?, ?, ?, ?, ?)")
197
+ .run(sequence, input.bodySequence, input.startedAt, input.schemaJson ?? null, input.initiator ?? null);
197
198
  if (input.call !== undefined) {
198
199
  const callSequence = Number(database.prepare("INSERT INTO timeline(kind) VALUES ('call')").run().lastInsertRowid);
199
200
  database
@@ -205,6 +206,7 @@ export function insertTurnStartFact(database, input) {
205
206
  sequence,
206
207
  bodySequence: input.bodySequence,
207
208
  startedAt: input.startedAt,
209
+ ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
208
210
  ...(input.schemaJson === undefined ? {} : { schemaJson: input.schemaJson }),
209
211
  };
210
212
  }
@@ -286,21 +288,21 @@ export function killFactForBody(database, bodySequence) {
286
288
  export function lastAnsweredTurnFact(database) {
287
289
  const row = database
288
290
  .prepare(`SELECT sequence, body_sequence, started_at, end_sequence, outcome, history_id,
289
- session_json, answer, answer_json, schema_json, diagnostic, completed_at FROM turns WHERE outcome = 'answered' ORDER BY end_sequence DESC LIMIT 1`)
291
+ session_json, answer, answer_json, schema_json, initiator, diagnostic, completed_at FROM turns WHERE outcome = 'answered' ORDER BY end_sequence DESC LIMIT 1`)
290
292
  .get();
291
293
  return row === undefined ? null : decodeTurnRow(row);
292
294
  }
293
295
  export function answeredTurnFact(database, turnSequence) {
294
296
  const row = database
295
297
  .prepare(`SELECT sequence, body_sequence, started_at, end_sequence, outcome, history_id,
296
- session_json, answer, answer_json, schema_json, diagnostic, completed_at FROM turns WHERE outcome = 'answered' AND sequence = ?`)
298
+ session_json, answer, answer_json, schema_json, initiator, diagnostic, completed_at FROM turns WHERE outcome = 'answered' AND sequence = ?`)
297
299
  .get(turnSequence);
298
300
  return row === undefined ? null : decodeTurnRow(row);
299
301
  }
300
302
  export function turnFact(database, turnSequence) {
301
303
  const row = database
302
304
  .prepare(`SELECT sequence, body_sequence, started_at, end_sequence, outcome, history_id,
303
- session_json, answer, answer_json, schema_json, diagnostic, completed_at FROM turns WHERE sequence = ?`)
305
+ session_json, answer, answer_json, schema_json, initiator, diagnostic, completed_at FROM turns WHERE sequence = ?`)
304
306
  .get(turnSequence);
305
307
  return row === undefined ? null : decodeTurnRow(row);
306
308
  }
@@ -2,5 +2,5 @@ import type { DatabaseSync } from "node:sqlite";
2
2
  export declare function assertHeartSchemaVersion(database: DatabaseSync): void;
3
3
  export declare function assertLeashSchemaVersion(database: DatabaseSync): void;
4
4
  export declare function heartSchemaIsCurrent(database: DatabaseSync): boolean;
5
- export declare const HEART_SCHEMA = "\n CREATE TABLE IF NOT EXISTS akuma_schema (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version = 28)\n ) STRICT;\n INSERT OR IGNORE INTO akuma_schema(singleton, version) VALUES (1, 28);\n CREATE TABLE IF NOT EXISTS soul (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n soul_json TEXT NOT NULL CHECK (json_valid(soul_json))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS bodies (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n leash_taken_at TEXT NOT NULL,\n hung_diagnostic TEXT,\n hung_at TEXT,\n end TEXT CHECK (end IN ('exited', 'broke-off', 'put-down')),\n ended_at TEXT,\n CHECK ((hung_diagnostic IS NULL AND hung_at IS NULL)\n OR (hung_diagnostic IS NOT NULL AND hung_at IS NOT NULL))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS sessions (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n provider TEXT NOT NULL,\n coordinate_json TEXT NOT NULL CHECK (json_valid(coordinate_json)),\n cwd TEXT NOT NULL,\n options_json TEXT NOT NULL CHECK (json_valid(options_json)),\n admitted_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS turns (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n body_sequence INTEGER NOT NULL REFERENCES bodies(sequence),\n started_at TEXT NOT NULL,\n end_sequence INTEGER UNIQUE REFERENCES timeline(sequence) ON DELETE SET NULL,\n outcome TEXT CHECK (outcome IN ('answered', 'failed', 'invalid-output')),\n history_id TEXT UNIQUE,\n session_json TEXT CHECK (session_json IS NULL OR json_valid(session_json)),\n answer TEXT,\n answer_json TEXT CHECK (answer_json IS NULL OR json_valid(answer_json)),\n schema_json TEXT CHECK (schema_json IS NULL OR json_valid(schema_json)),\n diagnostic TEXT,\n completed_at TEXT,\n CHECK (\n (outcome = 'answered' AND session_json IS NOT NULL AND answer IS NOT NULL AND diagnostic IS NULL\n AND ((schema_json IS NULL AND answer_json IS NULL) OR (schema_json IS NOT NULL AND answer_json IS NOT NULL)))\n OR (outcome = 'failed' AND history_id IS NULL AND session_json IS NULL AND answer IS NULL\n AND answer_json IS NULL AND diagnostic IS NOT NULL)\n OR (outcome = 'invalid-output' AND answer IS NOT NULL AND answer_json IS NULL\n AND diagnostic IS NOT NULL AND schema_json IS NOT NULL)\n OR (outcome IS NULL AND end_sequence IS NULL AND history_id IS NULL AND session_json IS NULL\n AND answer IS NULL AND answer_json IS NULL AND diagnostic IS NULL AND completed_at IS NULL)\n )\n ) STRICT;\n CREATE TABLE IF NOT EXISTS timeline (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n kind TEXT NOT NULL CHECK (kind IN ('turn-start', 'call', 'activity', 'tell', 'turn-end'))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS activity_retention (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n checked_sequence INTEGER NOT NULL\n ) STRICT;\n INSERT OR IGNORE INTO activity_retention(singleton, checked_sequence) VALUES (1, 0);\n CREATE TABLE IF NOT EXISTS calls (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n body TEXT NOT NULL,\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS activity (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n event_json TEXT NOT NULL CHECK (json_valid(event_json)),\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tells (\n id TEXT PRIMARY KEY,\n sequence INTEGER NOT NULL UNIQUE REFERENCES timeline(sequence) ON DELETE CASCADE,\n body TEXT NOT NULL,\n schema_json TEXT CHECK (schema_json IS NULL OR json_valid(schema_json)),\n recorded_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_bindings (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n tell_id TEXT NOT NULL REFERENCES tells(id) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n bound_at TEXT NOT NULL,\n UNIQUE (tell_id, turn_sequence)\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_deliveries (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n tell_id TEXT NOT NULL REFERENCES tells(id) ON DELETE CASCADE,\n route TEXT NOT NULL CHECK (route IN ('launch', 'live')),\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n fence TEXT NOT NULL,\n receipt TEXT CHECK (receipt IN ('unavailable', 'required')),\n delivered_at TEXT NOT NULL,\n CHECK ((route = 'launch' AND receipt IS NULL) OR (route = 'live' AND receipt IS NOT NULL)),\n UNIQUE (tell_id, turn_sequence, fence)\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_receipts (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n evidence TEXT NOT NULL CHECK (evidence IN ('exact', 'fence')),\n tell_id TEXT REFERENCES tells(id) ON DELETE CASCADE,\n turn_sequence INTEGER REFERENCES turns(sequence) ON DELETE CASCADE,\n fence TEXT,\n kind TEXT NOT NULL,\n received_at TEXT NOT NULL,\n CHECK (\n (evidence = 'exact' AND tell_id IS NOT NULL AND turn_sequence IS NULL AND fence IS NULL)\n OR (evidence = 'fence' AND tell_id IS NULL AND turn_sequence IS NOT NULL AND fence IS NOT NULL)\n )\n ) STRICT;\n CREATE UNIQUE INDEX IF NOT EXISTS tell_receipts_exact\n ON tell_receipts(tell_id, kind);\n CREATE UNIQUE INDEX IF NOT EXISTS tell_receipts_fence\n ON tell_receipts(turn_sequence, fence, kind);\n CREATE TABLE IF NOT EXISTS tell_dispositions (\n body_sequence INTEGER PRIMARY KEY REFERENCES bodies(sequence),\n decided_at TEXT NOT NULL,\n resolved_at TEXT\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_disposition_members (\n body_sequence INTEGER NOT NULL REFERENCES tell_dispositions(body_sequence) ON DELETE CASCADE,\n tell_id TEXT NOT NULL REFERENCES tells(id),\n PRIMARY KEY (body_sequence, tell_id)\n ) STRICT;\n CREATE INDEX IF NOT EXISTS calls_by_turn ON calls(turn_sequence);\n CREATE INDEX IF NOT EXISTS activity_by_turn ON activity(turn_sequence);\n CREATE INDEX IF NOT EXISTS tell_bindings_by_turn ON tell_bindings(turn_sequence);\n CREATE INDEX IF NOT EXISTS tell_deliveries_by_turn ON tell_deliveries(turn_sequence);\n CREATE INDEX IF NOT EXISTS tell_disposition_members_by_tell ON tell_disposition_members(tell_id);\n CREATE TABLE IF NOT EXISTS requests (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n id TEXT NOT NULL UNIQUE,\n requester TEXT NOT NULL,\n action TEXT NOT NULL,\n payload_json TEXT NOT NULL CHECK (json_valid(payload_json)),\n admitted_at TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('admitted', 'reserved', 'begun', 'served', 'refused', 'voided', 'unproven')),\n child TEXT,\n service_json TEXT CHECK (service_json IS NULL OR json_valid(service_json)),\n diagnostic TEXT,\n evidence TEXT,\n CHECK (\n (state = 'admitted' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'reserved' AND child IS NOT NULL AND service_json IS NULL\n AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'begun' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'served'\n AND ((child IS NOT NULL AND service_json IS NULL)\n OR (child IS NULL AND service_json IS NOT NULL))\n AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'refused' AND child IS NULL AND service_json IS NULL AND diagnostic IS NOT NULL AND evidence IS NULL)\n OR (state = 'voided' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NOT NULL)\n OR (state = 'unproven' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NOT NULL)\n )\n ) STRICT;\n CREATE TABLE IF NOT EXISTS control (\n kind TEXT PRIMARY KEY CHECK (kind IN ('stop', 'pause')),\n value_json TEXT NOT NULL CHECK (json_valid(value_json)),\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS kills (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n body_sequence INTEGER NOT NULL UNIQUE REFERENCES bodies(sequence),\n evidence TEXT NOT NULL CHECK (evidence = 'killed'),\n at TEXT NOT NULL\n ) STRICT;\n";
5
+ export declare const HEART_SCHEMA = "\n CREATE TABLE IF NOT EXISTS akuma_schema (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version = 29)\n ) STRICT;\n INSERT OR IGNORE INTO akuma_schema(singleton, version) VALUES (1, 29);\n CREATE TABLE IF NOT EXISTS soul (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n soul_json TEXT NOT NULL CHECK (json_valid(soul_json))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS bodies (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n leash_taken_at TEXT NOT NULL,\n hung_diagnostic TEXT,\n hung_at TEXT,\n end TEXT CHECK (end IN ('exited', 'broke-off', 'put-down')),\n ended_at TEXT,\n CHECK ((hung_diagnostic IS NULL AND hung_at IS NULL)\n OR (hung_diagnostic IS NOT NULL AND hung_at IS NOT NULL))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS sessions (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n provider TEXT NOT NULL,\n coordinate_json TEXT NOT NULL CHECK (json_valid(coordinate_json)),\n cwd TEXT NOT NULL,\n options_json TEXT NOT NULL CHECK (json_valid(options_json)),\n admitted_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS turns (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n body_sequence INTEGER NOT NULL REFERENCES bodies(sequence),\n started_at TEXT NOT NULL,\n initiator TEXT,\n end_sequence INTEGER UNIQUE REFERENCES timeline(sequence) ON DELETE SET NULL,\n outcome TEXT CHECK (outcome IN ('answered', 'failed', 'invalid-output')),\n history_id TEXT UNIQUE,\n session_json TEXT CHECK (session_json IS NULL OR json_valid(session_json)),\n answer TEXT,\n answer_json TEXT CHECK (answer_json IS NULL OR json_valid(answer_json)),\n schema_json TEXT CHECK (schema_json IS NULL OR json_valid(schema_json)),\n diagnostic TEXT,\n completed_at TEXT,\n CHECK (\n (outcome = 'answered' AND session_json IS NOT NULL AND answer IS NOT NULL AND diagnostic IS NULL\n AND ((schema_json IS NULL AND answer_json IS NULL) OR (schema_json IS NOT NULL AND answer_json IS NOT NULL)))\n OR (outcome = 'failed' AND history_id IS NULL AND session_json IS NULL AND answer IS NULL\n AND answer_json IS NULL AND diagnostic IS NOT NULL)\n OR (outcome = 'invalid-output' AND answer IS NOT NULL AND answer_json IS NULL\n AND diagnostic IS NOT NULL AND schema_json IS NOT NULL)\n OR (outcome IS NULL AND end_sequence IS NULL AND history_id IS NULL AND session_json IS NULL\n AND answer IS NULL AND answer_json IS NULL AND diagnostic IS NULL AND completed_at IS NULL)\n )\n ) STRICT;\n CREATE TABLE IF NOT EXISTS timeline (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n kind TEXT NOT NULL CHECK (kind IN ('turn-start', 'call', 'activity', 'tell', 'turn-end'))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS activity_retention (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n checked_sequence INTEGER NOT NULL\n ) STRICT;\n INSERT OR IGNORE INTO activity_retention(singleton, checked_sequence) VALUES (1, 0);\n CREATE TABLE IF NOT EXISTS calls (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n body TEXT NOT NULL,\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS activity (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n event_json TEXT NOT NULL CHECK (json_valid(event_json)),\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tells (\n id TEXT PRIMARY KEY,\n sequence INTEGER NOT NULL UNIQUE REFERENCES timeline(sequence) ON DELETE CASCADE,\n body TEXT NOT NULL,\n initiator TEXT,\n schema_json TEXT CHECK (schema_json IS NULL OR json_valid(schema_json)),\n recorded_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_bindings (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n tell_id TEXT NOT NULL REFERENCES tells(id) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n bound_at TEXT NOT NULL,\n UNIQUE (tell_id, turn_sequence)\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_deliveries (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n tell_id TEXT NOT NULL REFERENCES tells(id) ON DELETE CASCADE,\n route TEXT NOT NULL CHECK (route IN ('launch', 'live')),\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n fence TEXT NOT NULL,\n receipt TEXT CHECK (receipt IN ('unavailable', 'required')),\n delivered_at TEXT NOT NULL,\n CHECK ((route = 'launch' AND receipt IS NULL) OR (route = 'live' AND receipt IS NOT NULL)),\n UNIQUE (tell_id, turn_sequence, fence)\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_receipts (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n evidence TEXT NOT NULL CHECK (evidence IN ('exact', 'fence')),\n tell_id TEXT REFERENCES tells(id) ON DELETE CASCADE,\n turn_sequence INTEGER REFERENCES turns(sequence) ON DELETE CASCADE,\n fence TEXT,\n kind TEXT NOT NULL,\n received_at TEXT NOT NULL,\n CHECK (\n (evidence = 'exact' AND tell_id IS NOT NULL AND turn_sequence IS NULL AND fence IS NULL)\n OR (evidence = 'fence' AND tell_id IS NULL AND turn_sequence IS NOT NULL AND fence IS NOT NULL)\n )\n ) STRICT;\n CREATE UNIQUE INDEX IF NOT EXISTS tell_receipts_exact\n ON tell_receipts(tell_id, kind);\n CREATE UNIQUE INDEX IF NOT EXISTS tell_receipts_fence\n ON tell_receipts(turn_sequence, fence, kind);\n CREATE TABLE IF NOT EXISTS tell_dispositions (\n body_sequence INTEGER PRIMARY KEY REFERENCES bodies(sequence),\n decided_at TEXT NOT NULL,\n resolved_at TEXT\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_disposition_members (\n body_sequence INTEGER NOT NULL REFERENCES tell_dispositions(body_sequence) ON DELETE CASCADE,\n tell_id TEXT NOT NULL REFERENCES tells(id),\n PRIMARY KEY (body_sequence, tell_id)\n ) STRICT;\n CREATE INDEX IF NOT EXISTS calls_by_turn ON calls(turn_sequence);\n CREATE INDEX IF NOT EXISTS activity_by_turn ON activity(turn_sequence);\n CREATE INDEX IF NOT EXISTS tell_bindings_by_turn ON tell_bindings(turn_sequence);\n CREATE INDEX IF NOT EXISTS tell_deliveries_by_turn ON tell_deliveries(turn_sequence);\n CREATE INDEX IF NOT EXISTS tell_disposition_members_by_tell ON tell_disposition_members(tell_id);\n CREATE TABLE IF NOT EXISTS requests (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n id TEXT NOT NULL UNIQUE,\n requester TEXT NOT NULL,\n action TEXT NOT NULL,\n payload_json TEXT NOT NULL CHECK (json_valid(payload_json)),\n admitted_at TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('admitted', 'reserved', 'begun', 'served', 'refused', 'voided', 'unproven')),\n child TEXT,\n service_json TEXT CHECK (service_json IS NULL OR json_valid(service_json)),\n diagnostic TEXT,\n evidence TEXT,\n CHECK (\n (state = 'admitted' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'reserved' AND child IS NOT NULL AND service_json IS NULL\n AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'begun' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'served'\n AND ((child IS NOT NULL AND service_json IS NULL)\n OR (child IS NULL AND service_json IS NOT NULL))\n AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'refused' AND child IS NULL AND service_json IS NULL AND diagnostic IS NOT NULL AND evidence IS NULL)\n OR (state = 'voided' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NOT NULL)\n OR (state = 'unproven' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NOT NULL)\n )\n ) STRICT;\n CREATE TABLE IF NOT EXISTS control (\n kind TEXT PRIMARY KEY CHECK (kind IN ('stop', 'pause')),\n value_json TEXT NOT NULL CHECK (json_valid(value_json)),\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS kills (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n body_sequence INTEGER NOT NULL UNIQUE REFERENCES bodies(sequence),\n evidence TEXT NOT NULL CHECK (evidence = 'killed'),\n at TEXT NOT NULL\n ) STRICT;\n";
6
6
  export declare const LEASH_SCHEMA = "\n PRAGMA journal_mode=DELETE;\n CREATE TABLE IF NOT EXISTS leash_schema (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version = 4)\n ) STRICT;\n INSERT OR IGNORE INTO leash_schema(singleton, version) VALUES (1, 4);\n CREATE TABLE IF NOT EXISTS seal (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n evidence TEXT NOT NULL,\n at TEXT NOT NULL\n ) STRICT;\n";
@@ -1,4 +1,4 @@
1
- const HEART_SCHEMA_VERSION = 28;
1
+ const HEART_SCHEMA_VERSION = 29;
2
2
  const LEASH_SCHEMA_VERSION = 4;
3
3
  function assertSchemaVersion(database, table, expected) {
4
4
  const row = database.prepare(`SELECT version FROM ${table} WHERE singleton = 1`).get();
@@ -52,6 +52,7 @@ export const HEART_SCHEMA = `
52
52
  sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,
53
53
  body_sequence INTEGER NOT NULL REFERENCES bodies(sequence),
54
54
  started_at TEXT NOT NULL,
55
+ initiator TEXT,
55
56
  end_sequence INTEGER UNIQUE REFERENCES timeline(sequence) ON DELETE SET NULL,
56
57
  outcome TEXT CHECK (outcome IN ('answered', 'failed', 'invalid-output')),
57
58
  history_id TEXT UNIQUE,
@@ -97,6 +98,7 @@ export const HEART_SCHEMA = `
97
98
  id TEXT PRIMARY KEY,
98
99
  sequence INTEGER NOT NULL UNIQUE REFERENCES timeline(sequence) ON DELETE CASCADE,
99
100
  body TEXT NOT NULL,
101
+ initiator TEXT,
100
102
  schema_json TEXT CHECK (schema_json IS NULL OR json_valid(schema_json)),
101
103
  recorded_at TEXT NOT NULL
102
104
  ) STRICT;
@@ -52,6 +52,7 @@ function decodeTellRows(database, rows) {
52
52
  sequence: row.sequence,
53
53
  id: row.id,
54
54
  body: row.body,
55
+ ...(row.initiator === null ? {} : { initiator: row.initiator }),
55
56
  ...(row.schema_json === null ? {} : { schemaJson: row.schema_json }),
56
57
  state: row.state,
57
58
  recordedAt: row.recorded_at,
@@ -63,7 +64,7 @@ export function tellFactsAtSequences(database, sequences) {
63
64
  if (sequences.length === 0)
64
65
  return [];
65
66
  const rows = database
66
- .prepare(`SELECT sequence, id, body, schema_json, recorded_at, ${tellStateSql} AS state
67
+ .prepare(`SELECT sequence, id, body, initiator, schema_json, recorded_at, ${tellStateSql} AS state
67
68
  FROM tells WHERE sequence IN (SELECT value FROM json_each(?)) ORDER BY sequence`)
68
69
  .all(JSON.stringify(sequences));
69
70
  return decodeTellRows(database, rows);
@@ -74,13 +75,13 @@ export function hasPendingTell(database) {
74
75
  export function insertTellFact(database, tell) {
75
76
  const sequence = Number(database.prepare("INSERT INTO timeline(kind) VALUES ('tell')").run().lastInsertRowid);
76
77
  database
77
- .prepare("INSERT INTO tells(id, sequence, body, schema_json, recorded_at) VALUES (?, ?, ?, ?, ?)")
78
- .run(tell.id, sequence, tell.body, tell.schemaJson ?? null, tell.recordedAt);
78
+ .prepare("INSERT INTO tells(id, sequence, body, initiator, schema_json, recorded_at) VALUES (?, ?, ?, ?, ?, ?)")
79
+ .run(tell.id, sequence, tell.body, tell.initiator ?? null, tell.schemaJson ?? null, tell.recordedAt);
79
80
  return sequence;
80
81
  }
81
82
  export function tellFact(database, id) {
82
83
  const row = database
83
- .prepare(`SELECT sequence, id, body, schema_json, recorded_at, ${tellStateSql} AS state
84
+ .prepare(`SELECT sequence, id, body, initiator, schema_json, recorded_at, ${tellStateSql} AS state
84
85
  FROM tells WHERE id = ?`)
85
86
  .get(id);
86
87
  return row === undefined ? null : decodeTellRows(database, [row])[0];
@@ -119,7 +120,7 @@ export function tellIdsForFence(database, turnSequence, fence) {
119
120
  }
120
121
  export function pendingTellFacts(database) {
121
122
  const rows = database
122
- .prepare(`SELECT sequence, id, body, schema_json, recorded_at, ${tellStateSql} AS state FROM tells
123
+ .prepare(`SELECT sequence, id, body, initiator, schema_json, recorded_at, ${tellStateSql} AS state FROM tells
123
124
  WHERE ${tellStateSql} = 'pending' ORDER BY sequence`)
124
125
  .all();
125
126
  return decodeTellRows(database, rows);
@@ -57,7 +57,7 @@ function decodeTimelineRows(database, rows) {
57
57
  const facts = new Map();
58
58
  const turns = database
59
59
  .prepare(`SELECT sequence, body_sequence, started_at, end_sequence, outcome,
60
- history_id, session_json, answer, answer_json, schema_json, diagnostic, completed_at FROM turns
60
+ history_id, session_json, answer, answer_json, schema_json, initiator, diagnostic, completed_at FROM turns
61
61
  WHERE sequence IN (SELECT value FROM json_each(?)) OR end_sequence IN (SELECT value FROM json_each(?))`)
62
62
  .all(sequences("turn-start"), sequences("turn-end"));
63
63
  for (const row of turns) {
@@ -4,6 +4,7 @@ export type ProviderOptions = Readonly<{
4
4
  effort?: string;
5
5
  readonly?: true;
6
6
  network?: "disabled" | "enabled";
7
+ sandbox?: "full-access";
7
8
  systemPrompt?: string;
8
9
  systemPromptMode?: SystemPromptMode;
9
10
  }>;
@@ -33,6 +33,10 @@ export function decodeProviderOptions(value) {
33
33
  if (network !== undefined && network !== "disabled" && network !== "enabled") {
34
34
  throw new TypeError("provider option network must be disabled, enabled");
35
35
  }
36
+ const sandbox = options.sandbox;
37
+ if (sandbox !== undefined && sandbox !== "full-access") {
38
+ throw new TypeError("provider option sandbox must be full-access");
39
+ }
36
40
  const systemPrompt = optionText(options, "systemPrompt", "allow");
37
41
  const systemPromptMode = options.systemPromptMode;
38
42
  if (systemPromptMode !== undefined) {
@@ -48,6 +52,7 @@ export function decodeProviderOptions(value) {
48
52
  ...(effort === undefined ? {} : { effort }),
49
53
  ...(options.readonly === undefined ? {} : { readonly: true }),
50
54
  ...(network === undefined ? {} : { network }),
55
+ ...(sandbox === undefined ? {} : { sandbox }),
51
56
  ...(systemPrompt === undefined ? {} : { systemPrompt }),
52
57
  ...(systemPromptMode === undefined ? {} : { systemPromptMode }),
53
58
  });
@@ -1,7 +1,7 @@
1
1
  import { decodeResumeCoordinate, encodeResumeCoordinate, type ResumeCoordinate } from "./coordinate.js";
2
2
  import type { ProviderOptions, ReadonlyRestraint } from "./provider-recipe.js";
3
3
  export type { ResumeCoordinate } from "./coordinate.js";
4
- export declare const AKUMA_REQUESTS_ENV = "AKUMA_REQUESTS";
4
+ export { AKUMA_REQUESTS_ENV } from "./providers/execution-environment.js";
5
5
  export declare const AGENT_EVENT_TEXT_LIMIT = 16384;
6
6
  export declare const AGENT_THOUGHT_TEXT_LIMIT = 4000;
7
7
  export declare const AGENT_EVENT_QUEUE_LIMIT = 256;
@@ -1,5 +1,5 @@
1
1
  import { decodeResumeCoordinate, encodeResumeCoordinate } from "./coordinate.js";
2
- export const AKUMA_REQUESTS_ENV = "AKUMA_REQUESTS";
2
+ export { AKUMA_REQUESTS_ENV } from "./providers/execution-environment.js";
3
3
  export const AGENT_EVENT_TEXT_LIMIT = 16_384;
4
4
  export const AGENT_THOUGHT_TEXT_LIMIT = 4_000;
5
5
  export const AGENT_EVENT_QUEUE_LIMIT = 256;
@@ -1,7 +1,8 @@
1
1
  import { Readable, Writable } from "node:stream";
2
2
  import { spawnStdioProcess } from "../../../runtime/proc/stdio.js";
3
3
  import { abortable } from "../../abort.js";
4
- import { AKUMA_REQUESTS_ENV, AgentEventChannel, } from "../../provider.js";
4
+ import { AgentEventChannel, } from "../../provider.js";
5
+ import { akumaExecutionEnvironment } from "../execution-environment.js";
5
6
  import { EMPTY_ACP_EVENT_STATE, flushAcpEvents, mapAcpUpdate, } from "./events.js";
6
7
  function diagnostic(acp, error) {
7
8
  if (!(error instanceof Error))
@@ -156,11 +157,7 @@ export async function startAcpSession(launch, input, dependencies = {}, custody)
156
157
  const child = (dependencies.spawnProcess ?? spawnStdioProcess)({
157
158
  argv: launch.argv,
158
159
  cwd: input.cwd,
159
- env: {
160
- ...globalThis.process.env,
161
- ...launch.env,
162
- ...(input.requests === undefined ? {} : { [AKUMA_REQUESTS_ENV]: input.requests.dir }),
163
- },
160
+ env: akumaExecutionEnvironment(globalThis.process.env, launch.env, input.requests?.dir),
164
161
  });
165
162
  custody?.own({
166
163
  closed: child.exited.then(() => undefined),
@@ -3,6 +3,9 @@ import { decodeAcpConfig } from "./config.js";
3
3
  import { startAcpSession } from "./core.js";
4
4
  export { decodeAcpConfig } from "./config.js";
5
5
  function optionAdmission(options, config) {
6
+ if (options.sandbox !== undefined) {
7
+ return { kind: "refused", diagnostic: "ACP provider does not support the sandbox option" };
8
+ }
6
9
  if (options.network !== undefined) {
7
10
  return { kind: "refused", diagnostic: "ACP provider does not support the network option" };
8
11
  }
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { abortable } from "../../abort.js";
3
- import { AKUMA_REQUESTS_ENV, AgentEventChannel, createProviderAttempt, } from "../../provider.js";
3
+ import { AgentEventChannel, createProviderAttempt, } from "../../provider.js";
4
+ import { akumaExecutionEnvironment } from "../execution-environment.js";
4
5
  import { emitClaudeMessage } from "./events.js";
5
6
  import { claudeUserMessage, createClaudeInput, isClaudeTurnEnded } from "./input.js";
6
7
  export { CLAUDE_MESSAGE_DISPOSITIONS, CLAUDE_SYSTEM_DISPOSITIONS } from "./events.js";
@@ -38,6 +39,12 @@ class ReceiptChannel {
38
39
  }
39
40
  }
40
41
  function admitClaudeOptions(options) {
42
+ if (options.sandbox === "full-access" && options.readonly === true) {
43
+ return { kind: "refused", diagnostic: "Claude full-access sandbox cannot combine with readonly" };
44
+ }
45
+ if (options.sandbox === "full-access" && options.network === "disabled") {
46
+ return { kind: "refused", diagnostic: "Claude full-access sandbox cannot combine with disabled network" };
47
+ }
41
48
  if (options.network !== undefined) {
42
49
  return { kind: "refused", diagnostic: "Claude provider does not support the network option" };
43
50
  }
@@ -64,18 +71,11 @@ function claudeQueryOptions(input, execution, abortController) {
64
71
  abortController,
65
72
  ...(input.requests === undefined ? {} : { additionalDirectories: [input.requests.dir] }),
66
73
  ...(execution.executable === undefined ? {} : { pathToClaudeCodeExecutable: execution.executable }),
67
- ...(execution.env === undefined && input.requests === undefined
68
- ? {}
69
- : {
70
- env: {
71
- ...process.env,
72
- ...execution.env,
73
- ...(input.requests === undefined ? {} : { [AKUMA_REQUESTS_ENV]: input.requests.dir }),
74
- },
75
- }),
74
+ env: akumaExecutionEnvironment(process.env, execution.env, input.requests?.dir),
76
75
  permissionMode: mode,
77
76
  ...(mode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}),
78
77
  settingSources: ["user", "project", "local"],
78
+ ...(input.options.sandbox === "full-access" ? { sandbox: { enabled: false } } : {}),
79
79
  ...(input.options.model === undefined ? {} : { model: input.options.model }),
80
80
  ...(input.options.effort === undefined ? {} : { effort: input.options.effort }),
81
81
  ...(input.options.systemPrompt === undefined || input.options.systemPrompt.length === 0
@@ -1,5 +1,6 @@
1
1
  import { LineRpcProcess } from "../../../runtime/proc/line-rpc.js";
2
- import { AgentEventChannel, AKUMA_REQUESTS_ENV, createProviderAttempt, } from "../../provider.js";
2
+ import { AgentEventChannel, createProviderAttempt, } from "../../provider.js";
3
+ import { akumaExecutionEnvironment } from "../execution-environment.js";
3
4
  import { codexNotificationResult, codexObject, codexText } from "./events.js";
4
5
  export { CODEX_ITEM_DISPOSITIONS, CODEX_NOTIFICATION_DISPOSITIONS } from "./events.js";
5
6
  function diagnostic(error) {
@@ -48,6 +49,8 @@ async function steerTurn(server, state, tell) {
48
49
  return { kind: "accepted", fence: `${accepted}:${tell.id}` };
49
50
  }
50
51
  function sandbox(cwd, options, requests) {
52
+ if (options.sandbox === "full-access")
53
+ return { type: "dangerFullAccess" };
51
54
  if (options.readonly === true) {
52
55
  return { type: "readOnly", networkAccess: options.network === "enabled" };
53
56
  }
@@ -104,7 +107,7 @@ async function forkCodex(execution, input, custody) {
104
107
  const server = new LineRpcProcess({
105
108
  argv: [execution.executable ?? "codex", "app-server", "--listen", "stdio://"],
106
109
  cwd: input.cwd,
107
- ...(execution.env === undefined ? {} : { env: { ...process.env, ...execution.env } }),
110
+ env: akumaExecutionEnvironment(process.env, execution.env),
108
111
  });
109
112
  const closed = new Promise((resolve) => server.onExit(() => resolve()));
110
113
  custody.own({
@@ -135,15 +138,7 @@ function codexServer(execution, input) {
135
138
  return new LineRpcProcess({
136
139
  argv: [execution.executable ?? "codex", "app-server", "--listen", "stdio://"],
137
140
  cwd: input.cwd,
138
- ...(execution.env === undefined && input.requests === undefined
139
- ? {}
140
- : {
141
- env: {
142
- ...process.env,
143
- ...execution.env,
144
- ...(input.requests === undefined ? {} : { [AKUMA_REQUESTS_ENV]: input.requests.dir }),
145
- },
146
- }),
141
+ env: akumaExecutionEnvironment(process.env, execution.env, input.requests?.dir),
147
142
  });
148
143
  }
149
144
  async function startCodex(execution, input, custody) {
@@ -228,6 +223,12 @@ export function createCodexAppServerProvider(input = "codex") {
228
223
  const execution = typeof input === "string" ? { name: "codex-app-server", kind: "codex-app-server", executable: input } : input;
229
224
  return {
230
225
  admitOptions(options) {
226
+ if (options.sandbox === "full-access" && options.readonly === true) {
227
+ return { kind: "refused", diagnostic: "Codex full-access sandbox cannot combine with readonly" };
228
+ }
229
+ if (options.sandbox === "full-access" && options.network === "disabled") {
230
+ return { kind: "refused", diagnostic: "Codex full-access sandbox cannot combine with disabled network" };
231
+ }
231
232
  return {
232
233
  kind: "admitted",
233
234
  options: Object.freeze({ ...options }),
@@ -0,0 +1,6 @@
1
+ export declare const AKUMA_REQUESTS_ENV = "AKUMA_REQUESTS";
2
+ declare const PARENT_HARNESS_IDENTITY_KEYS: readonly ["CLAUDE_CODE_SESSION_ID", "CLAUDE_CODE_CHILD_SESSION", "CLAUDECODE", "CODEX_THREAD_ID", "OPENCODE_SESSION_ID", "PI_SESSION_ID", "PI_SESSION_FILE", "PASEO_AGENT_ID", "SQUARE_PARTICIPANT_NAME"];
3
+ type Environment = Readonly<Record<string, string | undefined>>;
4
+ /** Construct the environment for one isolated Akuma execution or native child. */
5
+ export declare function akumaExecutionEnvironment(inherited: Environment, overrides?: Environment, requests?: string, nativeIdentity?: readonly (typeof PARENT_HARNESS_IDENTITY_KEYS)[number][]): Record<string, string>;
6
+ export {};