@cortexkit/opencode-magic-context 0.49.25 → 0.49.27
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.
- package/dist/auto-search-worker.js +4 -4
- package/dist/chunk-embedding-write-worker.js +7 -7
- package/dist/{compartment-chunk-embedding-eypvn607.js → compartment-chunk-embedding-qgp0tbf7.js} +3 -3
- package/dist/config/schema/magic-context.d.ts +393 -393
- package/dist/{conflict-warning-hook-a27bhggg.js → conflict-warning-hook-tgnw019g.js} +4 -4
- package/dist/{context-keb00be8.js → context-t2k97d6v.js} +116 -116
- package/dist/{embedding-backfill-vddgmem3.js → embedding-backfill-cwnyr4fj.js} +5 -5
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-async.d.ts +1 -4
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts +1 -28
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/session-retention.fixture.d.ts +4 -0
- package/dist/features/magic-context/session-retention.fixture.d.ts.map +1 -0
- package/dist/features/magic-context/storage-session-tables.d.ts +5 -12
- package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
- package/dist/hooks/magic-context/caveman-cleanup.d.ts +14 -0
- package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +11 -0
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/foreign-text-parts.d.ts +47 -0
- package/dist/hooks/magic-context/foreign-text-parts.d.ts.map +1 -0
- package/dist/hooks/magic-context/historian-history-wait.d.ts +10 -0
- package/dist/hooks/magic-context/historian-history-wait.d.ts.map +1 -0
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-recovery-fence.d.ts +0 -5
- package/dist/hooks/magic-context/lkg-recovery-fence.d.ts.map +1 -1
- package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts +0 -10
- package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts +21 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts +20 -0
- package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +15 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/todo-view.d.ts +2 -2
- package/dist/hooks/magic-context/transform.d.ts +7 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-jcr6pe7z.js → index-077ht5cq.js} +1 -1
- package/dist/{index-ebsvmc5s.js → index-31y1mznz.js} +4 -4
- package/dist/{index-q7ywt6xt.js → index-4cpc59jv.js} +5 -5
- package/dist/{index-t6j3qxnd.js → index-4ypqzvhf.js} +1 -1
- package/dist/index-7gbcg8xv.js +559 -0
- package/dist/{index-9q1g3c5q.js → index-7kkphb6c.js} +1 -1
- package/dist/{index-bhyksfyy.js → index-89k1w6x2.js} +3 -3
- package/dist/{index-z05n7702.js → index-a2fz9hpa.js} +1 -1
- package/dist/{index-0s8454t2.js → index-dcqk0y27.js} +1560 -91
- package/dist/{index-n18sch77.js → index-dzfevacx.js} +9 -9
- package/dist/{index-axjgxeww.js → index-fq2p158w.js} +169 -13
- package/dist/{index-3d5wnkq7.js → index-mm93m7y6.js} +1 -1
- package/dist/{index-zzrzjnx5.js → index-n8qmmd7f.js} +3 -3
- package/dist/{index-whcgcfrv.js → index-np3rgfw4.js} +1 -1
- package/dist/{index-y6xpzjzr.js → index-qzbpbnqt.js} +585 -602
- package/dist/{index-7tdtpqrg.js → index-rverk2vz.js} +39 -8
- package/dist/{index-cfaet9cg.js → index-s1n8dd2n.js} +1 -1
- package/dist/{index-z928hmnp.js → index-t3rbb8wr.js} +2 -2
- package/dist/{index-2haxh8h3.js → index-tvzvjggy.js} +1 -1
- package/dist/{index-c9zrgcnt.js → index-v0dhhxsq.js} +1 -1
- package/dist/{index-szf8r0ba.js → index-v15ne3a3.js} +2 -5
- package/dist/{index-x9k3mqrf.js → index-xrnsygfq.js} +1 -1
- package/dist/{index-yrrsp47d.js → index-yzjhx10y.js} +20 -6
- package/dist/index.js +40 -38
- package/dist/{message-fts-rowid-map-9e1getgs.js → message-fts-rowid-map-va36knh4.js} +2 -4
- package/dist/{message-index-bounded-vaeqhp9w.js → message-index-bounded-7ayzb2ah.js} +22 -25
- package/dist/migration-worker.js +6 -6
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/{project-embedding-registry-rstzmb60.js → project-embedding-registry-94nncs5g.js} +4 -4
- package/dist/raw-ordinal-warmup-worker.js +7 -30
- package/dist/{read-session-chunk-z5gnc0zb.js → read-session-chunk-jzb6w9w5.js} +8 -6
- package/dist/{read-session-raw-s4amywnh.js → read-session-raw-b2sd67v4.js} +3 -1
- package/dist/{recomp-orchestrator-qwqeskhq.js → recomp-orchestrator-02sa2ngr.js} +17 -17
- package/dist/{search-archive-mfabzyn2.js → search-archive-q1vw7zg4.js} +7 -7
- package/dist/{search-84zfqeky.js → search-spq6nfyf.js} +14 -15
- package/dist/{send-session-notification-ygj4mja0.js → send-session-notification-afzzqy5b.js} +3 -3
- package/dist/{storage-tags-a77q4v77.js → storage-tags-6hvkk01c.js} +2 -2
- package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
- package/dist/{transform-postprocess-phase-hr1ntmjj.js → transform-postprocess-phase-6menyyxc.js} +17 -17
- package/dist/v2/auto-search-worker.js +4 -4
- package/dist/v2/chunk-embedding-write-worker.js +7 -7
- package/dist/v2/{compartment-chunk-embedding-tk6g4q80.js → compartment-chunk-embedding-63dzs31c.js} +3 -3
- package/dist/v2/{context-y7wfvdve.js → context-na0esngr.js} +342 -218
- package/dist/v2/{embedding-backfill-w5qp7t28.js → embedding-backfill-rh5dgsva.js} +5 -5
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/{message-fts-rowid-map-pqk3a55v.js → message-fts-rowid-map-78awh03v.js} +2 -4
- package/dist/v2/{message-index-bounded-te303atj.js → message-index-bounded-n09b74vr.js} +21 -24
- package/dist/v2/migration-worker.js +6 -6
- package/dist/v2/{project-embedding-registry-e7zftfvj.js → project-embedding-registry-6pak822h.js} +4 -4
- package/dist/v2/raw-ordinal-warmup-worker.js +7 -30
- package/dist/v2/{read-session-chunk-knvkq1hf.js → read-session-chunk-vpt69tw9.js} +7 -5
- package/dist/v2/{read-session-raw-ppjxnqk4.js → read-session-raw-5x088amc.js} +3 -1
- package/dist/v2/{recomp-orchestrator-e8a4jpvr.js → recomp-orchestrator-txsmbnvw.js} +14 -14
- package/dist/v2/{search-archive-vrwgxv6z.js → search-archive-t9bcz4ht.js} +6 -6
- package/dist/v2/{search-hav4dggf.js → search-dcy9b6gd.js} +13 -14
- package/dist/v2/{send-session-notification-f8scq6ae.js → send-session-notification-vdsgnf4c.js} +1 -1
- package/dist/v2/{server-pw21ypwb.js → server-4sn3at8p.js} +1 -1
- package/dist/v2/{server-8j2e7t31.js → server-6avtp9jp.js} +1 -1
- package/dist/v2/{server-wwaw5npa.js → server-6g98c227.js} +1 -1
- package/dist/v2/{server-swvhxhxz.js → server-6vd2n183.js} +39 -8
- package/dist/v2/{server-wxrdher8.js → server-awr8qa4c.js} +2 -5
- package/dist/v2/{server-7d6m1p2b.js → server-cqjvxyrp.js} +1 -1
- package/dist/v2/{server-e75vag9d.js → server-e3hc93wk.js} +5 -5
- package/dist/v2/{server-7weh65vd.js → server-jj9qye8y.js} +1520 -79
- package/dist/v2/{server-fa7vtp40.js → server-nxas8v1d.js} +1 -1
- package/dist/v2/{server-tfawsj08.js → server-txbc3czn.js} +9 -9
- package/dist/v2/{server-rqebawx1.js → server-v77xa5wj.js} +1 -1
- package/dist/v2/{server-5brp2rfn.js → server-xkvxss5g.js} +19 -5
- package/dist/v2/{server-q5z0gag0.js → server-yqek3s4k.js} +1 -1
- package/dist/v2/server-z2n2xaeh.js +538 -0
- package/dist/v2/{server-9xbbaekh.js → server-z3mk9jdc.js} +2 -2
- package/dist/v2/{server-m6yyn961.js → server-zmcrvpm3.js} +2 -2
- package/dist/v2/server.js +2 -2
- package/dist/v2/{storage-tags-q71rnr9f.js → storage-tags-18nbaanf.js} +2 -2
- package/dist/v2/store-reader.d.ts +0 -2
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/{wrapup-orchestrator-ycs8y6n4.js → wrapup-orchestrator-gjkszser.js} +14 -14
- package/dist/{wrapup-orchestrator-f642w8n3.js → wrapup-orchestrator-n5h5sr1x.js} +18 -18
- package/package.json +1 -1
- package/src/shared/write-transaction-attribution.test.ts +1 -6
- package/dist/index-awcftgmx.js +0 -2251
- package/dist/message-index-3g966xn7.js +0 -61
- package/dist/v2/message-index-fz6b4jeh.js +0 -60
- package/dist/v2/server-6a8pxpxg.js +0 -2220
|
@@ -92,12 +92,13 @@ import {
|
|
|
92
92
|
readRawSessionMessageIdOrdinalsForRange2,
|
|
93
93
|
hasRawSessionMessageById2,
|
|
94
94
|
readRawSessionMessageOrdinalById2,
|
|
95
|
+
resolveHistorianChunkStart2,
|
|
95
96
|
compareRawSessionMessageOrder2,
|
|
96
97
|
getRawSessionMessageCount2,
|
|
97
98
|
getRawSessionTagKeysThrough2,
|
|
98
99
|
getLegacyProtectedTailStartOrdinal2,
|
|
99
100
|
readSessionChunk2
|
|
100
|
-
} from "./index-
|
|
101
|
+
} from "./index-yzjhx10y.js";
|
|
101
102
|
import {
|
|
102
103
|
getHarness2,
|
|
103
104
|
harnessOwnsOpenCodeStore2
|
|
@@ -105,7 +106,8 @@ import {
|
|
|
105
106
|
import {
|
|
106
107
|
getDataDir,
|
|
107
108
|
ensureCortexKitArtifactGitignore,
|
|
108
|
-
getProjectMagicContextHistorianDir
|
|
109
|
+
getProjectMagicContextHistorianDir,
|
|
110
|
+
getMagicContextStorageDir
|
|
109
111
|
} from "./index-g2q4htwp.js";
|
|
110
112
|
import {
|
|
111
113
|
sanitizeDiagnosticText,
|
|
@@ -148,6 +150,14 @@ import {
|
|
|
148
150
|
MagicContextConfigSchema,
|
|
149
151
|
LIVE_RELOAD_CONFIG_PATHS
|
|
150
152
|
} from "./index-nxrsns5x.js";
|
|
153
|
+
import {
|
|
154
|
+
tagTombstoneOwnerRange,
|
|
155
|
+
tagTombstoneOwnerKey,
|
|
156
|
+
tagRevisionKey,
|
|
157
|
+
tagIdentityRevisionKey,
|
|
158
|
+
deleteTagIdentityRevisions,
|
|
159
|
+
getTableColumnNames
|
|
160
|
+
} from "./index-xrnsygfq.js";
|
|
151
161
|
import {
|
|
152
162
|
providerMass,
|
|
153
163
|
calibrationForModelKey,
|
|
@@ -164,11 +174,12 @@ import {
|
|
|
164
174
|
LATEST_SUPPORTED_VERSION,
|
|
165
175
|
getPersistedSchemaVersion,
|
|
166
176
|
openDatabase
|
|
167
|
-
} from "./index-
|
|
177
|
+
} from "./index-4cpc59jv.js";
|
|
168
178
|
import {
|
|
169
179
|
inRootAsyncContext2,
|
|
170
180
|
Database2,
|
|
171
181
|
getSqliteDatabasePath2,
|
|
182
|
+
prepareCachedStatement2,
|
|
172
183
|
withSqliteBackgroundWriter2,
|
|
173
184
|
withoutSqliteTransformPass2,
|
|
174
185
|
beginSqliteWriterAsync2
|
|
@@ -178,15 +189,20 @@ import {
|
|
|
178
189
|
resolveProjectIdentity
|
|
179
190
|
} from "./index-kq5w68dp.js";
|
|
180
191
|
import {
|
|
181
|
-
isPidAlive
|
|
192
|
+
isPidAlive,
|
|
193
|
+
readProcessStartTime
|
|
182
194
|
} from "./index-c7phnbvk.js";
|
|
183
195
|
import {
|
|
184
196
|
areRustHistorianSyntheticParts2,
|
|
185
197
|
isStrictGapHealingMessage2,
|
|
186
198
|
noteRawSessionSummaryRowWritten2,
|
|
187
199
|
RawOrdinalsNotReady2,
|
|
200
|
+
dropRawSessionOrdinalCheckpoints2,
|
|
188
201
|
runSessionWarmupWorker
|
|
189
|
-
} from "./index-
|
|
202
|
+
} from "./index-rverk2vz.js";
|
|
203
|
+
import {
|
|
204
|
+
deleteUnmappedMessageFtsRows2
|
|
205
|
+
} from "./index-v15ne3a3.js";
|
|
190
206
|
import {
|
|
191
207
|
layoutLkgPrefix,
|
|
192
208
|
assembleLkgPrefix,
|
|
@@ -197,10 +213,7 @@ import {
|
|
|
197
213
|
resolveStoredPathWorkspaceIdentity,
|
|
198
214
|
sourceNameForMemory,
|
|
199
215
|
computeWorkspaceEpochFingerprint
|
|
200
|
-
} from "./index-
|
|
201
|
-
import {
|
|
202
|
-
getTableColumnNames
|
|
203
|
-
} from "./index-x9k3mqrf.js";
|
|
216
|
+
} from "./index-7kkphb6c.js";
|
|
204
217
|
import {
|
|
205
218
|
V2_MEMORY_CATEGORIES,
|
|
206
219
|
CATEGORY_PRIORITY,
|
|
@@ -215,7 +228,7 @@ import {
|
|
|
215
228
|
import {
|
|
216
229
|
BoundedSessionMap,
|
|
217
230
|
getMeasuredToolDefinitionTokens
|
|
218
|
-
} from "./index-
|
|
231
|
+
} from "./index-s1n8dd2n.js";
|
|
219
232
|
import {
|
|
220
233
|
invalidateAutoEmbedSession,
|
|
221
234
|
drainBackgroundBatches,
|
|
@@ -224,7 +237,7 @@ import {
|
|
|
224
237
|
getProjectChunkEmbeddingModelId2,
|
|
225
238
|
getProjectEmbeddingMaxInputTokens2,
|
|
226
239
|
embedItemsForProject2
|
|
227
|
-
} from "./index-
|
|
240
|
+
} from "./index-a2fz9hpa.js";
|
|
228
241
|
import {
|
|
229
242
|
buildCanonicalChunkTextFromFts2,
|
|
230
243
|
buildCompartmentSummaryFallbackText2,
|
|
@@ -234,23 +247,14 @@ import {
|
|
|
234
247
|
replaceCompartmentChunkEmbeddings2,
|
|
235
248
|
deleteChunkEmbedBackoffForSession2,
|
|
236
249
|
chunkWindowSourceKey2
|
|
237
|
-
} from "./index-
|
|
250
|
+
} from "./index-mm93m7y6.js";
|
|
238
251
|
import {
|
|
239
252
|
clearCompressionDepth,
|
|
240
253
|
clearCompressionDepthRange,
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
commitLkgWithRecoveryFence,
|
|
246
|
-
clearLkgRecoveryFence,
|
|
247
|
-
gaDatabasePath,
|
|
248
|
-
V2StoreReader,
|
|
249
|
-
deleteSessionScopedRows,
|
|
250
|
-
toMessageIndexSource2,
|
|
251
|
-
clearIndexedMessagesInTransaction2,
|
|
252
|
-
indexSourcesAfterOrdinal2
|
|
253
|
-
} from "./index-awcftgmx.js";
|
|
254
|
+
toMessageIndexSource,
|
|
255
|
+
clearIndexedMessagesInTransaction,
|
|
256
|
+
indexSourcesAfterOrdinal
|
|
257
|
+
} from "./index-7gbcg8xv.js";
|
|
254
258
|
import {
|
|
255
259
|
stripWellFormedLeadingTagPrefix,
|
|
256
260
|
stripTagPrefix,
|
|
@@ -263,12 +267,12 @@ import {
|
|
|
263
267
|
foldShrunkPartTags2,
|
|
264
268
|
getTagNumberByMessageId2,
|
|
265
269
|
getActiveTagsBySession2
|
|
266
|
-
} from "./index-
|
|
270
|
+
} from "./index-np3rgfw4.js";
|
|
267
271
|
import {
|
|
268
272
|
openCodeDbExists,
|
|
269
273
|
withReadOnlySessionDb,
|
|
270
274
|
getMessageTimesFromOpenCodeDb
|
|
271
|
-
} from "./index-
|
|
275
|
+
} from "./index-v0dhhxsq.js";
|
|
272
276
|
import {
|
|
273
277
|
renderUserFacingFailure,
|
|
274
278
|
userFacingFailureCode,
|
|
@@ -277,7 +281,7 @@ import {
|
|
|
277
281
|
insertPrimerCandidates,
|
|
278
282
|
promoteSessionFactsDurable,
|
|
279
283
|
embedPromotedFacts
|
|
280
|
-
} from "./index-
|
|
284
|
+
} from "./index-t3rbb8wr.js";
|
|
281
285
|
import {
|
|
282
286
|
pushNotification2
|
|
283
287
|
} from "./index-x8a7jmkh.js";
|
|
@@ -297,7 +301,7 @@ import {
|
|
|
297
301
|
} from "./index-qgh1qwjj.js";
|
|
298
302
|
import {
|
|
299
303
|
sendStatusNotification2
|
|
300
|
-
} from "./index-
|
|
304
|
+
} from "./index-077ht5cq.js";
|
|
301
305
|
import {
|
|
302
306
|
isCompactionEnabled,
|
|
303
307
|
migrateLegacyAgentEnabledInMemory
|
|
@@ -305,6 +309,9 @@ import {
|
|
|
305
309
|
import {
|
|
306
310
|
piModelRefToCanonical
|
|
307
311
|
} from "./index-avwt563y.js";
|
|
312
|
+
import {
|
|
313
|
+
sameProjectDirectory
|
|
314
|
+
} from "./index-knvkbfvh.js";
|
|
308
315
|
import {
|
|
309
316
|
getErrorMessage,
|
|
310
317
|
describeError
|
|
@@ -318,7 +325,11 @@ import {
|
|
|
318
325
|
} from "./index-t5pck3ss.js";
|
|
319
326
|
import {
|
|
320
327
|
ensureStorageDirectorySync,
|
|
321
|
-
|
|
328
|
+
ensurePrivateStorageDirectorySync,
|
|
329
|
+
writeStorageFileSync,
|
|
330
|
+
writeStorageFileAtomicSync,
|
|
331
|
+
syncStorageDirectorySync,
|
|
332
|
+
writeStorageFileDurableAtomicSync
|
|
322
333
|
} from "./index-fvnzcnww.js";
|
|
323
334
|
|
|
324
335
|
// src/agents/permissions.ts
|
|
@@ -3373,6 +3384,84 @@ function createDreamerOutputCapSampler(boot, fresh) {
|
|
|
3373
3384
|
};
|
|
3374
3385
|
}
|
|
3375
3386
|
|
|
3387
|
+
// src/features/magic-context/session-activity.ts
|
|
3388
|
+
var PREFIX = "retrospective_activity:";
|
|
3389
|
+
var INTERVAL_MS = 15000;
|
|
3390
|
+
var pending = new WeakMap;
|
|
3391
|
+
function sessionActivityKey(sessionId) {
|
|
3392
|
+
return `${PREFIX}${sessionId}`;
|
|
3393
|
+
}
|
|
3394
|
+
function deleteSessionActivity(db, sessionIds) {
|
|
3395
|
+
if (sessionIds.length === 0)
|
|
3396
|
+
return;
|
|
3397
|
+
const sessions = pending.get(db);
|
|
3398
|
+
for (const sessionId of sessionIds) {
|
|
3399
|
+
const state = sessions?.get(sessionId);
|
|
3400
|
+
if (state?.timer)
|
|
3401
|
+
clearTimeout(state.timer);
|
|
3402
|
+
sessions?.delete(sessionId);
|
|
3403
|
+
}
|
|
3404
|
+
const placeholders = sessionIds.map(() => "?").join(", ");
|
|
3405
|
+
db.prepare(`DELETE FROM schema_migrations_meta WHERE key IN (${placeholders})`).run(...sessionIds.map(sessionActivityKey));
|
|
3406
|
+
deleteTagIdentityRevisions(db, sessionIds);
|
|
3407
|
+
}
|
|
3408
|
+
function advanceSessionActivity(db, sessionId, time) {
|
|
3409
|
+
if (!sessionId || !Number.isFinite(time) || time <= 0)
|
|
3410
|
+
return;
|
|
3411
|
+
db.prepare(`INSERT INTO schema_migrations_meta (key, value) VALUES (?, ?)
|
|
3412
|
+
ON CONFLICT(key) DO UPDATE SET value = CAST(MAX(CAST(value AS INTEGER), CAST(excluded.value AS INTEGER)) AS TEXT)`).run(sessionActivityKey(sessionId), String(Math.floor(time)));
|
|
3413
|
+
}
|
|
3414
|
+
function observeSessionActivity(db, sessionId, time = Date.now()) {
|
|
3415
|
+
if (!sessionId || !Number.isFinite(time) || time <= 0)
|
|
3416
|
+
return;
|
|
3417
|
+
let sessions = pending.get(db);
|
|
3418
|
+
if (!sessions) {
|
|
3419
|
+
sessions = new Map;
|
|
3420
|
+
pending.set(db, sessions);
|
|
3421
|
+
}
|
|
3422
|
+
const current = sessions.get(sessionId);
|
|
3423
|
+
if (!current || time - current.lastWrite >= INTERVAL_MS) {
|
|
3424
|
+
if (current?.timer)
|
|
3425
|
+
clearTimeout(current.timer);
|
|
3426
|
+
advanceSessionActivity(db, sessionId, Math.max(time, current?.latest ?? 0));
|
|
3427
|
+
sessions.set(sessionId, { lastWrite: time, latest: time });
|
|
3428
|
+
return;
|
|
3429
|
+
}
|
|
3430
|
+
current.latest = Math.max(current.latest, time);
|
|
3431
|
+
if (!current.timer) {
|
|
3432
|
+
current.timer = setTimeout(() => {
|
|
3433
|
+
current.timer = undefined;
|
|
3434
|
+
try {
|
|
3435
|
+
advanceSessionActivity(db, sessionId, current.latest);
|
|
3436
|
+
current.lastWrite = Date.now();
|
|
3437
|
+
} catch {
|
|
3438
|
+
sessions.delete(sessionId);
|
|
3439
|
+
}
|
|
3440
|
+
}, Math.max(1, INTERVAL_MS - (time - current.lastWrite)));
|
|
3441
|
+
current.timer.unref?.();
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
async function backfillSessionActivity(db, harness, latestTime) {
|
|
3445
|
+
const completedKey = `retrospective_activity_backfill:${harness}:v1`;
|
|
3446
|
+
if (db.prepare("SELECT 1 FROM schema_migrations_meta WHERE key = ?").get(completedKey))
|
|
3447
|
+
return;
|
|
3448
|
+
let cursor = "";
|
|
3449
|
+
while (true) {
|
|
3450
|
+
const rows = db.prepare(`SELECT session_id FROM session_projects
|
|
3451
|
+
WHERE harness = ? AND session_id > ? ORDER BY session_id LIMIT 100`).all(harness, cursor);
|
|
3452
|
+
if (rows.length === 0)
|
|
3453
|
+
break;
|
|
3454
|
+
for (const row of rows) {
|
|
3455
|
+
const time = await latestTime(row.session_id);
|
|
3456
|
+
if (time !== undefined)
|
|
3457
|
+
advanceSessionActivity(db, row.session_id, time);
|
|
3458
|
+
}
|
|
3459
|
+
cursor = rows[rows.length - 1].session_id;
|
|
3460
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
3461
|
+
}
|
|
3462
|
+
db.prepare("INSERT OR IGNORE INTO schema_migrations_meta (key, value) VALUES (?, 'completed')").run(completedKey);
|
|
3463
|
+
}
|
|
3464
|
+
|
|
3376
3465
|
// src/features/magic-context/memory-enabled.ts
|
|
3377
3466
|
function isProjectMemoryEnabled(enabled) {
|
|
3378
3467
|
return enabled !== false;
|
|
@@ -4929,10 +5018,10 @@ function readProjectDocsCanonical(projectDirectory) {
|
|
|
4929
5018
|
return { renderedBlock, canonicalHash };
|
|
4930
5019
|
}
|
|
4931
5020
|
// src/hooks/magic-context/lkg-slot.ts
|
|
4932
|
-
import { createHash as
|
|
5021
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
4933
5022
|
|
|
4934
5023
|
// src/hooks/magic-context/lkg-measured-request.ts
|
|
4935
|
-
import { createHash as
|
|
5024
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
4936
5025
|
|
|
4937
5026
|
// src/shared/provider-response-completion.ts
|
|
4938
5027
|
function providerResponseFailed(input) {
|
|
@@ -4949,8 +5038,432 @@ function isSuccessfulProviderCompletion(input) {
|
|
|
4949
5038
|
// src/features/magic-context/storage-meta-session.ts
|
|
4950
5039
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
4951
5040
|
|
|
5041
|
+
// src/hooks/magic-context/lkg-recovery-fence.ts
|
|
5042
|
+
import { createHash as createHash4, randomUUID as randomUUID2 } from "node:crypto";
|
|
5043
|
+
import { lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync7, rmdirSync, rmSync as rmSync3 } from "node:fs";
|
|
5044
|
+
import { basename as basename3, dirname as dirname4, join as join4 } from "node:path";
|
|
5045
|
+
|
|
5046
|
+
// src/shared/storage-file-mutex.ts
|
|
5047
|
+
import { execFileSync } from "node:child_process";
|
|
5048
|
+
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
5049
|
+
import { readdirSync, readFileSync as readFileSync6, rmSync as rmSync2 } from "node:fs";
|
|
5050
|
+
import { join as join3 } from "node:path";
|
|
5051
|
+
var ticketChecksum = (name, ticket) => createHash3("sha256").update(JSON.stringify([name, ticket.choosing, ticket.number, ticket.birth])).digest("hex");
|
|
5052
|
+
function processBirth(pid) {
|
|
5053
|
+
if (process.platform === "linux") {
|
|
5054
|
+
try {
|
|
5055
|
+
const stat = readFileSync6(`/proc/${pid}/stat`, "utf8");
|
|
5056
|
+
const ticks = stat.slice(stat.lastIndexOf(")") + 2).trim().split(/\s+/)[19];
|
|
5057
|
+
if (!ticks || !/^\d+$/.test(ticks))
|
|
5058
|
+
return null;
|
|
5059
|
+
return `${readFileSync6("/proc/sys/kernel/random/boot_id", "utf8").trim()}:${ticks}`;
|
|
5060
|
+
} catch {
|
|
5061
|
+
return null;
|
|
5062
|
+
}
|
|
5063
|
+
}
|
|
5064
|
+
if (process.platform === "darwin") {
|
|
5065
|
+
try {
|
|
5066
|
+
return execFileSync("ps", ["-p", String(pid), "-o", "lstart="], {
|
|
5067
|
+
encoding: "utf8",
|
|
5068
|
+
timeout: 1000,
|
|
5069
|
+
windowsHide: true,
|
|
5070
|
+
env: { ...process.env, TZ: "UTC", LC_ALL: "C" },
|
|
5071
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
5072
|
+
}).trim() || null;
|
|
5073
|
+
} catch {
|
|
5074
|
+
return null;
|
|
5075
|
+
}
|
|
5076
|
+
}
|
|
5077
|
+
const start = readProcessStartTime(pid);
|
|
5078
|
+
return start === null ? null : String(start);
|
|
5079
|
+
}
|
|
5080
|
+
var pause = new Int32Array(new SharedArrayBuffer(4));
|
|
5081
|
+
function withStorageFileMutex(directory, work, timeoutMs = 1000) {
|
|
5082
|
+
ensurePrivateStorageDirectorySync(directory);
|
|
5083
|
+
const name = `${process.pid}-${randomUUID()}.lock`;
|
|
5084
|
+
const ownPath = join3(directory, name);
|
|
5085
|
+
const birth = processBirth(process.pid);
|
|
5086
|
+
const ticket = { choosing: true, number: 0, birth, checksum: "" };
|
|
5087
|
+
const encodedTicket = () => JSON.stringify({ ...ticket, checksum: ticketChecksum(name, ticket) });
|
|
5088
|
+
for (let attempt = 0;; attempt++) {
|
|
5089
|
+
try {
|
|
5090
|
+
writeStorageFileSync(ownPath, encodedTicket(), { flag: "wx", forcePrivate: true });
|
|
5091
|
+
break;
|
|
5092
|
+
} catch (error) {
|
|
5093
|
+
if (error.code !== "ENOENT" || attempt >= 2)
|
|
5094
|
+
throw error;
|
|
5095
|
+
ensurePrivateStorageDirectorySync(directory);
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
const deadline = performance.now() + timeoutMs;
|
|
5099
|
+
const peers = () => {
|
|
5100
|
+
const found = [];
|
|
5101
|
+
for (const other of readdirSync(directory)) {
|
|
5102
|
+
if (other === name || !/^\d+-[\da-f-]+\.lock$/.test(other))
|
|
5103
|
+
continue;
|
|
5104
|
+
const pid = Number(other.split("-")[0]);
|
|
5105
|
+
const otherPath = join3(directory, other);
|
|
5106
|
+
let value = null;
|
|
5107
|
+
try {
|
|
5108
|
+
const parsed = JSON.parse(readFileSync6(otherPath, "utf8"));
|
|
5109
|
+
if (typeof parsed.choosing === "boolean" && Number.isSafeInteger(parsed.number) && parsed.number >= 0 && (parsed.birth === null || typeof parsed.birth === "string") && parsed.checksum === ticketChecksum(other, parsed))
|
|
5110
|
+
value = parsed;
|
|
5111
|
+
} catch (error) {
|
|
5112
|
+
if (error.code === "ENOENT")
|
|
5113
|
+
continue;
|
|
5114
|
+
}
|
|
5115
|
+
const alive = isPidAlive(pid);
|
|
5116
|
+
const actualBirth = alive === "alive" && value?.birth ? processBirth(pid) : null;
|
|
5117
|
+
if (alive === "dead" || actualBirth !== null && value?.birth && actualBirth !== value.birth) {
|
|
5118
|
+
rmSync2(otherPath, { force: true });
|
|
5119
|
+
continue;
|
|
5120
|
+
}
|
|
5121
|
+
found.push([other, value]);
|
|
5122
|
+
}
|
|
5123
|
+
return found;
|
|
5124
|
+
};
|
|
5125
|
+
try {
|
|
5126
|
+
ticket.number = 1 + Math.max(0, ...peers().map(([, value]) => value?.number ?? 0));
|
|
5127
|
+
ticket.choosing = false;
|
|
5128
|
+
writeStorageFileAtomicSync(ownPath, encodedTicket(), true);
|
|
5129
|
+
while (peers().some(([other, value]) => !value || value.choosing || value.number < ticket.number || value.number === ticket.number && other < name)) {
|
|
5130
|
+
if (performance.now() >= deadline)
|
|
5131
|
+
throw new Error("Storage safety publication lock is unavailable");
|
|
5132
|
+
Atomics.wait(pause, 0, 0, 10);
|
|
5133
|
+
}
|
|
5134
|
+
const result = work();
|
|
5135
|
+
if (result && typeof result.then === "function")
|
|
5136
|
+
throw new TypeError("Storage publication mutex requires synchronous work");
|
|
5137
|
+
return result;
|
|
5138
|
+
} finally {
|
|
5139
|
+
rmSync2(ownPath, { force: true });
|
|
5140
|
+
}
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
// src/hooks/magic-context/lkg-recovery-fence.ts
|
|
5144
|
+
class LkgRecoveryFenceError extends Error {
|
|
5145
|
+
constructor(message) {
|
|
5146
|
+
super(message);
|
|
5147
|
+
this.name = "LkgRecoveryFenceError";
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5150
|
+
var platform = process.platform;
|
|
5151
|
+
var observer;
|
|
5152
|
+
var knownFences = new BoundedSessionMap(1000);
|
|
5153
|
+
var ioObserver;
|
|
5154
|
+
var cacheKey = (sessionId) => `${getMagicContextStorageDir()}\x00${getHarness2()}\x00${sessionId}`;
|
|
5155
|
+
function remember(sessionId, value) {
|
|
5156
|
+
knownFences.set(cacheKey(sessionId), value);
|
|
5157
|
+
return value;
|
|
5158
|
+
}
|
|
5159
|
+
function known(sessionId) {
|
|
5160
|
+
const prior = knownFences.get(cacheKey(sessionId));
|
|
5161
|
+
if (prior)
|
|
5162
|
+
return prior;
|
|
5163
|
+
const record = read(sessionId);
|
|
5164
|
+
if (record)
|
|
5165
|
+
return remember(sessionId, { state: record.state, record });
|
|
5166
|
+
try {
|
|
5167
|
+
lstatSync2(lkgRecoveryFencePath(sessionId));
|
|
5168
|
+
} catch (error) {
|
|
5169
|
+
if (error.code === "ENOENT")
|
|
5170
|
+
return remember(sessionId, { state: "clean", record: null });
|
|
5171
|
+
}
|
|
5172
|
+
return remember(sessionId, { state: "invalid", record: null });
|
|
5173
|
+
}
|
|
5174
|
+
function clearLkgFenceProcessState(sessionId) {
|
|
5175
|
+
if (sessionId)
|
|
5176
|
+
knownFences.delete(cacheKey(sessionId));
|
|
5177
|
+
else
|
|
5178
|
+
knownFences.clear();
|
|
5179
|
+
}
|
|
5180
|
+
var durableFencesSupported = () => platform !== "win32";
|
|
5181
|
+
var hash = (value) => createHash4("sha256").update(value).digest("hex");
|
|
5182
|
+
var lkgServedArrayDigest = hash;
|
|
5183
|
+
function lkgRecoveryFencePath(sessionId) {
|
|
5184
|
+
return join4(getMagicContextStorageDir(), "lkg-recovery-fences", `${hash(sessionId)}.json`);
|
|
5185
|
+
}
|
|
5186
|
+
function metadata(slot) {
|
|
5187
|
+
return [
|
|
5188
|
+
slot.inputIdSeq,
|
|
5189
|
+
slot.inputContentDigests,
|
|
5190
|
+
slot.inputContentSignatures ?? null,
|
|
5191
|
+
slot.piOutputEntryIds ?? null,
|
|
5192
|
+
slot.lastInputMessageId,
|
|
5193
|
+
slot.modelKey,
|
|
5194
|
+
slot.providerKey
|
|
5195
|
+
];
|
|
5196
|
+
}
|
|
5197
|
+
function representationKey(slot) {
|
|
5198
|
+
return createHash4("sha256").update(slot.jsonPrefix).update(JSON.stringify(metadata(slot))).digest("hex");
|
|
5199
|
+
}
|
|
5200
|
+
function lkgRecoverySlotKey(slot) {
|
|
5201
|
+
return hash(JSON.stringify([
|
|
5202
|
+
representationKey(slot),
|
|
5203
|
+
slot.capturedAt,
|
|
5204
|
+
slot.rowVersion ?? null,
|
|
5205
|
+
slot.captureSequence ?? null
|
|
5206
|
+
]));
|
|
5207
|
+
}
|
|
5208
|
+
function payload(record) {
|
|
5209
|
+
return [
|
|
5210
|
+
record.version,
|
|
5211
|
+
record.sessionId,
|
|
5212
|
+
record.host,
|
|
5213
|
+
record.modelKey,
|
|
5214
|
+
record.providerKey,
|
|
5215
|
+
record.slotKey,
|
|
5216
|
+
record.servedDigest,
|
|
5217
|
+
record.revision,
|
|
5218
|
+
record.state
|
|
5219
|
+
];
|
|
5220
|
+
}
|
|
5221
|
+
function publishRecord(record) {
|
|
5222
|
+
ioObserver?.("write");
|
|
5223
|
+
try {
|
|
5224
|
+
if (record.state === "clean")
|
|
5225
|
+
observer?.("clean");
|
|
5226
|
+
writeStorageFileDurableAtomicSync(lkgRecoveryFencePath(record.sessionId), JSON.stringify({ ...record, checksum: hash(JSON.stringify(payload(record))) }), () => observer?.("temp-synced"));
|
|
5227
|
+
if (record.state === "dirty")
|
|
5228
|
+
observer?.("dirty");
|
|
5229
|
+
remember(record.sessionId, {
|
|
5230
|
+
state: record.state,
|
|
5231
|
+
record: { ...record, checksum: hash(JSON.stringify(payload(record))) }
|
|
5232
|
+
});
|
|
5233
|
+
} catch (error) {
|
|
5234
|
+
const visible = read(record.sessionId);
|
|
5235
|
+
if (record.state === "clean" && visible?.state === "clean" && visible.revision === record.revision && visible.slotKey === record.slotKey) {
|
|
5236
|
+
const dirty = { ...record, state: "dirty" };
|
|
5237
|
+
writeStorageFileDurableAtomicSync(lkgRecoveryFencePath(record.sessionId), JSON.stringify({ ...dirty, checksum: hash(JSON.stringify(payload(dirty))) }));
|
|
5238
|
+
}
|
|
5239
|
+
remember(record.sessionId, { state: "invalid", record: null });
|
|
5240
|
+
throw error;
|
|
5241
|
+
}
|
|
5242
|
+
}
|
|
5243
|
+
function read(sessionId) {
|
|
5244
|
+
ioObserver?.("read");
|
|
5245
|
+
try {
|
|
5246
|
+
const path = lkgRecoveryFencePath(sessionId);
|
|
5247
|
+
const stat = lstatSync2(path);
|
|
5248
|
+
const directory = lstatSync2(dirname4(path));
|
|
5249
|
+
if (!stat.isFile() || stat.size > 4096 || !directory.isDirectory() || directory.isSymbolicLink() || process.platform !== "win32" && ((stat.mode & 63) !== 0 || (directory.mode & 63) !== 0 || process.getuid && stat.uid !== process.getuid()))
|
|
5250
|
+
return null;
|
|
5251
|
+
const value = JSON.parse(readFileSync7(path, "utf8"));
|
|
5252
|
+
if (value.version !== 1 || value.sessionId !== sessionId || value.host !== getHarness2() || value.modelKey !== null && typeof value.modelKey !== "string" || value.providerKey !== null && typeof value.providerKey !== "string" || !/^[a-f0-9]{64}$/.test(value.slotKey) || !/^[a-f0-9]{64}$/.test(value.servedDigest) || typeof value.revision !== "string" || !["clean", "dirty"].includes(value.state) || value.checksum !== hash(JSON.stringify(payload(value))))
|
|
5253
|
+
return null;
|
|
5254
|
+
return value;
|
|
5255
|
+
} catch {
|
|
5256
|
+
return null;
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
function publish(sessionId, slot, state, revision) {
|
|
5260
|
+
const record = {
|
|
5261
|
+
version: 1,
|
|
5262
|
+
sessionId,
|
|
5263
|
+
host: getHarness2(),
|
|
5264
|
+
modelKey: slot.modelKey,
|
|
5265
|
+
providerKey: slot.providerKey,
|
|
5266
|
+
slotKey: lkgRecoverySlotKey(slot),
|
|
5267
|
+
servedDigest: hash(slot.jsonPrefix),
|
|
5268
|
+
revision,
|
|
5269
|
+
state
|
|
5270
|
+
};
|
|
5271
|
+
publishRecord(record);
|
|
5272
|
+
}
|
|
5273
|
+
function locked(sessionId, work) {
|
|
5274
|
+
ioObserver?.("mutex");
|
|
5275
|
+
return withStorageFileMutex(`${lkgRecoveryFencePath(sessionId)}.locks`, () => {
|
|
5276
|
+
const path = lkgRecoveryFencePath(sessionId);
|
|
5277
|
+
for (const name of readdirSync2(dirname4(path))) {
|
|
5278
|
+
if (name.startsWith(`${basename3(path)}.`) && name.endsWith(".tmp"))
|
|
5279
|
+
rmSync3(join4(dirname4(path), name), { force: true });
|
|
5280
|
+
}
|
|
5281
|
+
return work();
|
|
5282
|
+
});
|
|
5283
|
+
}
|
|
5284
|
+
function hasCleanLkgRecoveryFence(sessionId, _slot) {
|
|
5285
|
+
if (!durableFencesSupported())
|
|
5286
|
+
return false;
|
|
5287
|
+
const state = known(sessionId);
|
|
5288
|
+
return state.state === "clean";
|
|
5289
|
+
}
|
|
5290
|
+
function lkgFenceRequiresRebuild(sessionId, slot, processLocalProof) {
|
|
5291
|
+
return !processLocalProof && (durableFencesSupported() ? !hasCleanLkgRecoveryFence(sessionId, slot) : true);
|
|
5292
|
+
}
|
|
5293
|
+
function lkgRecoveryFenceUnclean(sessionId) {
|
|
5294
|
+
return durableFencesSupported() && known(sessionId).state !== "clean";
|
|
5295
|
+
}
|
|
5296
|
+
function dirtyLkgRecoveryRevision(sessionId, _slot) {
|
|
5297
|
+
if (!durableFencesSupported())
|
|
5298
|
+
return;
|
|
5299
|
+
const record = known(sessionId).record;
|
|
5300
|
+
return record?.state === "dirty" ? record.revision : undefined;
|
|
5301
|
+
}
|
|
5302
|
+
function ownsLkgDirtyFence(sessionId, revision) {
|
|
5303
|
+
if (!durableFencesSupported())
|
|
5304
|
+
return revision === "process-local";
|
|
5305
|
+
const record = known(sessionId).record;
|
|
5306
|
+
return revision !== undefined && record?.state === "dirty" && record.revision === revision;
|
|
5307
|
+
}
|
|
5308
|
+
function invalidateCleanLkgRecoveryFence(sessionId, load, ownRevision) {
|
|
5309
|
+
if (!durableFencesSupported())
|
|
5310
|
+
return "process-local";
|
|
5311
|
+
const prior = known(sessionId);
|
|
5312
|
+
if (prior.state === "dirty")
|
|
5313
|
+
return prior.record?.revision === ownRevision ? ownRevision : undefined;
|
|
5314
|
+
return locked(sessionId, () => {
|
|
5315
|
+
const slot = load() ?? {
|
|
5316
|
+
jsonPrefix: "",
|
|
5317
|
+
inputIdSeq: [],
|
|
5318
|
+
inputContentDigests: [],
|
|
5319
|
+
lastInputMessageId: "",
|
|
5320
|
+
modelKey: null,
|
|
5321
|
+
providerKey: null,
|
|
5322
|
+
capturedAt: 0
|
|
5323
|
+
};
|
|
5324
|
+
const record = read(sessionId);
|
|
5325
|
+
if (record?.state !== "dirty") {
|
|
5326
|
+
const revision = randomUUID2();
|
|
5327
|
+
publish(sessionId, slot, "dirty", revision);
|
|
5328
|
+
return revision;
|
|
5329
|
+
}
|
|
5330
|
+
return record?.state === "dirty" && record.revision === ownRevision ? ownRevision : undefined;
|
|
5331
|
+
});
|
|
5332
|
+
}
|
|
5333
|
+
function prepareLkgCaptureFence(args) {
|
|
5334
|
+
if (!durableFencesSupported())
|
|
5335
|
+
return "process-local";
|
|
5336
|
+
return locked(args.sessionId, () => {
|
|
5337
|
+
const before = read(args.sessionId);
|
|
5338
|
+
const owns = before?.state === "dirty" && before.revision === args.ownDirtyRevision;
|
|
5339
|
+
const unchangedBytes = before?.state === "clean" && before.servedDigest === hash(args.slot.jsonPrefix);
|
|
5340
|
+
if (!args.rebuild && before && !owns && !unchangedBytes && before.state !== "clean")
|
|
5341
|
+
throw new LkgRecoveryFenceError(`A concurrent recovery requires a declared prefix rebuild (state=${before?.state}, owned=${owns}, previous=${!!args.previousSlot}, bytes=${unchangedBytes})`);
|
|
5342
|
+
const revision = randomUUID2();
|
|
5343
|
+
if (before)
|
|
5344
|
+
publishRecord({ ...before, state: "dirty", revision });
|
|
5345
|
+
else
|
|
5346
|
+
publish(args.sessionId, args.previousSlot ?? args.slot, "dirty", revision);
|
|
5347
|
+
return revision;
|
|
5348
|
+
});
|
|
5349
|
+
}
|
|
5350
|
+
function certifyCommittedLkgCapture(args) {
|
|
5351
|
+
if (!durableFencesSupported())
|
|
5352
|
+
return false;
|
|
5353
|
+
const state = known(args.sessionId);
|
|
5354
|
+
if (state.state !== "dirty" || state.record?.revision !== args.revision)
|
|
5355
|
+
return false;
|
|
5356
|
+
return locked(args.sessionId, () => {
|
|
5357
|
+
const before = read(args.sessionId);
|
|
5358
|
+
if (before?.state !== "dirty" || before.revision !== args.revision)
|
|
5359
|
+
return false;
|
|
5360
|
+
const saved = args.load();
|
|
5361
|
+
if (!saved || representationKey(saved) !== representationKey(args.slot) || hash(saved.jsonPrefix) !== args.latestServedDigest)
|
|
5362
|
+
return false;
|
|
5363
|
+
publish(args.sessionId, saved, "clean", args.revision);
|
|
5364
|
+
return true;
|
|
5365
|
+
});
|
|
5366
|
+
}
|
|
5367
|
+
function markLkgRecoveryDirty(args) {
|
|
5368
|
+
if (!durableFencesSupported()) {
|
|
5369
|
+
if (!args.processLocalProof)
|
|
5370
|
+
throw new LkgRecoveryFenceError("Restart replay requires a healthy rebuild on Windows");
|
|
5371
|
+
return "process-local";
|
|
5372
|
+
}
|
|
5373
|
+
const state = known(args.sessionId);
|
|
5374
|
+
if (state.state === "dirty" && args.processLocalProof && state.record && state.record.revision === args.ownDirtyRevision)
|
|
5375
|
+
return state.record.revision;
|
|
5376
|
+
if (state.state === "invalid")
|
|
5377
|
+
throw new LkgRecoveryFenceError("No clean durable recovery certificate");
|
|
5378
|
+
return locked(args.sessionId, () => {
|
|
5379
|
+
const slot = args.slot;
|
|
5380
|
+
const before = read(args.sessionId);
|
|
5381
|
+
if (before?.state === "dirty") {
|
|
5382
|
+
if (!args.processLocalProof || before.revision !== args.ownDirtyRevision)
|
|
5383
|
+
throw new LkgRecoveryFenceError(`Recovery superseded this process's last-good request (local=${args.processLocalProof}, owned=${before.revision === args.ownDirtyRevision})`);
|
|
5384
|
+
return before.revision;
|
|
5385
|
+
}
|
|
5386
|
+
if (before && before.state !== "clean")
|
|
5387
|
+
throw new LkgRecoveryFenceError("No clean durable recovery certificate");
|
|
5388
|
+
const revision = randomUUID2();
|
|
5389
|
+
publish(args.sessionId, slot, "dirty", revision);
|
|
5390
|
+
return revision;
|
|
5391
|
+
});
|
|
5392
|
+
}
|
|
5393
|
+
function commitLkgWithRecoveryFence(args) {
|
|
5394
|
+
if (!durableFencesSupported())
|
|
5395
|
+
return args.commit();
|
|
5396
|
+
const state = known(args.sessionId);
|
|
5397
|
+
if (state.state === "clean" && !args.requiredRevision && !args.retainDirtyRevision) {
|
|
5398
|
+
const committed = args.commit();
|
|
5399
|
+
if (committed) {
|
|
5400
|
+
observer?.("committed");
|
|
5401
|
+
remember(args.sessionId, { state: "clean", record: null });
|
|
5402
|
+
}
|
|
5403
|
+
return committed;
|
|
5404
|
+
}
|
|
5405
|
+
if (state.state === "invalid" && !args.rebuild)
|
|
5406
|
+
throw new LkgRecoveryFenceError("Unproven prior request requires a prefix rebuild");
|
|
5407
|
+
return locked(args.sessionId, () => {
|
|
5408
|
+
const before = read(args.sessionId);
|
|
5409
|
+
if (args.requiredRevision && before?.revision !== args.requiredRevision)
|
|
5410
|
+
throw new LkgRecoveryFenceError("A later publisher superseded the rollback snapshot");
|
|
5411
|
+
const ownsDirty = before?.state === "dirty" && (before.revision === args.retainDirtyRevision || before.revision === args.ownDirtyRevision);
|
|
5412
|
+
if (before?.state === "dirty" && !ownsDirty && !args.rebuild)
|
|
5413
|
+
throw new LkgRecoveryFenceError("A concurrent recovery requires a declared prefix rebuild");
|
|
5414
|
+
if (before?.state !== "dirty" && state.state === "invalid")
|
|
5415
|
+
publish(args.sessionId, args.load() ?? args.slot, "dirty", randomUUID2());
|
|
5416
|
+
if (!args.commit())
|
|
5417
|
+
return false;
|
|
5418
|
+
observer?.("committed");
|
|
5419
|
+
const saved = args.load();
|
|
5420
|
+
if (!saved || representationKey(saved) !== representationKey(args.slot))
|
|
5421
|
+
throw new LkgRecoveryFenceError("Last-good commit did not match its certificate");
|
|
5422
|
+
if (args.retainDirtyRevision || args.cleanDigest !== undefined && hash(saved.jsonPrefix) !== args.cleanDigest)
|
|
5423
|
+
return true;
|
|
5424
|
+
const dirty = read(args.sessionId);
|
|
5425
|
+
if (dirty?.state === "dirty")
|
|
5426
|
+
publish(args.sessionId, saved, "clean", dirty.revision);
|
|
5427
|
+
else
|
|
5428
|
+
remember(args.sessionId, { state: "clean", record: null });
|
|
5429
|
+
return true;
|
|
5430
|
+
});
|
|
5431
|
+
}
|
|
5432
|
+
function clearLkgRecoveryFence(sessionId, remove, shouldClear) {
|
|
5433
|
+
if (!durableFencesSupported())
|
|
5434
|
+
return remove?.();
|
|
5435
|
+
const path = lkgRecoveryFencePath(sessionId);
|
|
5436
|
+
const missing = (file) => {
|
|
5437
|
+
try {
|
|
5438
|
+
lstatSync2(file);
|
|
5439
|
+
return false;
|
|
5440
|
+
} catch (error) {
|
|
5441
|
+
return error.code === "ENOENT";
|
|
5442
|
+
}
|
|
5443
|
+
};
|
|
5444
|
+
if (!remove && !shouldClear && missing(path) && missing(`${path}.locks`)) {
|
|
5445
|
+
clearLkgFenceProcessState(sessionId);
|
|
5446
|
+
return;
|
|
5447
|
+
}
|
|
5448
|
+
try {
|
|
5449
|
+
return locked(sessionId, () => {
|
|
5450
|
+
const result = remove?.();
|
|
5451
|
+
if (shouldClear && !shouldClear(result))
|
|
5452
|
+
return result;
|
|
5453
|
+
rmSync3(lkgRecoveryFencePath(sessionId), { force: true });
|
|
5454
|
+
syncStorageDirectorySync(dirname4(lkgRecoveryFencePath(sessionId)));
|
|
5455
|
+
clearLkgFenceProcessState(sessionId);
|
|
5456
|
+
return result;
|
|
5457
|
+
});
|
|
5458
|
+
} finally {
|
|
5459
|
+
try {
|
|
5460
|
+
rmdirSync(`${path}.locks`);
|
|
5461
|
+
} catch {}
|
|
5462
|
+
}
|
|
5463
|
+
}
|
|
5464
|
+
|
|
4952
5465
|
// src/shared/auto-search-lifecycle.ts
|
|
4953
|
-
var
|
|
5466
|
+
var pending2 = new Map;
|
|
4954
5467
|
var unpublishedNoHints = new Map;
|
|
4955
5468
|
function rememberUnpublishedAutoSearchNoHint(sessionId, messageId, reason) {
|
|
4956
5469
|
let messages = unpublishedNoHints.get(sessionId);
|
|
@@ -4978,28 +5491,731 @@ function clearUnpublishedAutoSearchNoHints(sessionId) {
|
|
|
4978
5491
|
}
|
|
4979
5492
|
function registerAutoSearchWork(sessionId) {
|
|
4980
5493
|
const controller = new AbortController;
|
|
4981
|
-
const work =
|
|
4982
|
-
|
|
5494
|
+
const work = pending2.get(sessionId) ?? new Set;
|
|
5495
|
+
pending2.set(sessionId, work);
|
|
4983
5496
|
work.add(controller);
|
|
4984
5497
|
return {
|
|
4985
5498
|
signal: controller.signal,
|
|
4986
5499
|
done: () => {
|
|
4987
5500
|
work.delete(controller);
|
|
4988
|
-
if (
|
|
4989
|
-
|
|
5501
|
+
if (pending2.get(sessionId) === work && work.size === 0)
|
|
5502
|
+
pending2.delete(sessionId);
|
|
4990
5503
|
}
|
|
4991
5504
|
};
|
|
4992
5505
|
}
|
|
4993
5506
|
function cancelAutoSearchWork(sessionId) {
|
|
4994
|
-
for (const [id, work] of
|
|
5507
|
+
for (const [id, work] of pending2) {
|
|
4995
5508
|
if (sessionId !== undefined && id !== sessionId)
|
|
4996
5509
|
continue;
|
|
4997
|
-
|
|
5510
|
+
pending2.delete(id);
|
|
4998
5511
|
for (const controller of work)
|
|
4999
5512
|
controller.abort();
|
|
5000
5513
|
}
|
|
5001
5514
|
}
|
|
5002
5515
|
|
|
5516
|
+
// src/v2/store-reader.ts
|
|
5517
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
5518
|
+
import { statSync as statSync5 } from "node:fs";
|
|
5519
|
+
import { hostname } from "node:os";
|
|
5520
|
+
import { resolve as resolve2 } from "node:path";
|
|
5521
|
+
function gaDatabasePath(dataHome, channel = "latest", env = process.env) {
|
|
5522
|
+
return resolveOpenCodeDbPath("v2", { dataHome, channel, env }).path;
|
|
5523
|
+
}
|
|
5524
|
+
var RAW_MESSAGE_TYPES = [
|
|
5525
|
+
"user",
|
|
5526
|
+
"synthetic",
|
|
5527
|
+
"assistant",
|
|
5528
|
+
"skill",
|
|
5529
|
+
"shell",
|
|
5530
|
+
"system"
|
|
5531
|
+
];
|
|
5532
|
+
var RAW_MESSAGE_TYPE_PARAMETERS = RAW_MESSAGE_TYPES.map(() => "?").join(", ");
|
|
5533
|
+
var V2_MESSAGE_PAGE_SQL = `WITH bounds AS (
|
|
5534
|
+
SELECT
|
|
5535
|
+
CASE WHEN ? = 0 THEN -1 ELSE COALESCE((
|
|
5536
|
+
SELECT seq FROM session_message
|
|
5537
|
+
WHERE session_id = ? AND type IN (${RAW_MESSAGE_TYPE_PARAMETERS})
|
|
5538
|
+
ORDER BY seq ASC LIMIT 1 OFFSET ?
|
|
5539
|
+
), (SELECT MAX(seq) FROM session_message WHERE session_id = ?), -1) END AS after_seq,
|
|
5540
|
+
COALESCE((
|
|
5541
|
+
SELECT seq FROM session_message
|
|
5542
|
+
WHERE session_id = ? AND type IN (${RAW_MESSAGE_TYPE_PARAMETERS})
|
|
5543
|
+
ORDER BY seq ASC LIMIT 1 OFFSET ?
|
|
5544
|
+
), ?) AS watermark_seq
|
|
5545
|
+
)
|
|
5546
|
+
SELECT id, session_id, type, seq, time_created, data FROM session_message, bounds
|
|
5547
|
+
WHERE session_id = ?
|
|
5548
|
+
AND type IN (${RAW_MESSAGE_TYPE_PARAMETERS})
|
|
5549
|
+
AND seq > bounds.after_seq
|
|
5550
|
+
AND seq <= bounds.watermark_seq
|
|
5551
|
+
ORDER BY seq ASC LIMIT ?`;
|
|
5552
|
+
var V2_STORE_READER_DEBUG_COUNTER_KEY = "magic-context.v2.store-reader-debug";
|
|
5553
|
+
var debugSymbol = Symbol.for(V2_STORE_READER_DEBUG_COUNTER_KEY);
|
|
5554
|
+
var debugGlobal = globalThis;
|
|
5555
|
+
var QUERY_STATEMENTS = {
|
|
5556
|
+
messagePage: V2_MESSAGE_PAGE_SQL,
|
|
5557
|
+
messageCount: "SELECT COUNT(*) AS count FROM session_message WHERE session_id = ? AND type IN (?)",
|
|
5558
|
+
storedMessageCount: "SELECT COUNT(*) AS count FROM session_message WHERE session_id = ?",
|
|
5559
|
+
messageById: "SELECT id, session_id, type, seq, time_created, data FROM session_message WHERE session_id = ? AND id = ? AND type IN (?) LIMIT 1",
|
|
5560
|
+
messageExistsById: "SELECT 1 FROM session_message WHERE id = ? AND session_id = ? AND type IN (?) LIMIT 1",
|
|
5561
|
+
messageOrdinalById: `WITH target AS (
|
|
5562
|
+
SELECT seq FROM session_message WHERE session_id = ? AND id = ? AND type IN (?) LIMIT 1
|
|
5563
|
+
)
|
|
5564
|
+
SELECT (SELECT COUNT(*) FROM session_message WHERE session_id = ? AND type IN (?) AND seq <= target.seq) AS ordinal FROM target`,
|
|
5565
|
+
messageIdOrdinals: "SELECT id FROM session_message WHERE session_id = ? AND type IN (?) ORDER BY seq ASC LIMIT ? OFFSET ?",
|
|
5566
|
+
messageOrdinalPage: "SELECT id, type, seq, json_valid(data) AS valid FROM session_message WHERE session_id = ? AND seq > ? ORDER BY seq ASC, id ASC LIMIT ?",
|
|
5567
|
+
rawRowsThrough: "SELECT id, session_id, type, seq, time_created, data FROM session_message WHERE session_id = ? AND type IN (?) AND seq <= ? ORDER BY seq DESC LIMIT ?"
|
|
5568
|
+
};
|
|
5569
|
+
function debugCounters() {
|
|
5570
|
+
const counters = debugGlobal[debugSymbol] ??= {
|
|
5571
|
+
decodedRows: 0,
|
|
5572
|
+
operations: {},
|
|
5573
|
+
openReaders: 0,
|
|
5574
|
+
maxOpenReaders: 0,
|
|
5575
|
+
readersOpened: 0,
|
|
5576
|
+
readersClosed: 0
|
|
5577
|
+
};
|
|
5578
|
+
counters.openReaders ??= 0;
|
|
5579
|
+
counters.maxOpenReaders ??= 0;
|
|
5580
|
+
counters.readersOpened ??= 0;
|
|
5581
|
+
counters.readersClosed ??= 0;
|
|
5582
|
+
return counters;
|
|
5583
|
+
}
|
|
5584
|
+
function returnedRowCount(value) {
|
|
5585
|
+
if (Array.isArray(value))
|
|
5586
|
+
return value.length;
|
|
5587
|
+
if (value === null || value === undefined || value === false)
|
|
5588
|
+
return 0;
|
|
5589
|
+
return 1;
|
|
5590
|
+
}
|
|
5591
|
+
function trackDecodeOperation(name, operation) {
|
|
5592
|
+
const counters = debugCounters();
|
|
5593
|
+
const before = counters.decodedRows;
|
|
5594
|
+
const started = performance.now();
|
|
5595
|
+
let value;
|
|
5596
|
+
try {
|
|
5597
|
+
value = operation();
|
|
5598
|
+
return value;
|
|
5599
|
+
} finally {
|
|
5600
|
+
const decodedRows = counters.decodedRows - before;
|
|
5601
|
+
const current = counters.operations[name] ?? {
|
|
5602
|
+
calls: 0,
|
|
5603
|
+
decodedRows: 0,
|
|
5604
|
+
maxDecodedRows: 0
|
|
5605
|
+
};
|
|
5606
|
+
current.calls += 1;
|
|
5607
|
+
current.decodedRows += decodedRows;
|
|
5608
|
+
current.maxDecodedRows = Math.max(current.maxDecodedRows, decodedRows);
|
|
5609
|
+
counters.operations[name] = current;
|
|
5610
|
+
const statement = QUERY_STATEMENTS[name];
|
|
5611
|
+
if (counters.captureQueries && statement) {
|
|
5612
|
+
(counters.queries ??= []).push({
|
|
5613
|
+
operation: name,
|
|
5614
|
+
statement,
|
|
5615
|
+
rows: returnedRowCount(value),
|
|
5616
|
+
elapsedMs: performance.now() - started
|
|
5617
|
+
});
|
|
5618
|
+
}
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5621
|
+
function decode(row) {
|
|
5622
|
+
debugCounters().decodedRows += 1;
|
|
5623
|
+
const data = JSON.parse(row.data);
|
|
5624
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
5625
|
+
throw new Error(`Invalid session_message data at seq ${row.seq}`);
|
|
5626
|
+
}
|
|
5627
|
+
if (row.type === "idle" && !["succeeded", "failed", "interrupted"].includes(String(data.outcome))) {
|
|
5628
|
+
throw new Error(`Invalid idle outcome at seq ${row.seq}`);
|
|
5629
|
+
}
|
|
5630
|
+
return { ...row, data };
|
|
5631
|
+
}
|
|
5632
|
+
function connect(path, identity = "") {
|
|
5633
|
+
const stat = statSync5(path);
|
|
5634
|
+
const acquiredIdentity = identity || `${stat.dev}:${stat.ino}:${stat.birthtimeMs}`;
|
|
5635
|
+
const db = new Database2(path, { readonly: true, fileMustExist: true });
|
|
5636
|
+
try {
|
|
5637
|
+
assertOpenCodeStoreGeneration(db, "v2", path);
|
|
5638
|
+
} catch (error) {
|
|
5639
|
+
db.close();
|
|
5640
|
+
throw error;
|
|
5641
|
+
}
|
|
5642
|
+
const counters = debugCounters();
|
|
5643
|
+
counters.openReaders += 1;
|
|
5644
|
+
counters.readersOpened += 1;
|
|
5645
|
+
counters.maxOpenReaders = Math.max(counters.maxOpenReaders, counters.openReaders);
|
|
5646
|
+
return { db, statements: new Map, identity: acquiredIdentity, leases: 0, retired: false };
|
|
5647
|
+
}
|
|
5648
|
+
function closeConnection(connection) {
|
|
5649
|
+
connection.statements.clear();
|
|
5650
|
+
try {
|
|
5651
|
+
connection.db.close();
|
|
5652
|
+
} finally {
|
|
5653
|
+
const counters = debugCounters();
|
|
5654
|
+
counters.openReaders = Math.max(0, counters.openReaders - 1);
|
|
5655
|
+
counters.readersClosed += 1;
|
|
5656
|
+
}
|
|
5657
|
+
}
|
|
5658
|
+
|
|
5659
|
+
class V2StoreReaderPool {
|
|
5660
|
+
capacity;
|
|
5661
|
+
connections = new Map;
|
|
5662
|
+
closed = false;
|
|
5663
|
+
closing = false;
|
|
5664
|
+
holds = 0;
|
|
5665
|
+
idleWaiters = new Set;
|
|
5666
|
+
constructor(capacity = 4) {
|
|
5667
|
+
this.capacity = capacity;
|
|
5668
|
+
if (!Number.isSafeInteger(capacity) || capacity < 1)
|
|
5669
|
+
throw new Error("Invalid reader capacity");
|
|
5670
|
+
}
|
|
5671
|
+
open(path) {
|
|
5672
|
+
return new V2StoreReader(path, this);
|
|
5673
|
+
}
|
|
5674
|
+
acquire(path) {
|
|
5675
|
+
if (this.closed)
|
|
5676
|
+
throw new Error("Store reader pool is closed");
|
|
5677
|
+
const key = resolve2(path);
|
|
5678
|
+
const stat = statSync5(key);
|
|
5679
|
+
const identity = `${stat.dev}:${stat.ino}:${stat.birthtimeMs}`;
|
|
5680
|
+
let connection = this.connections.get(key);
|
|
5681
|
+
if (connection && connection.identity !== identity) {
|
|
5682
|
+
this.connections.delete(key);
|
|
5683
|
+
this.retire(connection);
|
|
5684
|
+
connection = undefined;
|
|
5685
|
+
}
|
|
5686
|
+
if (!connection)
|
|
5687
|
+
connection = connect(key, identity);
|
|
5688
|
+
connection.leases++;
|
|
5689
|
+
this.connections.delete(key);
|
|
5690
|
+
this.connections.set(key, connection);
|
|
5691
|
+
while (this.connections.size > this.capacity) {
|
|
5692
|
+
const oldest = this.connections.entries().next().value;
|
|
5693
|
+
if (!oldest)
|
|
5694
|
+
break;
|
|
5695
|
+
this.connections.delete(oldest[0]);
|
|
5696
|
+
this.retire(oldest[1]);
|
|
5697
|
+
}
|
|
5698
|
+
return connection;
|
|
5699
|
+
}
|
|
5700
|
+
release(connection) {
|
|
5701
|
+
connection.leases--;
|
|
5702
|
+
if (connection.retired && connection.leases === 0)
|
|
5703
|
+
closeConnection(connection);
|
|
5704
|
+
}
|
|
5705
|
+
retire(connection) {
|
|
5706
|
+
connection.retired = true;
|
|
5707
|
+
if (connection.leases === 0)
|
|
5708
|
+
closeConnection(connection);
|
|
5709
|
+
}
|
|
5710
|
+
hold() {
|
|
5711
|
+
if (this.closed || this.closing)
|
|
5712
|
+
throw new Error("Store reader pool is closed");
|
|
5713
|
+
this.holds++;
|
|
5714
|
+
let released = false;
|
|
5715
|
+
return () => {
|
|
5716
|
+
if (released)
|
|
5717
|
+
return;
|
|
5718
|
+
released = true;
|
|
5719
|
+
this.holds--;
|
|
5720
|
+
if (this.holds === 0 && this.closing)
|
|
5721
|
+
this.finishClose();
|
|
5722
|
+
};
|
|
5723
|
+
}
|
|
5724
|
+
isClosed() {
|
|
5725
|
+
return this.closed;
|
|
5726
|
+
}
|
|
5727
|
+
holdCount() {
|
|
5728
|
+
return this.holds;
|
|
5729
|
+
}
|
|
5730
|
+
close() {
|
|
5731
|
+
if (this.closed || this.closing)
|
|
5732
|
+
return;
|
|
5733
|
+
this.closing = true;
|
|
5734
|
+
if (this.holds === 0)
|
|
5735
|
+
this.finishClose();
|
|
5736
|
+
}
|
|
5737
|
+
async closeWhenIdle(timeoutMs) {
|
|
5738
|
+
this.close();
|
|
5739
|
+
if (this.closed)
|
|
5740
|
+
return true;
|
|
5741
|
+
let timer;
|
|
5742
|
+
let waiter;
|
|
5743
|
+
try {
|
|
5744
|
+
await new Promise((resolve) => {
|
|
5745
|
+
waiter = resolve;
|
|
5746
|
+
this.idleWaiters.add(resolve);
|
|
5747
|
+
timer = setTimeout(resolve, Math.max(0, timeoutMs));
|
|
5748
|
+
});
|
|
5749
|
+
} finally {
|
|
5750
|
+
if (timer)
|
|
5751
|
+
clearTimeout(timer);
|
|
5752
|
+
if (waiter)
|
|
5753
|
+
this.idleWaiters.delete(waiter);
|
|
5754
|
+
}
|
|
5755
|
+
return this.closed;
|
|
5756
|
+
}
|
|
5757
|
+
finishClose() {
|
|
5758
|
+
if (this.closed)
|
|
5759
|
+
return;
|
|
5760
|
+
this.closed = true;
|
|
5761
|
+
for (const connection of this.connections.values())
|
|
5762
|
+
this.retire(connection);
|
|
5763
|
+
this.connections.clear();
|
|
5764
|
+
for (const resolve of this.idleWaiters)
|
|
5765
|
+
resolve();
|
|
5766
|
+
this.idleWaiters.clear();
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
5769
|
+
function messageTimesQuery(count) {
|
|
5770
|
+
return `SELECT id, COALESCE(time_created, json_extract(data, '$.time.created')) AS created,
|
|
5771
|
+
json_extract(data, '$.time.completed') AS completed
|
|
5772
|
+
FROM session_message WHERE +session_id = ? AND id IN (${Array.from({ length: count }, () => "?").join(",")})`;
|
|
5773
|
+
}
|
|
5774
|
+
|
|
5775
|
+
class V2StoreReader {
|
|
5776
|
+
path;
|
|
5777
|
+
pool;
|
|
5778
|
+
db;
|
|
5779
|
+
connection;
|
|
5780
|
+
closed = false;
|
|
5781
|
+
constructor(path, pool) {
|
|
5782
|
+
this.path = path;
|
|
5783
|
+
this.pool = pool;
|
|
5784
|
+
this.connection = pool ? pool.acquire(path) : connect(path);
|
|
5785
|
+
this.db = this.connection.db;
|
|
5786
|
+
}
|
|
5787
|
+
hostIdentity() {
|
|
5788
|
+
return createHash5("sha256").update(JSON.stringify([hostname(), resolve2(this.path), this.connection.identity])).digest("hex");
|
|
5789
|
+
}
|
|
5790
|
+
prepare(sql) {
|
|
5791
|
+
if (this.closed)
|
|
5792
|
+
throw new Error("Store reader is closed");
|
|
5793
|
+
const statements = this.connection.statements;
|
|
5794
|
+
let statement = statements.get(sql);
|
|
5795
|
+
if (!statement) {
|
|
5796
|
+
statement = this.db.prepare(sql);
|
|
5797
|
+
if (statements.size >= 128)
|
|
5798
|
+
statements.clear();
|
|
5799
|
+
statements.set(sql, statement);
|
|
5800
|
+
}
|
|
5801
|
+
return statement;
|
|
5802
|
+
}
|
|
5803
|
+
close() {
|
|
5804
|
+
if (this.closed)
|
|
5805
|
+
return;
|
|
5806
|
+
this.closed = true;
|
|
5807
|
+
if (this.pool)
|
|
5808
|
+
this.pool.release(this.connection);
|
|
5809
|
+
else
|
|
5810
|
+
closeConnection(this.connection);
|
|
5811
|
+
}
|
|
5812
|
+
page(sessionID, options = {}) {
|
|
5813
|
+
return trackDecodeOperation("page", () => {
|
|
5814
|
+
const limit = options.limit ?? 100;
|
|
5815
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e4)
|
|
5816
|
+
throw new Error("Invalid page limit");
|
|
5817
|
+
const after = options.after ?? -1;
|
|
5818
|
+
if (!Number.isSafeInteger(after))
|
|
5819
|
+
throw new Error("Invalid seq cursor");
|
|
5820
|
+
if (options.through !== undefined && !Number.isSafeInteger(options.through))
|
|
5821
|
+
throw new Error("Invalid seq upper bound");
|
|
5822
|
+
const predicates = ["session_id = ?", "seq > ?"];
|
|
5823
|
+
const parameters = [sessionID, after];
|
|
5824
|
+
if (options.through !== undefined) {
|
|
5825
|
+
predicates.push("seq <= ?");
|
|
5826
|
+
parameters.push(options.through);
|
|
5827
|
+
}
|
|
5828
|
+
if (options.type) {
|
|
5829
|
+
predicates.push("type = ?");
|
|
5830
|
+
parameters.push(options.type);
|
|
5831
|
+
}
|
|
5832
|
+
const rows = this.prepare(`SELECT id, session_id, type, seq, time_created, data FROM session_message
|
|
5833
|
+
WHERE ${predicates.join(" AND ")}
|
|
5834
|
+
ORDER BY seq ASC LIMIT ?`).all(...parameters, limit).map(decode);
|
|
5835
|
+
return { rows, cursor: rows.at(-1)?.seq };
|
|
5836
|
+
});
|
|
5837
|
+
}
|
|
5838
|
+
messagePage(sessionID, afterOrdinal, limit, finalWatermark, after) {
|
|
5839
|
+
return trackDecodeOperation("messagePage", () => {
|
|
5840
|
+
if (!Number.isSafeInteger(afterOrdinal) || afterOrdinal < 0)
|
|
5841
|
+
throw new Error("Invalid raw-message ordinal cursor");
|
|
5842
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e4)
|
|
5843
|
+
throw new Error("Invalid page limit");
|
|
5844
|
+
if (!Number.isSafeInteger(finalWatermark) || finalWatermark < 0)
|
|
5845
|
+
throw new Error("Invalid raw-message watermark");
|
|
5846
|
+
const pageSize = Math.min(limit, finalWatermark - afterOrdinal);
|
|
5847
|
+
if (pageSize <= 0)
|
|
5848
|
+
return [];
|
|
5849
|
+
if (after) {
|
|
5850
|
+
const anchor = this.prepare("SELECT seq FROM session_message WHERE session_id = ? AND id = ?").get(sessionID, after.id);
|
|
5851
|
+
if (anchor) {
|
|
5852
|
+
return this.prepare(`SELECT id, session_id, type, seq, time_created, data
|
|
5853
|
+
FROM session_message WHERE session_id = ? AND seq > ?
|
|
5854
|
+
AND type IN (${RAW_MESSAGE_TYPE_PARAMETERS}) ORDER BY seq ASC LIMIT ?`).all(sessionID, anchor.seq, ...RAW_MESSAGE_TYPES, pageSize).map(decode);
|
|
5855
|
+
}
|
|
5856
|
+
}
|
|
5857
|
+
const maximumSeq = Number.MAX_SAFE_INTEGER;
|
|
5858
|
+
const rows = this.prepare(V2_MESSAGE_PAGE_SQL).all(afterOrdinal, sessionID, ...RAW_MESSAGE_TYPES, Math.max(0, afterOrdinal - 1), sessionID, sessionID, ...RAW_MESSAGE_TYPES, finalWatermark - 1, maximumSeq, sessionID, ...RAW_MESSAGE_TYPES, pageSize);
|
|
5859
|
+
return rows.map(decode);
|
|
5860
|
+
});
|
|
5861
|
+
}
|
|
5862
|
+
messageCount(sessionID) {
|
|
5863
|
+
return trackDecodeOperation("messageCount", () => {
|
|
5864
|
+
const rawTypes = RAW_MESSAGE_TYPES.map(() => "?").join(", ");
|
|
5865
|
+
const row = this.prepare(`SELECT COUNT(*) AS count FROM session_message
|
|
5866
|
+
WHERE session_id = ? AND type IN (${rawTypes})`).get(sessionID, ...RAW_MESSAGE_TYPES);
|
|
5867
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
5868
|
+
});
|
|
5869
|
+
}
|
|
5870
|
+
messageCountAfterSequence(sessionID, after, through) {
|
|
5871
|
+
const rawTypes = RAW_MESSAGE_TYPES.map(() => "?").join(", ");
|
|
5872
|
+
const row = this.prepare(`SELECT COUNT(*) AS count FROM session_message
|
|
5873
|
+
WHERE session_id = ? AND seq > ? AND seq <= ? AND type IN (${rawTypes})`).get(sessionID, after, through, ...RAW_MESSAGE_TYPES);
|
|
5874
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
5875
|
+
}
|
|
5876
|
+
sessionDirectoryPage(afterSessionID, limit) {
|
|
5877
|
+
const rows = this.prepare(`SELECT id, COALESCE(directory, '') AS directory FROM session_v2
|
|
5878
|
+
WHERE id > ? ORDER BY id ASC LIMIT ?`).all(afterSessionID ?? "", limit);
|
|
5879
|
+
return rows.map((row) => ({ sessionId: row.id, directory: row.directory }));
|
|
5880
|
+
}
|
|
5881
|
+
latestMessageTime(sessionID) {
|
|
5882
|
+
const row = this.prepare("SELECT MAX(time_created) AS time FROM session_message WHERE session_id = ?").get(sessionID);
|
|
5883
|
+
return row?.time ?? undefined;
|
|
5884
|
+
}
|
|
5885
|
+
isSubagent(sessionID) {
|
|
5886
|
+
const row = this.prepare("SELECT parent_id FROM session_v2 WHERE id = ?").get(sessionID);
|
|
5887
|
+
if (!row)
|
|
5888
|
+
return null;
|
|
5889
|
+
return typeof row.parent_id === "string" && row.parent_id.length > 0;
|
|
5890
|
+
}
|
|
5891
|
+
latestRootSessionInDirectory(directory) {
|
|
5892
|
+
const columns = new Set(this.prepare("PRAGMA table_info(session_v2)").all().map((column) => column.name));
|
|
5893
|
+
const archived = columns.has("time_archived") ? " AND time_archived IS NULL" : "";
|
|
5894
|
+
const order = columns.has("time_updated") ? "time_updated DESC, id DESC" : "id DESC";
|
|
5895
|
+
const page = this.prepare(`SELECT id, COALESCE(directory, '') AS directory FROM session_v2
|
|
5896
|
+
WHERE parent_id IS NULL${archived}
|
|
5897
|
+
AND COALESCE(json_extract(metadata, '$.magic_context'), '') <> 'hidden-run'
|
|
5898
|
+
ORDER BY ${order} LIMIT ? OFFSET ?`);
|
|
5899
|
+
const pageSize = 500;
|
|
5900
|
+
for (let offset = 0;; offset += pageSize) {
|
|
5901
|
+
const rows = page.all(pageSize, offset);
|
|
5902
|
+
const match = rows.find((row) => sameProjectDirectory(row.directory, directory));
|
|
5903
|
+
if (match)
|
|
5904
|
+
return match.id;
|
|
5905
|
+
if (rows.length < pageSize)
|
|
5906
|
+
return;
|
|
5907
|
+
}
|
|
5908
|
+
}
|
|
5909
|
+
rootSessionActivity(sessionIDs) {
|
|
5910
|
+
const roots = new Map;
|
|
5911
|
+
for (let offset = 0;offset < sessionIDs.length; offset += 500) {
|
|
5912
|
+
const chunk = sessionIDs.slice(offset, offset + 500);
|
|
5913
|
+
const rows = this.prepare(`SELECT id, (
|
|
5914
|
+
SELECT MAX(time_created) FROM session_message
|
|
5915
|
+
WHERE session_id = session_v2.id AND type = 'user'
|
|
5916
|
+
) AS time FROM session_v2
|
|
5917
|
+
WHERE parent_id IS NULL
|
|
5918
|
+
AND COALESCE(json_extract(metadata, '$.magic_context'), '') <> 'hidden-run'
|
|
5919
|
+
AND id IN (${chunk.map(() => "?").join(",")})`).all(...chunk);
|
|
5920
|
+
for (const row of rows)
|
|
5921
|
+
if (row.time !== null)
|
|
5922
|
+
roots.set(row.id, row.time);
|
|
5923
|
+
}
|
|
5924
|
+
return roots;
|
|
5925
|
+
}
|
|
5926
|
+
oldestUserMessageTimesSince(sessionIDs, sinceMs) {
|
|
5927
|
+
const result = new Map;
|
|
5928
|
+
for (let offset = 0;offset < sessionIDs.length; offset += 500) {
|
|
5929
|
+
const chunk = sessionIDs.slice(offset, offset + 500);
|
|
5930
|
+
const rows = this.prepare(`SELECT session_id, MIN(time_created) AS time FROM session_message
|
|
5931
|
+
WHERE type = 'user' AND time_created > ? AND session_id IN (${chunk.map(() => "?").join(",")})
|
|
5932
|
+
GROUP BY session_id`).all(sinceMs, ...chunk);
|
|
5933
|
+
for (const row of rows)
|
|
5934
|
+
result.set(row.session_id, row.time);
|
|
5935
|
+
}
|
|
5936
|
+
return result;
|
|
5937
|
+
}
|
|
5938
|
+
retrospectiveUserPage(sessionID, options) {
|
|
5939
|
+
const { boundaryMs, before, limit, maxChars, truncationMarker } = options;
|
|
5940
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e4)
|
|
5941
|
+
throw new Error("Invalid page limit");
|
|
5942
|
+
if (!Number.isSafeInteger(maxChars) || maxChars <= truncationMarker.length)
|
|
5943
|
+
throw new Error("Invalid text limit");
|
|
5944
|
+
const direction = before ? "DESC" : "ASC";
|
|
5945
|
+
const head = Math.floor((maxChars - truncationMarker.length) / 2);
|
|
5946
|
+
const tail = maxChars - truncationMarker.length - head;
|
|
5947
|
+
return this.prepare(`WITH users AS (
|
|
5948
|
+
SELECT session_id, seq, time_created, data FROM session_message
|
|
5949
|
+
WHERE session_id = ? AND type = 'user' AND time_created ${before ? "<=" : ">"}
|
|
5950
|
+
?
|
|
5951
|
+
ORDER BY time_created ${direction}, seq ${direction} LIMIT ?
|
|
5952
|
+
), texts AS (
|
|
5953
|
+
SELECT session_id, seq, time_created, CASE
|
|
5954
|
+
WHEN json_extract(data, '$.synthetic') = 1 OR json_extract(data, '$.ignored') = 1 THEN ''
|
|
5955
|
+
WHEN json_type(data, '$.text') = 'text' THEN json_extract(data, '$.text')
|
|
5956
|
+
ELSE COALESCE((SELECT group_concat(json_extract(value, '$.text'), char(10))
|
|
5957
|
+
FROM json_each(users.data, '$.content')
|
|
5958
|
+
WHERE json_extract(value, '$.type') IN ('text', 'input_text')
|
|
5959
|
+
AND COALESCE(json_extract(value, '$.synthetic'), 0) <> 1
|
|
5960
|
+
AND COALESCE(json_extract(value, '$.ignored'), 0) <> 1), '') END AS text
|
|
5961
|
+
FROM users WHERE json_valid(data)
|
|
5962
|
+
) SELECT seq, time_created, CASE WHEN length(text) > ?
|
|
5963
|
+
THEN substr(text, 1, ?) || ? || substr(text, -?) ELSE text END AS text,
|
|
5964
|
+
EXISTS (
|
|
5965
|
+
SELECT 1 FROM session_message assistant_reply
|
|
5966
|
+
WHERE assistant_reply.session_id = texts.session_id
|
|
5967
|
+
AND assistant_reply.type = 'assistant'
|
|
5968
|
+
AND assistant_reply.seq < texts.seq
|
|
5969
|
+
AND EXISTS (
|
|
5970
|
+
SELECT 1 FROM session_message prior_user
|
|
5971
|
+
WHERE prior_user.session_id = texts.session_id
|
|
5972
|
+
AND prior_user.type = 'user'
|
|
5973
|
+
AND prior_user.seq < assistant_reply.seq
|
|
5974
|
+
)
|
|
5975
|
+
) AS follows_assistant_reply
|
|
5976
|
+
FROM texts ORDER BY time_created ${direction}, seq ${direction}`).all(sessionID, boundaryMs, limit, maxChars, head, truncationMarker, tail);
|
|
5977
|
+
}
|
|
5978
|
+
storedRowsAfter(sessionID, after) {
|
|
5979
|
+
const row = this.prepare("SELECT COUNT(*) AS count FROM session_message WHERE session_id = ? AND seq > ?").get(sessionID, after);
|
|
5980
|
+
return row.count;
|
|
5981
|
+
}
|
|
5982
|
+
storedMessageCount(sessionID) {
|
|
5983
|
+
return trackDecodeOperation("storedMessageCount", () => {
|
|
5984
|
+
const row = this.prepare("SELECT COUNT(*) AS count FROM session_message WHERE session_id = ?").get(sessionID);
|
|
5985
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
5986
|
+
});
|
|
5987
|
+
}
|
|
5988
|
+
messageById(sessionID, id) {
|
|
5989
|
+
return trackDecodeOperation("messageById", () => {
|
|
5990
|
+
const rawTypes = RAW_MESSAGE_TYPES.map(() => "?").join(", ");
|
|
5991
|
+
const row = this.prepare(`SELECT id, session_id, type, seq, time_created, data FROM session_message
|
|
5992
|
+
WHERE session_id = ? AND id = ? AND type IN (${rawTypes}) LIMIT 1`).get(sessionID, id, ...RAW_MESSAGE_TYPES);
|
|
5993
|
+
return row ? decode(row) : null;
|
|
5994
|
+
});
|
|
5995
|
+
}
|
|
5996
|
+
messageTimes(sessionID, ids) {
|
|
5997
|
+
const times = new Map;
|
|
5998
|
+
for (let offset = 0;offset < ids.length; offset += 500) {
|
|
5999
|
+
const batch = ids.slice(offset, offset + 500);
|
|
6000
|
+
const rows = this.prepare(messageTimesQuery(batch.length)).all(sessionID, ...batch);
|
|
6001
|
+
for (const row of rows)
|
|
6002
|
+
times.set(row.id, {
|
|
6003
|
+
created: typeof row.created === "number" ? row.created : undefined,
|
|
6004
|
+
completed: typeof row.completed === "number" ? row.completed : undefined
|
|
6005
|
+
});
|
|
6006
|
+
}
|
|
6007
|
+
return times;
|
|
6008
|
+
}
|
|
6009
|
+
messageExistsById(sessionID, id) {
|
|
6010
|
+
return trackDecodeOperation("messageExistsById", () => {
|
|
6011
|
+
const rawTypes = RAW_MESSAGE_TYPES.map(() => "?").join(", ");
|
|
6012
|
+
const row = this.prepare(`SELECT 1 FROM session_message
|
|
6013
|
+
WHERE id = ? AND session_id = ? AND type IN (${rawTypes}) LIMIT 1`).get(id, sessionID, ...RAW_MESSAGE_TYPES);
|
|
6014
|
+
return row != null;
|
|
6015
|
+
});
|
|
6016
|
+
}
|
|
6017
|
+
messageOrdinalById(sessionID, id) {
|
|
6018
|
+
return trackDecodeOperation("messageOrdinalById", () => {
|
|
6019
|
+
const rawTypes = RAW_MESSAGE_TYPES.map(() => "?").join(", ");
|
|
6020
|
+
const row = this.prepare(`WITH target AS (
|
|
6021
|
+
SELECT seq FROM session_message
|
|
6022
|
+
WHERE session_id = ? AND id = ? AND type IN (${rawTypes})
|
|
6023
|
+
LIMIT 1
|
|
6024
|
+
)
|
|
6025
|
+
SELECT (
|
|
6026
|
+
SELECT COUNT(*) FROM session_message
|
|
6027
|
+
WHERE session_id = ?
|
|
6028
|
+
AND type IN (${rawTypes})
|
|
6029
|
+
AND seq <= target.seq
|
|
6030
|
+
) AS ordinal
|
|
6031
|
+
FROM target`).get(sessionID, id, ...RAW_MESSAGE_TYPES, sessionID, ...RAW_MESSAGE_TYPES);
|
|
6032
|
+
return typeof row?.ordinal === "number" ? row.ordinal : null;
|
|
6033
|
+
});
|
|
6034
|
+
}
|
|
6035
|
+
messageIdOrdinals(sessionID, fromOrdinal, toOrdinal) {
|
|
6036
|
+
return trackDecodeOperation("messageIdOrdinals", () => {
|
|
6037
|
+
if (!Number.isSafeInteger(fromOrdinal) || fromOrdinal < 1)
|
|
6038
|
+
throw new Error("Invalid raw-message range start");
|
|
6039
|
+
if (!Number.isSafeInteger(toOrdinal) || toOrdinal < fromOrdinal)
|
|
6040
|
+
throw new Error("Invalid raw-message range end");
|
|
6041
|
+
const rawTypes = RAW_MESSAGE_TYPES.map(() => "?").join(", ");
|
|
6042
|
+
const rows = this.prepare(`SELECT id FROM session_message
|
|
6043
|
+
WHERE session_id = ? AND type IN (${rawTypes})
|
|
6044
|
+
ORDER BY seq ASC LIMIT ? OFFSET ?`).all(sessionID, ...RAW_MESSAGE_TYPES, toOrdinal - fromOrdinal + 1, fromOrdinal - 1);
|
|
6045
|
+
return new Map(rows.map((row, index) => [row.id, fromOrdinal + index]));
|
|
6046
|
+
});
|
|
6047
|
+
}
|
|
6048
|
+
messageOrdinalPage(sessionID, after, limit) {
|
|
6049
|
+
return trackDecodeOperation("messageOrdinalPage", () => {
|
|
6050
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e4)
|
|
6051
|
+
throw new Error("Invalid page limit");
|
|
6052
|
+
const rows = after ? this.prepare(`SELECT id, type, seq, json_valid(data) AS valid
|
|
6053
|
+
FROM session_message
|
|
6054
|
+
WHERE session_id = ? AND (seq > ? OR (seq = ? AND id > ?))
|
|
6055
|
+
ORDER BY seq ASC, id ASC LIMIT ?`).all(sessionID, after.timeCreated, after.timeCreated, after.id, limit) : this.prepare(`SELECT id, type, seq, json_valid(data) AS valid
|
|
6056
|
+
FROM session_message
|
|
6057
|
+
WHERE session_id = ?
|
|
6058
|
+
ORDER BY seq ASC, id ASC LIMIT ?`).all(sessionID, limit);
|
|
6059
|
+
const rawTypes = new Set(RAW_MESSAGE_TYPES);
|
|
6060
|
+
return rows.map((row) => ({
|
|
6061
|
+
id: row.id,
|
|
6062
|
+
timeCreated: row.seq,
|
|
6063
|
+
contributesOrdinal: rawTypes.has(row.type),
|
|
6064
|
+
hasValidInfo: row.valid === 1
|
|
6065
|
+
}));
|
|
6066
|
+
});
|
|
6067
|
+
}
|
|
6068
|
+
range(sessionID, after, through) {
|
|
6069
|
+
return trackDecodeOperation("range", () => through <= after ? [] : this.all(sessionID, after, undefined, through));
|
|
6070
|
+
}
|
|
6071
|
+
spanRowStamps(sessionID, after, through) {
|
|
6072
|
+
if (!Number.isSafeInteger(after) || !Number.isSafeInteger(through))
|
|
6073
|
+
throw new Error("Invalid seq span");
|
|
6074
|
+
const rows = this.prepare(`SELECT seq, id, time_updated AS updated, length(CAST(data AS BLOB)) AS bytes
|
|
6075
|
+
FROM session_message WHERE session_id = ? AND seq > ? AND seq <= ?
|
|
6076
|
+
ORDER BY seq ASC`).all(sessionID, after, through);
|
|
6077
|
+
const stamps = new Map;
|
|
6078
|
+
for (const row of rows)
|
|
6079
|
+
stamps.set(row.seq, `${row.id}\x00${row.updated ?? ""}\x00${row.bytes ?? ""}`);
|
|
6080
|
+
return stamps;
|
|
6081
|
+
}
|
|
6082
|
+
rawRowsThrough(sessionID, throughSeq, limit) {
|
|
6083
|
+
return trackDecodeOperation("rawRowsThrough", () => {
|
|
6084
|
+
if (!Number.isSafeInteger(throughSeq))
|
|
6085
|
+
throw new Error("Invalid seq upper bound");
|
|
6086
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e4)
|
|
6087
|
+
throw new Error("Invalid page limit");
|
|
6088
|
+
const rawTypes = RAW_MESSAGE_TYPES.map(() => "?").join(", ");
|
|
6089
|
+
return this.prepare(`SELECT id, session_id, type, seq, time_created, data FROM session_message
|
|
6090
|
+
WHERE session_id = ? AND type IN (${rawTypes}) AND seq <= ?
|
|
6091
|
+
ORDER BY seq DESC LIMIT ?`).all(sessionID, ...RAW_MESSAGE_TYPES, throughSeq, limit).map(decode);
|
|
6092
|
+
});
|
|
6093
|
+
}
|
|
6094
|
+
instructionRowsThrough(sessionID, throughSeq) {
|
|
6095
|
+
return trackDecodeOperation("instructionRowsThrough", () => {
|
|
6096
|
+
if (!Number.isSafeInteger(throughSeq))
|
|
6097
|
+
throw new Error("Invalid seq upper bound");
|
|
6098
|
+
return this.prepare(`SELECT id, session_id, type, seq, time_created, data FROM session_message
|
|
6099
|
+
WHERE session_id = ? AND type = 'system' AND seq <= ?
|
|
6100
|
+
ORDER BY seq ASC`).all(sessionID, throughSeq).map(decode);
|
|
6101
|
+
});
|
|
6102
|
+
}
|
|
6103
|
+
sequenceForId(sessionID, id) {
|
|
6104
|
+
if (!id)
|
|
6105
|
+
return;
|
|
6106
|
+
const row = this.prepare("SELECT seq FROM session_message WHERE session_id = ? AND id = ? LIMIT 1").get(sessionID, id);
|
|
6107
|
+
return typeof row?.seq === "number" ? row.seq : undefined;
|
|
6108
|
+
}
|
|
6109
|
+
syntheticMessageIDs(sessionID) {
|
|
6110
|
+
const rows = this.prepare("SELECT id FROM session_message WHERE session_id = ? AND type = 'synthetic'").all(sessionID);
|
|
6111
|
+
return new Set(rows.map((row) => row.id));
|
|
6112
|
+
}
|
|
6113
|
+
forkOrigin(sessionID) {
|
|
6114
|
+
const columns = new Set(this.prepare("PRAGMA table_info(session_v2)").all().map((column) => column.name));
|
|
6115
|
+
if (!columns.has("fork_session_id") || !columns.has("fork_boundary"))
|
|
6116
|
+
return null;
|
|
6117
|
+
const row = this.prepare("SELECT fork_session_id, fork_boundary FROM session_v2 WHERE id = ?").get(sessionID);
|
|
6118
|
+
if (!row?.fork_session_id || !row.fork_boundary)
|
|
6119
|
+
return null;
|
|
6120
|
+
try {
|
|
6121
|
+
const boundary = JSON.parse(row.fork_boundary);
|
|
6122
|
+
if (boundary.type !== "before" && boundary.type !== "through" || typeof boundary.messageID !== "string" || boundary.messageID.length === 0)
|
|
6123
|
+
return null;
|
|
6124
|
+
return {
|
|
6125
|
+
parentSessionID: row.fork_session_id,
|
|
6126
|
+
boundary: { type: boundary.type, messageID: boundary.messageID }
|
|
6127
|
+
};
|
|
6128
|
+
} catch {
|
|
6129
|
+
return null;
|
|
6130
|
+
}
|
|
6131
|
+
}
|
|
6132
|
+
sessionExists(sessionID) {
|
|
6133
|
+
return this.prepare("SELECT 1 FROM session_v2 WHERE id = ?").get(sessionID) != null;
|
|
6134
|
+
}
|
|
6135
|
+
rowStampsThrough(sessionID, throughSeq) {
|
|
6136
|
+
return this.prepare(`SELECT id, type, seq, time_created FROM session_message
|
|
6137
|
+
WHERE session_id = ? AND seq <= ? ORDER BY seq ASC`).all(sessionID, throughSeq);
|
|
6138
|
+
}
|
|
6139
|
+
latestSequenceForIds(sessionID, ids) {
|
|
6140
|
+
let latest = -1;
|
|
6141
|
+
for (let offset = 0;offset < ids.length; offset += 500) {
|
|
6142
|
+
const chunk = ids.slice(offset, offset + 500);
|
|
6143
|
+
const row = this.prepare(`SELECT MAX(seq) AS seq FROM session_message
|
|
6144
|
+
WHERE session_id = ? AND id IN (${chunk.map(() => "?").join(", ")})`).get(sessionID, ...chunk);
|
|
6145
|
+
if (typeof row?.seq === "number")
|
|
6146
|
+
latest = Math.max(latest, row.seq);
|
|
6147
|
+
}
|
|
6148
|
+
return latest;
|
|
6149
|
+
}
|
|
6150
|
+
compactionByStatus(sessionID, status) {
|
|
6151
|
+
const row = this.prepare(`SELECT id, session_id, type, seq, time_created, data FROM session_message
|
|
6152
|
+
WHERE session_id = ? AND type = 'compaction'
|
|
6153
|
+
AND json_extract(data, '$.status') = ?
|
|
6154
|
+
ORDER BY seq DESC LIMIT 1`).get(sessionID, status);
|
|
6155
|
+
return row ? decode(row) : undefined;
|
|
6156
|
+
}
|
|
6157
|
+
latestCompaction(sessionID) {
|
|
6158
|
+
return trackDecodeOperation("latestCompaction", () => this.compactionByStatus(sessionID, "completed"));
|
|
6159
|
+
}
|
|
6160
|
+
latestRunningCompaction(sessionID) {
|
|
6161
|
+
return trackDecodeOperation("latestRunningCompaction", () => this.compactionByStatus(sessionID, "running"));
|
|
6162
|
+
}
|
|
6163
|
+
idleRows(sessionID, after = -1) {
|
|
6164
|
+
return trackDecodeOperation("idleRows", () => this.all(sessionID, after, "idle"));
|
|
6165
|
+
}
|
|
6166
|
+
earliestSequence(sessionID) {
|
|
6167
|
+
const row = this.prepare("SELECT MIN(seq) AS seq FROM session_message WHERE session_id = ?").get(sessionID);
|
|
6168
|
+
return typeof row?.seq === "number" ? row.seq : undefined;
|
|
6169
|
+
}
|
|
6170
|
+
latestSequence(sessionID) {
|
|
6171
|
+
const row = this.prepare("SELECT MAX(seq) AS seq FROM session_message WHERE session_id = ?").get(sessionID);
|
|
6172
|
+
return typeof row?.seq === "number" ? row.seq : -1;
|
|
6173
|
+
}
|
|
6174
|
+
assistantSince(sessionID, afterSeq) {
|
|
6175
|
+
return trackDecodeOperation("assistantSince", () => {
|
|
6176
|
+
const rows = this.prepare(`SELECT id, session_id, type, seq, time_created, data FROM session_message
|
|
6177
|
+
WHERE session_id = ? AND type = 'assistant' AND seq > ?
|
|
6178
|
+
ORDER BY seq ASC`).all(sessionID, afterSeq);
|
|
6179
|
+
return rows.map((row) => decode(row));
|
|
6180
|
+
});
|
|
6181
|
+
}
|
|
6182
|
+
latestAssistant(sessionID) {
|
|
6183
|
+
return trackDecodeOperation("latestAssistant", () => {
|
|
6184
|
+
const row = this.prepare(`SELECT id, session_id, type, seq, time_created, data FROM session_message
|
|
6185
|
+
WHERE session_id = ? AND type = 'assistant'
|
|
6186
|
+
ORDER BY seq DESC LIMIT 1`).get(sessionID);
|
|
6187
|
+
return row ? decode(row) : undefined;
|
|
6188
|
+
});
|
|
6189
|
+
}
|
|
6190
|
+
latestIdle(sessionID) {
|
|
6191
|
+
return trackDecodeOperation("latestIdle", () => {
|
|
6192
|
+
const row = this.prepare(`SELECT id, session_id, type, seq, time_created, data FROM session_message
|
|
6193
|
+
WHERE session_id = ? AND type = 'idle'
|
|
6194
|
+
ORDER BY seq DESC LIMIT 1`).get(sessionID);
|
|
6195
|
+
return row ? decode(row) : undefined;
|
|
6196
|
+
});
|
|
6197
|
+
}
|
|
6198
|
+
window(sessionID) {
|
|
6199
|
+
return trackDecodeOperation("window", () => this.db.transaction(() => {
|
|
6200
|
+
const cut = this.latestCompaction(sessionID);
|
|
6201
|
+
return this.all(sessionID, cut ? cut.seq - 1 : -1);
|
|
6202
|
+
}).deferred());
|
|
6203
|
+
}
|
|
6204
|
+
history(sessionID) {
|
|
6205
|
+
return trackDecodeOperation("history", () => this.all(sessionID, -1));
|
|
6206
|
+
}
|
|
6207
|
+
all(sessionID, after, type, through) {
|
|
6208
|
+
const rows = [];
|
|
6209
|
+
for (;; ) {
|
|
6210
|
+
const page = this.page(sessionID, { after, through, type });
|
|
6211
|
+
rows.push(...page.rows);
|
|
6212
|
+
if (page.rows.length < 100 || page.cursor === undefined)
|
|
6213
|
+
return rows;
|
|
6214
|
+
after = page.cursor;
|
|
6215
|
+
}
|
|
6216
|
+
}
|
|
6217
|
+
}
|
|
6218
|
+
|
|
5003
6219
|
// src/features/magic-context/resolve-subagent-fallback.ts
|
|
5004
6220
|
function resolveIsSubagentFromOpenCodeDb(sessionId) {
|
|
5005
6221
|
try {
|
|
@@ -5027,6 +6243,142 @@ function resolveIsSubagentFromOpenCode2Db(sessionId) {
|
|
|
5027
6243
|
}
|
|
5028
6244
|
}
|
|
5029
6245
|
|
|
6246
|
+
// src/features/magic-context/storage-session-tables.ts
|
|
6247
|
+
var SESSION_SCOPED_TABLES = [
|
|
6248
|
+
{ table: "pending_ops", harnessScoped: true },
|
|
6249
|
+
{ table: "source_contents", harnessScoped: true },
|
|
6250
|
+
{ table: "tool_owner_backfill_state" },
|
|
6251
|
+
{ table: "tags", harnessScoped: true },
|
|
6252
|
+
{ table: "session_meta", harnessScoped: true },
|
|
6253
|
+
{
|
|
6254
|
+
table: "temporal_decisions",
|
|
6255
|
+
extraPredicate: "NOT EXISTS (SELECT 1 FROM session_meta AS remaining WHERE remaining.session_id = temporal_decisions.session_id)"
|
|
6256
|
+
},
|
|
6257
|
+
{
|
|
6258
|
+
table: "session_replay_decisions",
|
|
6259
|
+
extraPredicate: "NOT EXISTS (SELECT 1 FROM session_meta AS remaining WHERE remaining.session_id = session_replay_decisions.session_id)"
|
|
6260
|
+
},
|
|
6261
|
+
{ table: "session_projects", harnessScoped: true },
|
|
6262
|
+
{ table: "compartment_chunk_embeddings", harnessScoped: true },
|
|
6263
|
+
{ table: "compartments", harnessScoped: true },
|
|
6264
|
+
{
|
|
6265
|
+
table: "compartment_history_versions",
|
|
6266
|
+
extraPredicate: "NOT EXISTS (SELECT 1 FROM compartments AS remaining WHERE remaining.session_id = compartment_history_versions.session_id)"
|
|
6267
|
+
},
|
|
6268
|
+
{ table: "compression_depth", harnessScoped: true },
|
|
6269
|
+
{ table: "session_facts", harnessScoped: true },
|
|
6270
|
+
{ table: "compartment_state_lease" },
|
|
6271
|
+
{ table: "notes", harnessScoped: true, extraPredicate: "type = 'session'" },
|
|
6272
|
+
{ table: "recomp_compartments", harnessScoped: true },
|
|
6273
|
+
{ table: "recomp_facts", harnessScoped: true },
|
|
6274
|
+
{ table: "user_memory_candidates" },
|
|
6275
|
+
{ table: "primer_candidates", harnessScoped: true },
|
|
6276
|
+
{ table: "m0_mutation_log" },
|
|
6277
|
+
{ table: "compartment_events", harnessScoped: true },
|
|
6278
|
+
{ table: "subagent_invocations", harnessScoped: true },
|
|
6279
|
+
{ table: "historian_runs", harnessScoped: true },
|
|
6280
|
+
{ table: "plugin_messages" },
|
|
6281
|
+
{ table: "transform_decisions", harnessScoped: true },
|
|
6282
|
+
{ table: "synapse_batch_ledger" },
|
|
6283
|
+
{ table: "embedding_measurement_corpus" },
|
|
6284
|
+
{ table: "pending_session_cleanup", harnessScoped: true },
|
|
6285
|
+
{ table: "message_history_fts" },
|
|
6286
|
+
{ table: "message_fts_rowid_map" },
|
|
6287
|
+
{ table: "message_history_source", harnessScoped: true },
|
|
6288
|
+
{ table: "message_history_index", harnessScoped: true },
|
|
6289
|
+
{ table: "lkg_slots" },
|
|
6290
|
+
{ table: "lkg_slot_chunks" }
|
|
6291
|
+
];
|
|
6292
|
+
var cleanupStatements = new WeakMap;
|
|
6293
|
+
function cleanupStatement(db, sql) {
|
|
6294
|
+
let cache = cleanupStatements.get(db);
|
|
6295
|
+
if (!cache) {
|
|
6296
|
+
cache = new Map;
|
|
6297
|
+
cleanupStatements.set(db, cache);
|
|
6298
|
+
}
|
|
6299
|
+
let statement = cache.get(sql);
|
|
6300
|
+
if (!statement) {
|
|
6301
|
+
if (cache.size >= 256)
|
|
6302
|
+
cache.clear();
|
|
6303
|
+
statement = prepareCachedStatement2(db, sql);
|
|
6304
|
+
cache.set(sql, statement);
|
|
6305
|
+
}
|
|
6306
|
+
return statement;
|
|
6307
|
+
}
|
|
6308
|
+
function deleteSessionScopedRows(db, sessionIds, harness, options = {}) {
|
|
6309
|
+
if (sessionIds.length === 0)
|
|
6310
|
+
return 0;
|
|
6311
|
+
let deletableSessionIds = [...sessionIds];
|
|
6312
|
+
if (options.rustModuleCleanupAcknowledged !== true) {
|
|
6313
|
+
const placeholders = sessionIds.map(() => "?").join(", ");
|
|
6314
|
+
const harnessPredicate = harness === undefined ? "" : " AND harness = ?";
|
|
6315
|
+
const protectedRows = cleanupStatement(db, `SELECT session_id
|
|
6316
|
+
FROM pending_session_cleanup
|
|
6317
|
+
WHERE session_id IN (${placeholders})
|
|
6318
|
+
AND harness LIKE '%:rust'${harnessPredicate}`).all(...sessionIds, ...harness === undefined ? [] : [`${harness}:rust`]);
|
|
6319
|
+
const protectedSessionIds = new Set(protectedRows.map((row) => row.session_id));
|
|
6320
|
+
deletableSessionIds = sessionIds.filter((sessionId) => !protectedSessionIds.has(sessionId));
|
|
6321
|
+
}
|
|
6322
|
+
if (deletableSessionIds.length === 0)
|
|
6323
|
+
return 0;
|
|
6324
|
+
const placeholders = deletableSessionIds.map(() => "?").join(", ");
|
|
6325
|
+
const harnessTables = SESSION_SCOPED_TABLES.filter((definition) => definition.harnessScoped);
|
|
6326
|
+
if (options.preserveTagRevisionTombstones) {
|
|
6327
|
+
const owners = cleanupStatement(db, harnessTables.map((definition) => `SELECT session_id, harness FROM ${definition.table} WHERE session_id IN (${placeholders})${definition.extraPredicate ? ` AND ${definition.extraPredicate}` : ""}`).join(" UNION ")).all(...harnessTables.flatMap(() => deletableSessionIds));
|
|
6328
|
+
const record = cleanupStatement(db, "INSERT OR IGNORE INTO schema_migrations_meta (key, value) VALUES (?, ?)");
|
|
6329
|
+
for (const owner of owners)
|
|
6330
|
+
record.run(tagTombstoneOwnerKey(owner.session_id, owner.harness), owner.harness);
|
|
6331
|
+
const fallback = cleanupStatement(db, `INSERT INTO schema_migrations_meta (key, value)
|
|
6332
|
+
SELECT ?, ? WHERE NOT EXISTS (SELECT 1 FROM schema_migrations_meta WHERE key >= ? AND key < ?)`);
|
|
6333
|
+
for (const id of deletableSessionIds)
|
|
6334
|
+
fallback.run(tagTombstoneOwnerKey(id, getHarness2()), getHarness2(), ...tagTombstoneOwnerRange(id));
|
|
6335
|
+
}
|
|
6336
|
+
for (const sessionId of deletableSessionIds)
|
|
6337
|
+
deleteChunkEmbedBackoffForSession2(db, sessionId);
|
|
6338
|
+
for (const definition of SESSION_SCOPED_TABLES) {
|
|
6339
|
+
if (definition.table === "message_history_fts") {
|
|
6340
|
+
cleanupStatement(db, `DELETE FROM message_history_fts
|
|
6341
|
+
WHERE rowid IN (
|
|
6342
|
+
SELECT fts_rowid
|
|
6343
|
+
FROM message_fts_rowid_map
|
|
6344
|
+
WHERE session_id IN (${placeholders})
|
|
6345
|
+
)`).run(...deletableSessionIds);
|
|
6346
|
+
deleteUnmappedMessageFtsRows2(db, deletableSessionIds);
|
|
6347
|
+
continue;
|
|
6348
|
+
}
|
|
6349
|
+
const predicates = [`session_id IN (${placeholders})`];
|
|
6350
|
+
if (definition.extraPredicate)
|
|
6351
|
+
predicates.push(definition.extraPredicate);
|
|
6352
|
+
const bindHarness = harness !== undefined && definition.harnessScoped === true;
|
|
6353
|
+
if (bindHarness)
|
|
6354
|
+
predicates.push("harness = ?");
|
|
6355
|
+
const statement = cleanupStatement(db, `DELETE FROM ${definition.table} WHERE ${predicates.join(" AND ")}`);
|
|
6356
|
+
if (bindHarness)
|
|
6357
|
+
statement.run(...deletableSessionIds, harness);
|
|
6358
|
+
else
|
|
6359
|
+
statement.run(...deletableSessionIds);
|
|
6360
|
+
}
|
|
6361
|
+
deleteSessionActivity(db, deletableSessionIds);
|
|
6362
|
+
if (!options.preserveTagRevisionTombstones) {
|
|
6363
|
+
const retireOwner = cleanupStatement(db, harness === undefined ? "DELETE FROM schema_migrations_meta WHERE key >= ? AND key < ?" : "DELETE FROM schema_migrations_meta WHERE key = ?");
|
|
6364
|
+
const survivingRows = harnessTables.map((definition) => `EXISTS (SELECT 1 FROM ${definition.table} WHERE session_id = ?${definition.extraPredicate ? ` AND ${definition.extraPredicate}` : ""})`).join(" OR ");
|
|
6365
|
+
const retire = cleanupStatement(db, `DELETE FROM schema_migrations_meta WHERE key IN (?, ?)
|
|
6366
|
+
AND NOT (${survivingRows})
|
|
6367
|
+
AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta AS owners WHERE owners.key >= ? AND owners.key < ?)`);
|
|
6368
|
+
for (const id of deletableSessionIds) {
|
|
6369
|
+
if (harness === undefined)
|
|
6370
|
+
retireOwner.run(...tagTombstoneOwnerRange(id));
|
|
6371
|
+
else
|
|
6372
|
+
retireOwner.run(tagTombstoneOwnerKey(id, harness));
|
|
6373
|
+
retire.run(tagIdentityRevisionKey(id), tagRevisionKey(id), ...harnessTables.map(() => id), ...tagTombstoneOwnerRange(id));
|
|
6374
|
+
}
|
|
6375
|
+
}
|
|
6376
|
+
if (!options.deferRecoveryFenceCleanup)
|
|
6377
|
+
for (const sessionId of deletableSessionIds)
|
|
6378
|
+
clearLkgRecoveryFence(sessionId);
|
|
6379
|
+
return deletableSessionIds.length;
|
|
6380
|
+
}
|
|
6381
|
+
|
|
5030
6382
|
// src/features/magic-context/storage-meta-session.ts
|
|
5031
6383
|
var SESSION_META_FALLBACK_SELECTS = {
|
|
5032
6384
|
cache_ttl: "'5m' AS cache_ttl",
|
|
@@ -5280,7 +6632,7 @@ function hasOnlySystemHashMaterialization(sessions, sessionId) {
|
|
|
5280
6632
|
}
|
|
5281
6633
|
|
|
5282
6634
|
// src/hooks/magic-context/system-prompt-delivery.ts
|
|
5283
|
-
var
|
|
6635
|
+
var pending3 = new BoundedSessionMap(1000);
|
|
5284
6636
|
var retiredRequests = new WeakSet;
|
|
5285
6637
|
var heldRequests = new WeakSet;
|
|
5286
6638
|
var refreshOwners = new BoundedSessionMap(1000);
|
|
@@ -5296,11 +6648,11 @@ function recordSystemRefreshOwnership(sessionId, hash, ownsHistoryRefresh, histo
|
|
|
5296
6648
|
function preparation(sessionId, request) {
|
|
5297
6649
|
if (retiredRequests.has(request))
|
|
5298
6650
|
return;
|
|
5299
|
-
const previous =
|
|
6651
|
+
const previous = pending3.get(sessionId);
|
|
5300
6652
|
if (previous?.request === request)
|
|
5301
6653
|
return previous;
|
|
5302
6654
|
const next = { request, held: false };
|
|
5303
|
-
|
|
6655
|
+
pending3.set(sessionId, next);
|
|
5304
6656
|
return next;
|
|
5305
6657
|
}
|
|
5306
6658
|
function recordSystemPromptForRequest(sessionId, request, hash, db, ownsHistoryRefresh, history, materialization) {
|
|
@@ -5308,7 +6660,7 @@ function recordSystemPromptForRequest(sessionId, request, hash, db, ownsHistoryR
|
|
|
5308
6660
|
return;
|
|
5309
6661
|
if (ownsHistoryRefresh !== undefined)
|
|
5310
6662
|
recordSystemRefreshOwnership(sessionId, hash, ownsHistoryRefresh, history, materialization);
|
|
5311
|
-
const previous =
|
|
6663
|
+
const previous = pending3.get(sessionId);
|
|
5312
6664
|
if (previous?.request === request && previous.held && previous.hash && previous.hash !== hash) {
|
|
5313
6665
|
retirePendingSystemPromptDelivery(sessionId);
|
|
5314
6666
|
return;
|
|
@@ -5331,7 +6683,7 @@ function recordHeldHeadForRequest(sessionId, request, deferRefresh) {
|
|
|
5331
6683
|
}
|
|
5332
6684
|
}
|
|
5333
6685
|
function bindSystemPromptResponse(sessionId, request, response) {
|
|
5334
|
-
const saved =
|
|
6686
|
+
const saved = pending3.get(sessionId);
|
|
5335
6687
|
if (!saved || saved.request !== request || request?.kind !== "v2" || !response.responseId || response.responseId === request.previousResponseId || response.modelKey !== request.modelKey || !Number.isFinite(response.createdAt) || response.createdAt <= request.startedAt)
|
|
5336
6688
|
return;
|
|
5337
6689
|
if (saved.response && saved.response.id !== response.responseId)
|
|
@@ -5339,11 +6691,11 @@ function bindSystemPromptResponse(sessionId, request, response) {
|
|
|
5339
6691
|
saved.response = { id: response.responseId, createdAt: response.createdAt };
|
|
5340
6692
|
}
|
|
5341
6693
|
function isHeldHeadForRequest(sessionId, request) {
|
|
5342
|
-
const saved =
|
|
6694
|
+
const saved = pending3.get(sessionId);
|
|
5343
6695
|
return saved?.request === request && saved?.held === true || request !== undefined && retiredRequests.has(request) && heldRequests.has(request);
|
|
5344
6696
|
}
|
|
5345
6697
|
function acknowledgeSystemPromptDelivery(args) {
|
|
5346
|
-
const saved =
|
|
6698
|
+
const saved = pending3.get(args.sessionId);
|
|
5347
6699
|
if (!saved || saved.request !== args.request || !args.responseId)
|
|
5348
6700
|
return;
|
|
5349
6701
|
const request = saved.request;
|
|
@@ -5385,10 +6737,10 @@ function clearSystemPromptDelivery(sessionId) {
|
|
|
5385
6737
|
refreshOwners.delete(sessionId);
|
|
5386
6738
|
}
|
|
5387
6739
|
function retirePendingSystemPromptDelivery(sessionId) {
|
|
5388
|
-
const saved =
|
|
6740
|
+
const saved = pending3.get(sessionId);
|
|
5389
6741
|
if (saved)
|
|
5390
6742
|
retiredRequests.add(saved.request);
|
|
5391
|
-
|
|
6743
|
+
pending3.delete(sessionId);
|
|
5392
6744
|
}
|
|
5393
6745
|
|
|
5394
6746
|
// src/hooks/magic-context/lkg-measured-request.ts
|
|
@@ -5400,7 +6752,7 @@ function lkgProviderInputTotal(tokens) {
|
|
|
5400
6752
|
return counts.every((count) => Number.isSafeInteger(count) && count >= 0) ? counts.reduce((sum, count) => sum + count, 0) : Number.NaN;
|
|
5401
6753
|
}
|
|
5402
6754
|
function identity(slot) {
|
|
5403
|
-
return
|
|
6755
|
+
return createHash6("sha256").update(JSON.stringify([
|
|
5404
6756
|
slot.capturedAt,
|
|
5405
6757
|
slot.captureSequence,
|
|
5406
6758
|
slot.rowVersion,
|
|
@@ -5496,7 +6848,7 @@ function clearCapturedLkgMeasurement(sessionId) {
|
|
|
5496
6848
|
}
|
|
5497
6849
|
|
|
5498
6850
|
// src/hooks/magic-context/lkg-persist.ts
|
|
5499
|
-
import { createHash as
|
|
6851
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
5500
6852
|
function parseStringArray(value) {
|
|
5501
6853
|
if (typeof value !== "string")
|
|
5502
6854
|
return null;
|
|
@@ -5610,7 +6962,7 @@ function rememberFingerprint(db, sessionId, fingerprint) {
|
|
|
5610
6962
|
saved.set(sessionId, fingerprint);
|
|
5611
6963
|
}
|
|
5612
6964
|
function slotFingerprint(slot) {
|
|
5613
|
-
return
|
|
6965
|
+
return createHash7("sha256").update(JSON.stringify([
|
|
5614
6966
|
slot.jsonPrefix,
|
|
5615
6967
|
slot.inputIdSeq,
|
|
5616
6968
|
slot.inputContentDigests,
|
|
@@ -6758,7 +8110,7 @@ var DIGEST_CHUNK_BYTES = 64 * 1024;
|
|
|
6758
8110
|
var digestChunk;
|
|
6759
8111
|
function lkgContentDigestFromFields(fields) {
|
|
6760
8112
|
lkgDigestsComputed += 1;
|
|
6761
|
-
const hash =
|
|
8113
|
+
const hash = createHash8("sha256");
|
|
6762
8114
|
digestChunk ??= Buffer.allocUnsafe(DIGEST_CHUNK_BYTES);
|
|
6763
8115
|
const chunk = digestChunk;
|
|
6764
8116
|
let offset = 0;
|
|
@@ -6821,7 +8173,7 @@ function legacyLkgDigestFromFields(fields) {
|
|
|
6821
8173
|
const value = typeof field === "symbol" ? field.description ?? "" : String(field);
|
|
6822
8174
|
key += `${typeof field}:${value.length}:${value}\x00`;
|
|
6823
8175
|
}
|
|
6824
|
-
return
|
|
8176
|
+
return createHash8("sha256").update(key).digest("base64url");
|
|
6825
8177
|
}
|
|
6826
8178
|
function legacyLkgContentDigest(message) {
|
|
6827
8179
|
const fields = flattenContentFields(withoutEmptyUserDiffSummary(message));
|
|
@@ -7391,15 +8743,15 @@ function createPreAdoptionToolSweepResolver(db, sessionId) {
|
|
|
7391
8743
|
}
|
|
7392
8744
|
|
|
7393
8745
|
// src/features/magic-context/pi-content-decisions.ts
|
|
7394
|
-
var
|
|
8746
|
+
var PREFIX2 = "pi-content-replay-v1:";
|
|
7395
8747
|
function encodePiContentDecision(kind, messageId) {
|
|
7396
|
-
return
|
|
8748
|
+
return PREFIX2 + JSON.stringify([kind, messageId]);
|
|
7397
8749
|
}
|
|
7398
8750
|
function decodePiContentDecision(value) {
|
|
7399
|
-
if (!value.startsWith(
|
|
8751
|
+
if (!value.startsWith(PREFIX2))
|
|
7400
8752
|
return null;
|
|
7401
8753
|
try {
|
|
7402
|
-
const pair = JSON.parse(value.slice(
|
|
8754
|
+
const pair = JSON.parse(value.slice(PREFIX2.length));
|
|
7403
8755
|
if (Array.isArray(pair) && pair.length === 2 && (pair[0] === "reminder-strip" || pair[0] === "seam-temporal-strip" || pair[0] === "tag-identity-repair-once" || pair[0] === "tag-identity-repair-pending" || pair[0] === "tag-identity-rebuild-failed" || pair[0] === "tag-identity-recurring") && typeof pair[1] === "string" && pair[1].length > 0)
|
|
7404
8756
|
return [pair[0], pair[1]];
|
|
7405
8757
|
} catch {}
|
|
@@ -8294,7 +9646,7 @@ class HiddenCompletionRefusal extends Error {
|
|
|
8294
9646
|
}
|
|
8295
9647
|
// src/features/magic-context/dreamer/provider-output-failure.ts
|
|
8296
9648
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8297
|
-
import { createHash as
|
|
9649
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
8298
9650
|
var MAX_NEAR_ZERO_OUTPUT_TOKENS = 32;
|
|
8299
9651
|
|
|
8300
9652
|
class DreamerProviderOutputFailureError extends Error {
|
|
@@ -8391,12 +9743,12 @@ function providerOutputFailureFromInvalidManifest(messages, responseText, now =
|
|
|
8391
9743
|
const resetAt = quotaResetAt(responseText, now);
|
|
8392
9744
|
if (resetAt === undefined && completion.outputTokens > MAX_NEAR_ZERO_OUTPUT_TOKENS)
|
|
8393
9745
|
return null;
|
|
8394
|
-
const fingerprint =
|
|
9746
|
+
const fingerprint = createHash9("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
8395
9747
|
return new DreamerProviderOutputFailureError(fingerprint, completion.outputTokens, completion.reasoningTokens, responseText, resetAt);
|
|
8396
9748
|
}
|
|
8397
9749
|
|
|
8398
9750
|
// src/v2/hooks/hidden-child.ts
|
|
8399
|
-
import { createHash as
|
|
9751
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
8400
9752
|
|
|
8401
9753
|
// src/shared/historian-cache.ts
|
|
8402
9754
|
function withoutHistorianTailCache(body) {
|
|
@@ -8593,7 +9945,7 @@ function markerCandidates(text) {
|
|
|
8593
9945
|
function textDigest(text) {
|
|
8594
9946
|
return {
|
|
8595
9947
|
length: text.length,
|
|
8596
|
-
sha256:
|
|
9948
|
+
sha256: createHash10("sha256").update(text).digest("hex").slice(0, 16)
|
|
8597
9949
|
};
|
|
8598
9950
|
}
|
|
8599
9951
|
function firstDifference(a, b) {
|
|
@@ -10063,9 +11415,9 @@ async function promptAsyncAndWaitForIdle(client, request, options = {}) {
|
|
|
10063
11415
|
}
|
|
10064
11416
|
}
|
|
10065
11417
|
// src/shared/prompt-surface-runtime.ts
|
|
10066
|
-
import { createHash as
|
|
10067
|
-
import { existsSync as existsSync5, readFileSync as
|
|
10068
|
-
import { dirname as
|
|
11418
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
11419
|
+
import { existsSync as existsSync5, readFileSync as readFileSync8, statSync as statSync6 } from "node:fs";
|
|
11420
|
+
import { dirname as dirname5, isAbsolute as isAbsolute3, resolve as resolve3 } from "node:path";
|
|
10069
11421
|
|
|
10070
11422
|
// src/tools/light-descriptions.ts
|
|
10071
11423
|
var CTX_REDUCE_LIGHT_DESCRIPTION = `Stamp an item as no longer needed for the work ahead. Not a delete: stamping QUEUES it, the item stays readable until Magic Context clears stamped items in one sweep, newest tags are protected, and a cleared item goes to the archive (recent: a [dropped §N§] placeholder; older: removed) recoverable via ctx_expand(tag=N). The question is "does this need to stay on my desk for what comes next?" — a file you keep editing stays, the grep that found it goes. Stamp used reads/searches/outputs, acted-on build/test output, redundant dumps, extracted pasted payloads; keep user messages, your own text, unresolved errors, raw evidence, exact wording that may matter. Look at each tag; never blanket-stamp "1-50". Grammar: "3-5", "1,2,9", "1-5,8,12-15".`;
|
|
@@ -10096,22 +11448,22 @@ function promptSurfaceHashMaterial(systemContent, preset = "full") {
|
|
|
10096
11448
|
\x00magic-context-prompt-surface:${preset}`;
|
|
10097
11449
|
}
|
|
10098
11450
|
function systemPromptFingerprint(systemContent, preset = "full") {
|
|
10099
|
-
return
|
|
11451
|
+
return createHash11("md5").update(promptSurfaceHashMaterial(systemContent, preset)).digest("hex");
|
|
10100
11452
|
}
|
|
10101
11453
|
var PROMPT_SURFACE_TOOL_ID_SET = new Set(ACTIVE_TOOL_IDS);
|
|
10102
11454
|
function resolveUserConfigDirectory(options) {
|
|
10103
11455
|
if (options.userConfigDirectory)
|
|
10104
|
-
return
|
|
11456
|
+
return resolve3(options.userConfigDirectory);
|
|
10105
11457
|
const sharedBase = cortexKitUserConfigBasePath();
|
|
10106
11458
|
const shared = detectConfigFile(sharedBase);
|
|
10107
11459
|
if (shared.format !== "none")
|
|
10108
|
-
return
|
|
11460
|
+
return dirname5(shared.path);
|
|
10109
11461
|
if (options.harness) {
|
|
10110
11462
|
const legacy = resolveLegacyConfigSourcesForHarness(options.directory ?? process.cwd(), options.harness === "omp" ? "pi" : options.harness === "opencode2" ? "opencode" : options.harness).user.find((source) => existsSync5(source.path));
|
|
10111
11463
|
if (legacy)
|
|
10112
|
-
return
|
|
11464
|
+
return dirname5(legacy.path);
|
|
10113
11465
|
}
|
|
10114
|
-
return
|
|
11466
|
+
return dirname5(sharedBase);
|
|
10115
11467
|
}
|
|
10116
11468
|
function markerCount(content) {
|
|
10117
11469
|
return content.match(GUIDANCE_MARKER_LINE)?.length ?? 0;
|
|
@@ -10128,14 +11480,14 @@ function createPromptSurfaceRuntime(options) {
|
|
|
10128
11480
|
const readGuidanceOverride = (configuredPath) => {
|
|
10129
11481
|
if (!configuredPath)
|
|
10130
11482
|
return;
|
|
10131
|
-
const path = isAbsolute3(configuredPath) ? configuredPath :
|
|
11483
|
+
const path = isAbsolute3(configuredPath) ? configuredPath : resolve3(userConfigDirectory, configuredPath);
|
|
10132
11484
|
let content;
|
|
10133
11485
|
try {
|
|
10134
|
-
if (!
|
|
11486
|
+
if (!statSync6(path).isFile()) {
|
|
10135
11487
|
warnOnce(`guidance-not-file:${path}`, `prompt_surface.guidance_override_path (${path}) is not a file; using built-in guidance.`);
|
|
10136
11488
|
return;
|
|
10137
11489
|
}
|
|
10138
|
-
content =
|
|
11490
|
+
content = readFileSync8(path, "utf8");
|
|
10139
11491
|
} catch (error) {
|
|
10140
11492
|
const reason = error instanceof Error ? error.message : String(error);
|
|
10141
11493
|
warnOnce(`guidance-unreadable:${path}:${reason}`, `prompt_surface.guidance_override_path (${path}) could not be read (${reason}); using built-in guidance.`);
|
|
@@ -10284,7 +11636,7 @@ function parseFields(json) {
|
|
|
10284
11636
|
|
|
10285
11637
|
// src/hooks/magic-context/compartment-runner-historian.ts
|
|
10286
11638
|
import { mkdirSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
10287
|
-
import { join as
|
|
11639
|
+
import { join as join5 } from "node:path";
|
|
10288
11640
|
|
|
10289
11641
|
// src/agents/historian.ts
|
|
10290
11642
|
var HISTORIAN_AGENT = "historian";
|
|
@@ -10782,7 +12134,7 @@ function compareMemorySelectionPriority(left, right) {
|
|
|
10782
12134
|
}
|
|
10783
12135
|
|
|
10784
12136
|
// src/features/magic-context/mural/render-trigger.ts
|
|
10785
|
-
import { createHash as
|
|
12137
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
10786
12138
|
|
|
10787
12139
|
// src/features/magic-context/mural/mural-selection.ts
|
|
10788
12140
|
var DEFAULT_MURAL_MEMORY_BUDGET = 8000;
|
|
@@ -11486,7 +12838,7 @@ function ensureMuralRendered(db, projectIdentity, budgetTokens = DEFAULT_MURAL_M
|
|
|
11486
12838
|
return { ...cached.result };
|
|
11487
12839
|
}
|
|
11488
12840
|
const plan = planMuralRender(entries);
|
|
11489
|
-
const textHash =
|
|
12841
|
+
const textHash = createHash12("sha256").update(plan.layout.text).digest("hex");
|
|
11490
12842
|
if (existing && existing.contentHash === textHash && existing.width === plan.width && existing.height === plan.height) {
|
|
11491
12843
|
return rememberRender(db, projectIdentity, key, existing.image, {
|
|
11492
12844
|
hasMural: true,
|
|
@@ -11675,14 +13027,14 @@ function parseUserMemoryRow(row) {
|
|
|
11675
13027
|
}
|
|
11676
13028
|
|
|
11677
13029
|
// src/features/magic-context/compaction-marker.ts
|
|
11678
|
-
import { createHash as
|
|
11679
|
-
import { existsSync as existsSync6, statSync as
|
|
13030
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
13031
|
+
import { existsSync as existsSync6, statSync as statSync7 } from "node:fs";
|
|
11680
13032
|
var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
11681
13033
|
var ID_PREFIX_HEX_LENGTH = 12;
|
|
11682
13034
|
var ID_SUFFIX_LENGTH = 14;
|
|
11683
13035
|
var ID_PREFIX_MASK = (1n << BigInt(ID_PREFIX_HEX_LENGTH * 4)) - 1n;
|
|
11684
13036
|
function deterministicBase62(seed, length) {
|
|
11685
|
-
let value = BigInt(`0x${
|
|
13037
|
+
let value = BigInt(`0x${createHash13("sha256").update(seed).digest("hex")}`);
|
|
11686
13038
|
const chars = Array(length);
|
|
11687
13039
|
for (let index = length - 1;index >= 0; index -= 1) {
|
|
11688
13040
|
chars[index] = BASE62_CHARS[Number(value % 62n)];
|
|
@@ -11748,7 +13100,7 @@ function runMarkerWriteTransaction(db, site, operation) {
|
|
|
11748
13100
|
function markerWalPages(db) {
|
|
11749
13101
|
try {
|
|
11750
13102
|
const row = db.prepare("PRAGMA page_size").get();
|
|
11751
|
-
const bytes =
|
|
13103
|
+
const bytes = statSync7(`${getOpenCodeDbPath()}-wal`).size;
|
|
11752
13104
|
return Math.max(0, Math.floor((bytes - 32) / (row.page_size + 24)));
|
|
11753
13105
|
} catch {
|
|
11754
13106
|
return null;
|
|
@@ -18064,7 +19416,7 @@ function dumpHistorianResponse(sessionId, directory, label, text) {
|
|
|
18064
19416
|
ensureCortexKitArtifactGitignore(directory);
|
|
18065
19417
|
const safeSessionId = sanitizeDumpName(sessionId);
|
|
18066
19418
|
const safeLabel = sanitizeDumpName(label);
|
|
18067
|
-
const dumpPath =
|
|
19419
|
+
const dumpPath = join5(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
|
|
18068
19420
|
writeFileSync2(dumpPath, text, "utf8");
|
|
18069
19421
|
sessionLog2(sessionId, "compartment agent: historian response dumped", {
|
|
18070
19422
|
label,
|
|
@@ -18277,7 +19629,7 @@ function addToProjection(projection, messages, withIndexSources) {
|
|
|
18277
19629
|
if (isStrictGapHealingMessage2(message))
|
|
18278
19630
|
projection.nonNarrativeOrdinals.add(message.ordinal);
|
|
18279
19631
|
if (withIndexSources)
|
|
18280
|
-
projection.indexSources.push(
|
|
19632
|
+
projection.indexSources.push(toMessageIndexSource(message));
|
|
18281
19633
|
}
|
|
18282
19634
|
projection.messageCount += messages.length;
|
|
18283
19635
|
}
|
|
@@ -18644,7 +19996,7 @@ function* rebaseSteps(args) {
|
|
|
18644
19996
|
outcome.recompPartialRangeRebased = true;
|
|
18645
19997
|
}
|
|
18646
19998
|
if (indexNeedsRebuild) {
|
|
18647
|
-
|
|
19999
|
+
clearIndexedMessagesInTransaction(db, sessionId);
|
|
18648
20000
|
outcome.indexRebuilt = true;
|
|
18649
20001
|
outcome.compressionDepthRowsDropped = depthRowCount;
|
|
18650
20002
|
}
|
|
@@ -18682,7 +20034,7 @@ function* rebaseSteps(args) {
|
|
|
18682
20034
|
if (outcome.indexRebuilt) {
|
|
18683
20035
|
const sources = projection.indexSources;
|
|
18684
20036
|
for (let start = 0;start < sources.length; start += INDEX_REBUILD_CHUNK) {
|
|
18685
|
-
|
|
20037
|
+
indexSourcesAfterOrdinal(db, sessionId, sources.slice(start, start + INDEX_REBUILD_CHUNK), sources.length);
|
|
18686
20038
|
yield;
|
|
18687
20039
|
}
|
|
18688
20040
|
outcome.indexRowsRebuilt = countRows2(db, "SELECT COUNT(*) AS count FROM message_history_source WHERE session_id = ?", sessionId);
|
|
@@ -18874,6 +20226,60 @@ function queueDropsForCompartmentalizedMessages(db, sessionId, upToMessageIndex,
|
|
|
18874
20226
|
queuePreparedCompartmentDrops(db, prepareCompartmentDrops(db, sessionId, upToMessageIndex, observedKeys, fromMessageIndex));
|
|
18875
20227
|
}
|
|
18876
20228
|
|
|
20229
|
+
// src/hooks/magic-context/historian-history-wait.ts
|
|
20230
|
+
var historyWaits = new Map;
|
|
20231
|
+
function newestMessageId(snapshot) {
|
|
20232
|
+
try {
|
|
20233
|
+
const count = getRawSessionMessageOrdinalCount2(snapshot.sessionId);
|
|
20234
|
+
const ids = readRawSessionMessageIdOrdinalsForRange2(snapshot.sessionId, count, count);
|
|
20235
|
+
const newest = ids.keys().next().value;
|
|
20236
|
+
if (newest)
|
|
20237
|
+
return newest;
|
|
20238
|
+
} catch {}
|
|
20239
|
+
return snapshot.rawLastMessageIdAtTrigger;
|
|
20240
|
+
}
|
|
20241
|
+
function recoveryWindow(snapshot, percentage) {
|
|
20242
|
+
return percentage >= escalationBands(snapshot.executeThresholdPercentage).forceMaterializationPercentage || snapshot.emergencyTailScale !== undefined;
|
|
20243
|
+
}
|
|
20244
|
+
function clearHistorianHistoryWait(sessionId) {
|
|
20245
|
+
historyWaits.delete(sessionId);
|
|
20246
|
+
}
|
|
20247
|
+
function recordHistorianNoProgress(snapshot, emergency = false) {
|
|
20248
|
+
const newest = newestMessageId(snapshot);
|
|
20249
|
+
if (!newest)
|
|
20250
|
+
return;
|
|
20251
|
+
const previous = historyWaits.get(snapshot.sessionId);
|
|
20252
|
+
const sameHistory = previous?.newestMessageId === newest;
|
|
20253
|
+
historyWaits.set(snapshot.sessionId, {
|
|
20254
|
+
newestMessageId: newest,
|
|
20255
|
+
recoveryAttempted: sameHistory && previous.recoveryAttempted || emergency || recoveryWindow(snapshot, snapshot.usagePercentage),
|
|
20256
|
+
floorLiftAttempted: sameHistory && previous.floorLiftAttempted || snapshot.liftLivePromptFloor === true
|
|
20257
|
+
});
|
|
20258
|
+
}
|
|
20259
|
+
function shouldWaitForNewHistorianHistory(snapshot, options = {}) {
|
|
20260
|
+
const wait = historyWaits.get(snapshot.sessionId);
|
|
20261
|
+
if (!wait)
|
|
20262
|
+
return false;
|
|
20263
|
+
const newest = newestMessageId(snapshot);
|
|
20264
|
+
if (newest && newest !== wait.newestMessageId) {
|
|
20265
|
+
try {
|
|
20266
|
+
const order = compareRawSessionMessageOrder2(snapshot.sessionId, newest, wait.newestMessageId);
|
|
20267
|
+
if (order === null || order > 0)
|
|
20268
|
+
return false;
|
|
20269
|
+
} catch {}
|
|
20270
|
+
}
|
|
20271
|
+
const recovery = options.emergency || recoveryWindow(snapshot, options.usagePercentage ?? snapshot.usagePercentage);
|
|
20272
|
+
const floorLift = snapshot.liftLivePromptFloor === true;
|
|
20273
|
+
if (recovery && !wait.recoveryAttempted || floorLift && !wait.floorLiftAttempted) {
|
|
20274
|
+
if (options.claim) {
|
|
20275
|
+
wait.recoveryAttempted ||= recovery;
|
|
20276
|
+
wait.floorLiftAttempted ||= floorLift;
|
|
20277
|
+
}
|
|
20278
|
+
return false;
|
|
20279
|
+
}
|
|
20280
|
+
return true;
|
|
20281
|
+
}
|
|
20282
|
+
|
|
18877
20283
|
// src/tools/ctx-note/render.ts
|
|
18878
20284
|
var GLANCE_TITLE_MAX = 80;
|
|
18879
20285
|
var NUDGE_TITLE_MAX = 60;
|
|
@@ -20115,6 +21521,24 @@ function shouldSuppressHistorianAlert(sessionId) {
|
|
|
20115
21521
|
lastHistorianAlertBySession.set(sessionId, Date.now());
|
|
20116
21522
|
return false;
|
|
20117
21523
|
}
|
|
21524
|
+
function isServingOrdinalDriftSignal(detail) {
|
|
21525
|
+
if (!detail)
|
|
21526
|
+
return false;
|
|
21527
|
+
if (detail === "raw message count shrank")
|
|
21528
|
+
return true;
|
|
21529
|
+
return /(?:offset|protectedTailStart|eligibleEnd) ordinal \d+ id changed$/.test(detail);
|
|
21530
|
+
}
|
|
21531
|
+
function shouldRefuseStaleSnapshotForDrift(sessionId, detail) {
|
|
21532
|
+
if (hasRawMessageProvider2(sessionId) || !openCodeDbExists())
|
|
21533
|
+
return false;
|
|
21534
|
+
return isServingOrdinalDriftSignal(detail);
|
|
21535
|
+
}
|
|
21536
|
+
function dropDriftedServingOrdinalRanks(sessionId, detail) {
|
|
21537
|
+
if (hasRawMessageProvider2(sessionId) || !openCodeDbExists())
|
|
21538
|
+
return;
|
|
21539
|
+
withReadOnlySessionDb((reader) => dropRawSessionOrdinalCheckpoints2(reader, sessionId));
|
|
21540
|
+
sessionLog2(sessionId, `historian: dropped drifted ordinal checkpoints after exact-read disagreement (${detail}); the next run rebuilds them from a full scan`);
|
|
21541
|
+
}
|
|
20118
21542
|
function findDanglingPublicationBoundary(sessionId, compartments, messageExists = hasRawSessionMessageById2) {
|
|
20119
21543
|
for (const compartment of compartments) {
|
|
20120
21544
|
if (!messageExists(sessionId, compartment.startMessageId)) {
|
|
@@ -20282,7 +21706,16 @@ async function runCompartmentAgent(deps) {
|
|
|
20282
21706
|
}
|
|
20283
21707
|
return;
|
|
20284
21708
|
}
|
|
20285
|
-
|
|
21709
|
+
let offset;
|
|
21710
|
+
try {
|
|
21711
|
+
offset = resolveHistorianChunkStart2(sessionId, priorCompartments[priorCompartments.length - 1] ?? null);
|
|
21712
|
+
} catch (error) {
|
|
21713
|
+
if (error instanceof RawOrdinalsNotReady2) {
|
|
21714
|
+
deferUntilOrdinalsReady("chunk start unreadable");
|
|
21715
|
+
return;
|
|
21716
|
+
}
|
|
21717
|
+
throw error;
|
|
21718
|
+
}
|
|
20286
21719
|
let boundarySnapshot = deps.boundarySnapshot ?? null;
|
|
20287
21720
|
if (!boundarySnapshot) {
|
|
20288
21721
|
telemetry.failureReason = "missing protected-tail boundary snapshot";
|
|
@@ -20292,17 +21725,34 @@ async function runCompartmentAgent(deps) {
|
|
|
20292
21725
|
}
|
|
20293
21726
|
let validation = { ok: true };
|
|
20294
21727
|
if (boundarySnapshot.rawRangeFingerprint.length > 0) {
|
|
20295
|
-
|
|
20296
|
-
|
|
20297
|
-
|
|
20298
|
-
|
|
20299
|
-
|
|
21728
|
+
let checked;
|
|
21729
|
+
try {
|
|
21730
|
+
checked = await validateBoundarySnapshotOffThread({
|
|
21731
|
+
db,
|
|
21732
|
+
snapshot: boundarySnapshot,
|
|
21733
|
+
currentContextLimit: deps.currentContextLimit ?? boundarySnapshot.contextLimit
|
|
21734
|
+
});
|
|
21735
|
+
} catch (error) {
|
|
21736
|
+
if (error instanceof RawOrdinalsNotReady2) {
|
|
21737
|
+
deferUntilOrdinalsReady("boundary validation unreadable");
|
|
21738
|
+
return;
|
|
21739
|
+
}
|
|
21740
|
+
throw error;
|
|
21741
|
+
}
|
|
20300
21742
|
if (checked.kind === "not-ready") {
|
|
20301
21743
|
deferUntilOrdinalsReady(`boundary validation ${checked.reason}`);
|
|
20302
21744
|
return;
|
|
20303
21745
|
}
|
|
20304
21746
|
validation = checked.result;
|
|
20305
21747
|
}
|
|
21748
|
+
if (!validation.ok && validation.reason === "stale_snapshot" && shouldRefuseStaleSnapshotForDrift(sessionId, validation.detail)) {
|
|
21749
|
+
dropDriftedServingOrdinalRanks(sessionId, validation.detail ?? validation.reason ?? "stale_snapshot");
|
|
21750
|
+
sessionLog2(sessionId, `historian: refusing to publish over a stale protected-tail snapshot (was: ${validation.detail ?? "stale"}); ending the run without publishing`);
|
|
21751
|
+
telemetry.status = "noop";
|
|
21752
|
+
telemetry.failureReason = "stale_snapshot";
|
|
21753
|
+
rollbackDrainReservation();
|
|
21754
|
+
return;
|
|
21755
|
+
}
|
|
20306
21756
|
if (!validation.ok && validation.reason === "stale_snapshot") {
|
|
20307
21757
|
const refreshed = deps.refreshBoundarySnapshot ? deps.refreshBoundarySnapshot(boundarySnapshot, validation) : resolveOpenCodeProtectedTailBoundary({
|
|
20308
21758
|
db,
|
|
@@ -20389,6 +21839,14 @@ async function runCompartmentAgent(deps) {
|
|
|
20389
21839
|
sessionLog2(sessionId, `historian prompt fit: sized to ${producerModel ?? "unknown"} (${describeHistorianPromptTrim(promptFit)}; requestedChunkTokens=${historianChunkTokens})`);
|
|
20390
21840
|
}
|
|
20391
21841
|
const perRunCap = selectPerRunCap(boundarySnapshot);
|
|
21842
|
+
if (!deps.forceDrainQuota && shouldWaitForNewHistorianHistory(boundarySnapshot, {
|
|
21843
|
+
emergency: getOverflowState(db, sessionId).needsEmergencyRecovery
|
|
21844
|
+
})) {
|
|
21845
|
+
telemetry.status = "noop";
|
|
21846
|
+
telemetry.failureReason = "waiting for new history after no forward progress";
|
|
21847
|
+
sessionLog2(sessionId, "historian no-op: waiting for new history after no forward progress");
|
|
21848
|
+
return;
|
|
21849
|
+
}
|
|
20392
21850
|
const usable = Math.max(1, Math.round(boundarySnapshot.contextLimit * boundarySnapshot.executeThresholdPercentage / 100));
|
|
20393
21851
|
const reserve = deps.forceDrainQuota ? { ok: true, reservation: null } : reserveProtectedTailDrainTokens({
|
|
20394
21852
|
db,
|
|
@@ -20495,6 +21953,12 @@ ${chunkText}`,
|
|
|
20495
21953
|
const maxExistingSequence = priorCompartments.reduce((max, c) => c.sequence > max ? c.sequence : max, -1);
|
|
20496
21954
|
const sequenceOffset = priorCompartments.length === 0 ? 0 : maxExistingSequence + 1;
|
|
20497
21955
|
retainDrainReservationForRetryThrottle = true;
|
|
21956
|
+
if (!deps.forceDrainQuota) {
|
|
21957
|
+
shouldWaitForNewHistorianHistory(boundarySnapshot, {
|
|
21958
|
+
emergency: getOverflowState(db, sessionId).needsEmergencyRecovery,
|
|
21959
|
+
claim: true
|
|
21960
|
+
});
|
|
21961
|
+
}
|
|
20498
21962
|
const validatedPass = await runValidatedHistorianPass({
|
|
20499
21963
|
client,
|
|
20500
21964
|
hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
|
|
@@ -20546,7 +22010,11 @@ ${chunkText}`,
|
|
|
20546
22010
|
sessionLog2(sessionId, `historian failure: source=no-progress reason="historian returned compartments that did not advance past raw message ${offset - 1}" newCompartmentCount=${newCompartments.length} lastNewEnd=${lastNewEnd} priorEnd=${offset - 1}`);
|
|
20547
22011
|
sessionLog2(sessionId, "historian output discarded: reason=no_forward_progress");
|
|
20548
22012
|
const failCount = incrementHistorianFailure(db, sessionId, `no forward progress beyond raw message ${offset - 1}`);
|
|
20549
|
-
|
|
22013
|
+
try {
|
|
22014
|
+
await notifyHistorianIssue(buildHistorianFailureNotice(failCount, `historian made no forward progress beyond raw message ${offset - 1}`));
|
|
22015
|
+
} finally {
|
|
22016
|
+
recordHistorianNoProgress(boundarySnapshot, inEmergency);
|
|
22017
|
+
}
|
|
20550
22018
|
return;
|
|
20551
22019
|
}
|
|
20552
22020
|
retainDrainReservationForRetryThrottle = false;
|
|
@@ -20658,6 +22126,7 @@ ${chunkText}`,
|
|
|
20658
22126
|
db.exec("COMMIT");
|
|
20659
22127
|
published = true;
|
|
20660
22128
|
publishCommitted = true;
|
|
22129
|
+
clearHistorianHistoryWait(sessionId);
|
|
20661
22130
|
finishHistorianPublishStage(sessionId, "publish-txn", transactionStartedAt, "completed", `compartments=${persistedCompartments.length}`);
|
|
20662
22131
|
logSlowWriteTransaction("historian-publish", lockAcquiredAt);
|
|
20663
22132
|
} catch (error) {
|
|
@@ -21793,4 +23262,4 @@ async function executeContextRecomp(deps, options = {}) {
|
|
|
21793
23262
|
return (await executeContextRecompWithResult(deps, options)).message;
|
|
21794
23263
|
}
|
|
21795
23264
|
|
|
21796
|
-
export { denyTaskRoutingToCallerAgents, buildHiddenAgentRegistrations, buildZenReadAgentRegistrations, buildHiddenAgentConfig, getMagicContextBuiltinCommands, formatConfigParseStatusLine, claimConfigParseFailuresOnce, cortexKitUserConfigBasePath, cortexKitProjectConfigBasePath, resolveLegacyConfigSources, migrateMagicContextConfigLocations, getProtectedTokensTierOverrides, loadPluginConfigDetailed, historianRunConfig, dreamerRunConfig, pluginConfigReader, currentPluginConfigReader, withLiveDreamerOutputCap, createDreamerOutputCapSampler, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_EDITOR_SYSTEM_PROMPT, COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, clampProducerAtomChars, producerInputTokenLimit, historianProducerReserve, producerPromptFailureReason, DREAMER_AGENT, DREAMER_RETROSPECTIVE_AGENT, DREAMER_PRIMER_INVESTIGATOR_AGENT, DREAMER_MEMORY_MAPPER_AGENT, DREAMER_CLASSIFIER_AGENT, DREAMER_DOCS_AGENT, DREAMER_REVIEWER_AGENT, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLeaseBestEffort, isCompartmentLeaseHeld, queueM0Mutation, getMaxM0MutationId, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, getUncoveredCompartmentEndsThrough, providerResponseFailed, isSuccessfulProviderCompletion, rememberUnpublishedAutoSearchNoHint, getUnpublishedAutoSearchNoHint, forgetUnpublishedAutoSearchNoHint, registerAutoSearchWork, cancelAutoSearchWork, getOrCreateSessionMeta, updateSessionMeta, advanceToolReclaimWatermark, markSessionCleanupPending, retryPendingSessionCleanups, retryPendingRustSessionCleanupsForProject, clearSession, requestPendingMaterialization, pendingMaterializationOrigin, hasPendingMaterializationOrigin, clearPendingMaterialization, recordSystemPromptForRequest, recordHeldHeadForRequest, bindSystemPromptResponse, isHeldHeadForRequest, deferDeliveredSystemRefresh, retirePendingSystemPromptDelivery, lkgProviderInputTotal, beginV2LkgRequest, claimLkgRequestIdentity, currentLkgRequestIdentity, noteCapturedLkgRequest, noteLkgProviderResponse, measuredLkgPrefix, clearLkgMeasuredRequest, saveLkgSlotToDb, clearPersistedLkgSlotStrict, loadPersistedLkgSlot, drainStaleLkgSlots, createDbLkgPersistence, resolveLkgModelKeys, createLkgEntryProjector, captureLkgSlot, validateAnthropicReasoningRuns, validateLkgSeam, replayLkg, coldStartRawServedIndex, coldStartUncapturedReplay, noteUncertifiedNormalLkg, hasProcessLocalLkgProof, lkgDirtyRevision, rememberLkgDirtyRevision, readPersistedLkgUntaggedInputIds, persistLkgUntaggedInputIds, noteLkgRecoveryPrefix, readLkgRecoveryPrefix, noteLkgHealthyPrefix, lkgRecoveryReplayUnproven, lkgRecoveryEntryUnproven, registerLkgPersistence, beginLkgPass, visitMessageContentFields, contentSnapshotValue, messageContentFields, signatureForFields, exactReusablePrefix, incrementalLkgContentDigests, lkgSlotRejection, captureSlot, getInMemorySlot, getSlot, forgetInMemorySlot, dropSlot, noteEntry, getLkgSlotHeapStats, TOOL_SWEEP_SCOPED_MARKER, useScopedToolSweep, createPreAdoptionToolSweepResolver, copySessionStateForClone, queueMemoryMutation, getMaxMemoryMutationIdForProjects, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, createChildSessionWithFence, HiddenCompletionRefusal, DreamerProviderOutputFailureError, withDreamerModelCooldown, providerOutputFailureFromInvalidManifest, HIDDEN_HISTORIAN_AGENT, HIDDEN_DREAMER_AGENT, HIDDEN_CURATE_AGENT, hiddenAgentFor, hiddenToolLoop, HIDDEN_RUN_DISPOSED_REASON, noteChildOfDisposedInstance, hiddenChildPermissions, registerHiddenChildAgents, hiddenToolCallRefusal, HiddenAgentStepLimit, HiddenChildHook, extractLatestAssistantText, hasLengthCappedOutput, parseProviderModel, modelBodyField, toModelEntry, ModelProducedNoOutputError, noteModelActivityMonitored, noteModelOutputReceived, isPromptTimeoutError, getPromptFailureDetail, raceWithSignal, promptSyncWithValidatedOutputRetry, normalizeSDKResponse, annotateSubagentInvocationError, failedInvocationStatus, sumTokensFromChildMessages, recordChildInvocation, recordPromptSessionError, createPromptAsyncTransport, CTX_NOTE_LIGHT_DESCRIPTION, ACTIVE_TOOL_IDS, systemPromptFingerprint, createPromptSurfaceRuntime, createPromptSurfaceGuidanceEpochCache, setKeepSubagents, teardownChildSession, getCompartmentEvents, runTokenLog, formatRunTokenLog, buildMagicContextSection, getMuralIdentity, getMural, modelKeyAcceptsImages, resolveMuralWire, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, getOpenCodeDbPath, compareOpenCodeMessagesByCanonicalOrder, prepareCompactionMarkerCandidates, removeMcOwnedCompactionMarkers, MARKER_SUMMARY_TEXT, markerUpdateDefinitelyDidNotCut, applyDeferredCompactionMarker, removeCompactionMarkerForSession, checkCompactionMarkerConsistency, extractM0Block, formatDate, TEMPORAL_MARKER_REPLAY_PATTERN, collectTemporalCandidates, injectTemporalMarkers, clearInjectionCache, getVisibleMemoryIds, selectHiddenMessagesAtCompactionSeam, prepareCompartmentInjection, renderCompartmentInjection, MaterializeContentionError, mustMaterialize, trimMemoriesToBudgetV2, renderMemoryBlockV2, materializeM0, hydrateCachedM0Mural, resetPrefixTrimFallbackState, findHostCompactionWindow, capturePrefixTrimSourceOrder, prepareCachedM0M1Replay, hasCompleteCachedM0M1, injectM0M1, resolveHiddenCompletionExecutor, createV1HiddenCompletionExecutor, readCoordinateGeneration, readCoordinateRebaseNotice, formatCoordinateRebaseNotice, rebaseSessionCoordinatesAsync, EMPTY_READ_REPLY, noteTouchedAt, renderGlance, renderNotesById, formatWriteReply, observeNoteNudgeServe, onNoteTrigger, peekNoteNudgeText, markNoteNudgeDelivered, clearNoteNudgeTriggerAndCooldown, resetNoteNudgeCooldownOnly, clearNoteNudgeTriggerOnly, omitIncompleteFileTokenTotals, describeBoundaryDiagnostics, RECOVERY_NO_HEAD_LIMIT, deriveProtectedTailTokenTarget, selectPerRunCap, resolveOpenCodeProtectedTailBoundary, resolveWrapupProtectedTailBoundary, getRawHistoryEligibility, hasRunnableCompartmentWindow, recordHighPressureNoEligibleHead, noteTransformPassForExactOrdinalReads, runCompartmentAgent, snapRangeToCompartments, getActiveCompartmentRun, markActiveCompartmentRunPublished, registerActiveCompartmentRun, startCompartmentAgent, executeContextRecomp };
|
|
23265
|
+
export { denyTaskRoutingToCallerAgents, buildHiddenAgentRegistrations, buildZenReadAgentRegistrations, buildHiddenAgentConfig, getMagicContextBuiltinCommands, formatConfigParseStatusLine, claimConfigParseFailuresOnce, cortexKitUserConfigBasePath, cortexKitProjectConfigBasePath, resolveLegacyConfigSources, migrateMagicContextConfigLocations, getProtectedTokensTierOverrides, loadPluginConfigDetailed, historianRunConfig, dreamerRunConfig, pluginConfigReader, currentPluginConfigReader, withLiveDreamerOutputCap, createDreamerOutputCapSampler, advanceSessionActivity, observeSessionActivity, backfillSessionActivity, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_EDITOR_SYSTEM_PROMPT, COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, clampProducerAtomChars, producerInputTokenLimit, historianProducerReserve, producerPromptFailureReason, DREAMER_AGENT, DREAMER_RETROSPECTIVE_AGENT, DREAMER_PRIMER_INVESTIGATOR_AGENT, DREAMER_MEMORY_MAPPER_AGENT, DREAMER_CLASSIFIER_AGENT, DREAMER_DOCS_AGENT, DREAMER_REVIEWER_AGENT, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLeaseBestEffort, isCompartmentLeaseHeld, queueM0Mutation, getMaxM0MutationId, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, getUncoveredCompartmentEndsThrough, providerResponseFailed, isSuccessfulProviderCompletion, LkgRecoveryFenceError, lkgServedArrayDigest, hasCleanLkgRecoveryFence, dirtyLkgRecoveryRevision, ownsLkgDirtyFence, invalidateCleanLkgRecoveryFence, prepareLkgCaptureFence, certifyCommittedLkgCapture, markLkgRecoveryDirty, rememberUnpublishedAutoSearchNoHint, getUnpublishedAutoSearchNoHint, forgetUnpublishedAutoSearchNoHint, registerAutoSearchWork, cancelAutoSearchWork, gaDatabasePath, RAW_MESSAGE_TYPES, V2StoreReaderPool, V2StoreReader, getOrCreateSessionMeta, updateSessionMeta, advanceToolReclaimWatermark, markSessionCleanupPending, retryPendingSessionCleanups, retryPendingRustSessionCleanupsForProject, clearSession, requestPendingMaterialization, pendingMaterializationOrigin, hasPendingMaterializationOrigin, clearPendingMaterialization, recordSystemPromptForRequest, recordHeldHeadForRequest, bindSystemPromptResponse, isHeldHeadForRequest, deferDeliveredSystemRefresh, retirePendingSystemPromptDelivery, lkgProviderInputTotal, beginV2LkgRequest, claimLkgRequestIdentity, currentLkgRequestIdentity, noteCapturedLkgRequest, noteLkgProviderResponse, measuredLkgPrefix, clearLkgMeasuredRequest, saveLkgSlotToDb, clearPersistedLkgSlotStrict, loadPersistedLkgSlot, drainStaleLkgSlots, createDbLkgPersistence, resolveLkgModelKeys, createLkgEntryProjector, captureLkgSlot, validateAnthropicReasoningRuns, validateLkgSeam, replayLkg, coldStartRawServedIndex, coldStartUncapturedReplay, noteUncertifiedNormalLkg, hasProcessLocalLkgProof, lkgDirtyRevision, rememberLkgDirtyRevision, readPersistedLkgUntaggedInputIds, persistLkgUntaggedInputIds, noteLkgRecoveryPrefix, readLkgRecoveryPrefix, noteLkgHealthyPrefix, lkgRecoveryReplayUnproven, lkgRecoveryEntryUnproven, registerLkgPersistence, beginLkgPass, visitMessageContentFields, contentSnapshotValue, messageContentFields, signatureForFields, exactReusablePrefix, incrementalLkgContentDigests, lkgSlotRejection, captureSlot, getInMemorySlot, getSlot, forgetInMemorySlot, dropSlot, noteEntry, getLkgSlotHeapStats, TOOL_SWEEP_SCOPED_MARKER, useScopedToolSweep, createPreAdoptionToolSweepResolver, copySessionStateForClone, queueMemoryMutation, getMaxMemoryMutationIdForProjects, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, createChildSessionWithFence, HiddenCompletionRefusal, DreamerProviderOutputFailureError, withDreamerModelCooldown, providerOutputFailureFromInvalidManifest, HIDDEN_HISTORIAN_AGENT, HIDDEN_DREAMER_AGENT, HIDDEN_CURATE_AGENT, hiddenAgentFor, hiddenToolLoop, HIDDEN_RUN_DISPOSED_REASON, noteChildOfDisposedInstance, hiddenChildPermissions, registerHiddenChildAgents, hiddenToolCallRefusal, HiddenAgentStepLimit, HiddenChildHook, extractLatestAssistantText, hasLengthCappedOutput, parseProviderModel, modelBodyField, toModelEntry, ModelProducedNoOutputError, noteModelActivityMonitored, noteModelOutputReceived, isPromptTimeoutError, getPromptFailureDetail, raceWithSignal, promptSyncWithValidatedOutputRetry, normalizeSDKResponse, annotateSubagentInvocationError, failedInvocationStatus, sumTokensFromChildMessages, recordChildInvocation, recordPromptSessionError, createPromptAsyncTransport, CTX_NOTE_LIGHT_DESCRIPTION, ACTIVE_TOOL_IDS, systemPromptFingerprint, createPromptSurfaceRuntime, createPromptSurfaceGuidanceEpochCache, setKeepSubagents, teardownChildSession, getCompartmentEvents, runTokenLog, formatRunTokenLog, buildMagicContextSection, getMuralIdentity, getMural, modelKeyAcceptsImages, resolveMuralWire, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, getOpenCodeDbPath, compareOpenCodeMessagesByCanonicalOrder, prepareCompactionMarkerCandidates, removeMcOwnedCompactionMarkers, MARKER_SUMMARY_TEXT, markerUpdateDefinitelyDidNotCut, applyDeferredCompactionMarker, removeCompactionMarkerForSession, checkCompactionMarkerConsistency, extractM0Block, formatDate, TEMPORAL_MARKER_REPLAY_PATTERN, collectTemporalCandidates, injectTemporalMarkers, clearInjectionCache, getVisibleMemoryIds, selectHiddenMessagesAtCompactionSeam, prepareCompartmentInjection, renderCompartmentInjection, MaterializeContentionError, mustMaterialize, trimMemoriesToBudgetV2, renderMemoryBlockV2, materializeM0, hydrateCachedM0Mural, resetPrefixTrimFallbackState, findHostCompactionWindow, capturePrefixTrimSourceOrder, prepareCachedM0M1Replay, hasCompleteCachedM0M1, injectM0M1, resolveHiddenCompletionExecutor, createV1HiddenCompletionExecutor, readCoordinateGeneration, readCoordinateRebaseNotice, formatCoordinateRebaseNotice, rebaseSessionCoordinatesAsync, shouldWaitForNewHistorianHistory, EMPTY_READ_REPLY, noteTouchedAt, renderGlance, renderNotesById, formatWriteReply, observeNoteNudgeServe, onNoteTrigger, peekNoteNudgeText, markNoteNudgeDelivered, clearNoteNudgeTriggerAndCooldown, resetNoteNudgeCooldownOnly, clearNoteNudgeTriggerOnly, omitIncompleteFileTokenTotals, describeBoundaryDiagnostics, RECOVERY_NO_HEAD_LIMIT, deriveProtectedTailTokenTarget, selectPerRunCap, resolveOpenCodeProtectedTailBoundary, resolveWrapupProtectedTailBoundary, getRawHistoryEligibility, hasRunnableCompartmentWindow, recordHighPressureNoEligibleHead, noteTransformPassForExactOrdinalReads, runCompartmentAgent, snapRangeToCompartments, getActiveCompartmentRun, markActiveCompartmentRunPublished, registerActiveCompartmentRun, startCompartmentAgent, executeContextRecomp };
|