maka-agent 0.2.0-dev.22.20260905 → 0.2.0-dev.24.20260907

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 (194) hide show
  1. package/dist/acp/maka-acp-agent.js +2 -1
  2. package/dist/acp/session-configuration.js +143 -0
  3. package/dist/acp/session-registry.js +90 -4
  4. package/dist/cli-core.js +2 -0
  5. package/dist/pi-transcript.js +5 -12
  6. package/dist/pi-tui-runner.js +74 -4
  7. package/dist/runtime-host-cli-context.js +167 -78
  8. package/dist/runtime-host-cli-installation.js +8 -2
  9. package/dist/runtime-host-cli.js +31 -1
  10. package/dist/runtime-host-handoff-surface.js +81 -0
  11. package/dist/runtime-host-installed-update-bootstrap.js +13 -0
  12. package/dist/runtime-host-installed-update-coordinator.js +33 -0
  13. package/dist/runtime-host-lifecycle-transaction.js +9 -1
  14. package/dist/runtime-host-local-handoff.js +37 -4
  15. package/dist/runtime-host-local-managed-activation.js +84 -0
  16. package/dist/runtime-host-local-source-retirement.js +18 -2
  17. package/dist/runtime-host-managed-lifecycle-manager.js +1 -0
  18. package/dist/runtime-host-operator-retirement.js +50 -0
  19. package/dist/runtime-host-service-manager.js +3 -0
  20. package/dist/runtime-host-session-driver.js +4 -25
  21. package/dist/runtime-host-session-update.js +62 -0
  22. package/dist/runtime-host-tui-command.js +38 -73
  23. package/dist/runtime-host-tui-context.js +1 -0
  24. package/dist/runtime-host-tui-owner.js +226 -0
  25. package/dist/tui-copy-catalog.js +140 -3
  26. package/dist/tui-host-owner-copy.js +24 -0
  27. package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
  28. package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
  29. package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
  30. package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
  31. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  32. package/node_modules/@maka/core/dist/bot-events.js +18 -63
  33. package/node_modules/@maka/core/dist/canonical-runtime-event.js +3 -1
  34. package/node_modules/@maka/core/dist/model-call-attempt.js +0 -82
  35. package/node_modules/@maka/core/dist/model-call-usage-projection.js +0 -186
  36. package/node_modules/@maka/core/dist/model-failure.js +40 -0
  37. package/node_modules/@maka/core/dist/model-metadata.generated.js +4 -4
  38. package/node_modules/@maka/core/dist/model-metadata.js +3 -3
  39. package/node_modules/@maka/core/dist/model-web-search.js +5 -4
  40. package/node_modules/@maka/core/dist/provider-registry.js +45 -4
  41. package/node_modules/@maka/core/dist/record-schema.js +22 -2
  42. package/node_modules/@maka/core/dist/redaction.js +41 -58
  43. package/node_modules/@maka/core/dist/runtime-boundary.js +31 -11
  44. package/node_modules/@maka/core/dist/runtime-event.js +37 -6
  45. package/node_modules/@maka/core/dist/runtime-handoff.js +98 -0
  46. package/node_modules/@maka/core/dist/runtime-invocation.js +1 -1
  47. package/node_modules/@maka/core/dist/runtime-logical-execution.js +112 -0
  48. package/node_modules/@maka/core/dist/session-trace.js +5 -1
  49. package/node_modules/@maka/core/dist/session.js +54 -52
  50. package/node_modules/@maka/core/dist/slash-command-catalog.js +2 -0
  51. package/node_modules/@maka/core/dist/tool-result-archive-evidence.js +20 -0
  52. package/node_modules/@maka/core/dist/usage-ledger-merge.js +7 -9
  53. package/node_modules/@maka/core/dist/usage-record-schema.js +26 -35
  54. package/node_modules/@maka/core/dist/workhub-creation-intent.js +34 -20
  55. package/node_modules/@maka/core/package.json +4 -0
  56. package/node_modules/@maka/eval/harbor/egress-proxy/entrypoint.sh +2 -1
  57. package/node_modules/@maka/mcp/dist/index.js +131 -1
  58. package/node_modules/@maka/runtime/dist/agent-run.js +272 -105
  59. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +13 -5
  60. package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +109 -34
  61. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +155 -134
  62. package/node_modules/@maka/runtime/dist/bots/base-adapter.js +17 -0
  63. package/node_modules/@maka/runtime/dist/bots/bot-test.js +38 -22
  64. package/node_modules/@maka/runtime/dist/bots/dingtalk-bridge.js +7 -5
  65. package/node_modules/@maka/runtime/dist/bots/discord-bridge.js +4 -4
  66. package/node_modules/@maka/runtime/dist/bots/feishu-bridge.js +4 -5
  67. package/node_modules/@maka/runtime/dist/bots/qq-bridge.js +6 -4
  68. package/node_modules/@maka/runtime/dist/bots/slack-bridge.js +3 -4
  69. package/node_modules/@maka/runtime/dist/bots/telegram-bridge.js +4 -5
  70. package/node_modules/@maka/runtime/dist/bots/wechat-bridge.js +17 -19
  71. package/node_modules/@maka/runtime/dist/bots/wecom-bridge.js +5 -6
  72. package/node_modules/@maka/runtime/dist/bots/ws-bridge-base.js +2 -3
  73. package/node_modules/@maka/runtime/dist/context-budget.js +14 -9
  74. package/node_modules/@maka/runtime/dist/conversation-copy.js +5 -4
  75. package/node_modules/@maka/runtime/dist/goal-continuation.js +36 -4
  76. package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +18 -9
  77. package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +30 -22
  78. package/node_modules/@maka/runtime/dist/history-compaction.js +29 -4
  79. package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +106 -0
  80. package/node_modules/@maka/runtime/dist/message-authority.js +9 -0
  81. package/node_modules/@maka/runtime/dist/model-adapter.js +19 -98
  82. package/node_modules/@maka/runtime/dist/model-factory.js +19 -81
  83. package/node_modules/@maka/runtime/dist/model-fetcher.js +7 -0
  84. package/node_modules/@maka/runtime/dist/model-runtime.js +85 -111
  85. package/node_modules/@maka/runtime/dist/native-web-search-tool.js +2 -1
  86. package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +2 -2
  87. package/node_modules/@maka/runtime/dist/opencode-session-header.js +4 -2
  88. package/node_modules/@maka/runtime/dist/provider-error-classification.js +84 -123
  89. package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +68 -108
  90. package/node_modules/@maka/runtime/dist/run-handoff-gate.js +97 -0
  91. package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +82 -54
  92. package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +117 -159
  93. package/node_modules/@maka/runtime/dist/runtime-kernel.js +150 -112
  94. package/node_modules/@maka/runtime/dist/runtime-ledger-repair.js +160 -79
  95. package/node_modules/@maka/runtime/dist/runtime-read-model.js +30 -89
  96. package/node_modules/@maka/runtime/dist/runtime-resume.js +80 -4
  97. package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +5 -0
  98. package/node_modules/@maka/runtime/dist/session-manager.js +171 -288
  99. package/node_modules/@maka/runtime/dist/session-projection-helpers.js +0 -27
  100. package/node_modules/@maka/runtime/dist/session-trace-projection.js +3 -30
  101. package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +3 -4
  102. package/node_modules/@maka/runtime/dist/test-connection.js +16 -16
  103. package/node_modules/@maka/runtime/dist/tool-result-archive-encoding.js +38 -0
  104. package/node_modules/@maka/runtime/dist/tool-runtime.js +3 -61
  105. package/node_modules/@maka/runtime/package.json +1 -0
  106. package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +35 -0
  107. package/node_modules/@maka/runtime-host/dist/candidate-entry.js +4 -1
  108. package/node_modules/@maka/runtime-host/dist/client/connect-or-spawn.js +9 -1
  109. package/node_modules/@maka/runtime-host/dist/client/connection.js +3 -0
  110. package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +156 -0
  111. package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +273 -0
  112. package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +26 -5
  113. package/node_modules/@maka/runtime-host/dist/client/index.js +3 -1
  114. package/node_modules/@maka/runtime-host/dist/client/launcher.js +3 -0
  115. package/node_modules/@maka/runtime-host/dist/client/peer-client.js +13 -0
  116. package/node_modules/@maka/runtime-host/dist/client/registered-host-termination.js +0 -59
  117. package/node_modules/@maka/runtime-host/dist/client/remote-compatibility-error.js +2 -0
  118. package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +27 -5
  119. package/node_modules/@maka/runtime-host/dist/operator/index.js +2 -1
  120. package/node_modules/@maka/runtime-host/dist/operator/retirement-cancellation.js +20 -0
  121. package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +28 -16
  122. package/node_modules/@maka/runtime-host/dist/protocol/external-session.js +4 -0
  123. package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +29 -12
  124. package/node_modules/@maka/runtime-host/dist/protocol/index.js +37 -1
  125. package/node_modules/@maka/runtime-host/dist/protocol/operations.js +2 -0
  126. package/node_modules/@maka/runtime-host/dist/protocol/session-collaboration.js +28 -1
  127. package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +40 -20
  128. package/node_modules/@maka/runtime-host/dist/protocol/session-transcript.js +0 -5
  129. package/node_modules/@maka/runtime-host/dist/protocol/session-turns.js +29 -58
  130. package/node_modules/@maka/runtime-host/dist/protocol/turn.js +11 -1
  131. package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +33 -0
  132. package/node_modules/@maka/runtime-host/dist/server/access-authority.js +26 -1
  133. package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +6 -1
  134. package/node_modules/@maka/runtime-host/dist/server/canonical-turn-snapshot.js +19 -4
  135. package/node_modules/@maka/runtime-host/dist/server/canonical-usage-reader.js +24 -11
  136. package/node_modules/@maka/runtime-host/dist/server/connection-session.js +7 -6
  137. package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +7 -4
  138. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +168 -28
  139. package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +5 -5
  140. package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +3 -2
  141. package/node_modules/@maka/runtime-host/dist/server/external-session-coordinator.js +6 -3
  142. package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +40 -1
  143. package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +108 -23
  144. package/node_modules/@maka/runtime-host/dist/server/host-residency-registry.js +13 -7
  145. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-admission-registry.js +3 -1
  146. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +124 -62
  147. package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +85 -8
  148. package/node_modules/@maka/runtime-host/dist/server/root-admission-owner.js +7 -0
  149. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +344 -71
  150. package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +37 -2
  151. package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +45 -3
  152. package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +201 -12
  153. package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +87 -25
  154. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +8 -55
  155. package/node_modules/@maka/runtime-host/dist/server/session-sidecar-purge.js +1 -16
  156. package/node_modules/@maka/runtime-host/dist/server/session-transcript-pager.js +0 -1
  157. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +460 -70
  158. package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +1 -1
  159. package/node_modules/@maka/runtime-host/dist/server/storage-maintenance.js +109 -0
  160. package/node_modules/@maka/runtime-host/dist/server/usage-pricing-coordinator.js +4 -11
  161. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +44 -15
  162. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +6 -2
  163. package/node_modules/@maka/storage/dist/agent-run-store.js +44 -0
  164. package/node_modules/@maka/storage/dist/artifact-store.js +21 -10
  165. package/node_modules/@maka/storage/dist/artifact-stores.js +1 -1
  166. package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +0 -4
  167. package/node_modules/@maka/storage/dist/codex-session-adapter.js +0 -2
  168. package/node_modules/@maka/storage/dist/context-offload-snapshot.js +325 -0
  169. package/node_modules/@maka/storage/dist/conversation-operational-state.js +4 -0
  170. package/node_modules/@maka/storage/dist/execution-stores.js +11 -7
  171. package/node_modules/@maka/storage/dist/file-session-repository.js +1012 -0
  172. package/node_modules/@maka/storage/dist/model-call-ledger.js +199 -32
  173. package/node_modules/@maka/storage/dist/model-call-usage-sql.js +136 -0
  174. package/node_modules/@maka/storage/dist/opencode-session-adapter.js +0 -4
  175. package/node_modules/@maka/storage/dist/operational-state-backup.js +9 -5
  176. package/node_modules/@maka/storage/dist/operational-state-store-public.js +1 -1
  177. package/node_modules/@maka/storage/dist/operational-state-store.js +5 -3
  178. package/node_modules/@maka/storage/dist/runtime-event-persistence.js +1 -0
  179. package/node_modules/@maka/storage/dist/runtime-transcript-query.js +308 -0
  180. package/node_modules/@maka/storage/dist/session-bundle-policy.js +24 -4
  181. package/node_modules/@maka/storage/dist/session-message-projection.js +15 -0
  182. package/node_modules/@maka/storage/dist/session-repository.js +767 -0
  183. package/node_modules/@maka/storage/dist/session-store.js +25 -99
  184. package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +10 -3
  185. package/node_modules/@maka/storage/dist/sqlite-context-offload-store.js +24 -8
  186. package/node_modules/@maka/storage/dist/sqlite-core-execution-schema.js +17 -1
  187. package/node_modules/@maka/storage/dist/sqlite-runtime-schema.js +44 -1
  188. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +129 -25
  189. package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +109 -892
  190. package/node_modules/@maka/storage/dist/sqlite-usage-schema.js +200 -20
  191. package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +111 -0
  192. package/node_modules/@maka/storage/dist/usage-stores.js +6 -2
  193. package/node_modules/@maka/storage/package.json +2 -0
  194. package/package.json +1 -1
@@ -0,0 +1,325 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+ import { createHash } from 'node:crypto';
20
+ import { createReadStream } from 'node:fs';
21
+ import { chmod, copyFile, lstat, mkdir, realpath } from 'node:fs/promises';
22
+ import { dirname, join, resolve } from 'node:path';
23
+ import { backup, DatabaseSync } from 'node:sqlite';
24
+ import { isCanonicalStorageRef } from '@maka/core/events';
25
+ import { discoverMarkedStorageRoot, runWithStorageRootLease, tryAcquireInteractiveRootOwner, } from './root-authority.js';
26
+ import { migrateSqliteContextOffloadDatabase, SQLITE_CONTEXT_OFFLOAD_SCHEMA_VERSION, } from './sqlite-context-offload-schema.js';
27
+ import { CONTEXT_OFFLOAD_DATABASE_NAME, CONTEXT_OFFLOAD_VALUES_DIRECTORY_NAME, } from './sqlite-context-offload-store.js';
28
+ import { syncDirectoryChain, syncFile } from './stable-storage.js';
29
+ import { SQLITE_SESSION_MESSAGE_CHUNK_MARKER } from './sqlite-session-metadata-schema.js';
30
+ /**
31
+ * Existing artifact-only snapshots keep their old admission contract. Context
32
+ * snapshots require the root owner: a Session gate does not fence global GC.
33
+ * The callback must recheck absence before publishing an artifact-only snapshot.
34
+ */
35
+ export async function withOfflineContextSnapshot(root, operation) {
36
+ if (!(await exists(join(root, CONTEXT_OFFLOAD_DATABASE_NAME))))
37
+ return operation(false);
38
+ const capability = await discoverMarkedStorageRoot({ path: root });
39
+ const owner = await tryAcquireInteractiveRootOwner(capability);
40
+ if (!owner)
41
+ throw new Error('Context snapshot requires an offline Storage Root; stop the Runtime Host first');
42
+ try {
43
+ return await runWithStorageRootLease(owner.lease, 'interactive', 'write', () => operation(true));
44
+ }
45
+ finally {
46
+ await owner.close();
47
+ }
48
+ }
49
+ /** Copies under the offline owner and the caller's Artifact lock; never mutates the source DB. */
50
+ export async function copyContextSnapshot(sourceRoot, targetRoot, contextLocked, sessionId) {
51
+ const sourcePath = join(sourceRoot, CONTEXT_OFFLOAD_DATABASE_NAME);
52
+ if (!(await exists(sourcePath)))
53
+ return false;
54
+ if (!contextLocked)
55
+ throw new Error('Context storage appeared during snapshot; retry with the Runtime Host stopped');
56
+ await assertRegularPath(sourceRoot, CONTEXT_OFFLOAD_DATABASE_NAME);
57
+ const targetPath = join(targetRoot, CONTEXT_OFFLOAD_DATABASE_NAME);
58
+ const source = new DatabaseSync(sourcePath, { readOnly: true });
59
+ try {
60
+ await backup(source, targetPath);
61
+ }
62
+ finally {
63
+ source.close();
64
+ }
65
+ await chmod(targetPath, 0o600);
66
+ const target = new DatabaseSync(targetPath);
67
+ try {
68
+ target.exec('PRAGMA foreign_keys = ON');
69
+ migrateSqliteContextOffloadDatabase(target);
70
+ target.exec('BEGIN IMMEDIATE');
71
+ if (sessionId !== undefined)
72
+ target.prepare('DELETE FROM context_refs WHERE session_id <> ?').run(sessionId);
73
+ target.exec(`
74
+ DELETE FROM context_gc_candidates;
75
+ DELETE FROM context_file_deletions;
76
+ DELETE FROM context_blobs WHERE NOT EXISTS (
77
+ SELECT 1 FROM context_refs WHERE context_refs.blob_id = context_blobs.blob_id
78
+ );
79
+ DELETE FROM context_session_usage;
80
+ INSERT INTO context_session_usage
81
+ SELECT r.session_id, count(*), sum(b.size_bytes)
82
+ FROM context_refs r JOIN context_blobs b USING(blob_id) GROUP BY r.session_id;
83
+ UPDATE context_store_usage SET
84
+ blob_count = (SELECT count(*) FROM context_blobs),
85
+ physical_bytes = (SELECT coalesce(sum(size_bytes), 0) FROM context_blobs)
86
+ WHERE singleton = 1;
87
+ COMMIT;
88
+ PRAGMA journal_mode = DELETE;
89
+ VACUUM;
90
+ `);
91
+ // VACUUM on the private destination removes other Sessions' deleted bytes,
92
+ // including SQLite free pages. It is never run on the live source.
93
+ for (const row of target
94
+ .prepare("SELECT blob_id, payload, size_bytes FROM context_blobs WHERE storage_kind = 'managed_file'")
95
+ .iterate()) {
96
+ const path = managedPath(row.blob_id, row.payload);
97
+ await assertRegularPath(sourceRoot, path);
98
+ const destination = join(targetRoot, path);
99
+ await mkdir(dirname(destination), { recursive: true, mode: 0o700 });
100
+ await copyFile(join(sourceRoot, path), destination);
101
+ await chmod(destination, 0o600);
102
+ await syncFile(destination);
103
+ await syncDirectoryChain(dirname(destination), targetRoot);
104
+ }
105
+ }
106
+ finally {
107
+ target.close();
108
+ }
109
+ await syncFile(targetPath);
110
+ await syncDirectoryChain(targetRoot, targetRoot);
111
+ return true;
112
+ }
113
+ export async function planContextSnapshotFiles(root, sessionId) {
114
+ const path = join(root, CONTEXT_OFFLOAD_DATABASE_NAME);
115
+ if (!(await exists(path)))
116
+ return [];
117
+ await assertRegularPath(root, CONTEXT_OFFLOAD_DATABASE_NAME);
118
+ const database = new DatabaseSync(path, { readOnly: true });
119
+ try {
120
+ const version = Number(database.prepare('PRAGMA user_version').get()?.user_version);
121
+ if (![1, 2, SQLITE_CONTEXT_OFFLOAD_SCHEMA_VERSION].includes(version))
122
+ throw new Error('Unsupported context snapshot schema');
123
+ const files = [CONTEXT_OFFLOAD_DATABASE_NAME];
124
+ if (version < 3)
125
+ return files;
126
+ for (const row of database
127
+ .prepare(`SELECT DISTINCT b.blob_id, b.payload FROM context_refs r
128
+ JOIN context_blobs b ON b.blob_id = r.blob_id
129
+ WHERE r.session_id = ? AND b.storage_kind = 'managed_file' ORDER BY b.blob_id`)
130
+ .iterate(sessionId)) {
131
+ const file = managedPath(row.blob_id, row.payload);
132
+ await assertRegularPath(root, file);
133
+ files.push(file);
134
+ }
135
+ return files;
136
+ }
137
+ finally {
138
+ database.close();
139
+ }
140
+ }
141
+ /** Verifies both payload integrity and typed ledger/message references before publication. */
142
+ export async function validateContextSnapshot(root) {
143
+ let context;
144
+ const contextPath = join(root, CONTEXT_OFFLOAD_DATABASE_NAME);
145
+ try {
146
+ if (await exists(contextPath)) {
147
+ await assertRegularPath(root, CONTEXT_OFFLOAD_DATABASE_NAME);
148
+ context = new DatabaseSync(contextPath, { readOnly: true });
149
+ if (context.prepare('PRAGMA user_version').get()?.user_version !==
150
+ SQLITE_CONTEXT_OFFLOAD_SCHEMA_VERSION)
151
+ throw new Error('Unsupported context snapshot schema');
152
+ if (context.prepare('PRAGMA integrity_check').get()?.integrity_check !== 'ok' ||
153
+ context.prepare('PRAGMA foreign_key_check').get())
154
+ throw new Error('Invalid context snapshot database');
155
+ for (const row of context
156
+ .prepare('SELECT blob_id, storage_kind, payload, size_bytes FROM context_blobs')
157
+ .iterate()) {
158
+ const digest = blobHash(row.blob_id);
159
+ if (!Number.isSafeInteger(row.size_bytes) || Number(row.size_bytes) < 0)
160
+ throw new Error('Invalid context snapshot size');
161
+ if (row.storage_kind === 'managed_file') {
162
+ const path = managedPath(row.blob_id, row.payload);
163
+ await assertRegularPath(root, path);
164
+ const info = await lstat(join(root, path));
165
+ if (info.size !== row.size_bytes || (await hashFile(join(root, path))) !== digest) {
166
+ throw new Error('Context snapshot payload size/hash mismatch');
167
+ }
168
+ }
169
+ else if (row.storage_kind !== 'inline' ||
170
+ !(row.payload instanceof Uint8Array) ||
171
+ row.payload.byteLength !== row.size_bytes ||
172
+ createHash('sha256').update(row.payload).digest('hex') !== digest) {
173
+ throw new Error('Context snapshot inline payload size/hash mismatch');
174
+ }
175
+ }
176
+ const actual = context
177
+ .prepare('SELECT count(*) AS n, coalesce(sum(size_bytes), 0) AS bytes FROM context_blobs')
178
+ .get();
179
+ const usage = context
180
+ .prepare('SELECT blob_count, physical_bytes FROM context_store_usage WHERE singleton = 1')
181
+ .get();
182
+ if (usage?.blob_count !== actual.n || usage.physical_bytes !== actual.bytes)
183
+ throw new Error('Context snapshot usage mismatch');
184
+ if (context
185
+ .prepare(`SELECT 1 FROM (
186
+ SELECT r.session_id, count(*) AS reference_count, sum(b.size_bytes) AS logical_bytes
187
+ FROM context_refs r JOIN context_blobs b USING(blob_id) GROUP BY r.session_id
188
+ EXCEPT SELECT session_id, reference_count, logical_bytes FROM context_session_usage
189
+ ) LIMIT 1`)
190
+ .get())
191
+ throw new Error('Context snapshot Session usage mismatch');
192
+ }
193
+ validateLedgerContextRefs(root, context);
194
+ }
195
+ finally {
196
+ context?.close();
197
+ }
198
+ }
199
+ function validateLedgerContextRefs(root, context) {
200
+ const runtime = new DatabaseSync(join(root, 'runtime.sqlite'), { readOnly: true });
201
+ const find = context?.prepare('SELECT 1 FROM context_refs WHERE session_id = ? AND ref_id = ?');
202
+ const check = (value, sessionId) => {
203
+ const ref = record(value);
204
+ if (ref.kind !== 'session_context')
205
+ return;
206
+ if (!isCanonicalStorageRef(value) ||
207
+ ref.sessionId !== sessionId ||
208
+ !find?.get(sessionId, String(ref.refId)))
209
+ throw new Error('Snapshot has a missing or cross-Session context reference');
210
+ };
211
+ const content = (value, sessionId) => {
212
+ const item = record(value);
213
+ if (item.kind === 'image')
214
+ check(item.ref, sessionId);
215
+ };
216
+ const attachments = (value, sessionId) => {
217
+ const item = record(value);
218
+ if (Array.isArray(item.attachments)) {
219
+ for (const attachment of item.attachments)
220
+ check(record(attachment).ref, sessionId);
221
+ }
222
+ };
223
+ const projection = (value, sessionId) => {
224
+ const item = record(value);
225
+ if (item.kind === 'content' && Array.isArray(item.parts)) {
226
+ for (const part of item.parts) {
227
+ const entry = record(part);
228
+ if (entry.kind === 'artifact')
229
+ check(entry.ref, sessionId);
230
+ }
231
+ }
232
+ };
233
+ try {
234
+ for (const row of runtime
235
+ .prepare('SELECT session_id, payload_json FROM runtime_events')
236
+ .iterate()) {
237
+ const event = record(JSON.parse(String(row.payload_json)));
238
+ const item = record(event.content);
239
+ const sessionId = String(row.session_id);
240
+ if (item.kind === 'text')
241
+ attachments(item, sessionId);
242
+ if (item.kind === 'function_response') {
243
+ content(item.result, sessionId);
244
+ projection(item.modelProjection, sessionId);
245
+ }
246
+ }
247
+ for (const row of runtime
248
+ .prepare("SELECT session_id, record_json FROM core_agent_run_events WHERE event_type = 'model_projection_transition_recorded'")
249
+ .iterate()) {
250
+ const event = record(JSON.parse(String(row.record_json)));
251
+ projection(record(record(event.data).transition).replacement, String(row.session_id));
252
+ }
253
+ const chunks = runtime.prepare('SELECT data FROM session_message_chunks WHERE session_id = ? AND sequence = ? ORDER BY chunk_index');
254
+ for (const row of runtime
255
+ .prepare('SELECT session_id, sequence, record_json FROM session_messages')
256
+ .iterate()) {
257
+ const encoded = row.record_json === SQLITE_SESSION_MESSAGE_CHUNK_MARKER
258
+ ? Buffer.concat(chunks.all(row.session_id, row.sequence).map((chunk) => {
259
+ if (!(chunk.data instanceof Uint8Array))
260
+ throw new Error('Invalid snapshot message chunk');
261
+ return Buffer.from(chunk.data);
262
+ })).toString('utf8')
263
+ : String(row.record_json);
264
+ const message = record(JSON.parse(encoded));
265
+ const sessionId = String(row.session_id);
266
+ if (message.type === 'user')
267
+ attachments(message, sessionId);
268
+ if (message.type === 'tool_result')
269
+ content(message.content, sessionId);
270
+ }
271
+ }
272
+ finally {
273
+ runtime.close();
274
+ }
275
+ }
276
+ function record(value) {
277
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
278
+ ? value
279
+ : {};
280
+ }
281
+ function blobHash(value) {
282
+ if (!(value instanceof Uint8Array) || value.byteLength !== 32)
283
+ throw new Error('Invalid context snapshot blob identity');
284
+ return Buffer.from(value).toString('hex');
285
+ }
286
+ function managedPath(blobId, payload) {
287
+ const digest = blobHash(blobId);
288
+ const expected = `sha256/${digest.slice(0, 2)}/${digest}`;
289
+ if (!(payload instanceof Uint8Array) || !Buffer.from(payload).equals(Buffer.from(expected))) {
290
+ throw new Error('Invalid context snapshot managed locator');
291
+ }
292
+ return `${CONTEXT_OFFLOAD_VALUES_DIRECTORY_NAME}/${expected}`;
293
+ }
294
+ async function assertRegularPath(root, relativePath) {
295
+ const canonical = await realpath(root);
296
+ const parts = relativePath.split('/');
297
+ let path = canonical;
298
+ for (const [index, part] of parts.entries()) {
299
+ path = join(path, part);
300
+ const info = await lstat(path);
301
+ if (info.isSymbolicLink() ||
302
+ (index === parts.length - 1 ? !info.isFile() : !info.isDirectory())) {
303
+ throw new Error('Context snapshot path must not contain symlinks or special files');
304
+ }
305
+ }
306
+ if ((await realpath(path)) !== resolve(canonical, relativePath))
307
+ throw new Error('Context snapshot path escaped its root');
308
+ }
309
+ async function hashFile(path) {
310
+ const hash = createHash('sha256');
311
+ for await (const chunk of createReadStream(path))
312
+ hash.update(chunk);
313
+ return hash.digest('hex');
314
+ }
315
+ async function exists(path) {
316
+ try {
317
+ await lstat(path);
318
+ return true;
319
+ }
320
+ catch (error) {
321
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
322
+ return false;
323
+ throw error;
324
+ }
325
+ }
@@ -67,6 +67,10 @@ class SqliteConversationOperationalStateStore {
67
67
  database
68
68
  .prepare('DELETE FROM core_root_turn_start_rejections WHERE session_id = ?')
69
69
  .run(sessionId);
70
+ // Cascades this run's events and the Usage projection's checkpoints.
71
+ // `usage_model_call_attempts` is deliberately absent from this list:
72
+ // deleting a conversation must not erase its spend from all-time Usage
73
+ // totals, so those rows outlive the authority they were projected from.
70
74
  database.prepare('DELETE FROM core_agent_runs WHERE session_id = ?').run(sessionId);
71
75
  database
72
76
  .prepare('DELETE FROM core_client_capability_session_grants WHERE session_id = ?')
@@ -29,7 +29,7 @@ const executionStoresReaderKinds = new WeakMap();
29
29
  const executionStoresWritersByLease = new WeakMap();
30
30
  const executionStoresWritersOpeningByLease = new WeakMap();
31
31
  export { normalizeRootTurnAdmissionPayload, rootTurnAdmissionRecordFits, } from './agent-run-store.js';
32
- export { isSessionNotFoundError, SessionReadMarkerMessageNotFoundError, } from './session-store.js';
32
+ export { isSessionNotFoundError } from './session-store.js';
33
33
  export { SessionMetadataConflictError, SessionMetadataVersionConflictError, } from './sqlite-session-metadata-store.js';
34
34
  export { submittedTurnIntentsEqual } from './submitted-turn-intent.js';
35
35
  export function authenticateExecutionStoresWriter(stores, expectedKind) {
@@ -140,6 +140,7 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
140
140
  readSandboxBoundaryRequest: (sessionId, requestId) => run(() => sessionStore.readSandboxBoundaryRequest(sessionId, requestId)),
141
141
  listPendingSandboxBoundaryRequests: (sessionId) => run(() => sessionStore.listPendingSandboxBoundaryRequests(sessionId)),
142
142
  listSandboxBoundaryRestartClosures: (sessionId) => run(() => sessionStore.listSandboxBoundaryRestartClosures(sessionId)),
143
+ hasExplicitSandboxBoundaryDenial: (identities) => run(() => sessionStore.hasExplicitSandboxBoundaryDenial(identities)),
143
144
  settleSandboxBoundaryRequest: (input) => run(() => sessionStore.settleSandboxBoundaryRequest(input)),
144
145
  setExecutionBoundaryKind: (sessionId, boundaryKind, projection) => run(() => sessionStore.setExecutionBoundaryKind(sessionId, boundaryKind, projection)),
145
146
  list: (filter) => run(() => sessionStore.list(filter)),
@@ -151,19 +152,16 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
151
152
  readCatalogRecord: (sessionId) => run(() => sessionStore.readCatalogRecord(sessionId)),
152
153
  probeSessionRemoval: (sessionId) => run(() => sessionStore.probeSessionRemoval(sessionId)),
153
154
  readMessagesSnapshot: (sessionId) => run(() => sessionStore.readMessagesSnapshot(sessionId)),
154
- readTranscriptPageSnapshot: (sessionId, request) => run(() => sessionStore.readTranscriptPageSnapshot(sessionId, request)),
155
- readTranscriptRecordsSnapshot: (sessionId, request) => run(() => sessionStore.readTranscriptRecordsSnapshot(sessionId, request)),
156
155
  readTranscriptMessagesSnapshot: (sessionId, request) => run(() => sessionStore.readTranscriptMessagesSnapshot(sessionId, request)),
157
156
  readTranscriptHighWaterSnapshot: (sessionId) => run(() => sessionStore.readTranscriptHighWaterSnapshot(sessionId)),
158
- readTurnContributionsSnapshot: (sessionId, throughSequence, position, maxContributions) => run(() => sessionStore.readTurnContributionsSnapshot(sessionId, throughSequence, position, maxContributions)),
159
- readTurnLandmarksSnapshot: (sessionId, maxLandmarks) => run(() => sessionStore.readTurnLandmarksSnapshot(sessionId, maxLandmarks)),
160
- readMessagesForRecovery: (sessionId) => run(() => sessionStore.readMessagesForRecovery(sessionId)),
161
157
  listTurnsSnapshot: (sessionId) => run(() => sessionStore.listTurnsSnapshot(sessionId)),
162
158
  readHeader: (sessionId) => run(() => sessionStore.readHeader(sessionId)),
163
159
  readMessages: (sessionId) => run(() => sessionStore.readMessages(sessionId)),
160
+ readMessagesAfter: (sessionId, request) => run(() => sessionStore.readMessagesAfter(sessionId, request)),
164
161
  listTurns: (sessionId) => run(() => sessionStore.listTurns(sessionId)),
165
162
  appendMessage: (sessionId, message) => run(() => sessionStore.appendMessage(sessionId, message)),
166
163
  appendMessages: (sessionId, messages) => run(() => sessionStore.appendMessages(sessionId, messages)),
164
+ commitMessageCatalogProjection: (sessionId, message) => run(() => sessionStore.commitMessageCatalogProjection(sessionId, message)),
167
165
  commitMessageAdmission: (admission) => run(() => sessionStore.commitMessageAdmission(admission)),
168
166
  readMessageAdmission: (sessionId, messageId) => run(() => sessionStore.readMessageAdmission(sessionId, messageId)),
169
167
  hasCancelledMessageAdmission: (sessionId, messageId) => run(() => sessionStore.hasCancelledMessageAdmission(sessionId, messageId)),
@@ -177,7 +175,6 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
177
175
  updateHeader: (sessionId, patch) => run(() => sessionStore.updateHeader(sessionId, patch)),
178
176
  updateHeaderVersioned: (sessionId, patch, expectedRevision) => run(() => sessionStore.updateHeaderVersioned(sessionId, patch, expectedRevision)),
179
177
  updateSessionConfiguration: (sessionId, input) => run(() => sessionStore.updateSessionConfiguration(sessionId, input)),
180
- markSessionReadThroughMessage: (sessionId, messageId) => run(() => sessionStore.markSessionReadThroughMessage(sessionId, messageId)),
181
178
  setFlagged: (sessionId, isFlagged) => run(() => sessionStore.setFlagged(sessionId, isFlagged)),
182
179
  rename: (sessionId, name) => run(() => sessionStore.rename(sessionId, name)),
183
180
  setGeneratedTitleIfAbsent: (sessionId, title) => run(() => sessionStore.setGeneratedTitleIfAbsent(sessionId, title)),
@@ -210,6 +207,7 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
210
207
  repairEventProjection: (sessionId, type, event, options) => run(() => agentRunStore.repairEventProjection(sessionId, type, event, options)),
211
208
  admitRootTurn: (input) => run(() => agentRunStore.admitRootTurn(input)),
212
209
  readRootTurnAdmission: (sessionId, turnId) => run(() => agentRunStore.readRootTurnAdmission(sessionId, turnId)),
210
+ readRootTurnContinuationAdmission: (sessionId, sourceTurnId, sourceRunId) => run(() => agentRunStore.readRootTurnContinuationAdmission(sessionId, sourceTurnId, sourceRunId)),
213
211
  readRootTurnStartRejection: (sessionId, turnId) => run(() => agentRunStore.readRootTurnStartRejection(sessionId, turnId)),
214
212
  commitRootTurnStartRejection: (input) => run(() => agentRunStore.commitRootTurnStartRejection(input)),
215
213
  readRootTurnSourceMessageReceipt: (sessionId, sourceMessageId) => run(() => agentRunStore.readRootTurnSourceMessageReceipt(sessionId, sourceMessageId)),
@@ -235,6 +233,10 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
235
233
  readInvocation: (sessionId, invocationId) => run(() => runtimeEventStore.readInvocation(sessionId, invocationId)),
236
234
  readSessionRuntimeEvents: (sessionId) => run(() => runtimeEventStore.readSessionRuntimeEvents(sessionId)),
237
235
  readSessionRuntimeEventEntries: (sessionId) => run(() => runtimeEventStore.readSessionRuntimeEventEntries(sessionId)),
236
+ resequenceSessionEventOrdinals: (sessionId) => run(() => runtimeEventStore.resequenceSessionEventOrdinals(sessionId)),
237
+ readTranscriptHighWater: (sessionId) => run(() => runtimeEventStore.readTranscriptHighWater(sessionId)),
238
+ readTranscriptInvocations: (sessionId, request) => run(() => runtimeEventStore.readTranscriptInvocations(sessionId, request)),
239
+ readTranscriptLandmarks: (sessionId, throughOrdinal, limit) => run(() => runtimeEventStore.readTranscriptLandmarks(sessionId, throughOrdinal, limit)),
238
240
  claimContinuation: (input) => run(() => runtimeEventStore.claimContinuation(input)),
239
241
  readContinuationClaimByBoundary: (boundaryDigest) => run(() => runtimeEventStore.readContinuationClaimByBoundary(boundaryDigest)),
240
242
  readContinuationClaimStateByBoundary: (boundaryDigest) => run(() => runtimeEventStore.readContinuationClaimStateByBoundary(boundaryDigest)),
@@ -302,6 +304,7 @@ async function openExecutionStoresForRead(lease, kind, extension) {
302
304
  readEventsByTypeBounded: (sessionId, runId, type, budget) => run(() => agentRunStore.readEventsByTypeBounded(sessionId, runId, type, budget)),
303
305
  readEventProjection: (sessionId, type) => run(() => agentRunStore.readEventProjection(sessionId, type)),
304
306
  readRootTurnAdmission: (sessionId, turnId) => run(() => agentRunStore.readRootTurnAdmission(sessionId, turnId)),
307
+ readRootTurnContinuationAdmission: (sessionId, sourceTurnId, sourceRunId) => run(() => agentRunStore.readRootTurnContinuationAdmission(sessionId, sourceTurnId, sourceRunId)),
305
308
  readRootTurnSourceMessageReceipt: (sessionId, sourceMessageId) => run(() => agentRunStore.readRootTurnSourceMessageReceipt(sessionId, sourceMessageId)),
306
309
  },
307
310
  runtimeEventStore: {
@@ -314,6 +317,7 @@ async function openExecutionStoresForRead(lease, kind, extension) {
314
317
  listSessionInvocationsPage: (sessionId, input) => run(() => runtimeEventStore.listSessionInvocationsPage(sessionId, input)),
315
318
  readInvocation: (sessionId, invocationId) => run(() => runtimeEventStore.readInvocation(sessionId, invocationId)),
316
319
  readSessionRuntimeEvents: (sessionId) => run(() => runtimeEventStore.readSessionRuntimeEvents(sessionId)),
320
+ readSessionRuntimeEventEntries: (sessionId) => run(() => runtimeEventStore.readSessionRuntimeEventEntries(sessionId)),
317
321
  },
318
322
  };
319
323
  freezeExecutionStoresFacade(stores);