@astrosheep/keiyaku 4.6.4 → 4.6.6

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 (191) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +43 -8
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +7 -8
  3. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -3
  4. package/build/src/akuma/akuma-observe.d.ts +18 -15
  5. package/build/src/akuma/akuma-observe.js +75 -16
  6. package/build/src/akuma/akuma-wait.d.ts +4 -3
  7. package/build/src/akuma/akuma-wait.js +75 -53
  8. package/build/src/akuma/akuma.d.ts +6 -4
  9. package/build/src/akuma/akuma.js +4 -0
  10. package/build/src/akuma/call-initial-tell.d.ts +2 -2
  11. package/build/src/akuma/call-initial-tell.js +1 -1
  12. package/build/src/akuma/call-request.d.ts +2 -2
  13. package/build/src/akuma/heart/index.d.ts +7 -2
  14. package/build/src/akuma/heart/index.js +50 -5
  15. package/build/src/akuma/heart/tells.d.ts +33 -2
  16. package/build/src/akuma/heart/tells.js +24 -18
  17. package/build/src/akuma/heart/timeline.d.ts +23 -1
  18. package/build/src/akuma/heart/timeline.js +28 -21
  19. package/build/src/akuma/projection.d.ts +10 -10
  20. package/build/src/akuma/providers/pi/index.js +72 -39
  21. package/build/src/akuma/selection-observation.d.ts +20 -20
  22. package/build/src/akuma-body.js +1 -0
  23. package/build/src/alias/index.d.ts +0 -1
  24. package/build/src/alias/index.js +0 -4
  25. package/build/src/body/amend.d.ts +0 -4
  26. package/build/src/body/amend.js +0 -3
  27. package/build/src/body/region.d.ts +0 -1
  28. package/build/src/body/region.js +0 -3
  29. package/build/src/body/verification.d.ts +0 -1
  30. package/build/src/cli/commands/akuma-grammar.js +23 -66
  31. package/build/src/cli/commands/akuma.js +17 -30
  32. package/build/src/cli/commands/contract-grammar.d.ts +14 -1
  33. package/build/src/cli/commands/contract-grammar.js +54 -21
  34. package/build/src/cli/commands/contract-help.d.ts +9 -8
  35. package/build/src/cli/commands/contract-help.js +14 -7
  36. package/build/src/cli/commands/contract.js +57 -117
  37. package/build/src/cli/commands/install.d.ts +5 -5
  38. package/build/src/cli/commands/install.js +1 -4
  39. package/build/src/cli/commands/task-grammar.js +10 -66
  40. package/build/src/cli/commands/task.d.ts +0 -1
  41. package/build/src/cli/commands/task.js +34 -53
  42. package/build/src/cli/coordinates.d.ts +1 -2
  43. package/build/src/cli/coordinates.js +1 -4
  44. package/build/src/cli/parse.d.ts +2 -3
  45. package/build/src/cli/parse.js +24 -66
  46. package/build/src/cli/render/akuma.d.ts +3 -16
  47. package/build/src/cli/render/akuma.js +1 -13
  48. package/build/src/cli/render/audit.js +1 -1
  49. package/build/src/cli/render/contract.js +34 -32
  50. package/build/src/cli/render/kanshi-akuma.d.ts +8 -2
  51. package/build/src/cli/render/kanshi-akuma.js +14 -7
  52. package/build/src/cli/render/kanshi.d.ts +3 -1
  53. package/build/src/cli/render/kanshi.js +44 -32
  54. package/build/src/cli/render/receipt.js +6 -1
  55. package/build/src/cli/render/task.d.ts +1 -1
  56. package/build/src/cli/render/task.js +3 -27
  57. package/build/src/cli/render/terminal.d.ts +6 -2
  58. package/build/src/cli/render/terminal.js +8 -2
  59. package/build/src/cli/runtime.js +3 -16
  60. package/build/src/cli/scan.d.ts +26 -0
  61. package/build/src/cli/scan.js +82 -0
  62. package/build/src/cli/streams.d.ts +5 -0
  63. package/build/src/cli/streams.js +11 -0
  64. package/build/src/contract-worktree.js +38 -21
  65. package/build/src/core/facts/codec.d.ts +1 -2
  66. package/build/src/core/facts/codec.js +5 -11
  67. package/build/src/core/facts/types.d.ts +16 -2
  68. package/build/src/core/facts/types.js +15 -0
  69. package/build/src/core/verbs/abandon.js +3 -9
  70. package/build/src/core/verbs/amend.js +2 -9
  71. package/build/src/core/verbs/arc.js +6 -13
  72. package/build/src/core/verbs/attestation.js +2 -9
  73. package/build/src/core/verbs/bind.js +2 -9
  74. package/build/src/core/verbs/deliver.js +2 -9
  75. package/build/src/core/verbs/placement.d.ts +1 -1
  76. package/build/src/core/verbs/placement.js +2 -9
  77. package/build/src/core/verbs/reintegrate.d.ts +1 -1
  78. package/build/src/core/verbs/reintegrate.js +2 -9
  79. package/build/src/dispatch/index.d.ts +2 -2
  80. package/build/src/dispatch/index.js +33 -11
  81. package/build/src/git/hooks.d.ts +2 -4
  82. package/build/src/git/hooks.js +0 -12
  83. package/build/src/git/integration.d.ts +5 -3
  84. package/build/src/git/integration.js +36 -25
  85. package/build/src/git/nuke.js +4 -4
  86. package/build/src/git/observe.d.ts +4 -4
  87. package/build/src/git/observe.js +5 -5
  88. package/build/src/git/process.d.ts +1 -4
  89. package/build/src/git/process.js +1 -11
  90. package/build/src/git/read-observation.js +1 -1
  91. package/build/src/git/reconcile.d.ts +1 -1
  92. package/build/src/git/reconcile.js +15 -13
  93. package/build/src/git/repository.d.ts +2 -6
  94. package/build/src/git/repository.js +18 -31
  95. package/build/src/git/scratch.d.ts +6 -6
  96. package/build/src/git/scratch.js +110 -46
  97. package/build/src/git/target-placement.d.ts +5 -5
  98. package/build/src/git/target-placement.js +18 -33
  99. package/build/src/git/tender.d.ts +6 -2
  100. package/build/src/git/tender.js +19 -12
  101. package/build/src/git/terminal-reconcile.js +24 -13
  102. package/build/src/git/terminal-seal.d.ts +2 -5
  103. package/build/src/git/terminal-seal.js +5 -3
  104. package/build/src/git/workspace.d.ts +17 -13
  105. package/build/src/git/workspace.js +58 -41
  106. package/build/src/kanshi/index.d.ts +2 -2
  107. package/build/src/kanshi/index.js +1 -1
  108. package/build/src/kanshi/read.d.ts +8 -1
  109. package/build/src/kanshi/read.js +72 -7
  110. package/build/src/kanshi/report.d.ts +12 -0
  111. package/build/src/library/akuma-creation.d.ts +4 -4
  112. package/build/src/library/bind.d.ts +1 -63
  113. package/build/src/library/bind.js +3 -9
  114. package/build/src/library/contract-creation.js +2 -30
  115. package/build/src/library/contract-execution.d.ts +0 -1
  116. package/build/src/library/contract-execution.js +9 -34
  117. package/build/src/library/contract-operations.d.ts +5 -1
  118. package/build/src/library/contract-operations.js +7 -3
  119. package/build/src/library/contract-types.d.ts +1 -1
  120. package/build/src/library/delivery.d.ts +91 -93
  121. package/build/src/library/delivery.js +2 -1
  122. package/build/src/library/input.d.ts +0 -2
  123. package/build/src/library/input.js +0 -4
  124. package/build/src/library/invocation.d.ts +0 -1
  125. package/build/src/library/invocation.js +3 -25
  126. package/build/src/library/outcome.d.ts +651 -602
  127. package/build/src/library/outcome.js +4 -4
  128. package/build/src/library/reconcile.d.ts +6 -0
  129. package/build/src/library/reconcile.js +31 -1
  130. package/build/src/library/repo.d.ts +0 -1
  131. package/build/src/library/selection.d.ts +1 -10
  132. package/build/src/library/selection.js +14 -15
  133. package/build/src/protocol/abandon.d.ts +1 -1
  134. package/build/src/protocol/abandon.js +3 -10
  135. package/build/src/protocol/amend.js +2 -5
  136. package/build/src/protocol/arc.d.ts +1 -1
  137. package/build/src/protocol/arc.js +2 -9
  138. package/build/src/protocol/attempt.d.ts +3 -20
  139. package/build/src/protocol/attempt.js +6 -5
  140. package/build/src/protocol/audit.d.ts +1 -0
  141. package/build/src/protocol/audit.js +10 -11
  142. package/build/src/protocol/completion.d.ts +129 -55
  143. package/build/src/protocol/completion.js +62 -73
  144. package/build/src/protocol/deliver.d.ts +7 -5
  145. package/build/src/protocol/deliver.js +74 -44
  146. package/build/src/protocol/execution-observation.d.ts +2 -4
  147. package/build/src/protocol/execution-observation.js +3 -7
  148. package/build/src/protocol/intent.d.ts +1 -1
  149. package/build/src/protocol/intent.js +1 -0
  150. package/build/src/protocol/operations.d.ts +24 -12
  151. package/build/src/protocol/operations.js +36 -15
  152. package/build/src/protocol/placement.d.ts +2 -1
  153. package/build/src/protocol/placement.js +21 -5
  154. package/build/src/protocol/progress.d.ts +1 -1
  155. package/build/src/protocol/read/status.js +58 -41
  156. package/build/src/protocol/reintegrate.d.ts +1 -1
  157. package/build/src/protocol/reintegrate.js +10 -19
  158. package/build/src/protocol/review.d.ts +3 -28
  159. package/build/src/protocol/review.js +10 -37
  160. package/build/src/protocol/run.d.ts +19 -7
  161. package/build/src/protocol/run.js +19 -9
  162. package/build/src/runtime/proc/windows-launch.exe +0 -0
  163. package/build/src/settlement/holder.d.ts +2 -4
  164. package/build/src/settlement/holder.js +3 -6
  165. package/build/src/task/board.d.ts +6 -0
  166. package/build/src/task/board.js +30 -1
  167. package/build/src/task/catalog.js +1 -4
  168. package/build/src/task/compose.d.ts +0 -1
  169. package/build/src/task/compose.js +0 -1
  170. package/build/src/task/context.d.ts +0 -1
  171. package/build/src/task/context.js +0 -3
  172. package/build/src/task/created-observation.d.ts +5 -1
  173. package/build/src/task/created-observation.js +12 -5
  174. package/build/src/task/index.d.ts +1 -1
  175. package/build/src/task/index.js +7 -6
  176. package/build/src/task/input.d.ts +0 -6
  177. package/build/src/task/input.js +2 -14
  178. package/build/src/task/mutation.d.ts +3 -4
  179. package/build/src/task/mutation.js +11 -39
  180. package/build/src/task/operations.d.ts +2 -7
  181. package/build/src/task/operations.js +37 -49
  182. package/build/src/task/query.d.ts +0 -1
  183. package/build/src/task/query.js +1 -4
  184. package/build/src/task/store.d.ts +0 -2
  185. package/build/src/task/store.js +27 -11
  186. package/build/src/verification/declaration.js +3 -2
  187. package/build/src/verification/execution.d.ts +3 -2
  188. package/build/src/verification/execution.js +10 -6
  189. package/build/src/workspace-place.d.ts +0 -1
  190. package/build/src/workspace-place.js +0 -11
  191. package/package.json +7 -3
@@ -1,7 +1,7 @@
1
1
  import { parsePublicHistoryId } from "../identity.js";
2
2
  import { answeredTurnFact, endBodyFact, finishBodyFact, deleteStopControl, insertActivityFact, insertTurnEndFact, insertTurnStartFact, insertPauseControl, insertKillFact, insertSessionFact, insertStopControl, killFactForBody, latestBodyFact, latestKillFact, latestSessionFact, latestTurnFactForBody, lastAnsweredTurnFact, pauseFact, sessionFactForCoordinate, stopFact, turnFact, } from "./rows.js";
3
3
  import { insertTellDeliveryFact, dispositionSnapshotProven, insertTellBindingFact, insertTellDispositionSnapshot, insertTellFact, insertTellReceiptFact, insertUndeliveredTellReceipts, latestOpenTellDisposition, openBoundTurns, openTellDispositionIds, pendingTellFacts, hasPendingTell, resolveTellDispositionSnapshot, tellDispositionResolved, tellFact, tellIdsForFence, turnParticipants, } from "./tells.js";
4
- import { activityFactSlice, statusFacts, lastActivityAt as readLastActivityAt, pruneActivityFacts, } from "./timeline.js";
4
+ import { activityFactSlice, statusFacts, readStatusBatch, decodeTimelineBatch, lastActivityAt as readLastActivityAt, pruneActivityFacts, } from "./timeline.js";
5
5
  import { isHeartAbsent, readSealFromLeash, withHeartTransaction, withReadOnlyHeart } from "./storage.js";
6
6
  import { soulFact } from "./soul.js";
7
7
  import { AkumaBusyError, HeartAuthorityCorruptionError } from "./facts.js";
@@ -53,11 +53,56 @@ export async function appendActivity(paths, input) {
53
53
  export async function activitySlice(paths) {
54
54
  return await withReadOnlyHeart(paths, (heart) => activityFactSlice(heart));
55
55
  }
56
- export async function readStatusFacts(paths, input) {
57
- return await withReadOnlyHeart(paths, (heart) => statusFacts(heart, input));
56
+ export async function readStatusFacts(paths, input, signal) {
57
+ return await withReadOnlyHeart(paths, (heart) => statusFacts(heart, input), signal);
58
+ }
59
+ // Each query returns a fixed set of scalar columns; compare JSON columns as text.
60
+ function sameRawRows(left, right) {
61
+ if (left.length !== right.length)
62
+ return false;
63
+ if (left.length === 0)
64
+ return true;
65
+ const columns = Object.keys(left[0]);
66
+ return left.every((row, index) => columns.every((column) => row[column] === right[index][column]));
67
+ }
68
+ function sameStatusBatch(left, right) {
69
+ return (left.frontier === right.frontier &&
70
+ sameRawRows(left.rows, right.rows) &&
71
+ sameRawRows(left.turns, right.turns) &&
72
+ sameRawRows(left.calls, right.calls) &&
73
+ sameRawRows(left.activity, right.activity) &&
74
+ sameRawRows(left.tells.rows, right.tells.rows) &&
75
+ sameRawRows(left.tells.deliveries, right.tells.deliveries) &&
76
+ sameRawRows(left.tells.bindings, right.tells.bindings));
77
+ }
78
+ /** One live observation's successful raw input and decoded frontier, never a connection. */
79
+ export function createStatusFactReader(paths) {
80
+ let memo;
81
+ return {
82
+ clear() {
83
+ memo = undefined;
84
+ },
85
+ async read(input, signal) {
86
+ try {
87
+ const next = await withReadOnlyHeart(paths, (heart) => {
88
+ const batch = readStatusBatch(heart, input);
89
+ if (memo !== undefined && sameStatusBatch(batch, memo.batch))
90
+ return memo;
91
+ return { batch, facts: decodeTimelineBatch(batch) };
92
+ }, signal);
93
+ // Publication follows COMMIT, so failed reads can never supply a fallback.
94
+ memo = next;
95
+ return next.facts;
96
+ }
97
+ catch (error) {
98
+ memo = undefined;
99
+ throw error;
100
+ }
101
+ },
102
+ };
58
103
  }
59
104
  /** Lifecycle probes do not load narration, Tell bodies, or delivery histories. */
60
- export async function readLifeSnapshot(paths) {
105
+ export async function readLifeSnapshot(paths, signal) {
61
106
  try {
62
107
  return await withReadOnlyHeart(paths, (heart) => ({
63
108
  soul: soulFact(heart),
@@ -65,7 +110,7 @@ export async function readLifeSnapshot(paths) {
65
110
  latestSession: latestSessionFact(heart),
66
111
  latestKill: latestKillFact(heart),
67
112
  hasPendingTell: hasPendingTell(heart),
68
- }));
113
+ }), signal);
69
114
  }
70
115
  catch (error) {
71
116
  if (isHeartAbsent(error))
@@ -1,9 +1,39 @@
1
1
  import type { DatabaseSync } from "node:sqlite";
2
- import { type TellDeliveryInput, type TellFact, type TellReceiptInput } from "./facts.js";
2
+ import { type TellDelivery, type TellDeliveryInput, type TellFact, type TellReceiptInput } from "./facts.js";
3
+ type TellRow = Readonly<{
4
+ sequence: number;
5
+ id: string;
6
+ body: string;
7
+ schema_json: string | null;
8
+ initiator: string | null;
9
+ recorded_at: string;
10
+ state: TellFact["state"];
11
+ }>;
12
+ type TellDeliveryRow = Readonly<{
13
+ turn_sequence: number;
14
+ route: TellDelivery["route"];
15
+ receipt: TellDelivery["receipt"] | null;
16
+ delivered_at: string;
17
+ }>;
3
18
  export declare const tellStateSql = "CASE\n WHEN EXISTS (\n SELECT 1 FROM tell_deliveries d\n WHERE d.tell_id = tells.id AND (d.route = 'launch' OR d.receipt = 'unavailable')\n ) THEN 'told'\n WHEN EXISTS (SELECT 1 FROM tell_receipts r WHERE r.evidence = 'exact' AND r.tell_id = tells.id) THEN 'told'\n WHEN EXISTS (\n SELECT 1 FROM tell_receipts r\n JOIN tell_deliveries d ON d.turn_sequence = r.turn_sequence AND d.fence = r.fence\n WHERE r.evidence = 'fence' AND d.tell_id = tells.id\n ) THEN 'told'\n ELSE 'pending'\nEND";
4
19
  export declare const pendingTellSequencesSql = "SELECT tells.sequence FROM tells WHERE CASE\n WHEN EXISTS (\n SELECT 1 FROM tell_deliveries d\n WHERE d.tell_id = tells.id AND (d.route = 'launch' OR d.receipt = 'unavailable')\n ) THEN 'told'\n WHEN EXISTS (SELECT 1 FROM tell_receipts r WHERE r.evidence = 'exact' AND r.tell_id = tells.id) THEN 'told'\n WHEN EXISTS (\n SELECT 1 FROM tell_receipts r\n JOIN tell_deliveries d ON d.turn_sequence = r.turn_sequence AND d.fence = r.fence\n WHERE r.evidence = 'fence' AND d.tell_id = tells.id\n ) THEN 'told'\n ELSE 'pending'\nEND = 'pending'\n UNION SELECT tells.sequence FROM tells JOIN tell_disposition_members m ON m.tell_id = tells.id";
5
20
  export declare const pendingTellProtectionSql = "SELECT d.turn_sequence FROM tell_deliveries d\n JOIN tells ON tells.id = d.tell_id WHERE CASE\n WHEN EXISTS (\n SELECT 1 FROM tell_deliveries d\n WHERE d.tell_id = tells.id AND (d.route = 'launch' OR d.receipt = 'unavailable')\n ) THEN 'told'\n WHEN EXISTS (SELECT 1 FROM tell_receipts r WHERE r.evidence = 'exact' AND r.tell_id = tells.id) THEN 'told'\n WHEN EXISTS (\n SELECT 1 FROM tell_receipts r\n JOIN tell_deliveries d ON d.turn_sequence = r.turn_sequence AND d.fence = r.fence\n WHERE r.evidence = 'fence' AND d.tell_id = tells.id\n ) THEN 'told'\n ELSE 'pending'\nEND = 'pending'\n UNION SELECT d.turn_sequence FROM tell_deliveries d JOIN tell_disposition_members m ON m.tell_id = d.tell_id";
6
- export declare function tellFactsAtSequences(database: DatabaseSync, sequences: readonly number[]): readonly TellFact[];
21
+ type TellBatch = Readonly<{
22
+ rows: readonly TellRow[];
23
+ deliveries: readonly (TellDeliveryRow & {
24
+ sequence: number;
25
+ tell_id: string;
26
+ fence: string;
27
+ })[];
28
+ bindings: readonly {
29
+ sequence: number;
30
+ tell_id: string;
31
+ turn_sequence: number;
32
+ bound_at: string;
33
+ }[];
34
+ }>;
35
+ export declare function decodeTellBatch(batch: TellBatch): readonly TellFact[];
36
+ export declare function tellBatchAtSequences(database: DatabaseSync, sequences: readonly number[]): TellBatch;
7
37
  export declare function hasPendingTell(database: DatabaseSync): boolean;
8
38
  export declare function insertTellFact(database: DatabaseSync, tell: Omit<TellFact, "sequence" | "state" | "deliveries">): number;
9
39
  export declare function tellFact(database: DatabaseSync, id: string): TellFact | null;
@@ -30,3 +60,4 @@ export declare function insertTellBindingFact(database: DatabaseSync, input: Rea
30
60
  export declare function turnParticipants(database: DatabaseSync, turnSequence: number): readonly string[];
31
61
  export declare function drainPendingTells(pending: readonly TellFact[], activeTurnSequences?: readonly number[]): readonly TellFact[];
32
62
  export declare function openBoundTurns(database: DatabaseSync, bodySequence: number): readonly number[];
63
+ export {};
@@ -18,16 +18,26 @@ export const pendingTellSequencesSql = `SELECT tells.sequence FROM tells WHERE $
18
18
  export const pendingTellProtectionSql = `SELECT d.turn_sequence FROM tell_deliveries d
19
19
  JOIN tells ON tells.id = d.tell_id WHERE ${tellStateSql} = 'pending'
20
20
  UNION SELECT d.turn_sequence FROM tell_deliveries d JOIN tell_disposition_members m ON m.tell_id = d.tell_id`;
21
- function decodeTellRows(database, rows) {
21
+ function readTellBatch(database, rows) {
22
22
  if (rows.length === 0)
23
- return [];
23
+ return { rows, deliveries: [], bindings: [] };
24
24
  const ids = JSON.stringify(rows.map((row) => row.id));
25
- const deliveries = new Map();
26
- const deliveryRows = database
27
- .prepare(`SELECT tell_id, turn_sequence, route, receipt, delivered_at
25
+ const deliveries = database
26
+ .prepare(`SELECT sequence, tell_id, turn_sequence, fence, route, receipt, delivered_at
28
27
  FROM tell_deliveries WHERE tell_id IN (SELECT value FROM json_each(?)) ORDER BY sequence`)
29
28
  .all(ids);
30
- for (const row of deliveryRows) {
29
+ const bindings = database
30
+ .prepare(`SELECT sequence, tell_id, turn_sequence, bound_at FROM tell_bindings
31
+ WHERE sequence IN (
32
+ SELECT MAX(sequence) FROM tell_bindings
33
+ WHERE tell_id IN (SELECT value FROM json_each(?)) GROUP BY tell_id
34
+ ) ORDER BY sequence`)
35
+ .all(ids);
36
+ return { rows, deliveries, bindings };
37
+ }
38
+ export function decodeTellBatch(batch) {
39
+ const deliveries = new Map();
40
+ for (const row of batch.deliveries) {
31
41
  const group = deliveries.get(row.tell_id) ?? [];
32
42
  group.push({
33
43
  turnSequence: row.turn_sequence,
@@ -38,16 +48,9 @@ function decodeTellRows(database, rows) {
38
48
  deliveries.set(row.tell_id, group);
39
49
  }
40
50
  const bindings = new Map();
41
- const bindingRows = database
42
- .prepare(`SELECT tell_id, turn_sequence, bound_at FROM tell_bindings
43
- WHERE sequence IN (
44
- SELECT MAX(sequence) FROM tell_bindings
45
- WHERE tell_id IN (SELECT value FROM json_each(?)) GROUP BY tell_id
46
- )`)
47
- .all(ids);
48
- for (const row of bindingRows)
51
+ for (const row of batch.bindings)
49
52
  bindings.set(row.tell_id, { turnSequence: row.turn_sequence, boundAt: row.bound_at });
50
- return rows.map((row) => ({
53
+ return batch.rows.map((row) => ({
51
54
  kind: "tell",
52
55
  sequence: row.sequence,
53
56
  id: row.id,
@@ -60,14 +63,17 @@ function decodeTellRows(database, rows) {
60
63
  ...(bindings.has(row.id) ? { binding: bindings.get(row.id) } : {}),
61
64
  }));
62
65
  }
63
- export function tellFactsAtSequences(database, sequences) {
66
+ function decodeTellRows(database, rows) {
67
+ return decodeTellBatch(readTellBatch(database, rows));
68
+ }
69
+ export function tellBatchAtSequences(database, sequences) {
64
70
  if (sequences.length === 0)
65
- return [];
71
+ return { rows: [], deliveries: [], bindings: [] };
66
72
  const rows = database
67
73
  .prepare(`SELECT sequence, id, body, initiator, schema_json, recorded_at, ${tellStateSql} AS state
68
74
  FROM tells WHERE sequence IN (SELECT value FROM json_each(?)) ORDER BY sequence`)
69
75
  .all(JSON.stringify(sequences));
70
- return decodeTellRows(database, rows);
76
+ return readTellBatch(database, rows);
71
77
  }
72
78
  export function hasPendingTell(database) {
73
79
  return database.prepare(`SELECT 1 FROM tells WHERE ${tellStateSql} = 'pending' LIMIT 1`).get() !== undefined;
@@ -1,6 +1,7 @@
1
1
  import type { DatabaseSync } from "node:sqlite";
2
2
  import type { CallFact, TellFact, TurnEndFact, TurnStartFact } from "./facts.js";
3
- import { type ActivityFact } from "./rows.js";
3
+ import { type ActivityFact, type ActivityRow, type CallRow, type TurnRow } from "./rows.js";
4
+ import { tellBatchAtSequences } from "./tells.js";
4
5
  export type TimelineFact = TurnStartFact | CallFact | ActivityFact | TellFact | TurnEndFact;
5
6
  export type ActivityFactSlice = Readonly<{
6
7
  rows: readonly TimelineFact[];
@@ -9,10 +10,31 @@ export type ActivityFactSlice = Readonly<{
9
10
  }>;
10
11
  export declare function lastActivityAt(database: DatabaseSync): string | null;
11
12
  export declare function pruneActivityFacts(database: DatabaseSync, limit: number, protectionReleased?: boolean): void;
13
+ type TimelineRow = Readonly<{
14
+ sequence: number;
15
+ kind: "turn-start" | "call" | "activity" | "tell" | "turn-end";
16
+ }>;
17
+ type TimelineBatch = Readonly<{
18
+ rows: readonly TimelineRow[];
19
+ turns: readonly TurnRow[];
20
+ calls: readonly CallRow[];
21
+ activity: readonly ActivityRow[];
22
+ tells: ReturnType<typeof tellBatchAtSequences>;
23
+ }>;
24
+ export declare function decodeTimelineBatch(batch: TimelineBatch): readonly TimelineFact[];
12
25
  export type StatusFactInput = Readonly<{
13
26
  aperture: "monitoring" | "receipt";
14
27
  admittedTellId?: string;
15
28
  }>;
16
29
  /** Select the frontier and its delivered Tells, plus aperture-required Tell pins. */
30
+ export declare function readStatusBatch(database: DatabaseSync, input: StatusFactInput): {
31
+ rows: readonly TimelineRow[];
32
+ turns: readonly TurnRow[];
33
+ calls: readonly CallRow[];
34
+ activity: readonly ActivityRow[];
35
+ tells: ReturnType<typeof tellBatchAtSequences>;
36
+ frontier: number | null;
37
+ };
17
38
  export declare function statusFacts(database: DatabaseSync, input: StatusFactInput): readonly TimelineFact[];
18
39
  export declare function activityFactSlice(database: DatabaseSync): ActivityFactSlice;
40
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { decodeActivityRow, decodeCallRow, decodeTurnRow, } from "./rows.js";
2
- import { tellFactsAtSequences, tellStateSql, pendingTellProtectionSql, pendingTellSequencesSql } from "./tells.js";
2
+ import { decodeTellBatch, tellBatchAtSequences, tellStateSql, pendingTellProtectionSql, pendingTellSequencesSql, } from "./tells.js";
3
3
  export function lastActivityAt(database) {
4
4
  const row = database
5
5
  .prepare(`SELECT CASE timeline.kind
@@ -52,36 +52,40 @@ export function pruneActivityFacts(database, limit, protectionReleased = false)
52
52
  DELETE FROM timeline WHERE sequence < ? AND sequence NOT IN protected`)
53
53
  .run(cutoff.sequence, cutoff.sequence, cutoff.sequence, cutoff.sequence);
54
54
  }
55
- function decodeTimelineRows(database, rows) {
55
+ function readTimelineBatch(database, rows) {
56
56
  const sequences = (kind) => JSON.stringify(rows.filter((row) => row.kind === kind).map((row) => row.sequence));
57
- const facts = new Map();
58
57
  const turns = database
59
58
  .prepare(`SELECT sequence, body_sequence, started_at, end_sequence, outcome,
60
59
  history_id, session_json, answer, answer_json, schema_json, initiator, diagnostic, completed_at FROM turns
61
- WHERE sequence IN (SELECT value FROM json_each(?)) OR end_sequence IN (SELECT value FROM json_each(?))`)
60
+ WHERE sequence IN (SELECT value FROM json_each(?)) OR end_sequence IN (SELECT value FROM json_each(?))
61
+ ORDER BY sequence`)
62
62
  .all(sequences("turn-start"), sequences("turn-end"));
63
- for (const row of turns) {
64
- const { end, ...start } = decodeTurnRow(row);
65
- facts.set(start.sequence, start);
66
- if (end !== undefined)
67
- facts.set(end.sequence, end);
68
- }
69
63
  const calls = database
70
64
  .prepare(`SELECT sequence, turn_sequence, body, at FROM calls
71
- WHERE sequence IN (SELECT value FROM json_each(?))`)
65
+ WHERE sequence IN (SELECT value FROM json_each(?)) ORDER BY sequence`)
72
66
  .all(sequences("call"));
73
- for (const row of calls)
74
- facts.set(row.sequence, decodeCallRow(row));
75
67
  const activity = database
76
68
  .prepare(`SELECT sequence, turn_sequence, event_json, at FROM activity
77
- WHERE sequence IN (SELECT value FROM json_each(?))`)
69
+ WHERE sequence IN (SELECT value FROM json_each(?)) ORDER BY sequence`)
78
70
  .all(sequences("activity"));
79
- for (const row of activity)
71
+ const tells = tellBatchAtSequences(database, rows.filter((row) => row.kind === "tell").map((row) => row.sequence));
72
+ return { rows, turns, calls, activity, tells };
73
+ }
74
+ export function decodeTimelineBatch(batch) {
75
+ const facts = new Map();
76
+ for (const row of batch.turns) {
77
+ const { end, ...start } = decodeTurnRow(row);
78
+ facts.set(start.sequence, start);
79
+ if (end !== undefined)
80
+ facts.set(end.sequence, end);
81
+ }
82
+ for (const row of batch.calls)
83
+ facts.set(row.sequence, decodeCallRow(row));
84
+ for (const row of batch.activity)
80
85
  facts.set(row.sequence, decodeActivityRow(row));
81
- const tells = tellFactsAtSequences(database, rows.filter((row) => row.kind === "tell").map((row) => row.sequence));
82
- for (const fact of tells)
86
+ for (const fact of decodeTellBatch(batch.tells))
83
87
  facts.set(fact.sequence, fact);
84
- return rows.map((row) => {
88
+ return batch.rows.map((row) => {
85
89
  const fact = facts.get(row.sequence);
86
90
  if (fact === undefined || fact.kind !== row.kind)
87
91
  throw new Error(`Akuma timeline references missing ${row.kind} ${row.sequence}`);
@@ -89,7 +93,7 @@ function decodeTimelineRows(database, rows) {
89
93
  });
90
94
  }
91
95
  /** Select the frontier and its delivered Tells, plus aperture-required Tell pins. */
92
- export function statusFacts(database, input) {
96
+ export function readStatusBatch(database, input) {
93
97
  const frontier = database.prepare("SELECT sequence FROM turns ORDER BY sequence DESC LIMIT 1").get();
94
98
  const rows = database
95
99
  .prepare(`WITH selected(sequence) AS (
@@ -104,7 +108,10 @@ export function statusFacts(database, input) {
104
108
  UNION SELECT sequence FROM tells WHERE ? AND ${tellStateSql} = 'pending'
105
109
  ) SELECT timeline.sequence, timeline.kind FROM timeline JOIN selected USING(sequence) ORDER BY sequence`)
106
110
  .all(frontier?.sequence ?? null, frontier?.sequence ?? null, frontier?.sequence ?? null, frontier?.sequence ?? null, frontier?.sequence ?? null, input.admittedTellId ?? null, input.aperture === "monitoring" || input.admittedTellId === undefined ? 1 : 0);
107
- return decodeTimelineRows(database, rows);
111
+ return { frontier: frontier?.sequence ?? null, ...readTimelineBatch(database, rows) };
112
+ }
113
+ export function statusFacts(database, input) {
114
+ return decodeTimelineBatch(readStatusBatch(database, input));
108
115
  }
109
116
  export function activityFactSlice(database) {
110
117
  const bounds = database.prepare("SELECT MIN(sequence) AS lowest, MAX(sequence) AS highest FROM timeline").get();
@@ -112,7 +119,7 @@ export function activityFactSlice(database) {
112
119
  .prepare("SELECT sequence, kind FROM timeline ORDER BY sequence")
113
120
  .all();
114
121
  return {
115
- rows: decodeTimelineRows(database, rows),
122
+ rows: decodeTimelineBatch(readTimelineBatch(database, rows)),
116
123
  lowestRetained: bounds.lowest,
117
124
  highest: bounds.highest,
118
125
  };
@@ -41,8 +41,8 @@ export declare const tellRowSchema: z.ZodObject<{
41
41
  }>;
42
42
  turnSequence: z.ZodNumber;
43
43
  receipt: z.ZodOptional<z.ZodEnum<{
44
- required: "required";
45
44
  unavailable: "unavailable";
45
+ required: "required";
46
46
  }>>;
47
47
  }, z.core.$strict>, z.ZodTransform<Readonly<{
48
48
  turnSequence: number;
@@ -53,7 +53,7 @@ export declare const tellRowSchema: z.ZodObject<{
53
53
  deliveredAt: string;
54
54
  route: "live" | "launch";
55
55
  turnSequence: number;
56
- receipt?: "required" | "unavailable" | undefined;
56
+ receipt?: "unavailable" | "required" | undefined;
57
57
  }>>>>;
58
58
  }, z.core.$strict>;
59
59
  declare const outcomeSchema: z.ZodUnion<readonly [z.ZodObject<{
@@ -283,8 +283,8 @@ declare const openSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z
283
283
  }>;
284
284
  turnSequence: z.ZodNumber;
285
285
  receipt: z.ZodOptional<z.ZodEnum<{
286
- required: "required";
287
286
  unavailable: "unavailable";
287
+ required: "required";
288
288
  }>>;
289
289
  }, z.core.$strict>, z.ZodTransform<Readonly<{
290
290
  turnSequence: number;
@@ -295,7 +295,7 @@ declare const openSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z
295
295
  deliveredAt: string;
296
296
  route: "live" | "launch";
297
297
  turnSequence: number;
298
- receipt?: "required" | "unavailable" | undefined;
298
+ receipt?: "unavailable" | "required" | undefined;
299
299
  }>>>>;
300
300
  }, z.core.$strict>]>, z.ZodObject<{
301
301
  kind: z.ZodLiteral<"tool">;
@@ -449,8 +449,8 @@ declare const idleSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z
449
449
  }>;
450
450
  turnSequence: z.ZodNumber;
451
451
  receipt: z.ZodOptional<z.ZodEnum<{
452
- required: "required";
453
452
  unavailable: "unavailable";
453
+ required: "required";
454
454
  }>>;
455
455
  }, z.core.$strict>, z.ZodTransform<Readonly<{
456
456
  turnSequence: number;
@@ -461,7 +461,7 @@ declare const idleSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z
461
461
  deliveredAt: string;
462
462
  route: "live" | "launch";
463
463
  turnSequence: number;
464
- receipt?: "required" | "unavailable" | undefined;
464
+ receipt?: "unavailable" | "required" | undefined;
465
465
  }>>>>;
466
466
  }, z.core.$strict>]>, z.ZodObject<{
467
467
  kind: z.ZodLiteral<"tool">;
@@ -638,8 +638,8 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
638
638
  }>;
639
639
  turnSequence: z.ZodNumber;
640
640
  receipt: z.ZodOptional<z.ZodEnum<{
641
- required: "required";
642
641
  unavailable: "unavailable";
642
+ required: "required";
643
643
  }>>;
644
644
  }, z.core.$strict>, z.ZodTransform<Readonly<{
645
645
  turnSequence: number;
@@ -650,7 +650,7 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
650
650
  deliveredAt: string;
651
651
  route: "live" | "launch";
652
652
  turnSequence: number;
653
- receipt?: "required" | "unavailable" | undefined;
653
+ receipt?: "unavailable" | "required" | undefined;
654
654
  }>>>>;
655
655
  }, z.core.$strict>]>, z.ZodObject<{
656
656
  kind: z.ZodLiteral<"tool">;
@@ -845,8 +845,8 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
845
845
  }>;
846
846
  turnSequence: z.ZodNumber;
847
847
  receipt: z.ZodOptional<z.ZodEnum<{
848
- required: "required";
849
848
  unavailable: "unavailable";
849
+ required: "required";
850
850
  }>>;
851
851
  }, z.core.$strict>, z.ZodTransform<Readonly<{
852
852
  turnSequence: number;
@@ -857,7 +857,7 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
857
857
  deliveredAt: string;
858
858
  route: "live" | "launch";
859
859
  turnSequence: number;
860
- receipt?: "required" | "unavailable" | undefined;
860
+ receipt?: "unavailable" | "required" | undefined;
861
861
  }>>>>;
862
862
  }, z.core.$strict>]>, z.ZodObject<{
863
863
  kind: z.ZodLiteral<"tool">;
@@ -115,6 +115,37 @@ async function runPiPrompt(native, input, events, state, settle) {
115
115
  : { kind: "failed", diagnostic: diagnostic(error) });
116
116
  }
117
117
  }
118
+ async function retirePiSession(native) {
119
+ let failure;
120
+ let unsubscribe;
121
+ try {
122
+ const runner = native.extensionRunner;
123
+ unsubscribe = runner?.onError((error) => {
124
+ if (error.event === "session_shutdown")
125
+ failure ??= new Error(error.error);
126
+ });
127
+ await runner?.emit({ type: "session_shutdown", reason: "quit" });
128
+ }
129
+ catch (error) {
130
+ failure ??= error;
131
+ }
132
+ finally {
133
+ try {
134
+ unsubscribe?.();
135
+ }
136
+ catch (error) {
137
+ failure ??= error;
138
+ }
139
+ try {
140
+ native.dispose();
141
+ }
142
+ catch (error) {
143
+ failure ??= error;
144
+ }
145
+ }
146
+ if (failure !== undefined)
147
+ throw failure;
148
+ }
118
149
  async function drivePi(sdk, execution, input, signal, custody) {
119
150
  const created = await createPiSession(sdk, execution, input);
120
151
  const native = created.session;
@@ -144,33 +175,7 @@ async function drivePi(sdk, execution, input, signal, custody) {
144
175
  const agent = native.agent;
145
176
  let unsubscribeAgent;
146
177
  let unsubscribe;
147
- try {
148
- unsubscribeAgent = agent.subscribe((event) => {
149
- if (event.type === "message_end") {
150
- const waiter = pendingTells.get(event.message);
151
- if (waiter !== undefined) {
152
- pendingTells.delete(event.message);
153
- waiter.resolve({ kind: "accepted", fence: `${native.sessionId}:${waiter.id}` });
154
- }
155
- }
156
- });
157
- unsubscribe = native.subscribe((event) => {
158
- if (event.type === "agent_end" && !event.willRetry) {
159
- state.terminalFailure = piTerminalFailure(event.messages);
160
- }
161
- for (const translated of translatePiEvent(event, eventState))
162
- events.emit(translated);
163
- });
164
- }
165
- catch (error) {
166
- try {
167
- unsubscribeAgent?.();
168
- }
169
- finally {
170
- native.dispose();
171
- }
172
- throw error;
173
- }
178
+ let binding;
174
179
  const settle = (result) => {
175
180
  if (state.settled)
176
181
  return closed;
@@ -178,7 +183,7 @@ async function drivePi(sdk, execution, input, signal, custody) {
178
183
  endPendingTells();
179
184
  let failure;
180
185
  try {
181
- unsubscribe();
186
+ unsubscribe?.();
182
187
  }
183
188
  catch (error) {
184
189
  failure = error;
@@ -191,16 +196,19 @@ async function drivePi(sdk, execution, input, signal, custody) {
191
196
  }
192
197
  events.end();
193
198
  settleCompletion(result);
194
- try {
195
- native.dispose();
196
- }
197
- catch (error) {
198
- failure ??= error;
199
- }
200
- if (failure === undefined)
201
- settleRetired();
202
- else
203
- failRetired(failure);
199
+ void (async () => {
200
+ // Binding can create extension resources after cancellation. Shutdown must
201
+ // run after that work, while its contexts are still valid.
202
+ await binding?.catch(() => undefined);
203
+ try {
204
+ await retirePiSession(native);
205
+ }
206
+ catch (error) {
207
+ failure ??= error;
208
+ }
209
+ if (failure !== undefined)
210
+ throw failure;
211
+ })().then(settleRetired, failRetired);
204
212
  return closed;
205
213
  };
206
214
  const forceDispose = async () => {
@@ -209,6 +217,28 @@ async function drivePi(sdk, execution, input, signal, custody) {
209
217
  await settle({ kind: "failed", diagnostic: "Pi session force-disposed" });
210
218
  };
211
219
  custody?.own({ closed, abort: forceDispose, forceDispose });
220
+ try {
221
+ unsubscribeAgent = agent.subscribe((event) => {
222
+ if (event.type === "message_end") {
223
+ const waiter = pendingTells.get(event.message);
224
+ if (waiter !== undefined) {
225
+ pendingTells.delete(event.message);
226
+ waiter.resolve({ kind: "accepted", fence: `${native.sessionId}:${waiter.id}` });
227
+ }
228
+ }
229
+ });
230
+ unsubscribe = native.subscribe((event) => {
231
+ if (event.type === "agent_end" && !event.willRetry) {
232
+ state.terminalFailure = piTerminalFailure(event.messages);
233
+ }
234
+ for (const translated of translatePiEvent(event, eventState))
235
+ events.emit(translated);
236
+ });
237
+ }
238
+ catch (error) {
239
+ await settle({ kind: "failed", diagnostic: diagnostic(error) });
240
+ throw error;
241
+ }
212
242
  if (signal.aborted) {
213
243
  await settle({ kind: "failed", diagnostic: "Pi session aborted" });
214
244
  signal.throwIfAborted();
@@ -217,9 +247,12 @@ async function drivePi(sdk, execution, input, signal, custody) {
217
247
  await settle({ kind: "failed", diagnostic: "Pi session admitted without sessionFile" });
218
248
  throw new Error("Pi session admitted without sessionFile");
219
249
  }
250
+ binding = Promise.resolve().then(() => native.bindExtensions({}));
251
+ await abortable(binding, signal);
252
+ signal.throwIfAborted();
220
253
  events.emit({ type: "session", coordinate: { sessionFile: native.sessionFile, sessionId: native.sessionId } });
221
254
  void runPiPrompt(native, input, eventState, state, (result) => {
222
- void settle(result);
255
+ void settle(result).catch(() => undefined);
223
256
  });
224
257
  return {
225
258
  admission: { fence: native.sessionId },