@astrosheep/keiyaku 4.0.0 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/README.md +133 -8
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +2 -2
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +4 -4
  4. package/build/integrations/marketplace/plugins/keiyaku/opencode.js +2 -2
  5. package/build/integrations/marketplace/plugins/keiyaku/package.json +2 -2
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +13 -5
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -32
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +134 -0
  9. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/agents/openai.yaml +4 -0
  10. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +41 -6
  11. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +262 -46
  12. package/build/src/akuma/abort.d.ts +2 -0
  13. package/build/src/akuma/abort.js +50 -0
  14. package/build/src/akuma/akuma.d.ts +50 -33
  15. package/build/src/akuma/akuma.js +175 -127
  16. package/build/src/akuma/archetype.d.ts +14 -5
  17. package/build/src/akuma/archetype.js +85 -39
  18. package/build/src/akuma/body.d.ts +3 -5
  19. package/build/src/akuma/body.js +490 -183
  20. package/build/src/akuma/coordinate.d.ts +9 -0
  21. package/build/src/akuma/coordinate.js +22 -0
  22. package/build/src/akuma/heart/facts.d.ts +88 -45
  23. package/build/src/akuma/heart/facts.js +19 -8
  24. package/build/src/akuma/heart/index.d.ts +64 -55
  25. package/build/src/akuma/heart/index.js +172 -252
  26. package/build/src/akuma/heart/rows.d.ts +38 -83
  27. package/build/src/akuma/heart/rows.js +117 -155
  28. package/build/src/akuma/heart/schema.d.ts +1 -1
  29. package/build/src/akuma/heart/schema.js +61 -22
  30. package/build/src/akuma/heart/soul.d.ts +8 -0
  31. package/build/src/akuma/heart/soul.js +136 -0
  32. package/build/src/akuma/heart/storage.d.ts +47 -0
  33. package/build/src/akuma/heart/storage.js +224 -0
  34. package/build/src/akuma/heart/tells.d.ts +12 -0
  35. package/build/src/akuma/heart/tells.js +79 -0
  36. package/build/src/akuma/heart/timeline.d.ts +15 -0
  37. package/build/src/akuma/heart/timeline.js +86 -0
  38. package/build/src/akuma/identity.d.ts +2 -2
  39. package/build/src/akuma/identity.js +9 -9
  40. package/build/src/akuma/index.d.ts +10 -3
  41. package/build/src/akuma/index.js +7 -1
  42. package/build/src/akuma/projection.d.ts +176 -0
  43. package/build/src/akuma/projection.js +256 -0
  44. package/build/src/akuma/provider-recipe.d.ts +24 -0
  45. package/build/src/akuma/provider-recipe.js +100 -0
  46. package/build/src/akuma/provider.d.ts +67 -13
  47. package/build/src/akuma/provider.js +172 -105
  48. package/build/src/akuma/providers/acp/core.d.ts +19 -0
  49. package/build/src/akuma/providers/acp/core.js +159 -0
  50. package/build/src/akuma/providers/acp/events.d.ts +20 -0
  51. package/build/src/akuma/providers/acp/events.js +73 -0
  52. package/build/src/akuma/providers/acp/index.d.ts +12 -0
  53. package/build/src/akuma/providers/acp/index.js +94 -0
  54. package/build/src/akuma/providers/{claude.d.ts → claude/events.d.ts} +9 -41
  55. package/build/src/akuma/providers/claude/events.js +238 -0
  56. package/build/src/akuma/providers/claude/index.d.ts +47 -0
  57. package/build/src/akuma/providers/claude/index.js +279 -0
  58. package/build/src/akuma/providers/claude/input.d.ts +13 -0
  59. package/build/src/akuma/providers/claude/input.js +109 -0
  60. package/build/src/akuma/providers/codex-app-server/events.d.ts +1 -1
  61. package/build/src/akuma/providers/codex-app-server/events.js +15 -12
  62. package/build/src/akuma/providers/codex-app-server/index.d.ts +15 -13
  63. package/build/src/akuma/providers/codex-app-server/index.js +77 -33
  64. package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
  65. package/build/src/akuma/providers/grok-build/index.js +70 -0
  66. package/build/src/akuma/providers/index.d.ts +5 -3
  67. package/build/src/akuma/providers/index.js +35 -56
  68. package/build/src/akuma/providers/opencode-sdk/events.d.ts +54 -0
  69. package/build/src/akuma/providers/opencode-sdk/events.js +235 -0
  70. package/build/src/akuma/providers/opencode-sdk/index.d.ts +33 -0
  71. package/build/src/akuma/providers/opencode-sdk/index.js +308 -0
  72. package/build/src/akuma/providers/opencode-sdk/session.d.ts +26 -0
  73. package/build/src/akuma/providers/opencode-sdk/session.js +63 -0
  74. package/build/src/akuma/providers/pi/events.d.ts +33 -0
  75. package/build/src/akuma/providers/pi/events.js +166 -0
  76. package/build/src/akuma/providers/pi/index.d.ts +11 -0
  77. package/build/src/akuma/providers/pi/index.js +191 -0
  78. package/build/src/akuma/publication.d.ts +3 -3
  79. package/build/src/akuma/publication.js +28 -40
  80. package/build/src/akuma/requests.d.ts +9 -6
  81. package/build/src/akuma/requests.js +95 -65
  82. package/build/src/alias/index.d.ts +4 -3
  83. package/build/src/alias/index.js +12 -13
  84. package/build/src/body/decode.js +7 -1
  85. package/build/src/body/region.d.ts +2 -0
  86. package/build/src/body/region.js +77 -7
  87. package/build/src/body/render.js +2 -1
  88. package/build/src/body/shape.js +7 -1
  89. package/build/src/body/verification.js +19 -4
  90. package/build/src/cli/accepted.d.ts +18 -12
  91. package/build/src/cli/accepted.js +73 -34
  92. package/build/src/cli/actor.js +3 -3
  93. package/build/src/cli/commands/akuma-invoke.d.ts +44 -19
  94. package/build/src/cli/commands/akuma-invoke.js +101 -52
  95. package/build/src/cli/commands/akuma.d.ts +27 -9
  96. package/build/src/cli/commands/akuma.js +151 -80
  97. package/build/src/cli/commands/contract.d.ts +155 -0
  98. package/build/src/cli/commands/contract.js +20 -0
  99. package/build/src/cli/commands/install.js +2 -0
  100. package/build/src/cli/commands/task-invoke.d.ts +19 -4
  101. package/build/src/cli/commands/task-invoke.js +65 -17
  102. package/build/src/cli/commands/task-query.d.ts +5 -0
  103. package/build/src/cli/commands/task-query.js +247 -0
  104. package/build/src/cli/commands/task.d.ts +3 -1
  105. package/build/src/cli/commands/task.js +52 -14
  106. package/build/src/cli/coordinates.d.ts +18 -0
  107. package/build/src/cli/coordinates.js +120 -0
  108. package/build/src/cli/draft.d.ts +8 -0
  109. package/build/src/cli/draft.js +96 -0
  110. package/build/src/cli/invoke.d.ts +9 -3
  111. package/build/src/cli/invoke.js +287 -108
  112. package/build/src/cli/main.js +54 -7
  113. package/build/src/cli/parse.d.ts +21 -117
  114. package/build/src/cli/parse.js +79 -84
  115. package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
  116. package/build/src/cli/render/akuma-tool-command.js +144 -0
  117. package/build/src/cli/render/akuma-tool.d.ts +4 -2
  118. package/build/src/cli/render/akuma-tool.js +35 -5
  119. package/build/src/cli/render/akuma.d.ts +3 -1
  120. package/build/src/cli/render/akuma.js +247 -212
  121. package/build/src/cli/render/audit.d.ts +3 -0
  122. package/build/src/cli/render/audit.js +104 -0
  123. package/build/src/cli/render/catalog.d.ts +2 -0
  124. package/build/src/cli/render/catalog.js +16 -0
  125. package/build/src/cli/render/contract.d.ts +3 -3
  126. package/build/src/cli/render/contract.js +200 -54
  127. package/build/src/cli/render/kanshi.js +272 -129
  128. package/build/src/cli/render/receipt.d.ts +19 -0
  129. package/build/src/cli/render/receipt.js +106 -0
  130. package/build/src/cli/render/refusal.d.ts +16 -2
  131. package/build/src/cli/render/refusal.js +88 -3
  132. package/build/src/cli/render/region.d.ts +2 -0
  133. package/build/src/cli/render/region.js +17 -0
  134. package/build/src/cli/render/task.d.ts +2 -1
  135. package/build/src/cli/render/task.js +223 -60
  136. package/build/src/cli/render/terminal.d.ts +20 -0
  137. package/build/src/cli/render/terminal.js +121 -0
  138. package/build/src/cli/render/text.js +11 -3
  139. package/build/src/cli/result.d.ts +126 -19
  140. package/build/src/cli/usage.d.ts +1 -0
  141. package/build/src/cli/usage.js +3 -0
  142. package/build/src/contract-worktree.d.ts +44 -0
  143. package/build/src/contract-worktree.js +251 -0
  144. package/build/src/coordination/durable-file.d.ts +5 -1
  145. package/build/src/coordination/durable-file.js +57 -10
  146. package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
  147. package/build/src/coordination/sqlite-transaction-lock.js +22 -5
  148. package/build/src/core/facts/codec.js +23 -4
  149. package/build/src/core/facts/eligibility.d.ts +1 -10
  150. package/build/src/core/facts/eligibility.js +0 -49
  151. package/build/src/core/facts/fold.js +1 -6
  152. package/build/src/core/facts/gate.d.ts +1 -0
  153. package/build/src/core/facts/gate.js +1 -0
  154. package/build/src/core/facts/observation.d.ts +3 -0
  155. package/build/src/core/facts/observation.js +12 -0
  156. package/build/src/core/facts/types.d.ts +10 -3
  157. package/build/src/core/subject.js +2 -2
  158. package/build/src/core/verbs/amend.d.ts +1 -1
  159. package/build/src/core/verbs/amend.js +3 -18
  160. package/build/src/core/verbs/bind.js +2 -16
  161. package/build/src/core/verbs/deliver.d.ts +1 -1
  162. package/build/src/core/verbs/deliver.js +14 -4
  163. package/build/src/core/verbs/placement.d.ts +1 -1
  164. package/build/src/core/verbs/placement.js +7 -9
  165. package/build/src/dispatch/index.d.ts +5 -3
  166. package/build/src/dispatch/index.js +30 -21
  167. package/build/src/duration.d.ts +10 -0
  168. package/build/src/duration.js +22 -0
  169. package/build/src/git/admission.d.ts +2 -2
  170. package/build/src/git/admission.js +33 -23
  171. package/build/src/git/hooks.d.ts +15 -0
  172. package/build/src/git/hooks.js +70 -18
  173. package/build/src/git/identity.d.ts +5 -1
  174. package/build/src/git/identity.js +23 -4
  175. package/build/src/git/integration.d.ts +48 -0
  176. package/build/src/git/integration.js +250 -0
  177. package/build/src/git/observe.d.ts +29 -15
  178. package/build/src/git/observe.js +185 -76
  179. package/build/src/git/read-observation.d.ts +41 -0
  180. package/build/src/git/read-observation.js +361 -0
  181. package/build/src/git/reconcile.d.ts +17 -5
  182. package/build/src/git/reconcile.js +305 -109
  183. package/build/src/git/repository.d.ts +41 -18
  184. package/build/src/git/repository.js +220 -114
  185. package/build/src/git/scratch.d.ts +17 -0
  186. package/build/src/git/scratch.js +73 -0
  187. package/build/src/git/target-placement.d.ts +92 -0
  188. package/build/src/git/target-placement.js +375 -0
  189. package/build/src/git/tender.d.ts +49 -0
  190. package/build/src/git/tender.js +63 -0
  191. package/build/src/git/terminal-seal.d.ts +24 -0
  192. package/build/src/git/terminal-seal.js +89 -0
  193. package/build/src/git/tree.d.ts +2 -2
  194. package/build/src/git/tree.js +4 -0
  195. package/build/src/git/workspace.d.ts +53 -0
  196. package/build/src/git/workspace.js +139 -0
  197. package/build/src/identity/selector.d.ts +6 -0
  198. package/build/src/identity/selector.js +19 -0
  199. package/build/src/index.d.ts +4 -2
  200. package/build/src/index.js +2 -1
  201. package/build/src/kanshi/index.d.ts +2 -2
  202. package/build/src/kanshi/index.js +1 -1
  203. package/build/src/kanshi/read.d.ts +7 -3
  204. package/build/src/kanshi/read.js +245 -45
  205. package/build/src/kanshi/report.d.ts +81 -6
  206. package/build/src/kanshi/select.d.ts +5 -0
  207. package/build/src/kanshi/select.js +33 -1
  208. package/build/src/library/address.d.ts +57 -0
  209. package/build/src/library/address.js +165 -0
  210. package/build/src/library/akuma-creation.d.ts +16 -7
  211. package/build/src/library/akuma-creation.js +96 -22
  212. package/build/src/library/audit.d.ts +18 -0
  213. package/build/src/library/audit.js +44 -0
  214. package/build/src/library/bind.d.ts +21 -0
  215. package/build/src/library/bind.js +56 -0
  216. package/build/src/library/catalog.d.ts +58 -0
  217. package/build/src/library/catalog.js +69 -0
  218. package/build/src/library/configuration.d.ts +6 -15
  219. package/build/src/library/configuration.js +14 -17
  220. package/build/src/library/contract.d.ts +23 -49
  221. package/build/src/library/contract.js +171 -185
  222. package/build/src/library/delivery.d.ts +24 -0
  223. package/build/src/library/delivery.js +21 -0
  224. package/build/src/library/fleet.d.ts +65 -0
  225. package/build/src/library/fleet.js +153 -0
  226. package/build/src/library/input.d.ts +3 -0
  227. package/build/src/library/input.js +19 -0
  228. package/build/src/library/keiyaku.d.ts +18 -3
  229. package/build/src/library/keiyaku.js +12 -1
  230. package/build/src/library/mutation.d.ts +39 -0
  231. package/build/src/library/mutation.js +37 -0
  232. package/build/src/library/reconcile.d.ts +29 -0
  233. package/build/src/library/reconcile.js +179 -0
  234. package/build/src/library/refusal.d.ts +21 -0
  235. package/build/src/library/refusal.js +29 -0
  236. package/build/src/library/region.d.ts +14 -1
  237. package/build/src/library/region.js +18 -4
  238. package/build/src/library/repo.d.ts +4 -13
  239. package/build/src/library/repo.js +14 -24
  240. package/build/src/protocol/attempt.d.ts +16 -3
  241. package/build/src/protocol/attempt.js +41 -10
  242. package/build/src/protocol/bind.d.ts +9 -2
  243. package/build/src/protocol/bind.js +48 -40
  244. package/build/src/protocol/intent.d.ts +57 -20
  245. package/build/src/protocol/intent.js +55 -79
  246. package/build/src/protocol/operations.d.ts +152 -43
  247. package/build/src/protocol/operations.js +482 -166
  248. package/build/src/protocol/outcome.d.ts +14 -3
  249. package/build/src/protocol/outcome.js +11 -3
  250. package/build/src/protocol/placement.d.ts +41 -0
  251. package/build/src/protocol/placement.js +147 -0
  252. package/build/src/protocol/read/documents.d.ts +2 -2
  253. package/build/src/protocol/read/documents.js +4 -4
  254. package/build/src/protocol/read/status.d.ts +18 -5
  255. package/build/src/protocol/read/status.js +73 -13
  256. package/build/src/protocol/run.d.ts +49 -7
  257. package/build/src/protocol/run.js +53 -25
  258. package/build/src/runtime/proc/line-rpc.d.ts +4 -8
  259. package/build/src/runtime/proc/line-rpc.js +22 -28
  260. package/build/src/runtime/proc/run.d.ts +23 -21
  261. package/build/src/runtime/proc/run.js +123 -89
  262. package/build/src/runtime/proc/stdio.d.ts +18 -0
  263. package/build/src/runtime/proc/stdio.js +58 -0
  264. package/build/src/settings.d.ts +7 -1
  265. package/build/src/settings.js +32 -17
  266. package/build/src/settlement/fence.d.ts +5 -0
  267. package/build/src/settlement/fence.js +14 -0
  268. package/build/src/settlement/holder.d.ts +35 -4
  269. package/build/src/settlement/holder.js +127 -28
  270. package/build/src/settlement/settle.d.ts +9 -1
  271. package/build/src/settlement/settle.js +74 -37
  272. package/build/src/task/board.d.ts +23 -5
  273. package/build/src/task/board.js +17 -10
  274. package/build/src/task/compose.d.ts +2 -2
  275. package/build/src/task/compose.js +18 -10
  276. package/build/src/task/context.d.ts +3 -3
  277. package/build/src/task/context.js +15 -20
  278. package/build/src/task/document.d.ts +2 -1
  279. package/build/src/task/document.js +15 -5
  280. package/build/src/task/index.d.ts +27 -15
  281. package/build/src/task/index.js +57 -35
  282. package/build/src/task/operations.d.ts +38 -13
  283. package/build/src/task/operations.js +80 -46
  284. package/build/src/task/query.d.ts +67 -0
  285. package/build/src/task/query.js +279 -0
  286. package/build/src/task/store.d.ts +5 -7
  287. package/build/src/task/store.js +43 -28
  288. package/build/src/verification/declaration.d.ts +1 -0
  289. package/build/src/verification/execution.d.ts +51 -0
  290. package/build/src/verification/execution.js +108 -0
  291. package/build/src/workspace-place.d.ts +41 -0
  292. package/build/src/workspace-place.js +386 -0
  293. package/build/src/world.d.ts +24 -0
  294. package/build/src/world.js +136 -0
  295. package/package.json +8 -4
  296. package/build/src/akuma/activity.d.ts +0 -66
  297. package/build/src/akuma/activity.js +0 -139
  298. package/build/src/akuma/providers/claude.js +0 -305
  299. package/build/src/context-root.d.ts +0 -4
  300. package/build/src/context-root.js +0 -15
  301. package/build/src/git/delivery.d.ts +0 -20
  302. package/build/src/git/delivery.js +0 -109
  303. package/build/src/git/verification.d.ts +0 -14
  304. package/build/src/git/verification.js +0 -56
  305. package/build/src/protocol/read/audit.d.ts +0 -25
  306. package/build/src/protocol/read/audit.js +0 -39
  307. package/build/src/verification/producer.d.ts +0 -23
  308. package/build/src/verification/producer.js +0 -54
@@ -1,27 +1,15 @@
1
1
  import type { DatabaseSync } from "node:sqlite";
2
2
  import type { AkuId } from "../identity.js";
3
- import type { BodyEnd, BodyFact, Collar, DeathFact, RequestFact, RequestInput, ResumeCoordinate, SessionFact, Soul, TellFact, TellState, TurnFact } from "./facts.js";
4
- export type SoulRow = Readonly<{
5
- id: string;
6
- archetype: string;
7
- description: string | null;
8
- provider_json: string;
9
- options_json: string;
10
- cwd: string;
11
- origin_json: string;
12
- confinement_json: string;
13
- created_at: string;
14
- }>;
3
+ import type { BodyEnd, BodyFact, CallFact, KillFact, PauseFact, RequestFact, RequestInput, ResumeCoordinate, SessionFact, StopFact, TurnFact, TurnStartFact, TurnEndFact } from "./facts.js";
15
4
  export type SealRow = Readonly<{
16
5
  evidence: string;
17
6
  at: string;
18
7
  }>;
19
8
  export type BodyRow = Readonly<{
20
9
  sequence: number;
21
- pid: number;
22
- process_group: number;
23
- spawned_at: string;
24
10
  leash_taken_at: string;
11
+ hung_diagnostic: string | null;
12
+ hung_at: string | null;
25
13
  end: BodyEnd | null;
26
14
  ended_at: string | null;
27
15
  }>;
@@ -36,18 +24,20 @@ export type SessionRow = Readonly<{
36
24
  export type TurnRow = Readonly<{
37
25
  sequence: number;
38
26
  body_sequence: number;
39
- outcome: "answered" | "failed";
27
+ started_at: string;
28
+ end_sequence: number | null;
29
+ outcome: "answered" | "failed" | null;
40
30
  history_id: string | null;
41
31
  session_json: string | null;
42
32
  answer: string | null;
43
33
  diagnostic: string | null;
44
- completed_at: string;
34
+ completed_at: string | null;
45
35
  }>;
46
- export type TellRow = Readonly<{
47
- id: string;
36
+ export type CallRow = Readonly<{
37
+ sequence: number;
38
+ turn_sequence: number;
48
39
  body: string;
49
- state: TellState;
50
- recorded_at: string;
40
+ at: string;
51
41
  }>;
52
42
  export type RequestRow = Readonly<{
53
43
  sequence: number;
@@ -65,80 +55,52 @@ export type RequestRow = Readonly<{
65
55
  }>;
66
56
  export type ActivityRow = Readonly<{
67
57
  sequence: number;
68
- body_sequence: number;
58
+ turn_sequence: number;
69
59
  event_json: string;
70
60
  at: string;
71
61
  }>;
72
62
  export type ActivityFact = Readonly<{
63
+ kind: "activity";
73
64
  sequence: number;
74
- bodySequence: number;
65
+ turnSequence: number;
75
66
  event: unknown;
76
67
  at: string;
77
68
  }>;
78
- export type ActivityFactSlice = Readonly<{
79
- rows: readonly ActivityFact[];
80
- lowestRetained: number | null;
81
- highest: number | null;
82
- }>;
83
- export type DeathRow = Readonly<{
84
- value_json: string;
69
+ export type KillRow = Readonly<{
70
+ sequence: number;
71
+ body_sequence: number;
72
+ evidence: "killed";
85
73
  at: string;
86
74
  }>;
87
- export declare function encodeSoulRow(soul: Soul): readonly [
88
- AkuId,
89
- string,
90
- string | null,
91
- string,
92
- string,
93
- string,
94
- string,
95
- string,
96
- string
97
- ];
98
- export declare function decodeSoulRow(row: SoulRow): Soul;
99
75
  export declare function encodeSessionRow(session: Omit<SessionFact, "sequence">): readonly [string, string, string, string, string];
100
76
  export declare function encodeResumeCoordinate(coordinate: ResumeCoordinate): string;
101
77
  export declare function decodeSessionRow(row: SessionRow): SessionFact;
102
78
  export declare function decodeBodyRow(row: BodyRow): BodyFact;
103
79
  export declare function decodeTurnRow(row: TurnRow): TurnFact;
104
- export declare function decodeTellRow(row: TellRow): TellFact;
80
+ export declare function decodeCallRow(row: CallRow): CallFact;
105
81
  export declare function decodeRequestRow(row: RequestRow): RequestFact;
106
82
  export declare function encodeActivityEvent(event: unknown): string;
107
83
  export declare function decodeActivityRow(row: ActivityRow): ActivityFact;
108
- export declare function encodeDeathRow(death: DeathFact): string;
109
- export declare function decodeDeathRow(row: DeathRow): DeathFact;
110
- export declare function soulFact(database: DatabaseSync): Soul | null;
111
84
  export declare function sealExists(database: DatabaseSync): boolean;
112
- export declare function insertSoulFact(database: DatabaseSync, soul: Soul): void;
113
85
  export declare function insertSealFact(database: DatabaseSync, input: Readonly<{
114
86
  evidence: string;
115
87
  at: string;
116
88
  }>): void;
117
89
  export declare function deletePauseControl(database: DatabaseSync): void;
90
+ export declare function deleteStopControl(database: DatabaseSync): void;
118
91
  export declare function sealFact(database: DatabaseSync): Readonly<{
119
92
  evidence: string;
120
93
  at: string;
121
94
  }> | null;
122
95
  export declare function insertBodyFact(database: DatabaseSync, input: Readonly<{
123
- collar: Collar;
124
96
  leashTakenAt: string;
125
97
  }>): number;
126
98
  export declare function insertSessionFact(database: DatabaseSync, input: Omit<SessionFact, "sequence">): number;
127
99
  export declare function insertActivityFact(database: DatabaseSync, input: Readonly<{
128
- bodySequence: number;
100
+ turnSequence: number;
129
101
  event: unknown;
130
102
  at: string;
131
103
  }>): number;
132
- export declare function pruneActivityFacts(database: DatabaseSync, limit: number): void;
133
- export declare function activityFactSlice(database: DatabaseSync, input: Readonly<{
134
- before?: number;
135
- since?: number;
136
- limit: number;
137
- }>): ActivityFactSlice;
138
- export declare function deathExists(database: DatabaseSync): boolean;
139
- export declare function insertTellFact(database: DatabaseSync, tell: Omit<TellFact, "state">): void;
140
- export declare function tellState(database: DatabaseSync, id: string): TellState | null;
141
- export declare function updateTellState(database: DatabaseSync, id: string, state: TellState): void;
142
104
  export declare function insertRequestFact(database: DatabaseSync, input: RequestInput & Readonly<{
143
105
  admittedAt: string;
144
106
  }>): void;
@@ -148,31 +110,27 @@ export declare function updateRequestReserved(database: DatabaseSync, id: string
148
110
  export declare function updateRequestServed(database: DatabaseSync, id: string, child: AkuId): void;
149
111
  export declare function updateRequestRefused(database: DatabaseSync, id: string, diagnostic: string): void;
150
112
  export declare function updateRequestVoided(database: DatabaseSync, id: string, evidence: string): void;
151
- export declare function insertStopControl(database: DatabaseSync, at: string): void;
113
+ export declare function insertStopControl(database: DatabaseSync, bodySequence: number, at: string): void;
152
114
  export declare function insertPauseControl(database: DatabaseSync, at: string): void;
153
- export declare function stopExists(database: DatabaseSync): boolean;
154
- export declare function pauseExists(database: DatabaseSync): boolean;
155
- export declare function deleteAbandonedControls(database: DatabaseSync): void;
156
- export declare function insertDeathFact(database: DatabaseSync, death: DeathFact): void;
157
- export declare function voidTellsByDeath(database: DatabaseSync): void;
158
- export declare function voidRequestsByDeath(database: DatabaseSync, evidence: string): void;
115
+ export declare function stopFact(database: DatabaseSync): StopFact | null;
116
+ export declare function pauseFact(database: DatabaseSync): PauseFact | null;
117
+ export declare function insertKillFact(database: DatabaseSync, bodySequence: number, at: string): void;
159
118
  export declare function endBodyFact(database: DatabaseSync, input: Readonly<{
160
119
  sequence: number;
161
120
  end: BodyEnd;
162
121
  at: string;
163
122
  }>): void;
164
- type AnsweredTurn = Omit<TurnFact, "sequence" | "outcome"> & Readonly<{
165
- outcome: Extract<TurnFact["outcome"], {
166
- kind: "answered";
167
- }>;
168
- }>;
169
- export declare function insertAnsweredTurnFact(database: DatabaseSync, input: AnsweredTurn): number;
170
- type FailedTurn = Omit<TurnFact, "sequence" | "outcome"> & Readonly<{
171
- outcome: Extract<TurnFact["outcome"], {
172
- kind: "failed";
173
- }>;
174
- }>;
175
- export declare function insertFailedTurnFact(database: DatabaseSync, input: FailedTurn): number;
123
+ export declare function markBodyHung(database: DatabaseSync, input: Readonly<{
124
+ sequence: number;
125
+ diagnostic: string;
126
+ at: string;
127
+ }>): void;
128
+ export declare function insertTurnStartFact(database: DatabaseSync, input: Readonly<{
129
+ bodySequence: number;
130
+ startedAt: string;
131
+ call?: string;
132
+ }>): TurnStartFact;
133
+ export declare function insertTurnEndFact(database: DatabaseSync, input: Omit<TurnEndFact, "sequence">): TurnEndFact;
176
134
  export declare function finishBodyFact(database: DatabaseSync, input: Readonly<{
177
135
  sequence: number;
178
136
  at: string;
@@ -180,10 +138,7 @@ export declare function finishBodyFact(database: DatabaseSync, input: Readonly<{
180
138
  export declare function latestBodyFact(database: DatabaseSync): BodyFact | null;
181
139
  export declare function latestSessionFact(database: DatabaseSync): SessionFact | null;
182
140
  export declare function sessionFactForCoordinate(database: DatabaseSync, coordinate: ResumeCoordinate): SessionFact | null;
183
- export declare function pendingTellFacts(database: DatabaseSync): readonly TellFact[];
184
- export declare function deathFact(database: DatabaseSync): DeathFact | null;
185
- export declare function historyFacts(database: DatabaseSync): readonly TurnFact[];
141
+ export declare function latestKillFact(database: DatabaseSync): KillFact | null;
142
+ export declare function killFactForBody(database: DatabaseSync, bodySequence: number): KillFact | null;
186
143
  export declare function lastAnsweredTurnFact(database: DatabaseSync): TurnFact | null;
187
- export declare function latestTurnFact(database: DatabaseSync): TurnFact | null;
188
144
  export declare function answeredTurnFact(database: DatabaseSync, historyId: string): TurnFact | null;
189
- export {};
@@ -1,3 +1,4 @@
1
+ import { decodeResumeCoordinate, encodeResumeCoordinate as encodeCoordinate } from "../coordinate.js";
1
2
  function json(value) {
2
3
  return JSON.stringify(value);
3
4
  }
@@ -6,43 +7,23 @@ function parsed(value) {
6
7
  throw new Error("Akuma authority contains non-text JSON");
7
8
  return JSON.parse(value);
8
9
  }
9
- export function encodeSoulRow(soul) {
10
- return [
11
- soul.id,
12
- soul.archetype,
13
- soul.description ?? null,
14
- json(soul.provider),
15
- json(soul.options),
16
- soul.cwd,
17
- json(soul.origin),
18
- json(soul.confinement),
19
- soul.createdAt,
20
- ];
21
- }
22
- export function decodeSoulRow(row) {
23
- return {
24
- id: row.id,
25
- archetype: row.archetype,
26
- ...(row.description === null ? {} : { description: row.description }),
27
- provider: parsed(row.provider_json),
28
- options: parsed(row.options_json),
29
- cwd: row.cwd,
30
- origin: parsed(row.origin_json),
31
- confinement: parsed(row.confinement_json),
32
- createdAt: row.created_at,
33
- };
10
+ function resumeCoordinate(value) {
11
+ const coordinate = decodeResumeCoordinate(value);
12
+ if (coordinate === null)
13
+ throw new Error("Akuma authority contains an invalid resume coordinate");
14
+ return coordinate;
34
15
  }
35
16
  export function encodeSessionRow(session) {
36
- return [session.provider, json(session.coordinate), session.cwd, json(session.options), session.admittedAt];
17
+ return [session.provider, encodeResumeCoordinate(session.coordinate), session.cwd, json(session.options), session.admittedAt];
37
18
  }
38
19
  export function encodeResumeCoordinate(coordinate) {
39
- return json(coordinate);
20
+ return json(encodeCoordinate(coordinate));
40
21
  }
41
22
  export function decodeSessionRow(row) {
42
23
  return {
43
24
  sequence: row.sequence,
44
25
  provider: row.provider,
45
- coordinate: parsed(row.coordinate_json),
26
+ coordinate: resumeCoordinate(parsed(row.coordinate_json)),
46
27
  cwd: row.cwd,
47
28
  options: parsed(row.options_json),
48
29
  admittedAt: row.admitted_at,
@@ -51,29 +32,39 @@ export function decodeSessionRow(row) {
51
32
  export function decodeBodyRow(row) {
52
33
  return {
53
34
  sequence: row.sequence,
54
- collar: { pid: row.pid, processGroup: row.process_group, spawnedAt: row.spawned_at },
55
35
  leashTakenAt: row.leash_taken_at,
36
+ ...(row.hung_diagnostic === null ? {} : { hung: { diagnostic: row.hung_diagnostic, at: row.hung_at } }),
56
37
  ...(row.end === null ? {} : { end: row.end }),
57
38
  ...(row.ended_at === null ? {} : { endedAt: row.ended_at }),
58
39
  };
59
40
  }
60
41
  export function decodeTurnRow(row) {
61
- return {
42
+ const start = {
43
+ kind: "turn-start",
62
44
  sequence: row.sequence,
63
45
  bodySequence: row.body_sequence,
46
+ startedAt: row.started_at,
47
+ };
48
+ if (row.outcome === null)
49
+ return start;
50
+ const end = {
51
+ kind: "turn-end",
52
+ sequence: row.end_sequence,
53
+ turnSequence: row.sequence,
64
54
  outcome: row.outcome === "answered"
65
55
  ? {
66
56
  kind: "answered",
67
- historyId: row.history_id,
68
- session: parsed(row.session_json),
57
+ ...(row.history_id === null ? {} : { historyId: row.history_id }),
58
+ session: resumeCoordinate(parsed(row.session_json)),
69
59
  answer: row.answer,
70
60
  }
71
61
  : { kind: "failed", diagnostic: row.diagnostic },
72
62
  completedAt: row.completed_at,
73
63
  };
64
+ return { ...start, end };
74
65
  }
75
- export function decodeTellRow(row) {
76
- return { id: row.id, body: row.body, state: row.state, recordedAt: row.recorded_at };
66
+ export function decodeCallRow(row) {
67
+ return { kind: "call", sequence: row.sequence, turnSequence: row.turn_sequence, body: row.body, at: row.at };
77
68
  }
78
69
  export function decodeRequestRow(row) {
79
70
  const input = {
@@ -99,30 +90,16 @@ export function encodeActivityEvent(event) {
99
90
  }
100
91
  export function decodeActivityRow(row) {
101
92
  return {
93
+ kind: "activity",
102
94
  sequence: row.sequence,
103
- bodySequence: row.body_sequence,
95
+ turnSequence: row.turn_sequence,
104
96
  event: parsed(row.event_json),
105
97
  at: row.at,
106
98
  };
107
99
  }
108
- export function encodeDeathRow(death) {
109
- return json({ evidence: death.evidence });
110
- }
111
- export function decodeDeathRow(row) {
112
- return { evidence: parsed(row.value_json).evidence, at: row.at };
113
- }
114
- export function soulFact(database) {
115
- const row = database.prepare(`SELECT id, archetype, description, provider_json, options_json, cwd,
116
- origin_json, confinement_json, created_at FROM soul WHERE singleton = 1`).get();
117
- return row === undefined ? null : decodeSoulRow(row);
118
- }
119
100
  export function sealExists(database) {
120
101
  return database.prepare("SELECT singleton FROM seal WHERE singleton = 1").get() !== undefined;
121
102
  }
122
- export function insertSoulFact(database, soul) {
123
- database.prepare(`INSERT INTO soul(singleton, id, archetype, description, provider_json, options_json, cwd, origin_json, confinement_json, created_at)
124
- VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(...encodeSoulRow(soul));
125
- }
126
103
  export function insertSealFact(database, input) {
127
104
  database.prepare("INSERT OR IGNORE INTO seal(singleton, evidence, at) VALUES (1, ?, ?)")
128
105
  .run(input.evidence, input.at);
@@ -130,13 +107,15 @@ export function insertSealFact(database, input) {
130
107
  export function deletePauseControl(database) {
131
108
  database.prepare("DELETE FROM control WHERE kind = 'pause'").run();
132
109
  }
110
+ export function deleteStopControl(database) {
111
+ database.prepare("DELETE FROM control WHERE kind = 'stop'").run();
112
+ }
133
113
  export function sealFact(database) {
134
114
  const row = database.prepare("SELECT evidence, at FROM seal WHERE singleton = 1").get();
135
115
  return row === undefined ? null : { evidence: row.evidence, at: row.at };
136
116
  }
137
117
  export function insertBodyFact(database, input) {
138
- const result = database.prepare(`INSERT INTO bodies(pid, process_group, spawned_at, leash_taken_at)
139
- VALUES (?, ?, ?, ?)`).run(input.collar.pid, input.collar.processGroup, input.collar.spawnedAt, input.leashTakenAt);
118
+ const result = database.prepare("INSERT INTO bodies(leash_taken_at) VALUES (?)").run(input.leashTakenAt);
140
119
  return Number(result.lastInsertRowid);
141
120
  }
142
121
  export function insertSessionFact(database, input) {
@@ -145,53 +124,10 @@ export function insertSessionFact(database, input) {
145
124
  return Number(result.lastInsertRowid);
146
125
  }
147
126
  export function insertActivityFact(database, input) {
148
- const result = database.prepare("INSERT INTO activity(body_sequence, event_json, at) VALUES (?, ?, ?)")
149
- .run(input.bodySequence, encodeActivityEvent(input.event), input.at);
150
- return Number(result.lastInsertRowid);
151
- }
152
- export function pruneActivityFacts(database, limit) {
153
- database.prepare(`DELETE FROM activity
154
- WHERE sequence NOT IN (SELECT sequence FROM activity ORDER BY sequence DESC LIMIT ?)`)
155
- .run(limit);
156
- }
157
- export function activityFactSlice(database, input) {
158
- const bounds = database.prepare("SELECT MIN(sequence) AS lowest, MAX(sequence) AS highest FROM activity")
159
- .get();
160
- let rows;
161
- if (input.before !== undefined) {
162
- rows = database.prepare(`SELECT sequence, body_sequence, event_json, at FROM (
163
- SELECT sequence, body_sequence, event_json, at FROM activity
164
- WHERE sequence < ? ORDER BY sequence DESC LIMIT ?
165
- ) ORDER BY sequence`).all(input.before, input.limit);
166
- }
167
- else if (input.since !== undefined) {
168
- rows = database.prepare(`SELECT sequence, body_sequence, event_json, at FROM activity
169
- WHERE sequence > ? ORDER BY sequence LIMIT ?`).all(input.since, input.limit);
170
- }
171
- else {
172
- rows = database.prepare(`SELECT sequence, body_sequence, event_json, at FROM (
173
- SELECT sequence, body_sequence, event_json, at FROM activity ORDER BY sequence DESC LIMIT ?
174
- ) ORDER BY sequence`).all(input.limit);
175
- }
176
- return {
177
- rows: rows.map(decodeActivityRow),
178
- lowestRetained: bounds.lowest,
179
- highest: bounds.highest,
180
- };
181
- }
182
- export function deathExists(database) {
183
- return database.prepare("SELECT kind FROM control WHERE kind = 'death'").get() !== undefined;
184
- }
185
- export function insertTellFact(database, tell) {
186
- database.prepare(`INSERT INTO tells(id, body, state, recorded_at)
187
- VALUES (?, ?, 'recorded', ?)`).run(tell.id, tell.body, tell.recordedAt);
188
- }
189
- export function tellState(database, id) {
190
- const row = database.prepare("SELECT state FROM tells WHERE id = ?").get(id);
191
- return row?.state ?? null;
192
- }
193
- export function updateTellState(database, id, state) {
194
- database.prepare("UPDATE tells SET state = ? WHERE id = ?").run(state, id);
127
+ const sequence = Number(database.prepare("INSERT INTO timeline(kind) VALUES ('activity')").run().lastInsertRowid);
128
+ database.prepare("INSERT INTO activity(sequence, turn_sequence, event_json, at) VALUES (?, ?, ?, ?)")
129
+ .run(sequence, input.turnSequence, encodeActivityEvent(input.event), input.at);
130
+ return sequence;
195
131
  }
196
132
  const REQUEST_COLUMNS = `sequence, id, archetype, body, cwd, world, recipe_json, admitted_at,
197
133
  state, child, diagnostic, evidence`;
@@ -224,54 +160,80 @@ export function updateRequestVoided(database, id, evidence) {
224
160
  database.prepare(`UPDATE requests SET state = 'voided', child = NULL, evidence = ?
225
161
  WHERE id = ? AND state IN ('admitted', 'reserved')`).run(evidence, id);
226
162
  }
227
- export function insertStopControl(database, at) {
228
- database.prepare("INSERT OR IGNORE INTO control(kind, value_json, at) VALUES ('stop', '{}', ?)").run(at);
163
+ export function insertStopControl(database, bodySequence, at) {
164
+ database.prepare("INSERT OR IGNORE INTO control(kind, value_json, at) VALUES ('stop', ?, ?)")
165
+ .run(json({ bodySequence }), at);
229
166
  }
230
167
  export function insertPauseControl(database, at) {
231
- database.prepare("INSERT OR IGNORE INTO control(kind, value_json, at) VALUES ('pause', '{}', ?)").run(at);
232
- }
233
- export function stopExists(database) {
234
- return database.prepare("SELECT kind FROM control WHERE kind = 'stop'").get() !== undefined;
235
- }
236
- export function pauseExists(database) {
237
- return database.prepare("SELECT kind FROM control WHERE kind = 'pause'").get() !== undefined;
238
- }
239
- export function deleteAbandonedControls(database) {
240
- database.prepare("DELETE FROM control WHERE kind IN ('stop', 'pause')").run();
241
- }
242
- export function insertDeathFact(database, death) {
243
- database.prepare("INSERT INTO control(kind, value_json, at) VALUES ('death', ?, ?)")
244
- .run(encodeDeathRow(death), death.at);
245
- }
246
- export function voidTellsByDeath(database) {
247
- database.prepare("UPDATE tells SET state = 'voided-by-death' WHERE state NOT IN ('consumed', 'voided-by-death')").run();
168
+ const body = latestBodyFact(database);
169
+ if (body === null)
170
+ throw new Error("Akuma has no Body to interrupt");
171
+ database.prepare("INSERT OR IGNORE INTO control(kind, value_json, at) VALUES ('pause', ?, ?)")
172
+ .run(json({ bodySequence: body.sequence }), at);
173
+ }
174
+ export function stopFact(database) {
175
+ const row = database.prepare("SELECT value_json, at FROM control WHERE kind = 'stop'").get();
176
+ if (row === undefined)
177
+ return null;
178
+ const value = parsed(row.value_json);
179
+ if (!Number.isSafeInteger(value.bodySequence) || value.bodySequence <= 0) {
180
+ throw new Error("Akuma stop control has an invalid Body sequence");
181
+ }
182
+ return { bodySequence: value.bodySequence, requestedAt: row.at };
183
+ }
184
+ export function pauseFact(database) {
185
+ const row = database.prepare("SELECT value_json, at FROM control WHERE kind = 'pause'").get();
186
+ if (row === undefined)
187
+ return null;
188
+ const value = parsed(row.value_json);
189
+ if (!Number.isSafeInteger(value.bodySequence) || value.bodySequence <= 0) {
190
+ throw new Error("Akuma pause control has an invalid Body sequence");
191
+ }
192
+ return { bodySequence: value.bodySequence, requestedAt: row.at };
248
193
  }
249
- export function voidRequestsByDeath(database, evidence) {
250
- database.prepare(`UPDATE requests SET state = 'voided',
251
- evidence = CASE WHEN child IS NULL THEN ? ELSE ? || '; child=' || child END,
252
- child = NULL
253
- WHERE state IN ('admitted', 'reserved')`).run(evidence, evidence);
194
+ export function insertKillFact(database, bodySequence, at) {
195
+ database.prepare("INSERT OR IGNORE INTO kills(body_sequence, evidence, at) VALUES (?, 'killed', ?)")
196
+ .run(bodySequence, at);
254
197
  }
255
198
  export function endBodyFact(database, input) {
256
199
  database.prepare("UPDATE bodies SET end = ?, ended_at = ? WHERE sequence = ? AND end IS NULL")
257
200
  .run(input.end, input.at, input.sequence);
258
201
  }
259
- export function insertAnsweredTurnFact(database, input) {
260
- const result = database.prepare(`INSERT INTO turns(body_sequence, outcome, history_id, session_json, answer, completed_at)
261
- VALUES (?, 'answered', ?, ?, ?, ?)`).run(input.bodySequence, input.outcome.historyId, encodeResumeCoordinate(input.outcome.session), input.outcome.answer, input.completedAt);
262
- return Number(result.lastInsertRowid);
263
- }
264
- export function insertFailedTurnFact(database, input) {
265
- const result = database.prepare(`INSERT INTO turns(body_sequence, outcome, diagnostic, completed_at)
266
- VALUES (?, 'failed', ?, ?)`).run(input.bodySequence, input.outcome.diagnostic, input.completedAt);
267
- return Number(result.lastInsertRowid);
202
+ export function markBodyHung(database, input) {
203
+ const result = database.prepare(`UPDATE bodies SET hung_diagnostic = ?, hung_at = ?
204
+ WHERE sequence = ? AND end IS NULL AND hung_diagnostic IS NULL`)
205
+ .run(input.diagnostic, input.at, input.sequence);
206
+ if (result.changes !== 1)
207
+ throw new Error(`Akuma Body ${input.sequence} cannot record hung custody`);
208
+ }
209
+ export function insertTurnStartFact(database, input) {
210
+ const sequence = Number(database.prepare("INSERT INTO timeline(kind) VALUES ('turn-start')").run().lastInsertRowid);
211
+ database.prepare("INSERT INTO turns(sequence, body_sequence, started_at) VALUES (?, ?, ?)")
212
+ .run(sequence, input.bodySequence, input.startedAt);
213
+ if (input.call !== undefined) {
214
+ const callSequence = Number(database.prepare("INSERT INTO timeline(kind) VALUES ('call')").run().lastInsertRowid);
215
+ database.prepare("INSERT INTO calls(sequence, turn_sequence, body, at) VALUES (?, ?, ?, ?)")
216
+ .run(callSequence, sequence, input.call, input.startedAt);
217
+ }
218
+ return { kind: "turn-start", sequence, bodySequence: input.bodySequence, startedAt: input.startedAt };
219
+ }
220
+ export function insertTurnEndFact(database, input) {
221
+ const sequence = Number(database.prepare("INSERT INTO timeline(kind) VALUES ('turn-end')").run().lastInsertRowid);
222
+ const result = input.outcome.kind === "answered"
223
+ ? database.prepare(`UPDATE turns SET end_sequence = ?, outcome = 'answered', history_id = ?,
224
+ session_json = ?, answer = ?, completed_at = ? WHERE sequence = ? AND end_sequence IS NULL`).run(sequence, input.outcome.historyId ?? null, encodeResumeCoordinate(input.outcome.session), input.outcome.answer, input.completedAt, input.turnSequence)
225
+ : database.prepare(`UPDATE turns SET end_sequence = ?, outcome = 'failed', diagnostic = ?, completed_at = ?
226
+ WHERE sequence = ? AND end_sequence IS NULL`).run(sequence, input.outcome.diagnostic, input.completedAt, input.turnSequence);
227
+ if (result.changes !== 1)
228
+ throw new Error(`Akuma Turn ${input.turnSequence} is not open`);
229
+ return { ...input, kind: "turn-end", sequence };
268
230
  }
269
231
  export function finishBodyFact(database, input) {
270
232
  database.prepare("UPDATE bodies SET end = 'exited', ended_at = ? WHERE sequence = ? AND end IS NULL")
271
233
  .run(input.at, input.sequence);
272
234
  }
273
235
  export function latestBodyFact(database) {
274
- const row = database.prepare(`SELECT sequence, pid, process_group, spawned_at, leash_taken_at, end, ended_at
236
+ const row = database.prepare(`SELECT sequence, leash_taken_at, hung_diagnostic, hung_at, end, ended_at
275
237
  FROM bodies ORDER BY sequence DESC LIMIT 1`).get();
276
238
  return row === undefined ? null : decodeBodyRow(row);
277
239
  }
@@ -286,34 +248,34 @@ export function sessionFactForCoordinate(database, coordinate) {
286
248
  .get(encodeResumeCoordinate(coordinate));
287
249
  return row === undefined ? null : decodeSessionRow(row);
288
250
  }
289
- export function pendingTellFacts(database) {
290
- const rows = database.prepare(`SELECT id, body, state, recorded_at FROM tells
291
- WHERE state NOT IN ('consumed', 'voided-by-death') ORDER BY recorded_at, id`)
292
- .all();
293
- return rows.map(decodeTellRow);
294
- }
295
- export function deathFact(database) {
296
- const row = database.prepare("SELECT value_json, at FROM control WHERE kind = 'death'").get();
297
- return row === undefined ? null : decodeDeathRow(row);
251
+ export function latestKillFact(database) {
252
+ const row = database.prepare(`SELECT sequence, body_sequence, evidence, at
253
+ FROM kills ORDER BY sequence DESC LIMIT 1`).get();
254
+ return row === undefined ? null : {
255
+ sequence: row.sequence,
256
+ bodySequence: row.body_sequence,
257
+ evidence: row.evidence,
258
+ at: row.at,
259
+ };
298
260
  }
299
- export function historyFacts(database) {
300
- const rows = database.prepare(`SELECT sequence, body_sequence, outcome, history_id, session_json,
301
- answer, diagnostic, completed_at FROM turns ORDER BY sequence`).all();
302
- return rows.map(decodeTurnRow);
261
+ export function killFactForBody(database, bodySequence) {
262
+ const row = database.prepare(`SELECT sequence, body_sequence, evidence, at
263
+ FROM kills WHERE body_sequence = ?`).get(bodySequence);
264
+ return row === undefined ? null : {
265
+ sequence: row.sequence,
266
+ bodySequence: row.body_sequence,
267
+ evidence: row.evidence,
268
+ at: row.at,
269
+ };
303
270
  }
304
271
  export function lastAnsweredTurnFact(database) {
305
- const row = database.prepare(`SELECT sequence, body_sequence, outcome, history_id, session_json,
306
- answer, diagnostic, completed_at FROM turns WHERE outcome = 'answered' ORDER BY sequence DESC LIMIT 1`)
272
+ const row = database.prepare(`SELECT sequence, body_sequence, started_at, end_sequence, outcome, history_id,
273
+ session_json, answer, diagnostic, completed_at FROM turns WHERE outcome = 'answered' ORDER BY end_sequence DESC LIMIT 1`)
307
274
  .get();
308
275
  return row === undefined ? null : decodeTurnRow(row);
309
276
  }
310
- export function latestTurnFact(database) {
311
- const row = database.prepare(`SELECT sequence, body_sequence, outcome, history_id, session_json,
312
- answer, diagnostic, completed_at FROM turns ORDER BY sequence DESC LIMIT 1`).get();
313
- return row === undefined ? null : decodeTurnRow(row);
314
- }
315
277
  export function answeredTurnFact(database, historyId) {
316
- const row = database.prepare(`SELECT sequence, body_sequence, outcome, history_id, session_json,
317
- answer, diagnostic, completed_at FROM turns WHERE outcome = 'answered' AND history_id = ?`).get(historyId);
278
+ const row = database.prepare(`SELECT sequence, body_sequence, started_at, end_sequence, outcome, history_id,
279
+ session_json, answer, diagnostic, completed_at FROM turns WHERE outcome = 'answered' AND history_id = ?`).get(historyId);
318
280
  return row === undefined ? null : decodeTurnRow(row);
319
281
  }
@@ -1,5 +1,5 @@
1
1
  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
- 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 = 6)\n ) STRICT;\n INSERT OR IGNORE INTO akuma_schema(singleton, version) VALUES (1, 6);\n CREATE TABLE IF NOT EXISTS soul (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n id TEXT NOT NULL UNIQUE,\n archetype TEXT NOT NULL,\n description TEXT,\n provider_json TEXT NOT NULL CHECK (json_valid(provider_json)),\n options_json TEXT NOT NULL CHECK (json_valid(options_json)),\n cwd TEXT NOT NULL,\n origin_json TEXT NOT NULL CHECK (json_valid(origin_json)),\n confinement_json TEXT NOT NULL CHECK (json_valid(confinement_json)),\n created_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS bodies (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n pid INTEGER NOT NULL CHECK (pid > 0),\n process_group INTEGER NOT NULL CHECK (process_group > 0),\n spawned_at TEXT NOT NULL,\n leash_taken_at TEXT NOT NULL,\n end TEXT CHECK (end IN ('exited', 'broke-off', 'put-down')),\n ended_at TEXT\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 AUTOINCREMENT,\n body_sequence INTEGER NOT NULL REFERENCES bodies(sequence),\n outcome TEXT NOT NULL CHECK (outcome IN ('answered', 'failed')),\n history_id TEXT UNIQUE,\n session_json TEXT CHECK (session_json IS NULL OR json_valid(session_json)),\n answer TEXT,\n diagnostic TEXT,\n completed_at TEXT NOT NULL,\n CHECK (\n (outcome = 'answered' AND history_id IS NOT NULL AND session_json IS NOT NULL AND answer IS NOT NULL AND diagnostic IS NULL)\n OR (outcome = 'failed' AND history_id IS NULL AND session_json IS NULL AND answer IS NULL AND diagnostic IS NOT NULL)\n )\n ) STRICT;\n CREATE TABLE IF NOT EXISTS activity (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n body_sequence INTEGER NOT NULL REFERENCES bodies(sequence),\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 body TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('recorded', 'delivered', 'seen', 'consumed', 'voided-by-death')),\n recorded_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS requests (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n id TEXT NOT NULL UNIQUE,\n archetype TEXT NOT NULL,\n body TEXT NOT NULL,\n cwd TEXT,\n world TEXT NOT NULL,\n recipe_json TEXT NOT NULL CHECK (json_valid(recipe_json)),\n admitted_at TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('admitted', 'reserved', 'served', 'refused', 'voided')),\n child TEXT,\n diagnostic TEXT,\n evidence TEXT,\n CHECK (\n (state = 'admitted' AND child IS NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state IN ('reserved', 'served') AND child IS NOT NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'refused' AND child IS NULL AND diagnostic IS NOT NULL AND evidence IS NULL)\n OR (state = 'voided' AND child 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', 'death')),\n value_json TEXT NOT NULL CHECK (json_valid(value_json)),\n at TEXT NOT NULL\n ) STRICT;\n";
4
+ 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 = 14)\n ) STRICT;\n INSERT OR IGNORE INTO akuma_schema(singleton, version) VALUES (1, 14);\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) OR (hung_diagnostic IS NOT NULL AND hung_at IS NOT NULL AND end IS 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')),\n history_id TEXT UNIQUE,\n session_json TEXT CHECK (session_json IS NULL OR json_valid(session_json)),\n answer TEXT,\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 OR (outcome = 'failed' AND history_id IS NULL AND session_json IS NULL AND answer IS NULL AND diagnostic IS NOT NULL)\n OR (outcome IS NULL AND end_sequence IS NULL AND history_id IS NULL AND session_json IS NULL AND answer 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 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 recorded_at TEXT NOT NULL\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) WHERE evidence = 'exact';\n CREATE UNIQUE INDEX IF NOT EXISTS tell_receipts_fence\n ON tell_receipts(turn_sequence, fence, kind) WHERE evidence = 'fence';\n CREATE TABLE IF NOT EXISTS requests (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n id TEXT NOT NULL UNIQUE,\n archetype TEXT NOT NULL,\n body TEXT NOT NULL,\n cwd TEXT,\n world TEXT NOT NULL,\n recipe_json TEXT NOT NULL CHECK (json_valid(recipe_json)),\n admitted_at TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('admitted', 'reserved', 'served', 'refused', 'voided')),\n child TEXT,\n diagnostic TEXT,\n evidence TEXT,\n CHECK (\n (state = 'admitted' AND child IS NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state IN ('reserved', 'served') AND child IS NOT NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'refused' AND child IS NULL AND diagnostic IS NOT NULL AND evidence IS NULL)\n OR (state = 'voided' AND child 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
5
  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";