@cortexkit/pi-magic-context 0.32.0 → 0.32.1
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/index.js +984 -479
- package/dist/subagent-entry.js +430 -229
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14951,7 +14951,9 @@ __export(exports_rpc_notifications, {
|
|
|
14951
14951
|
registerNotificationSink: () => registerNotificationSink,
|
|
14952
14952
|
pushNotification: () => pushNotification,
|
|
14953
14953
|
isTuiConnected: () => isTuiConnected,
|
|
14954
|
-
drainNotifications: () => drainNotifications
|
|
14954
|
+
drainNotifications: () => drainNotifications,
|
|
14955
|
+
acknowledgeNotifications: () => acknowledgeNotifications,
|
|
14956
|
+
__resetNotificationStateForTests: () => __resetNotificationStateForTests
|
|
14955
14957
|
});
|
|
14956
14958
|
function registerNotificationSink(sink) {
|
|
14957
14959
|
sinks.add(sink);
|
|
@@ -14960,7 +14962,11 @@ function registerNotificationSink(sink) {
|
|
|
14960
14962
|
};
|
|
14961
14963
|
}
|
|
14962
14964
|
function notificationMatchesSink(notification, sink) {
|
|
14963
|
-
|
|
14965
|
+
if (notification.sessionId === undefined)
|
|
14966
|
+
return true;
|
|
14967
|
+
if (sink.sessionId !== undefined)
|
|
14968
|
+
return notification.sessionId === sink.sessionId;
|
|
14969
|
+
return sink.protocol !== 2;
|
|
14964
14970
|
}
|
|
14965
14971
|
function pushNotification(type, payload, sessionId) {
|
|
14966
14972
|
const notification = { id: nextNotificationId++, type, payload, sessionId };
|
|
@@ -14973,23 +14979,31 @@ function pushNotification(type, payload, sessionId) {
|
|
|
14973
14979
|
} catch {}
|
|
14974
14980
|
}
|
|
14975
14981
|
if (queue.length > 100) {
|
|
14976
|
-
const
|
|
14977
|
-
|
|
14978
|
-
|
|
14979
|
-
|
|
14980
|
-
|
|
14981
|
-
|
|
14982
|
-
|
|
14983
|
-
|
|
14984
|
-
|
|
14985
|
-
const kept = [];
|
|
14986
|
-
for (const n of byNewest) {
|
|
14987
|
-
if (kept.length < 50 || mustKeep.has(n.id))
|
|
14988
|
-
kept.push(n);
|
|
14982
|
+
const reservedIds = new Set;
|
|
14983
|
+
const reservedScopes = new Set;
|
|
14984
|
+
for (let i = queue.length - 1;i >= 0 && reservedScopes.size < 25; i -= 1) {
|
|
14985
|
+
const candidate = queue[i];
|
|
14986
|
+
const scope = candidate.sessionId ?? "\x00global";
|
|
14987
|
+
if (reservedScopes.has(scope))
|
|
14988
|
+
continue;
|
|
14989
|
+
reservedScopes.add(scope);
|
|
14990
|
+
reservedIds.add(candidate.id);
|
|
14989
14991
|
}
|
|
14990
|
-
|
|
14992
|
+
const evictionIndex = queue.findIndex((candidate) => !reservedIds.has(candidate.id));
|
|
14993
|
+
queue.splice(evictionIndex >= 0 ? evictionIndex : 0, 1);
|
|
14991
14994
|
}
|
|
14992
14995
|
}
|
|
14996
|
+
function acknowledgeNotifications(ids) {
|
|
14997
|
+
const acknowledged = new Set(ids.filter((id) => Number.isSafeInteger(id) && id > 0));
|
|
14998
|
+
if (acknowledged.size === 0)
|
|
14999
|
+
return;
|
|
15000
|
+
queue = queue.filter((notification) => !acknowledged.has(notification.id));
|
|
15001
|
+
}
|
|
15002
|
+
function __resetNotificationStateForTests() {
|
|
15003
|
+
queue = [];
|
|
15004
|
+
nextNotificationId = 1;
|
|
15005
|
+
sinks.clear();
|
|
15006
|
+
}
|
|
14993
15007
|
function cursor(value) {
|
|
14994
15008
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
14995
15009
|
}
|
|
@@ -15032,7 +15046,9 @@ function isTuiConnected(sessionId) {
|
|
|
15032
15046
|
if (sessionId === undefined)
|
|
15033
15047
|
return true;
|
|
15034
15048
|
for (const sink of sinks) {
|
|
15035
|
-
if (sink.sessionId ===
|
|
15049
|
+
if (sink.sessionId === sessionId)
|
|
15050
|
+
return true;
|
|
15051
|
+
if (sink.sessionId === undefined && sink.protocol !== 2)
|
|
15036
15052
|
return true;
|
|
15037
15053
|
}
|
|
15038
15054
|
return false;
|
|
@@ -16088,11 +16104,11 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
|
|
|
16088
16104
|
}
|
|
16089
16105
|
transaction(fn) {
|
|
16090
16106
|
const self2 = this;
|
|
16091
|
-
const
|
|
16107
|
+
const execute = (mode, receiver, args) => {
|
|
16092
16108
|
const nested = self2.isTransaction === true;
|
|
16093
|
-
self2.exec(nested ? `SAVEPOINT ${SAVEPOINT}` :
|
|
16109
|
+
self2.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : `BEGIN${mode ? ` ${mode}` : ""}`);
|
|
16094
16110
|
try {
|
|
16095
|
-
const result = fn.apply(
|
|
16111
|
+
const result = fn.apply(receiver, args);
|
|
16096
16112
|
self2.exec(nested ? `RELEASE ${SAVEPOINT}` : "COMMIT");
|
|
16097
16113
|
return result;
|
|
16098
16114
|
} catch (error) {
|
|
@@ -16105,6 +16121,21 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
|
|
|
16105
16121
|
throw error;
|
|
16106
16122
|
}
|
|
16107
16123
|
};
|
|
16124
|
+
const wrapped = function(...args) {
|
|
16125
|
+
return execute("", this, args);
|
|
16126
|
+
};
|
|
16127
|
+
wrapped.default = function(...args) {
|
|
16128
|
+
return execute("", this, args);
|
|
16129
|
+
};
|
|
16130
|
+
wrapped.deferred = function(...args) {
|
|
16131
|
+
return execute("DEFERRED", this, args);
|
|
16132
|
+
};
|
|
16133
|
+
wrapped.immediate = function(...args) {
|
|
16134
|
+
return execute("IMMEDIATE", this, args);
|
|
16135
|
+
};
|
|
16136
|
+
wrapped.exclusive = function(...args) {
|
|
16137
|
+
return execute("EXCLUSIVE", this, args);
|
|
16138
|
+
};
|
|
16108
16139
|
return wrapped;
|
|
16109
16140
|
}
|
|
16110
16141
|
}
|
|
@@ -148826,6 +148857,66 @@ function readRawSessionMessagesFromDb(db, sessionId) {
|
|
|
148826
148857
|
};
|
|
148827
148858
|
});
|
|
148828
148859
|
}
|
|
148860
|
+
function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark = Number.MAX_SAFE_INTEGER) {
|
|
148861
|
+
const remaining = Math.max(0, Math.floor(finalWatermark) - Math.floor(afterOrdinal));
|
|
148862
|
+
const pageSize = Math.min(Math.max(1, Math.floor(limit)), remaining);
|
|
148863
|
+
if (pageSize === 0)
|
|
148864
|
+
return [];
|
|
148865
|
+
const messageRows = db.prepare(`SELECT id, data, time_created, time_updated
|
|
148866
|
+
FROM message
|
|
148867
|
+
WHERE session_id = ?
|
|
148868
|
+
AND NOT (
|
|
148869
|
+
CASE WHEN json_valid(data) = 1
|
|
148870
|
+
THEN COALESCE(json_extract(data, '$.summary'), 0)
|
|
148871
|
+
ELSE 0 END = 1
|
|
148872
|
+
AND CASE WHEN json_valid(data) = 1
|
|
148873
|
+
THEN COALESCE(json_extract(data, '$.finish'), '')
|
|
148874
|
+
ELSE '' END = 'stop'
|
|
148875
|
+
)
|
|
148876
|
+
ORDER BY time_created ASC, id ASC
|
|
148877
|
+
LIMIT ? OFFSET ?`).all(sessionId, pageSize, Math.max(0, Math.floor(afterOrdinal))).filter(isRawMessageRow).map((row, index) => ({
|
|
148878
|
+
...row,
|
|
148879
|
+
ordinal: Math.floor(afterOrdinal) + index + 1
|
|
148880
|
+
}));
|
|
148881
|
+
if (messageRows.length === 0)
|
|
148882
|
+
return [];
|
|
148883
|
+
const placeholders = messageRows.map(() => "?").join(", ");
|
|
148884
|
+
const partRows = db.prepare(`SELECT message_id, data, time_updated
|
|
148885
|
+
FROM part
|
|
148886
|
+
WHERE session_id = ? AND message_id IN (${placeholders})
|
|
148887
|
+
ORDER BY time_created ASC, id ASC`).all(sessionId, ...messageRows.map((row) => row.id)).filter(isRawPartRow);
|
|
148888
|
+
const partsByMessageId = new Map;
|
|
148889
|
+
for (const part of partRows) {
|
|
148890
|
+
const list = partsByMessageId.get(part.message_id) ?? [];
|
|
148891
|
+
list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
|
|
148892
|
+
partsByMessageId.set(part.message_id, list);
|
|
148893
|
+
}
|
|
148894
|
+
return messageRows.map((row) => {
|
|
148895
|
+
const info = parseJsonRecord(row.data);
|
|
148896
|
+
return {
|
|
148897
|
+
ordinal: row.ordinal,
|
|
148898
|
+
id: row.id,
|
|
148899
|
+
role: typeof info?.role === "string" ? info.role : "unknown",
|
|
148900
|
+
parts: partsByMessageId.get(row.id) ?? [],
|
|
148901
|
+
createdAt: row.time_created ?? null,
|
|
148902
|
+
version: row.time_updated ?? null
|
|
148903
|
+
};
|
|
148904
|
+
});
|
|
148905
|
+
}
|
|
148906
|
+
function countRawSessionMessageOrdinalsFromDb(db, sessionId) {
|
|
148907
|
+
const row = db.prepare(`SELECT COUNT(*) AS count
|
|
148908
|
+
FROM message
|
|
148909
|
+
WHERE session_id = ?
|
|
148910
|
+
AND NOT (
|
|
148911
|
+
CASE WHEN json_valid(data) = 1
|
|
148912
|
+
THEN COALESCE(json_extract(data, '$.summary'), 0)
|
|
148913
|
+
ELSE 0 END = 1
|
|
148914
|
+
AND CASE WHEN json_valid(data) = 1
|
|
148915
|
+
THEN COALESCE(json_extract(data, '$.finish'), '')
|
|
148916
|
+
ELSE '' END = 'stop'
|
|
148917
|
+
)`).get(sessionId);
|
|
148918
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
148919
|
+
}
|
|
148829
148920
|
function isAnchorRow(row) {
|
|
148830
148921
|
return row !== null && typeof row === "object" && typeof row.time_created === "number" && typeof row.id === "string";
|
|
148831
148922
|
}
|
|
@@ -149133,6 +149224,31 @@ function readRawSessionMessages(sessionId) {
|
|
|
149133
149224
|
}
|
|
149134
149225
|
return readRawSessionMessagesFromSource(sessionId);
|
|
149135
149226
|
}
|
|
149227
|
+
function readRawSessionMessagePage(sessionId, afterOrdinal, limit, finalWatermark) {
|
|
149228
|
+
const provider = sessionProviders.get(sessionId);
|
|
149229
|
+
if (provider?.readMessagePage) {
|
|
149230
|
+
return provider.readMessagePage(afterOrdinal, limit, finalWatermark);
|
|
149231
|
+
}
|
|
149232
|
+
if (provider) {
|
|
149233
|
+
return provider.readMessages().filter((message) => message.ordinal > afterOrdinal && message.ordinal <= finalWatermark).slice(0, limit);
|
|
149234
|
+
}
|
|
149235
|
+
if (!openCodeDbExists())
|
|
149236
|
+
return [];
|
|
149237
|
+
return withReadOnlySessionDb((db) => readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark));
|
|
149238
|
+
}
|
|
149239
|
+
function getRawSessionMessageOrdinalCount(sessionId) {
|
|
149240
|
+
const provider = sessionProviders.get(sessionId);
|
|
149241
|
+
if (provider) {
|
|
149242
|
+
if (provider.getMessageCount)
|
|
149243
|
+
return provider.getMessageCount();
|
|
149244
|
+
return provider.readMessages().length;
|
|
149245
|
+
}
|
|
149246
|
+
if (!openCodeDbExists())
|
|
149247
|
+
return 0;
|
|
149248
|
+
return withReadOnlySessionDb((db) => countRawSessionMessageOrdinalsFromDb(db, sessionId));
|
|
149249
|
+
}
|
|
149250
|
+
readRawSessionMessages.readPage = readRawSessionMessagePage;
|
|
149251
|
+
readRawSessionMessages.getCount = getRawSessionMessageOrdinalCount;
|
|
149136
149252
|
function primeTailRawMessageCache(args) {
|
|
149137
149253
|
const { sessionId, lastCompartmentEnd, anchorMessageId } = args;
|
|
149138
149254
|
if (!activeRawMessageCache)
|
|
@@ -149413,11 +149529,10 @@ function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
|
|
|
149413
149529
|
// ../plugin/src/features/magic-context/message-index.ts
|
|
149414
149530
|
var lastIndexedStatements = new WeakMap;
|
|
149415
149531
|
var insertMessageStatements = new WeakMap;
|
|
149416
|
-
var
|
|
149417
|
-
var upsertCleanIndexStatements = new WeakMap;
|
|
149532
|
+
var upsertProgressStatements = new WeakMap;
|
|
149418
149533
|
var upsertDirtyFloorStatements = new WeakMap;
|
|
149419
149534
|
var deleteFtsStatements = new WeakMap;
|
|
149420
|
-
var
|
|
149535
|
+
var deleteFtsRangeStatements = new WeakMap;
|
|
149421
149536
|
var deleteIndexStatements = new WeakMap;
|
|
149422
149537
|
var countIndexedMessageStatements = new WeakMap;
|
|
149423
149538
|
function normalizeIndexText(text) {
|
|
@@ -149439,19 +149554,11 @@ function getInsertMessageStatement(db) {
|
|
|
149439
149554
|
}
|
|
149440
149555
|
return stmt;
|
|
149441
149556
|
}
|
|
149442
|
-
function
|
|
149443
|
-
let stmt =
|
|
149444
|
-
if (!stmt) {
|
|
149445
|
-
stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, updated_at, harness) VALUES (?, ?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = excluded.last_indexed_ordinal, updated_at = excluded.updated_at");
|
|
149446
|
-
upsertIndexStatements.set(db, stmt);
|
|
149447
|
-
}
|
|
149448
|
-
return stmt;
|
|
149449
|
-
}
|
|
149450
|
-
function getUpsertCleanIndexStatement(db) {
|
|
149451
|
-
let stmt = upsertCleanIndexStatements.get(db);
|
|
149557
|
+
function getUpsertProgressStatement(db) {
|
|
149558
|
+
let stmt = upsertProgressStatements.get(db);
|
|
149452
149559
|
if (!stmt) {
|
|
149453
|
-
stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, dirty_floor_ordinal, updated_at, harness) VALUES (?, ?,
|
|
149454
|
-
|
|
149560
|
+
stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, dirty_floor_ordinal, updated_at, harness) VALUES (?, ?, ?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = excluded.last_indexed_ordinal, dirty_floor_ordinal = excluded.dirty_floor_ordinal, updated_at = excluded.updated_at");
|
|
149561
|
+
upsertProgressStatements.set(db, stmt);
|
|
149455
149562
|
}
|
|
149456
149563
|
return stmt;
|
|
149457
149564
|
}
|
|
@@ -149463,27 +149570,11 @@ function getUpsertDirtyFloorStatement(db) {
|
|
|
149463
149570
|
}
|
|
149464
149571
|
return stmt;
|
|
149465
149572
|
}
|
|
149466
|
-
function
|
|
149467
|
-
let stmt =
|
|
149468
|
-
if (!stmt) {
|
|
149469
|
-
stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ?");
|
|
149470
|
-
deleteFtsStatements.set(db, stmt);
|
|
149471
|
-
}
|
|
149472
|
-
return stmt;
|
|
149473
|
-
}
|
|
149474
|
-
function getDeleteFtsFromOrdinalStatement(db) {
|
|
149475
|
-
let stmt = deleteFtsFromOrdinalStatements.get(db);
|
|
149476
|
-
if (!stmt) {
|
|
149477
|
-
stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ? AND CAST(message_ordinal AS INTEGER) >= ?");
|
|
149478
|
-
deleteFtsFromOrdinalStatements.set(db, stmt);
|
|
149479
|
-
}
|
|
149480
|
-
return stmt;
|
|
149481
|
-
}
|
|
149482
|
-
function getDeleteIndexStatement(db) {
|
|
149483
|
-
let stmt = deleteIndexStatements.get(db);
|
|
149573
|
+
function getDeleteFtsRangeStatement(db) {
|
|
149574
|
+
let stmt = deleteFtsRangeStatements.get(db);
|
|
149484
149575
|
if (!stmt) {
|
|
149485
|
-
stmt = db.prepare("DELETE FROM
|
|
149486
|
-
|
|
149576
|
+
stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ? AND CAST(message_ordinal AS INTEGER) BETWEEN ? AND ?");
|
|
149577
|
+
deleteFtsRangeStatements.set(db, stmt);
|
|
149487
149578
|
}
|
|
149488
149579
|
return stmt;
|
|
149489
149580
|
}
|
|
@@ -149511,16 +149602,17 @@ function isMessageAlreadyIndexed(db, sessionId, messageId) {
|
|
|
149511
149602
|
const row = getCountIndexedMessageStatement(db).get(sessionId, messageId);
|
|
149512
149603
|
return (typeof row?.count === "number" ? row.count : 0) > 0;
|
|
149513
149604
|
}
|
|
149514
|
-
function
|
|
149515
|
-
|
|
149516
|
-
getUpsertIndexStatement(db).run(sessionId, Math.max(current, ordinal), now, getHarness());
|
|
149605
|
+
function setIndexProgress(db, sessionId, watermark, dirtyFloor, now) {
|
|
149606
|
+
getUpsertProgressStatement(db).run(sessionId, Math.max(0, Math.floor(watermark)), dirtyFloor ?? 0, now, getHarness());
|
|
149517
149607
|
}
|
|
149518
|
-
function
|
|
149519
|
-
db
|
|
149520
|
-
|
|
149521
|
-
|
|
149522
|
-
|
|
149523
|
-
|
|
149608
|
+
function getMessageIndexReconciliationStartOrdinal(db, sessionId) {
|
|
149609
|
+
const watermark = getLastIndexedOrdinal(db, sessionId);
|
|
149610
|
+
const dirtyFloor = getDirtyIndexFloor(db, sessionId);
|
|
149611
|
+
return dirtyFloor === null ? watermark : Math.min(watermark, dirtyFloor - 1);
|
|
149612
|
+
}
|
|
149613
|
+
function isMessageIndexReconciledThrough(db, sessionId, finalWatermark) {
|
|
149614
|
+
const dirtyFloor = getDirtyIndexFloor(db, sessionId);
|
|
149615
|
+
return getLastIndexedOrdinal(db, sessionId) >= finalWatermark && dirtyFloor === null;
|
|
149524
149616
|
}
|
|
149525
149617
|
function getIndexableContent(role, parts) {
|
|
149526
149618
|
if (role === "user") {
|
|
@@ -149535,22 +149627,21 @@ function getIndexableContent(role, parts) {
|
|
|
149535
149627
|
return "";
|
|
149536
149628
|
}
|
|
149537
149629
|
function indexSingleMessageInTransaction(db, sessionId, message, now) {
|
|
149538
|
-
|
|
149539
|
-
|
|
149540
|
-
|
|
149541
|
-
}
|
|
149542
|
-
const content = getIndexableContent(message.role, message.parts);
|
|
149543
|
-
if (content.length === 0) {
|
|
149544
|
-
advanceIndexWatermark(db, sessionId, message.ordinal, now);
|
|
149630
|
+
const currentWatermark = getLastIndexedOrdinal(db, sessionId);
|
|
149631
|
+
const dirtyFloor = getDirtyIndexFloor(db, sessionId);
|
|
149632
|
+
if (message.ordinal !== currentWatermark + 1 || dirtyFloor !== null && dirtyFloor !== message.ordinal) {
|
|
149545
149633
|
return false;
|
|
149546
149634
|
}
|
|
149547
|
-
|
|
149548
|
-
|
|
149549
|
-
|
|
149635
|
+
let inserted = false;
|
|
149636
|
+
if (message.role === "user" || message.role === "assistant") {
|
|
149637
|
+
const content = getIndexableContent(message.role, message.parts);
|
|
149638
|
+
if (content.length > 0 && !isMessageAlreadyIndexed(db, sessionId, message.id)) {
|
|
149639
|
+
getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
|
|
149640
|
+
inserted = true;
|
|
149641
|
+
}
|
|
149550
149642
|
}
|
|
149551
|
-
|
|
149552
|
-
|
|
149553
|
-
return true;
|
|
149643
|
+
setIndexProgress(db, sessionId, message.ordinal, null, now);
|
|
149644
|
+
return inserted;
|
|
149554
149645
|
}
|
|
149555
149646
|
function indexSingleMessage(db, sessionId, message) {
|
|
149556
149647
|
db.exec("BEGIN IMMEDIATE");
|
|
@@ -149568,38 +149659,44 @@ function indexSingleMessage(db, sessionId, message) {
|
|
|
149568
149659
|
}
|
|
149569
149660
|
}
|
|
149570
149661
|
}
|
|
149571
|
-
function indexMessagesAfterOrdinal(db, sessionId, messages,
|
|
149662
|
+
function indexMessagesAfterOrdinal(db, sessionId, messages, _lastIndexedOrdinal, finalWatermark = messages.length) {
|
|
149572
149663
|
const now = Date.now();
|
|
149573
149664
|
let inserted = 0;
|
|
149574
149665
|
db.exec("BEGIN IMMEDIATE");
|
|
149575
149666
|
let committed = false;
|
|
149576
149667
|
try {
|
|
149577
|
-
|
|
149668
|
+
const currentWatermark = getLastIndexedOrdinal(db, sessionId);
|
|
149578
149669
|
const dirtyFloor = getDirtyIndexFloor(db, sessionId);
|
|
149579
|
-
|
|
149580
|
-
|
|
149581
|
-
|
|
149582
|
-
getDeleteFtsFromOrdinalStatement(db).run(sessionId, rewindOrdinal);
|
|
149583
|
-
}
|
|
149584
|
-
effectiveWatermark = Math.min(effectiveWatermark, rewindOrdinal - 1);
|
|
149670
|
+
const effectiveWatermark = dirtyFloor === null ? currentWatermark : Math.min(currentWatermark, Math.max(0, dirtyFloor - 1));
|
|
149671
|
+
if (dirtyFloor !== null && dirtyFloor <= finalWatermark) {
|
|
149672
|
+
getDeleteFtsRangeStatement(db).run(sessionId, dirtyFloor, finalWatermark);
|
|
149585
149673
|
}
|
|
149586
|
-
const
|
|
149674
|
+
const messagesByOrdinal = new Map;
|
|
149587
149675
|
for (const message of messages) {
|
|
149588
|
-
if (message.ordinal <=
|
|
149589
|
-
|
|
149676
|
+
if (message.ordinal > effectiveWatermark && message.ordinal <= finalWatermark) {
|
|
149677
|
+
messagesByOrdinal.set(message.ordinal, message);
|
|
149590
149678
|
}
|
|
149591
|
-
|
|
149679
|
+
}
|
|
149680
|
+
let coveredWatermark = effectiveWatermark;
|
|
149681
|
+
while (coveredWatermark < finalWatermark && messagesByOrdinal.has(coveredWatermark + 1)) {
|
|
149682
|
+
coveredWatermark += 1;
|
|
149683
|
+
}
|
|
149684
|
+
for (let ordinal = effectiveWatermark + 1;ordinal <= coveredWatermark; ordinal++) {
|
|
149685
|
+
const message = messagesByOrdinal.get(ordinal);
|
|
149686
|
+
if (!message || message.role !== "user" && message.role !== "assistant") {
|
|
149592
149687
|
continue;
|
|
149593
149688
|
}
|
|
149594
149689
|
const content = getIndexableContent(message.role, message.parts);
|
|
149595
|
-
if (content.length === 0) {
|
|
149690
|
+
if (content.length === 0 || isMessageAlreadyIndexed(db, sessionId, message.id)) {
|
|
149596
149691
|
continue;
|
|
149597
149692
|
}
|
|
149598
|
-
|
|
149599
|
-
inserted
|
|
149693
|
+
getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
|
|
149694
|
+
inserted += 1;
|
|
149600
149695
|
}
|
|
149601
|
-
const
|
|
149602
|
-
|
|
149696
|
+
const missingFloor = coveredWatermark < finalWatermark ? coveredWatermark + 1 : null;
|
|
149697
|
+
const preservedFloor = dirtyFloor !== null && dirtyFloor > finalWatermark ? dirtyFloor : null;
|
|
149698
|
+
const nextDirtyFloor = missingFloor === null ? preservedFloor : preservedFloor === null ? missingFloor : Math.min(missingFloor, preservedFloor);
|
|
149699
|
+
setIndexProgress(db, sessionId, coveredWatermark, nextDirtyFloor, now);
|
|
149603
149700
|
db.exec("COMMIT");
|
|
149604
149701
|
committed = true;
|
|
149605
149702
|
} finally {
|
|
@@ -149630,6 +149727,7 @@ function isDatabaseLockedError(error) {
|
|
|
149630
149727
|
return false;
|
|
149631
149728
|
}
|
|
149632
149729
|
var INCREMENTAL_DEBOUNCE_MS = 100;
|
|
149730
|
+
var RECONCILIATION_BATCH_SIZE = 100;
|
|
149633
149731
|
var reconciledSessions = new Set;
|
|
149634
149732
|
var reconciliationScheduledSessions = new Set;
|
|
149635
149733
|
var sessionLocks = new Map;
|
|
@@ -149644,6 +149742,9 @@ function defer(fn) {
|
|
|
149644
149742
|
}
|
|
149645
149743
|
setTimeout(fn, 0);
|
|
149646
149744
|
}
|
|
149745
|
+
function yieldToEventLoop() {
|
|
149746
|
+
return new Promise((resolve) => defer(resolve));
|
|
149747
|
+
}
|
|
149647
149748
|
function runWithSessionLock(sessionId, operation) {
|
|
149648
149749
|
const previous = sessionLocks.get(sessionId) ?? Promise.resolve();
|
|
149649
149750
|
const run = previous.catch(() => {
|
|
@@ -149670,24 +149771,27 @@ function logIndexingError(sessionId, action, error) {
|
|
|
149670
149771
|
log(`[message-index-async] ${action} failed for ${sessionId}:`, error);
|
|
149671
149772
|
}
|
|
149672
149773
|
async function reconcileSessionIndex(db, sessionId, readMessages) {
|
|
149673
|
-
await runWithSessionLock(sessionId, () => {
|
|
149674
|
-
if (reconciledSessions.has(sessionId))
|
|
149774
|
+
await runWithSessionLock(sessionId, async () => {
|
|
149775
|
+
if (reconciledSessions.has(sessionId))
|
|
149675
149776
|
return;
|
|
149777
|
+
let fallbackSnapshot = null;
|
|
149778
|
+
const finalWatermark = readMessages.getCount ? readMessages.getCount(sessionId) : (fallbackSnapshot = readMessages(sessionId)).length;
|
|
149779
|
+
let cursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
|
|
149780
|
+
while (cursor < finalWatermark) {
|
|
149781
|
+
const pageEnd = Math.min(finalWatermark, cursor + RECONCILIATION_BATCH_SIZE);
|
|
149782
|
+
const messages = readMessages.readPage ? readMessages.readPage(sessionId, cursor, RECONCILIATION_BATCH_SIZE, finalWatermark) : (fallbackSnapshot ?? []).filter((message) => message.ordinal > cursor && message.ordinal <= pageEnd);
|
|
149783
|
+
indexMessagesAfterOrdinal(db, sessionId, messages, cursor, pageEnd);
|
|
149784
|
+
const nextCursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
|
|
149785
|
+
if (nextCursor <= cursor)
|
|
149786
|
+
break;
|
|
149787
|
+
cursor = nextCursor;
|
|
149788
|
+
if (cursor < finalWatermark) {
|
|
149789
|
+
await yieldToEventLoop();
|
|
149790
|
+
}
|
|
149676
149791
|
}
|
|
149677
|
-
|
|
149678
|
-
if (messages.length === 0) {
|
|
149679
|
-
clearIndexedMessages(db, sessionId);
|
|
149792
|
+
if (isMessageIndexReconciledThrough(db, sessionId, finalWatermark)) {
|
|
149680
149793
|
reconciledSessions.add(sessionId);
|
|
149681
|
-
return;
|
|
149682
|
-
}
|
|
149683
|
-
let lastIndexedOrdinal = getLastIndexedOrdinal(db, sessionId);
|
|
149684
|
-
if (lastIndexedOrdinal > messages.length) {
|
|
149685
|
-
clearIndexedMessages(db, sessionId);
|
|
149686
|
-
lastIndexedOrdinal = 0;
|
|
149687
149794
|
}
|
|
149688
|
-
const watermark = Math.min(lastIndexedOrdinal, messages.length);
|
|
149689
|
-
indexMessagesAfterOrdinal(db, sessionId, messages, watermark, messages.length);
|
|
149690
|
-
reconciledSessions.add(sessionId);
|
|
149691
149795
|
});
|
|
149692
149796
|
}
|
|
149693
149797
|
function scheduleReconciliation(db, sessionId, readMessages) {
|
|
@@ -149711,16 +149815,23 @@ function scheduleIncrementalIndex(db, sessionId, messageId, messageSource) {
|
|
|
149711
149815
|
const timer = setTimeout(() => {
|
|
149712
149816
|
incrementalTimers.delete(key);
|
|
149713
149817
|
pendingIncrementalKeys.add(key);
|
|
149714
|
-
let attemptedOrdinal = null;
|
|
149715
149818
|
runWithSessionLock(sessionId, () => {
|
|
149716
149819
|
const message = typeof messageSource === "function" ? messageSource(sessionId, messageId) : messageSource;
|
|
149717
149820
|
if (!message)
|
|
149718
149821
|
return;
|
|
149719
|
-
|
|
149822
|
+
const currentWatermark = getLastIndexedOrdinal(db, sessionId);
|
|
149823
|
+
if (message.ordinal <= currentWatermark && isMessageIndexReconciledThrough(db, sessionId, currentWatermark)) {
|
|
149824
|
+
completedIncrementalKeys.add(key);
|
|
149825
|
+
return;
|
|
149826
|
+
}
|
|
149827
|
+
const wasReconciled = reconciledSessions.delete(sessionId);
|
|
149828
|
+
markMessageIndexDirty(db, sessionId, Math.min(message.ordinal, getLastIndexedOrdinal(db, sessionId) + 1));
|
|
149720
149829
|
indexSingleMessage(db, sessionId, message);
|
|
149830
|
+
if (wasReconciled && isMessageIndexReconciledThrough(db, sessionId, message.ordinal)) {
|
|
149831
|
+
reconciledSessions.add(sessionId);
|
|
149832
|
+
}
|
|
149721
149833
|
completedIncrementalKeys.add(key);
|
|
149722
149834
|
}).catch((error) => {
|
|
149723
|
-
markMessageIndexDirty(db, sessionId, attemptedOrdinal ?? getLastIndexedOrdinal(db, sessionId) + 1);
|
|
149724
149835
|
reconciledSessions.delete(sessionId);
|
|
149725
149836
|
logIndexingError(sessionId, `incremental index for ${messageId}`, error);
|
|
149726
149837
|
}).finally(() => {
|
|
@@ -149860,9 +149971,11 @@ function parseReportedLimit(message) {
|
|
|
149860
149971
|
|
|
149861
149972
|
// ../plugin/src/features/magic-context/session-project-backfill.ts
|
|
149862
149973
|
init_logger();
|
|
149974
|
+
import { randomUUID } from "node:crypto";
|
|
149863
149975
|
import { existsSync as existsSync5 } from "node:fs";
|
|
149864
149976
|
|
|
149865
149977
|
// ../plugin/src/features/magic-context/session-project-storage.ts
|
|
149978
|
+
var SESSION_CHUNK_REPAIR_BATCH_SIZE = 100;
|
|
149866
149979
|
var upsertSessionProjectStatements = new WeakMap;
|
|
149867
149980
|
var repairSessionChunkProjectStatements = new WeakMap;
|
|
149868
149981
|
var repairProjectChunkProjectStatements = new WeakMap;
|
|
@@ -149884,9 +149997,14 @@ function getRepairSessionChunkProjectStatement(db) {
|
|
|
149884
149997
|
if (!stmt) {
|
|
149885
149998
|
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
149886
149999
|
SET project_path = ?
|
|
149887
|
-
WHERE
|
|
149888
|
-
|
|
149889
|
-
|
|
150000
|
+
WHERE id IN (
|
|
150001
|
+
SELECT id
|
|
150002
|
+
FROM compartment_chunk_embeddings
|
|
150003
|
+
WHERE session_id = ?
|
|
150004
|
+
AND harness = ?
|
|
150005
|
+
AND project_path <> ?
|
|
150006
|
+
LIMIT ?
|
|
150007
|
+
)`);
|
|
149890
150008
|
repairSessionChunkProjectStatements.set(db, stmt);
|
|
149891
150009
|
}
|
|
149892
150010
|
return stmt;
|
|
@@ -149924,7 +150042,7 @@ function recordSessionProjectIdentity(db, sessionId, projectPath) {
|
|
|
149924
150042
|
const now = Date.now();
|
|
149925
150043
|
db.transaction(() => {
|
|
149926
150044
|
getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
|
|
149927
|
-
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
|
|
150045
|
+
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath, SESSION_CHUNK_REPAIR_BATCH_SIZE);
|
|
149928
150046
|
})();
|
|
149929
150047
|
}
|
|
149930
150048
|
function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
@@ -149935,18 +150053,30 @@ function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
|
149935
150053
|
|
|
149936
150054
|
// ../plugin/src/features/magic-context/session-project-backfill.ts
|
|
149937
150055
|
var LEASE_TTL_MS = 10 * 60 * 1000;
|
|
150056
|
+
var SESSION_PAGE_SIZE = 100;
|
|
149938
150057
|
var SESSION_QUERY_CHUNK_SIZE = 250;
|
|
149939
|
-
var
|
|
150058
|
+
var YIELD_EVERY_PROCESSED_SESSIONS = 25;
|
|
150059
|
+
var YIELD_EVERY_IDENTITY_RESOLUTIONS = 2;
|
|
149940
150060
|
function ensureBackfillStateTable(db) {
|
|
149941
150061
|
db.exec(`
|
|
149942
150062
|
CREATE TABLE IF NOT EXISTS session_project_backfill_state (
|
|
149943
150063
|
harness TEXT PRIMARY KEY,
|
|
149944
150064
|
status TEXT NOT NULL CHECK (status IN ('running', 'completed')),
|
|
150065
|
+
holder_id TEXT,
|
|
149945
150066
|
started_at INTEGER,
|
|
149946
150067
|
lease_expires_at INTEGER,
|
|
149947
150068
|
completed_at INTEGER
|
|
149948
150069
|
);
|
|
149949
150070
|
`);
|
|
150071
|
+
const columns = db.prepare("PRAGMA table_info(session_project_backfill_state)").all();
|
|
150072
|
+
if (!columns.some((column) => column.name === "holder_id")) {
|
|
150073
|
+
try {
|
|
150074
|
+
db.exec("ALTER TABLE session_project_backfill_state ADD COLUMN holder_id TEXT");
|
|
150075
|
+
} catch (error) {
|
|
150076
|
+
if (!/duplicate column name/i.test(String(error)))
|
|
150077
|
+
throw error;
|
|
150078
|
+
}
|
|
150079
|
+
}
|
|
149950
150080
|
}
|
|
149951
150081
|
function withImmediateTransaction(db, fn) {
|
|
149952
150082
|
db.exec("BEGIN IMMEDIATE");
|
|
@@ -149964,54 +150094,52 @@ function withImmediateTransaction(db, fn) {
|
|
|
149964
150094
|
function defaultYieldFn() {
|
|
149965
150095
|
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
149966
150096
|
}
|
|
149967
|
-
function acquireBackfillLease(db, harness, now) {
|
|
150097
|
+
function acquireBackfillLease(db, harness, holderId, now) {
|
|
149968
150098
|
ensureBackfillStateTable(db);
|
|
149969
150099
|
return withImmediateTransaction(db, () => {
|
|
149970
|
-
const current = db.prepare(`SELECT harness, status, started_at, lease_expires_at, completed_at
|
|
150100
|
+
const current = db.prepare(`SELECT harness, status, holder_id, started_at, lease_expires_at, completed_at
|
|
149971
150101
|
FROM session_project_backfill_state
|
|
149972
150102
|
WHERE harness = ?`).get(harness);
|
|
149973
|
-
if (current?.status === "completed")
|
|
150103
|
+
if (current?.status === "completed")
|
|
149974
150104
|
return "already_completed";
|
|
149975
|
-
}
|
|
149976
150105
|
if (current?.status === "running" && current.lease_expires_at !== null && current.lease_expires_at > now) {
|
|
149977
150106
|
return "blocked_by_lease";
|
|
149978
150107
|
}
|
|
149979
150108
|
db.prepare(`INSERT INTO session_project_backfill_state(
|
|
149980
150109
|
harness,
|
|
149981
150110
|
status,
|
|
150111
|
+
holder_id,
|
|
149982
150112
|
started_at,
|
|
149983
150113
|
lease_expires_at,
|
|
149984
150114
|
completed_at
|
|
149985
150115
|
)
|
|
149986
|
-
VALUES (?, 'running', ?, ?, NULL)
|
|
150116
|
+
VALUES (?, 'running', ?, ?, ?, NULL)
|
|
149987
150117
|
ON CONFLICT(harness) DO UPDATE SET
|
|
149988
150118
|
status = 'running',
|
|
150119
|
+
holder_id = excluded.holder_id,
|
|
149989
150120
|
started_at = excluded.started_at,
|
|
149990
150121
|
lease_expires_at = excluded.lease_expires_at,
|
|
149991
|
-
completed_at = NULL`).run(harness, now, now + LEASE_TTL_MS);
|
|
149992
|
-
return "
|
|
150122
|
+
completed_at = NULL`).run(harness, holderId, now, now + LEASE_TTL_MS);
|
|
150123
|
+
return "acquired";
|
|
149993
150124
|
});
|
|
149994
150125
|
}
|
|
149995
|
-
function renewBackfillLease(db, harness, now) {
|
|
150126
|
+
function renewBackfillLease(db, harness, holderId, now) {
|
|
149996
150127
|
ensureBackfillStateTable(db);
|
|
149997
|
-
db.prepare(`UPDATE session_project_backfill_state
|
|
149998
|
-
|
|
149999
|
-
|
|
150128
|
+
return db.prepare(`UPDATE session_project_backfill_state
|
|
150129
|
+
SET lease_expires_at = ?
|
|
150130
|
+
WHERE harness = ? AND status = 'running' AND holder_id = ?`).run(now + LEASE_TTL_MS, harness, holderId).changes === 1;
|
|
150131
|
+
}
|
|
150132
|
+
function markBackfillCompleted(db, harness, holderId, now) {
|
|
150133
|
+
ensureBackfillStateTable(db);
|
|
150134
|
+
return db.prepare(`UPDATE session_project_backfill_state
|
|
150135
|
+
SET status = 'completed', lease_expires_at = NULL, completed_at = ?
|
|
150136
|
+
WHERE harness = ? AND status = 'running' AND holder_id = ?`).run(now, harness, holderId).changes === 1;
|
|
150000
150137
|
}
|
|
150001
|
-
function
|
|
150138
|
+
function markBackfillRetryPending(db, harness, holderId, now) {
|
|
150002
150139
|
ensureBackfillStateTable(db);
|
|
150003
|
-
db.prepare(`
|
|
150004
|
-
|
|
150005
|
-
|
|
150006
|
-
started_at,
|
|
150007
|
-
lease_expires_at,
|
|
150008
|
-
completed_at
|
|
150009
|
-
)
|
|
150010
|
-
VALUES (?, 'completed', ?, NULL, ?)
|
|
150011
|
-
ON CONFLICT(harness) DO UPDATE SET
|
|
150012
|
-
status = 'completed',
|
|
150013
|
-
lease_expires_at = NULL,
|
|
150014
|
-
completed_at = excluded.completed_at`).run(harness, now, now);
|
|
150140
|
+
return db.prepare(`UPDATE session_project_backfill_state
|
|
150141
|
+
SET lease_expires_at = ?
|
|
150142
|
+
WHERE harness = ? AND status = 'running' AND holder_id = ?`).run(now, harness, holderId).changes === 1;
|
|
150015
150143
|
}
|
|
150016
150144
|
function dedupeSessions(sessions) {
|
|
150017
150145
|
const sessionsById = new Map;
|
|
@@ -150019,14 +150147,7 @@ function dedupeSessions(sessions) {
|
|
|
150019
150147
|
if (!session.sessionId)
|
|
150020
150148
|
continue;
|
|
150021
150149
|
const existing = sessionsById.get(session.sessionId);
|
|
150022
|
-
if (!existing) {
|
|
150023
|
-
sessionsById.set(session.sessionId, {
|
|
150024
|
-
sessionId: session.sessionId,
|
|
150025
|
-
directory: session.directory
|
|
150026
|
-
});
|
|
150027
|
-
continue;
|
|
150028
|
-
}
|
|
150029
|
-
if (!existing.directory && session.directory) {
|
|
150150
|
+
if (!existing || !existing.directory && session.directory) {
|
|
150030
150151
|
sessionsById.set(session.sessionId, {
|
|
150031
150152
|
sessionId: session.sessionId,
|
|
150032
150153
|
directory: session.directory
|
|
@@ -150046,22 +150167,34 @@ function getMappedSessionIds(db, harness, sessions) {
|
|
|
150046
150167
|
FROM session_projects
|
|
150047
150168
|
WHERE harness = ?
|
|
150048
150169
|
AND session_id IN (${placeholders})`).all(harness, ...chunk.map((session) => session.sessionId));
|
|
150049
|
-
for (const row of rows)
|
|
150170
|
+
for (const row of rows)
|
|
150050
150171
|
mapped.add(row.session_id);
|
|
150051
|
-
}
|
|
150052
150172
|
}
|
|
150053
150173
|
return mapped;
|
|
150054
150174
|
}
|
|
150055
|
-
|
|
150175
|
+
function createPageReader(source) {
|
|
150176
|
+
if (typeof source === "function") {
|
|
150177
|
+
return async (afterSessionId, limit) => source(afterSessionId, limit);
|
|
150178
|
+
}
|
|
150179
|
+
const sessions = dedupeSessions(source);
|
|
150180
|
+
let offset = 0;
|
|
150181
|
+
return async (_afterSessionId, limit) => {
|
|
150182
|
+
const page = sessions.slice(offset, offset + limit);
|
|
150183
|
+
offset += page.length;
|
|
150184
|
+
return page;
|
|
150185
|
+
};
|
|
150186
|
+
}
|
|
150187
|
+
async function runSessionProjectBackfill(db, source, options = {}) {
|
|
150056
150188
|
const startedAt = performance.now();
|
|
150057
150189
|
const harness = getHarness();
|
|
150058
150190
|
const now = options.now ?? Date.now;
|
|
150059
150191
|
const resolveIdentity = options.resolveIdentity ?? resolveProjectIdentity;
|
|
150060
150192
|
const yieldFn = options.yieldFn ?? defaultYieldFn;
|
|
150061
|
-
const
|
|
150193
|
+
const holderId = options.holderId ?? randomUUID();
|
|
150194
|
+
const readPage = createPageReader(source);
|
|
150062
150195
|
const result = {
|
|
150063
150196
|
status: "completed",
|
|
150064
|
-
totalSessions:
|
|
150197
|
+
totalSessions: 0,
|
|
150065
150198
|
alreadyMappedSessions: 0,
|
|
150066
150199
|
unmappedSessions: 0,
|
|
150067
150200
|
backfilledSessions: 0,
|
|
@@ -150069,47 +150202,95 @@ async function runSessionProjectBackfill(db, sessions, options = {}) {
|
|
|
150069
150202
|
skippedEmptyDirectories: 0,
|
|
150070
150203
|
durationMs: 0
|
|
150071
150204
|
};
|
|
150072
|
-
const leaseStatus = acquireBackfillLease(db, harness, now());
|
|
150073
|
-
if (leaseStatus !== "
|
|
150205
|
+
const leaseStatus = acquireBackfillLease(db, harness, holderId, now());
|
|
150206
|
+
if (leaseStatus !== "acquired") {
|
|
150074
150207
|
result.status = leaseStatus;
|
|
150075
150208
|
result.durationMs = performance.now() - startedAt;
|
|
150076
150209
|
return result;
|
|
150077
150210
|
}
|
|
150078
|
-
const
|
|
150079
|
-
|
|
150211
|
+
const finishWithLostLease = () => {
|
|
150212
|
+
result.status = "lost_lease";
|
|
150213
|
+
result.durationMs = performance.now() - startedAt;
|
|
150214
|
+
return result;
|
|
150215
|
+
};
|
|
150216
|
+
const yieldAndRenew = async () => {
|
|
150217
|
+
if (!renewBackfillLease(db, harness, holderId, now()))
|
|
150218
|
+
return false;
|
|
150219
|
+
await yieldFn();
|
|
150220
|
+
return renewBackfillLease(db, harness, holderId, now());
|
|
150221
|
+
};
|
|
150080
150222
|
const existenceCache = new Map;
|
|
150081
150223
|
const identityCache2 = new Map;
|
|
150082
|
-
|
|
150083
|
-
|
|
150084
|
-
|
|
150085
|
-
|
|
150086
|
-
|
|
150087
|
-
|
|
150088
|
-
if (
|
|
150089
|
-
|
|
150090
|
-
|
|
150091
|
-
|
|
150092
|
-
|
|
150093
|
-
|
|
150094
|
-
|
|
150095
|
-
|
|
150096
|
-
|
|
150097
|
-
|
|
150098
|
-
|
|
150099
|
-
|
|
150100
|
-
|
|
150101
|
-
|
|
150102
|
-
|
|
150103
|
-
|
|
150104
|
-
|
|
150105
|
-
|
|
150106
|
-
|
|
150224
|
+
const seenSessionIds = new Set;
|
|
150225
|
+
let processedSinceYield = 0;
|
|
150226
|
+
let identityResolutionsSinceYield = 0;
|
|
150227
|
+
let afterSessionId = null;
|
|
150228
|
+
for (;; ) {
|
|
150229
|
+
const sourcePage = await readPage(afterSessionId, SESSION_PAGE_SIZE);
|
|
150230
|
+
if (sourcePage.length === 0)
|
|
150231
|
+
break;
|
|
150232
|
+
afterSessionId = sourcePage.at(-1)?.sessionId ?? afterSessionId;
|
|
150233
|
+
const page = dedupeSessions(sourcePage).filter((session) => {
|
|
150234
|
+
if (seenSessionIds.has(session.sessionId))
|
|
150235
|
+
return false;
|
|
150236
|
+
seenSessionIds.add(session.sessionId);
|
|
150237
|
+
return true;
|
|
150238
|
+
});
|
|
150239
|
+
const mappedSessionIds = getMappedSessionIds(db, harness, page);
|
|
150240
|
+
for (const session of page) {
|
|
150241
|
+
result.totalSessions += 1;
|
|
150242
|
+
processedSinceYield += 1;
|
|
150243
|
+
if (mappedSessionIds.has(session.sessionId)) {
|
|
150244
|
+
result.alreadyMappedSessions += 1;
|
|
150245
|
+
} else {
|
|
150246
|
+
result.unmappedSessions += 1;
|
|
150247
|
+
if (!session.directory) {
|
|
150248
|
+
result.skippedEmptyDirectories += 1;
|
|
150249
|
+
} else {
|
|
150250
|
+
const stillExists = existenceCache.get(session.directory) ?? existsSync5(session.directory);
|
|
150251
|
+
existenceCache.set(session.directory, stillExists);
|
|
150252
|
+
if (!stillExists) {
|
|
150253
|
+
result.skippedDeadDirectories += 1;
|
|
150254
|
+
} else {
|
|
150255
|
+
let identity = identityCache2.get(session.directory);
|
|
150256
|
+
if (!identity) {
|
|
150257
|
+
if (identityResolutionsSinceYield >= YIELD_EVERY_IDENTITY_RESOLUTIONS) {
|
|
150258
|
+
if (!await yieldAndRenew())
|
|
150259
|
+
return finishWithLostLease();
|
|
150260
|
+
processedSinceYield = 0;
|
|
150261
|
+
identityResolutionsSinceYield = 0;
|
|
150262
|
+
}
|
|
150263
|
+
identity = await resolveIdentity(session.directory);
|
|
150264
|
+
identityResolutionsSinceYield += 1;
|
|
150265
|
+
if (!renewBackfillLease(db, harness, holderId, now())) {
|
|
150266
|
+
return finishWithLostLease();
|
|
150267
|
+
}
|
|
150268
|
+
identityCache2.set(session.directory, identity);
|
|
150269
|
+
}
|
|
150270
|
+
recordSessionProjectIdentity(db, session.sessionId, identity);
|
|
150271
|
+
result.backfilledSessions += 1;
|
|
150272
|
+
}
|
|
150273
|
+
}
|
|
150107
150274
|
}
|
|
150275
|
+
if (processedSinceYield >= YIELD_EVERY_PROCESSED_SESSIONS) {
|
|
150276
|
+
if (!await yieldAndRenew())
|
|
150277
|
+
return finishWithLostLease();
|
|
150278
|
+
processedSinceYield = 0;
|
|
150279
|
+
identityResolutionsSinceYield = 0;
|
|
150280
|
+
}
|
|
150281
|
+
}
|
|
150282
|
+
if (sourcePage.length < SESSION_PAGE_SIZE)
|
|
150283
|
+
break;
|
|
150284
|
+
}
|
|
150285
|
+
const hasSkippedSessions = result.skippedDeadDirectories > 0 || result.skippedEmptyDirectories > 0;
|
|
150286
|
+
if (hasSkippedSessions) {
|
|
150287
|
+
if (!markBackfillRetryPending(db, harness, holderId, now())) {
|
|
150288
|
+
return finishWithLostLease();
|
|
150108
150289
|
}
|
|
150109
|
-
|
|
150110
|
-
|
|
150290
|
+
result.status = "retry_pending";
|
|
150291
|
+
} else if (!markBackfillCompleted(db, harness, holderId, now())) {
|
|
150292
|
+
return finishWithLostLease();
|
|
150111
150293
|
}
|
|
150112
|
-
markBackfillCompleted(db, harness, now());
|
|
150113
150294
|
result.durationMs = performance.now() - startedAt;
|
|
150114
150295
|
log(`[session-projects] backfilled ${result.backfilledSessions} of ${result.unmappedSessions} unmapped sessions (skipped ${result.skippedDeadDirectories} dead dirs) in ${Math.round(result.durationMs)}ms`);
|
|
150115
150296
|
return result;
|
|
@@ -150667,10 +150848,16 @@ function healAllNullColumns(db) {
|
|
|
150667
150848
|
healNullIntegerColumns(db);
|
|
150668
150849
|
healMissingMemoryBlockIds(db);
|
|
150669
150850
|
}
|
|
150851
|
+
function getSessionMetaColumns(db) {
|
|
150852
|
+
const rows = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
150853
|
+
return new Set(rows.flatMap((row) => typeof row.name === "string" ? [row.name] : []));
|
|
150854
|
+
}
|
|
150670
150855
|
function healMissingMemoryBlockIds(db) {
|
|
150671
|
-
|
|
150672
|
-
|
|
150673
|
-
|
|
150856
|
+
const columns = getSessionMetaColumns(db);
|
|
150857
|
+
if (!columns.has("memory_block_cache") || !columns.has("memory_block_ids") || !columns.has("memory_block_count")) {
|
|
150858
|
+
return;
|
|
150859
|
+
}
|
|
150860
|
+
db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
|
|
150674
150861
|
}
|
|
150675
150862
|
function healNullTextColumns(db) {
|
|
150676
150863
|
const columns = [
|
|
@@ -150699,10 +150886,11 @@ function healNullTextColumns(db) {
|
|
|
150699
150886
|
["compaction_marker_state", ""],
|
|
150700
150887
|
["key_files", ""]
|
|
150701
150888
|
];
|
|
150889
|
+
const existingColumns = getSessionMetaColumns(db);
|
|
150702
150890
|
for (const [column, fallback] of columns) {
|
|
150703
|
-
|
|
150704
|
-
|
|
150705
|
-
}
|
|
150891
|
+
if (!existingColumns.has(column))
|
|
150892
|
+
continue;
|
|
150893
|
+
db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
|
|
150706
150894
|
}
|
|
150707
150895
|
}
|
|
150708
150896
|
function healNullIntegerColumns(db) {
|
|
@@ -150733,10 +150921,11 @@ function healNullIntegerColumns(db) {
|
|
|
150733
150921
|
["emergency_drain_active", 0],
|
|
150734
150922
|
["historian_drain_failure_at", 0]
|
|
150735
150923
|
];
|
|
150924
|
+
const existingColumns = getSessionMetaColumns(db);
|
|
150736
150925
|
for (const [column, fallback] of columns) {
|
|
150737
|
-
|
|
150738
|
-
|
|
150739
|
-
}
|
|
150926
|
+
if (!existingColumns.has(column))
|
|
150927
|
+
continue;
|
|
150928
|
+
db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
|
|
150740
150929
|
}
|
|
150741
150930
|
}
|
|
150742
150931
|
|
|
@@ -152384,6 +152573,34 @@ var MIGRATIONS = [
|
|
|
152384
152573
|
ensureColumn(db, "session_meta", "wrapup_in_progress_state", "TEXT");
|
|
152385
152574
|
}
|
|
152386
152575
|
}
|
|
152576
|
+
},
|
|
152577
|
+
{
|
|
152578
|
+
version: 51,
|
|
152579
|
+
description: "version tool-owner backfill state and repair legacy NULL session metadata",
|
|
152580
|
+
up(db) {
|
|
152581
|
+
db.exec(`
|
|
152582
|
+
CREATE TABLE IF NOT EXISTS tool_owner_backfill_state (
|
|
152583
|
+
session_id TEXT PRIMARY KEY,
|
|
152584
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'skipped')),
|
|
152585
|
+
started_at INTEGER,
|
|
152586
|
+
lease_expires_at INTEGER,
|
|
152587
|
+
completed_at INTEGER,
|
|
152588
|
+
last_error TEXT
|
|
152589
|
+
);
|
|
152590
|
+
CREATE INDEX IF NOT EXISTS idx_tool_owner_backfill_state_status
|
|
152591
|
+
ON tool_owner_backfill_state(status);
|
|
152592
|
+
`);
|
|
152593
|
+
healAllNullColumns(db);
|
|
152594
|
+
}
|
|
152595
|
+
},
|
|
152596
|
+
{
|
|
152597
|
+
version: 52,
|
|
152598
|
+
description: "persist emergency recovery origin",
|
|
152599
|
+
up(db) {
|
|
152600
|
+
if (tableExists2(db, "session_meta")) {
|
|
152601
|
+
ensureColumn(db, "session_meta", "emergency_recovery_origin", "TEXT DEFAULT ''");
|
|
152602
|
+
}
|
|
152603
|
+
}
|
|
152387
152604
|
}
|
|
152388
152605
|
];
|
|
152389
152606
|
var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -152413,40 +152630,45 @@ function isSiblingMigrationConflict(db, error, version) {
|
|
|
152413
152630
|
}
|
|
152414
152631
|
function runMigrations(db) {
|
|
152415
152632
|
ensureMigrationsTable(db);
|
|
152416
|
-
let
|
|
152417
|
-
|
|
152418
|
-
|
|
152419
|
-
|
|
152420
|
-
}
|
|
152421
|
-
log(`[migrations] current schema version: ${currentVersion}, applying ${pendingMigrations.length} migration(s)`);
|
|
152422
|
-
let migrationIndex = 0;
|
|
152423
|
-
while (migrationIndex < pendingMigrations.length) {
|
|
152424
|
-
const migration = pendingMigrations[migrationIndex];
|
|
152633
|
+
let loggedPlan = false;
|
|
152634
|
+
while (true) {
|
|
152635
|
+
let migration;
|
|
152636
|
+
let currentVersion = 0;
|
|
152425
152637
|
try {
|
|
152426
|
-
db.transaction(() => {
|
|
152638
|
+
const applied = db.transaction(() => {
|
|
152639
|
+
currentVersion = getCurrentVersion(db);
|
|
152640
|
+
migration = MIGRATIONS.find((candidate) => candidate.version > currentVersion);
|
|
152641
|
+
if (!migration)
|
|
152642
|
+
return false;
|
|
152643
|
+
if (!loggedPlan) {
|
|
152644
|
+
const pendingCount = MIGRATIONS.filter((candidate) => candidate.version > currentVersion).length;
|
|
152645
|
+
log(`[migrations] current schema version: ${currentVersion}, applying ${pendingCount} migration(s)`);
|
|
152646
|
+
loggedPlan = true;
|
|
152647
|
+
}
|
|
152427
152648
|
migration.up(db);
|
|
152428
152649
|
db.prepare("INSERT INTO schema_migrations (version, description, applied_at) VALUES (?, ?, ?)").run(migration.version, migration.description, Date.now());
|
|
152429
|
-
|
|
152650
|
+
return true;
|
|
152651
|
+
}).immediate();
|
|
152652
|
+
if (!applied || !migration)
|
|
152653
|
+
break;
|
|
152430
152654
|
log(`[migrations] applied v${migration.version}: ${migration.description}`);
|
|
152431
|
-
migrationIndex += 1;
|
|
152432
152655
|
} catch (error) {
|
|
152433
|
-
if (isSiblingMigrationConflict(db, error, migration.version)) {
|
|
152656
|
+
if (migration && isSiblingMigrationConflict(db, error, migration.version)) {
|
|
152434
152657
|
log(`[migrations] v${migration.version} already applied by sibling instance — resuming with re-read version`);
|
|
152435
152658
|
const reReadVersion = getCurrentVersion(db);
|
|
152436
|
-
if (reReadVersion
|
|
152437
|
-
|
|
152438
|
-
|
|
152439
|
-
}
|
|
152440
|
-
currentVersion = reReadVersion;
|
|
152441
|
-
pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
|
|
152442
|
-
migrationIndex = 0;
|
|
152443
|
-
continue;
|
|
152659
|
+
if (reReadVersion > currentVersion)
|
|
152660
|
+
continue;
|
|
152661
|
+
throw new Error(`Migration v${migration.version} failed: sibling conflict reported but version did not advance. Database may need manual repair.`);
|
|
152444
152662
|
}
|
|
152445
|
-
|
|
152446
|
-
|
|
152663
|
+
const version = migration?.version ?? currentVersion + 1;
|
|
152664
|
+
const description = migration?.description ?? "acquire migration write lock";
|
|
152665
|
+
log(`[migrations] FAILED v${version}: ${description} — ${error instanceof Error ? error.message : String(error)}`);
|
|
152666
|
+
throw new Error(`Migration v${version} failed: ${error instanceof Error ? error.message : String(error)}. Database may need manual repair.`);
|
|
152447
152667
|
}
|
|
152448
152668
|
}
|
|
152449
|
-
|
|
152669
|
+
if (loggedPlan) {
|
|
152670
|
+
log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
|
|
152671
|
+
}
|
|
152450
152672
|
}
|
|
152451
152673
|
// ../plugin/src/features/magic-context/project-docs-hash.ts
|
|
152452
152674
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -152959,7 +153181,8 @@ function countSessionsByStatus(db, status) {
|
|
|
152959
153181
|
function acquireSessionLease(db, sessionId, now) {
|
|
152960
153182
|
const expiresAt = now + LEASE_DURATION_MS;
|
|
152961
153183
|
const result = db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, started_at, lease_expires_at)
|
|
152962
|
-
|
|
153184
|
+
SELECT ?, 'running', ?, ?
|
|
153185
|
+
WHERE EXISTS (SELECT 1 FROM tags WHERE session_id = ?)
|
|
152963
153186
|
ON CONFLICT(session_id) DO UPDATE SET
|
|
152964
153187
|
status = 'running',
|
|
152965
153188
|
started_at = excluded.started_at,
|
|
@@ -152967,7 +153190,7 @@ function acquireSessionLease(db, sessionId, now) {
|
|
|
152967
153190
|
last_error = NULL
|
|
152968
153191
|
WHERE tool_owner_backfill_state.status IN ('pending', 'skipped')
|
|
152969
153192
|
OR (tool_owner_backfill_state.status = 'running'
|
|
152970
|
-
AND tool_owner_backfill_state.lease_expires_at < ?)`).run(sessionId, now, expiresAt, now);
|
|
153193
|
+
AND tool_owner_backfill_state.lease_expires_at < ?)`).run(sessionId, now, expiresAt, sessionId, now);
|
|
152971
153194
|
return (result.changes ?? 0) === 1;
|
|
152972
153195
|
}
|
|
152973
153196
|
function renewSessionLease(db, sessionId, now) {
|
|
@@ -152987,13 +153210,9 @@ function markSessionPendingRetry(db, sessionId) {
|
|
|
152987
153210
|
WHERE session_id = ?`).run(sessionId);
|
|
152988
153211
|
}
|
|
152989
153212
|
function markSessionSkipped(db, sessionId, now, reason) {
|
|
152990
|
-
db.prepare(`
|
|
152991
|
-
|
|
152992
|
-
|
|
152993
|
-
status = 'skipped',
|
|
152994
|
-
completed_at = excluded.completed_at,
|
|
152995
|
-
last_error = excluded.last_error,
|
|
152996
|
-
lease_expires_at = NULL`).run(sessionId, now, reason);
|
|
153213
|
+
db.prepare(`UPDATE tool_owner_backfill_state
|
|
153214
|
+
SET status = 'skipped', completed_at = ?, last_error = ?, lease_expires_at = NULL
|
|
153215
|
+
WHERE session_id = ? AND status = 'running'`).run(now, reason, sessionId);
|
|
152997
153216
|
}
|
|
152998
153217
|
function markSessionErrored(db, sessionId, error) {
|
|
152999
153218
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -153077,7 +153296,7 @@ function applyOwnersForSession(db, sessionId, ownersByCallId) {
|
|
|
153077
153296
|
const result = updateRowStmt.run(ownerId, orphan.id);
|
|
153078
153297
|
rowsUpdated += result.changes ?? 0;
|
|
153079
153298
|
}
|
|
153080
|
-
})();
|
|
153299
|
+
}).immediate();
|
|
153081
153300
|
const rowsLeftNull = db.prepare(`SELECT COUNT(*) AS c FROM tags
|
|
153082
153301
|
WHERE session_id = ? AND type = 'tool'
|
|
153083
153302
|
AND tool_owner_message_id IS NULL`).get(sessionId).c;
|
|
@@ -153127,7 +153346,7 @@ var persistenceByDatabase = new WeakMap;
|
|
|
153127
153346
|
var persistenceErrorByDatabase = new WeakMap;
|
|
153128
153347
|
var pathByDatabase = new WeakMap;
|
|
153129
153348
|
var lastSchemaFenceRejection = null;
|
|
153130
|
-
var LATEST_SUPPORTED_VERSION =
|
|
153349
|
+
var LATEST_SUPPORTED_VERSION = 52;
|
|
153131
153350
|
var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
|
|
153132
153351
|
function ensureSecureStorageDir(dir) {
|
|
153133
153352
|
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
@@ -153820,6 +154039,17 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
153820
154039
|
pi_stable_id_scheme INTEGER
|
|
153821
154040
|
);
|
|
153822
154041
|
|
|
154042
|
+
CREATE TABLE IF NOT EXISTS tool_owner_backfill_state (
|
|
154043
|
+
session_id TEXT PRIMARY KEY,
|
|
154044
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'skipped')),
|
|
154045
|
+
started_at INTEGER,
|
|
154046
|
+
lease_expires_at INTEGER,
|
|
154047
|
+
completed_at INTEGER,
|
|
154048
|
+
last_error TEXT
|
|
154049
|
+
);
|
|
154050
|
+
CREATE INDEX IF NOT EXISTS idx_tool_owner_backfill_state_status
|
|
154051
|
+
ON tool_owner_backfill_state(status);
|
|
154052
|
+
|
|
153823
154053
|
CREATE TABLE IF NOT EXISTS subagent_invocations (
|
|
153824
154054
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
153825
154055
|
session_id TEXT NOT NULL,
|
|
@@ -154053,6 +154283,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
154053
154283
|
ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
|
|
154054
154284
|
ensureColumn(db, "session_meta", "detected_context_limit_model_key", "TEXT");
|
|
154055
154285
|
ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
|
|
154286
|
+
ensureColumn(db, "session_meta", "emergency_recovery_origin", "TEXT DEFAULT ''");
|
|
154056
154287
|
ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
|
|
154057
154288
|
ensureColumn(db, "session_meta", "pending_pi_compaction_marker_state", "TEXT");
|
|
154058
154289
|
ensureColumn(db, "session_meta", "new_work_tokens", "INTEGER NOT NULL DEFAULT 0");
|
|
@@ -155120,13 +155351,17 @@ function clearHistorianFailureState(db, sessionId) {
|
|
|
155120
155351
|
function normalizeDetectedLimitModelKey(modelKey) {
|
|
155121
155352
|
return typeof modelKey === "string" && modelKey.length > 0 ? modelKey : null;
|
|
155122
155353
|
}
|
|
155354
|
+
function normalizeEmergencyRecoveryOrigin(value) {
|
|
155355
|
+
return value === "provider_overflow" || value === "proactive_model_shrink" ? value : null;
|
|
155356
|
+
}
|
|
155123
155357
|
function getOverflowState(db, sessionId, modelKey) {
|
|
155124
|
-
const result = db.prepare("SELECT detected_context_limit, detected_context_limit_model_key, needs_emergency_recovery FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
155358
|
+
const result = db.prepare("SELECT detected_context_limit, detected_context_limit_model_key, needs_emergency_recovery, emergency_recovery_origin FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
155125
155359
|
if (!result) {
|
|
155126
155360
|
return {
|
|
155127
155361
|
detectedContextLimit: 0,
|
|
155128
155362
|
detectedContextLimitModelKey: null,
|
|
155129
|
-
needsEmergencyRecovery: false
|
|
155363
|
+
needsEmergencyRecovery: false,
|
|
155364
|
+
emergencyRecoveryOrigin: null
|
|
155130
155365
|
};
|
|
155131
155366
|
}
|
|
155132
155367
|
const storedModelKey = normalizeDetectedLimitModelKey(result.detected_context_limit_model_key);
|
|
@@ -155134,19 +155369,22 @@ function getOverflowState(db, sessionId, modelKey) {
|
|
|
155134
155369
|
const limit = typeof result.detected_context_limit === "number" && result.detected_context_limit > 0 ? result.detected_context_limit : 0;
|
|
155135
155370
|
const modelMatches = limit > 0 && requestedModelKey && storedModelKey ? requestedModelKey === storedModelKey : true;
|
|
155136
155371
|
const needs = typeof result.needs_emergency_recovery === "number" && result.needs_emergency_recovery > 0;
|
|
155372
|
+
const persistedOrigin = normalizeEmergencyRecoveryOrigin(result.emergency_recovery_origin);
|
|
155373
|
+
const recoveryOrigin = needs ? persistedOrigin ?? (limit > 0 ? "provider_overflow" : null) : null;
|
|
155137
155374
|
return {
|
|
155138
155375
|
detectedContextLimit: modelMatches ? limit : 0,
|
|
155139
155376
|
detectedContextLimitModelKey: storedModelKey,
|
|
155140
|
-
needsEmergencyRecovery: needs
|
|
155377
|
+
needsEmergencyRecovery: needs,
|
|
155378
|
+
emergencyRecoveryOrigin: recoveryOrigin
|
|
155141
155379
|
};
|
|
155142
155380
|
}
|
|
155143
|
-
function recordOverflowDetected(db, sessionId, reportedLimit, modelKey) {
|
|
155381
|
+
function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin = "provider_overflow") {
|
|
155144
155382
|
db.transaction(() => {
|
|
155145
155383
|
ensureSessionMetaRow(db, sessionId);
|
|
155146
155384
|
if (typeof reportedLimit === "number" && reportedLimit > 0) {
|
|
155147
|
-
db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, needs_emergency_recovery = 1, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), sessionId);
|
|
155385
|
+
db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), origin, sessionId);
|
|
155148
155386
|
} else {
|
|
155149
|
-
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 1, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(sessionId);
|
|
155387
|
+
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(origin, sessionId);
|
|
155150
155388
|
}
|
|
155151
155389
|
})();
|
|
155152
155390
|
}
|
|
@@ -155154,9 +155392,9 @@ function clearEmergencyRecovery(db, sessionId) {
|
|
|
155154
155392
|
db.transaction(() => {
|
|
155155
155393
|
ensureSessionMetaRow(db, sessionId);
|
|
155156
155394
|
try {
|
|
155157
|
-
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0, recovery_no_eligible_head_count = 0 WHERE session_id = ?").run(sessionId);
|
|
155395
|
+
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0, emergency_recovery_origin = '', recovery_no_eligible_head_count = 0 WHERE session_id = ?").run(sessionId);
|
|
155158
155396
|
} catch {
|
|
155159
|
-
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0 WHERE session_id = ?").run(sessionId);
|
|
155397
|
+
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0, emergency_recovery_origin = '' WHERE session_id = ?").run(sessionId);
|
|
155160
155398
|
}
|
|
155161
155399
|
})();
|
|
155162
155400
|
}
|
|
@@ -156785,12 +157023,12 @@ async function runDeferredV22Backfill(db, options = {}) {
|
|
|
156785
157023
|
};
|
|
156786
157024
|
}
|
|
156787
157025
|
const resolveIdentity = options.resolveIdentity ?? resolveBackfillIdentity;
|
|
156788
|
-
const
|
|
157026
|
+
const yieldToEventLoop2 = options.yieldToEventLoop ?? defaultYieldToEventLoop;
|
|
156789
157027
|
let lastCursor = parseCursor(readMeta(db, BACKFILL_CURSOR_META_KEY));
|
|
156790
157028
|
let processedRows = 0;
|
|
156791
157029
|
let changedRows = 0;
|
|
156792
157030
|
let failedRows = 0;
|
|
156793
|
-
await
|
|
157031
|
+
await yieldToEventLoop2();
|
|
156794
157032
|
while (true) {
|
|
156795
157033
|
const batch = db.prepare(`SELECT id, project_path, category, normalized_hash, seen_count
|
|
156796
157034
|
FROM memories
|
|
@@ -156812,7 +157050,7 @@ async function runDeferredV22Backfill(db, options = {}) {
|
|
|
156812
157050
|
failedBatchRows.push({ ...row, ...classified });
|
|
156813
157051
|
}
|
|
156814
157052
|
if ((index + 1) % YIELD_EVERY_N_ROWS === 0 && index + 1 < batch.length) {
|
|
156815
|
-
await
|
|
157053
|
+
await yieldToEventLoop2();
|
|
156816
157054
|
}
|
|
156817
157055
|
}
|
|
156818
157056
|
await options.onBatchResolved?.(batch);
|
|
@@ -156871,10 +157109,10 @@ async function runDeferredV22Backfill(db, options = {}) {
|
|
|
156871
157109
|
bumpProjectMemoryEpochInTransaction(db, identity, now);
|
|
156872
157110
|
}
|
|
156873
157111
|
writeMeta(db, BACKFILL_CURSOR_META_KEY, String(finalCursor));
|
|
156874
|
-
})();
|
|
157112
|
+
}).immediate();
|
|
156875
157113
|
processedRows += batch.length;
|
|
156876
157114
|
lastCursor = finalCursor;
|
|
156877
|
-
await
|
|
157115
|
+
await yieldToEventLoop2();
|
|
156878
157116
|
}
|
|
156879
157117
|
const status = updateFinalBackfillStatus(db);
|
|
156880
157118
|
const failureCount = countFailures(db);
|
|
@@ -156916,9 +157154,15 @@ function loadPersistedApiCacheOnce() {
|
|
|
156916
157154
|
const raw = readFileSync4(persistFilePath(), "utf-8");
|
|
156917
157155
|
const obj = JSON.parse(raw);
|
|
156918
157156
|
const map = new Map;
|
|
156919
|
-
for (const [key,
|
|
156920
|
-
|
|
156921
|
-
|
|
157157
|
+
for (const [key, persisted] of Object.entries(obj)) {
|
|
157158
|
+
const limit = typeof persisted === "number" ? persisted : persisted.limit;
|
|
157159
|
+
const inputLimit = typeof persisted === "number" ? undefined : persisted.inputLimit;
|
|
157160
|
+
if (isSaneLimit(limit)) {
|
|
157161
|
+
map.set(key, {
|
|
157162
|
+
limit,
|
|
157163
|
+
inputLimit: isSaneLimit(inputLimit) ? inputLimit : undefined
|
|
157164
|
+
});
|
|
157165
|
+
}
|
|
156922
157166
|
}
|
|
156923
157167
|
if (map.size > 0) {
|
|
156924
157168
|
apiCache = map;
|
|
@@ -173968,10 +174212,10 @@ function civilMinuteKey(date5) {
|
|
|
173968
174212
|
const p = (n, w = 2) => String(n).padStart(w, "0");
|
|
173969
174213
|
return `${p(date5.getFullYear(), 4)}-${p(date5.getMonth() + 1)}-${p(date5.getDate())} ${p(date5.getHours())}:${p(date5.getMinutes())}`;
|
|
173970
174214
|
}
|
|
173971
|
-
function nextOccurrence(cron, after, excludeCivilMinute) {
|
|
174215
|
+
function nextOccurrence(cron, after, excludeCivilMinute, maxSearchMs = MAX_SEARCH_MS) {
|
|
173972
174216
|
const afterMs = after.getTime();
|
|
173973
174217
|
let cursorMs = Math.floor(afterMs / MINUTE_MS) * MINUTE_MS + MINUTE_MS;
|
|
173974
|
-
const capMs = afterMs + MAX_SEARCH_MS;
|
|
174218
|
+
const capMs = afterMs + Math.max(0, Math.min(MAX_SEARCH_MS, maxSearchMs));
|
|
173975
174219
|
while (cursorMs <= capMs) {
|
|
173976
174220
|
const candidate = new Date(cursorMs);
|
|
173977
174221
|
if (matchesCron(cron, candidate)) {
|
|
@@ -173983,14 +174227,14 @@ function nextOccurrence(cron, after, excludeCivilMinute) {
|
|
|
173983
174227
|
}
|
|
173984
174228
|
return null;
|
|
173985
174229
|
}
|
|
173986
|
-
function nextDueAtMs(expression, afterMs, consumedScheduledAtMs) {
|
|
174230
|
+
function nextDueAtMs(expression, afterMs, consumedScheduledAtMs, maxSearchMs = MAX_SEARCH_MS) {
|
|
173987
174231
|
if (expression.trim().length === 0)
|
|
173988
174232
|
return null;
|
|
173989
174233
|
const parsed = parseCron(expression);
|
|
173990
174234
|
if (!parsed.ok)
|
|
173991
174235
|
return null;
|
|
173992
174236
|
const exclude = consumedScheduledAtMs !== undefined ? civilMinuteKey(new Date(consumedScheduledAtMs)) : undefined;
|
|
173993
|
-
const next = nextOccurrence(parsed.cron, new Date(afterMs), exclude);
|
|
174237
|
+
const next = nextOccurrence(parsed.cron, new Date(afterMs), exclude, maxSearchMs);
|
|
173994
174238
|
return next ? next.getTime() : null;
|
|
173995
174239
|
}
|
|
173996
174240
|
|
|
@@ -174385,22 +174629,6 @@ function getInsertEmbeddingStatement(db) {
|
|
|
174385
174629
|
}
|
|
174386
174630
|
return stmt;
|
|
174387
174631
|
}
|
|
174388
|
-
function getClearProjectStatement(db) {
|
|
174389
|
-
let stmt = clearProjectStatements.get(db);
|
|
174390
|
-
if (!stmt) {
|
|
174391
|
-
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ?");
|
|
174392
|
-
clearProjectStatements.set(db, stmt);
|
|
174393
|
-
}
|
|
174394
|
-
return stmt;
|
|
174395
|
-
}
|
|
174396
|
-
function getClearProjectModelStatement(db) {
|
|
174397
|
-
let stmt = clearProjectModelStatements.get(db);
|
|
174398
|
-
if (!stmt) {
|
|
174399
|
-
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ? AND model_id = ?");
|
|
174400
|
-
clearProjectModelStatements.set(db, stmt);
|
|
174401
|
-
}
|
|
174402
|
-
return stmt;
|
|
174403
|
-
}
|
|
174404
174632
|
function getSearchRowsStatement(db, withModel) {
|
|
174405
174633
|
const map2 = withModel ? searchRowsByModelStatements : searchRowsStatements;
|
|
174406
174634
|
let stmt = map2.get(db);
|
|
@@ -174704,12 +174932,6 @@ function replaceCompartmentChunkEmbeddings(db, rows) {
|
|
|
174704
174932
|
}
|
|
174705
174933
|
})();
|
|
174706
174934
|
}
|
|
174707
|
-
function clearChunkEmbeddingsForProject(db, projectPath, modelId) {
|
|
174708
|
-
if (modelId) {
|
|
174709
|
-
return getClearProjectModelStatement(db).run(projectPath, modelId).changes;
|
|
174710
|
-
}
|
|
174711
|
-
return getClearProjectStatement(db).run(projectPath).changes;
|
|
174712
|
-
}
|
|
174713
174935
|
function loadCompartmentChunkEmbeddingsForSearch(db, sessionId, projectPath, modelId) {
|
|
174714
174936
|
if (!modelId) {
|
|
174715
174937
|
throw new Error("loadCompartmentChunkEmbeddingsForSearch requires a current model id");
|
|
@@ -175634,22 +175856,6 @@ function getLoadAllEmbeddingsStatement(db) {
|
|
|
175634
175856
|
}
|
|
175635
175857
|
return stmt;
|
|
175636
175858
|
}
|
|
175637
|
-
function getClearAllEmbeddingsStatement(db) {
|
|
175638
|
-
let stmt = clearAllEmbeddingsStatements.get(db);
|
|
175639
|
-
if (!stmt) {
|
|
175640
|
-
stmt = db.prepare("DELETE FROM memory_embeddings WHERE memory_id IN (SELECT id FROM memories WHERE project_path = ?)");
|
|
175641
|
-
clearAllEmbeddingsStatements.set(db, stmt);
|
|
175642
|
-
}
|
|
175643
|
-
return stmt;
|
|
175644
|
-
}
|
|
175645
|
-
function getClearModelEmbeddingsStatement(db) {
|
|
175646
|
-
let stmt = clearModelEmbeddingsStatements.get(db);
|
|
175647
|
-
if (!stmt) {
|
|
175648
|
-
stmt = db.prepare("DELETE FROM memory_embeddings WHERE model_id = ? AND memory_id IN (SELECT id FROM memories WHERE project_path = ?)");
|
|
175649
|
-
clearModelEmbeddingsStatements.set(db, stmt);
|
|
175650
|
-
}
|
|
175651
|
-
return stmt;
|
|
175652
|
-
}
|
|
175653
175859
|
function saveEmbedding(db, memoryId, embedding, modelId) {
|
|
175654
175860
|
const blob = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
175655
175861
|
getSaveEmbeddingStatement(db).run(memoryId, blob, modelId);
|
|
@@ -175669,12 +175875,6 @@ function loadAllEmbeddings(db, projectPath, modelId) {
|
|
|
175669
175875
|
}
|
|
175670
175876
|
return embeddings;
|
|
175671
175877
|
}
|
|
175672
|
-
function clearEmbeddingsForProject(db, projectPath, modelId) {
|
|
175673
|
-
if (modelId) {
|
|
175674
|
-
return getClearModelEmbeddingsStatement(db).run(modelId, projectPath).changes;
|
|
175675
|
-
}
|
|
175676
|
-
return getClearAllEmbeddingsStatement(db).run(projectPath).changes;
|
|
175677
|
-
}
|
|
175678
175878
|
function getMemoryEmbedCoverage(db, projectPath, modelId) {
|
|
175679
175879
|
const row = db.prepare(`SELECT
|
|
175680
175880
|
COUNT(*) AS total,
|
|
@@ -175691,7 +175891,7 @@ function getMemoryEmbedCoverage(db, projectPath, modelId) {
|
|
|
175691
175891
|
}
|
|
175692
175892
|
|
|
175693
175893
|
// ../plugin/src/features/magic-context/project-embedding-registry.ts
|
|
175694
|
-
import { createHash as createHash8, randomUUID } from "node:crypto";
|
|
175894
|
+
import { createHash as createHash8, randomUUID as randomUUID2 } from "node:crypto";
|
|
175695
175895
|
init_logger();
|
|
175696
175896
|
|
|
175697
175897
|
// ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
|
|
@@ -175747,24 +175947,6 @@ function getCountEmbeddedStatement(db) {
|
|
|
175747
175947
|
}
|
|
175748
175948
|
return stmt;
|
|
175749
175949
|
}
|
|
175750
|
-
function getClearProjectStatement2(db) {
|
|
175751
|
-
let stmt = clearProjectStatements2.get(db);
|
|
175752
|
-
if (!stmt) {
|
|
175753
|
-
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
175754
|
-
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
175755
|
-
clearProjectStatements2.set(db, stmt);
|
|
175756
|
-
}
|
|
175757
|
-
return stmt;
|
|
175758
|
-
}
|
|
175759
|
-
function getClearProjectModelStatement2(db) {
|
|
175760
|
-
let stmt = clearProjectModelStatements2.get(db);
|
|
175761
|
-
if (!stmt) {
|
|
175762
|
-
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
175763
|
-
WHERE model_id = ? AND sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
175764
|
-
clearProjectModelStatements2.set(db, stmt);
|
|
175765
|
-
}
|
|
175766
|
-
return stmt;
|
|
175767
|
-
}
|
|
175768
175950
|
function saveCommitEmbedding(db, sha, embedding, modelId) {
|
|
175769
175951
|
const bytes = new Uint8Array(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
175770
175952
|
getSaveStatement(db).run(sha, bytes, modelId, Date.now());
|
|
@@ -175785,12 +175967,6 @@ function countEmbeddedCommits(db, projectPath, modelId) {
|
|
|
175785
175967
|
const row = getCountEmbeddedStatement(db).get(projectPath, modelId);
|
|
175786
175968
|
return row?.count ?? 0;
|
|
175787
175969
|
}
|
|
175788
|
-
function clearProjectCommitEmbeddings(db, projectPath, modelId) {
|
|
175789
|
-
if (modelId) {
|
|
175790
|
-
return getClearProjectModelStatement2(db).run(modelId, projectPath).changes;
|
|
175791
|
-
}
|
|
175792
|
-
return getClearProjectStatement2(db).run(projectPath).changes;
|
|
175793
|
-
}
|
|
175794
175970
|
|
|
175795
175971
|
// ../plugin/src/features/magic-context/git-commits/storage-git-commits.ts
|
|
175796
175972
|
init_logger();
|
|
@@ -176098,6 +176274,7 @@ var COMMIT_DRAIN_BATCH_SIZE = 16;
|
|
|
176098
176274
|
var COMMIT_DRAIN_MAX_PER_SWEEP = 500;
|
|
176099
176275
|
var CHUNK_DRAIN_BATCH_SIZE = 8;
|
|
176100
176276
|
var EMBEDDING_IDENTITY_GC_GRACE_MS = 14 * 24 * 60 * 60 * 1000;
|
|
176277
|
+
var STALE_EMBEDDING_GC_BATCH_SIZE = 250;
|
|
176101
176278
|
var MAX_WINDOWS_PER_EMBED_CALL = 2;
|
|
176102
176279
|
var SESSION_EMBED_LEASE_RENEWAL_MS = 60 * 1000;
|
|
176103
176280
|
var EMBED_SLICE_RETRY_ATTEMPTS = 3;
|
|
@@ -176326,6 +176503,55 @@ function staleModelsForScope(db, projectIdentity, scope, currentModelId, cutoff)
|
|
|
176326
176503
|
const rows = getStaleIdentityStatement(db, scope).all(projectIdentity, scope, currentModelId, cutoff);
|
|
176327
176504
|
return rows.map((row) => row.modelId).filter((modelId) => typeof modelId === "string");
|
|
176328
176505
|
}
|
|
176506
|
+
function deleteStaleEmbeddingBatch(db, scope, projectIdentity, modelId, limit) {
|
|
176507
|
+
if (scope === "memory") {
|
|
176508
|
+
return db.prepare(`DELETE FROM memory_embeddings
|
|
176509
|
+
WHERE rowid IN (
|
|
176510
|
+
SELECT me.rowid
|
|
176511
|
+
FROM memory_embeddings me
|
|
176512
|
+
JOIN memories m ON m.id = me.memory_id
|
|
176513
|
+
WHERE m.project_path = ? AND me.model_id = ?
|
|
176514
|
+
LIMIT ?
|
|
176515
|
+
)`).run(projectIdentity, modelId, limit).changes;
|
|
176516
|
+
}
|
|
176517
|
+
if (scope === "commit") {
|
|
176518
|
+
return db.prepare(`DELETE FROM git_commit_embeddings
|
|
176519
|
+
WHERE rowid IN (
|
|
176520
|
+
SELECT gce.rowid
|
|
176521
|
+
FROM git_commit_embeddings gce
|
|
176522
|
+
JOIN git_commits gc ON gc.sha = gce.sha
|
|
176523
|
+
WHERE gc.project_path = ? AND gce.model_id = ?
|
|
176524
|
+
LIMIT ?
|
|
176525
|
+
)`).run(projectIdentity, modelId, limit).changes;
|
|
176526
|
+
}
|
|
176527
|
+
return db.prepare(`DELETE FROM compartment_chunk_embeddings
|
|
176528
|
+
WHERE id IN (
|
|
176529
|
+
SELECT id
|
|
176530
|
+
FROM compartment_chunk_embeddings
|
|
176531
|
+
WHERE project_path = ? AND model_id = ?
|
|
176532
|
+
LIMIT ?
|
|
176533
|
+
)`).run(projectIdentity, modelId, limit).changes;
|
|
176534
|
+
}
|
|
176535
|
+
function hasStaleEmbeddingRows(db, scope, projectIdentity, modelId) {
|
|
176536
|
+
if (scope === "memory") {
|
|
176537
|
+
return Boolean(db.prepare(`SELECT 1
|
|
176538
|
+
FROM memory_embeddings me
|
|
176539
|
+
JOIN memories m ON m.id = me.memory_id
|
|
176540
|
+
WHERE m.project_path = ? AND me.model_id = ?
|
|
176541
|
+
LIMIT 1`).get(projectIdentity, modelId));
|
|
176542
|
+
}
|
|
176543
|
+
if (scope === "commit") {
|
|
176544
|
+
return Boolean(db.prepare(`SELECT 1
|
|
176545
|
+
FROM git_commit_embeddings gce
|
|
176546
|
+
JOIN git_commits gc ON gc.sha = gce.sha
|
|
176547
|
+
WHERE gc.project_path = ? AND gce.model_id = ?
|
|
176548
|
+
LIMIT 1`).get(projectIdentity, modelId));
|
|
176549
|
+
}
|
|
176550
|
+
return Boolean(db.prepare(`SELECT 1
|
|
176551
|
+
FROM compartment_chunk_embeddings
|
|
176552
|
+
WHERE project_path = ? AND model_id = ?
|
|
176553
|
+
LIMIT 1`).get(projectIdentity, modelId));
|
|
176554
|
+
}
|
|
176329
176555
|
function sweepStaleEmbeddingIdentitiesForProject(db, projectIdentity, now = Date.now()) {
|
|
176330
176556
|
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
176331
176557
|
const result = {
|
|
@@ -176340,24 +176566,45 @@ function sweepStaleEmbeddingIdentitiesForProject(db, projectIdentity, now = Date
|
|
|
176340
176566
|
return result;
|
|
176341
176567
|
const cutoff = now - EMBEDDING_IDENTITY_GC_GRACE_MS;
|
|
176342
176568
|
const deleteTracking = getDeleteActiveIdentityStatement(db);
|
|
176569
|
+
const scopes = [
|
|
176570
|
+
{
|
|
176571
|
+
scope: "memory",
|
|
176572
|
+
enabled: snapshot.enabled && snapshot.modelId !== "off",
|
|
176573
|
+
currentModelId: snapshot.modelId
|
|
176574
|
+
},
|
|
176575
|
+
{
|
|
176576
|
+
scope: "commit",
|
|
176577
|
+
enabled: snapshot.gitCommitEnabled && snapshot.modelId !== "off",
|
|
176578
|
+
currentModelId: snapshot.modelId
|
|
176579
|
+
},
|
|
176580
|
+
{
|
|
176581
|
+
scope: "chunk",
|
|
176582
|
+
enabled: snapshot.enabled && snapshot.chunkModelId !== "off",
|
|
176583
|
+
currentModelId: snapshot.chunkModelId
|
|
176584
|
+
}
|
|
176585
|
+
];
|
|
176586
|
+
let remainingBudget = STALE_EMBEDDING_GC_BATCH_SIZE;
|
|
176343
176587
|
db.exec("BEGIN IMMEDIATE");
|
|
176344
176588
|
try {
|
|
176345
|
-
|
|
176346
|
-
|
|
176347
|
-
|
|
176348
|
-
|
|
176349
|
-
|
|
176350
|
-
|
|
176351
|
-
|
|
176352
|
-
|
|
176353
|
-
|
|
176354
|
-
|
|
176355
|
-
|
|
176356
|
-
|
|
176357
|
-
|
|
176358
|
-
|
|
176359
|
-
|
|
176360
|
-
|
|
176589
|
+
for (const { scope, enabled, currentModelId } of scopes) {
|
|
176590
|
+
if (!enabled || remainingBudget === 0)
|
|
176591
|
+
continue;
|
|
176592
|
+
for (const modelId of staleModelsForScope(db, projectIdentity, scope, currentModelId, cutoff)) {
|
|
176593
|
+
if (remainingBudget === 0)
|
|
176594
|
+
break;
|
|
176595
|
+
const deleted = deleteStaleEmbeddingBatch(db, scope, projectIdentity, modelId, remainingBudget);
|
|
176596
|
+
remainingBudget -= deleted;
|
|
176597
|
+
if (scope === "memory")
|
|
176598
|
+
result.memoryRowsDeleted += deleted;
|
|
176599
|
+
else if (scope === "commit")
|
|
176600
|
+
result.commitRowsDeleted += deleted;
|
|
176601
|
+
else
|
|
176602
|
+
result.chunkRowsDeleted += deleted;
|
|
176603
|
+
if (!hasStaleEmbeddingRows(db, scope, projectIdentity, modelId)) {
|
|
176604
|
+
result.trackingRowsDeleted += deleteTracking.run(projectIdentity, scope, modelId).changes;
|
|
176605
|
+
} else if (deleted === 0) {
|
|
176606
|
+
remainingBudget = 0;
|
|
176607
|
+
}
|
|
176361
176608
|
}
|
|
176362
176609
|
}
|
|
176363
176610
|
db.exec("COMMIT");
|
|
@@ -176367,9 +176614,8 @@ function sweepStaleEmbeddingIdentitiesForProject(db, projectIdentity, now = Date
|
|
|
176367
176614
|
} catch {}
|
|
176368
176615
|
throw error51;
|
|
176369
176616
|
}
|
|
176370
|
-
if (result.memoryRowsDeleted > 0)
|
|
176617
|
+
if (result.memoryRowsDeleted > 0)
|
|
176371
176618
|
invalidateProject(projectIdentity);
|
|
176372
|
-
}
|
|
176373
176619
|
return result;
|
|
176374
176620
|
}
|
|
176375
176621
|
function registerProjectEmbedding(db, projectIdentity, config2, features, sourceDirectory) {
|
|
@@ -176583,22 +176829,33 @@ async function drainCommitBacklogForProject(db, projectIdentity, deadline) {
|
|
|
176583
176829
|
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
176584
176830
|
if (!snapshot?.gitCommitEnabled)
|
|
176585
176831
|
return 0;
|
|
176586
|
-
const holderId = `embed-sweep-${
|
|
176832
|
+
const holderId = `embed-sweep-${randomUUID2()}`;
|
|
176587
176833
|
const lease = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
|
|
176588
176834
|
if (!lease.acquired) {
|
|
176589
176835
|
return 0;
|
|
176590
176836
|
}
|
|
176591
176837
|
let total = 0;
|
|
176838
|
+
let leaseLost = false;
|
|
176839
|
+
const renewal = setInterval(() => {
|
|
176840
|
+
try {
|
|
176841
|
+
if (!renewGitSweepLease(db, projectIdentity, holderId))
|
|
176842
|
+
leaseLost = true;
|
|
176843
|
+
} catch {}
|
|
176844
|
+
}, SESSION_EMBED_LEASE_RENEWAL_MS);
|
|
176845
|
+
renewal.unref?.();
|
|
176592
176846
|
try {
|
|
176593
|
-
while (Date.now() < deadline && total < COMMIT_DRAIN_MAX_PER_SWEEP) {
|
|
176847
|
+
while (!leaseLost && Date.now() < deadline && total < COMMIT_DRAIN_MAX_PER_SWEEP) {
|
|
176594
176848
|
const embedded = await embedCommitBatch(db, projectIdentity, COMMIT_DRAIN_BATCH_SIZE);
|
|
176595
|
-
if (
|
|
176849
|
+
if (!renewGitSweepLease(db, projectIdentity, holderId))
|
|
176850
|
+
leaseLost = true;
|
|
176851
|
+
if (leaseLost || embedded === 0)
|
|
176596
176852
|
break;
|
|
176597
176853
|
total += embedded;
|
|
176598
176854
|
if (embedded < COMMIT_DRAIN_BATCH_SIZE)
|
|
176599
176855
|
break;
|
|
176600
176856
|
}
|
|
176601
176857
|
} finally {
|
|
176858
|
+
clearInterval(renewal);
|
|
176602
176859
|
releaseGitSweepLease(db, projectIdentity, holderId);
|
|
176603
176860
|
}
|
|
176604
176861
|
return total;
|
|
@@ -176705,13 +176962,23 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
|
|
|
176705
176962
|
const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId);
|
|
176706
176963
|
if (total === 0)
|
|
176707
176964
|
return { status: "nothing", embedded: 0, total: 0 };
|
|
176708
|
-
const holderId = `session-embed-${
|
|
176965
|
+
const holderId = `session-embed-${randomUUID2()}`;
|
|
176709
176966
|
const lease = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
|
|
176710
176967
|
if (!lease.acquired)
|
|
176711
176968
|
return { status: "busy", embedded: 0, total };
|
|
176969
|
+
let leaseLost = false;
|
|
176970
|
+
const drainAbort = new AbortController;
|
|
176971
|
+
const forwardCallerAbort = () => drainAbort.abort();
|
|
176972
|
+
if (options?.signal?.aborted)
|
|
176973
|
+
drainAbort.abort();
|
|
176974
|
+
else
|
|
176975
|
+
options?.signal?.addEventListener("abort", forwardCallerAbort, { once: true });
|
|
176712
176976
|
const renewal = setInterval(() => {
|
|
176713
176977
|
try {
|
|
176714
|
-
renewGitSweepLease(db, projectIdentity, holderId)
|
|
176978
|
+
if (!renewGitSweepLease(db, projectIdentity, holderId)) {
|
|
176979
|
+
leaseLost = true;
|
|
176980
|
+
drainAbort.abort();
|
|
176981
|
+
}
|
|
176715
176982
|
} catch {}
|
|
176716
176983
|
}, SESSION_EMBED_LEASE_RENEWAL_MS);
|
|
176717
176984
|
renewal.unref?.();
|
|
@@ -176725,7 +176992,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
|
|
|
176725
176992
|
try {
|
|
176726
176993
|
options?.onProgress?.({ embedded, total });
|
|
176727
176994
|
for (;; ) {
|
|
176728
|
-
if (
|
|
176995
|
+
if (leaseLost || drainAbort.signal.aborted) {
|
|
176729
176996
|
aborted2 = true;
|
|
176730
176997
|
break;
|
|
176731
176998
|
}
|
|
@@ -176736,7 +177003,13 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
|
|
|
176736
177003
|
embedded: n,
|
|
176737
177004
|
noWork,
|
|
176738
177005
|
failed
|
|
176739
|
-
} = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates,
|
|
177006
|
+
} = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, drainAbort.signal);
|
|
177007
|
+
if (leaseLost || !renewGitSweepLease(db, projectIdentity, holderId)) {
|
|
177008
|
+
leaseLost = true;
|
|
177009
|
+
drainAbort.abort();
|
|
177010
|
+
aborted2 = true;
|
|
177011
|
+
break;
|
|
177012
|
+
}
|
|
176740
177013
|
for (const id of noWork)
|
|
176741
177014
|
skipIds.push(id);
|
|
176742
177015
|
for (const id of failed)
|
|
@@ -176756,6 +177029,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
|
|
|
176756
177029
|
}
|
|
176757
177030
|
} finally {
|
|
176758
177031
|
clearInterval(renewal);
|
|
177032
|
+
options?.signal?.removeEventListener("abort", forwardCallerAbort);
|
|
176759
177033
|
try {
|
|
176760
177034
|
releaseGitSweepLease(db, projectIdentity, holderId);
|
|
176761
177035
|
} catch (error51) {
|
|
@@ -178661,13 +178935,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
178661
178935
|
})).filter((u) => Boolean(u.memoryId) && u.content.length > 0);
|
|
178662
178936
|
const dismissals = (parsed.dismiss_existing ?? []).filter((d) => Boolean(d.memory_id));
|
|
178663
178937
|
const consumeCandidateIds = parsed.consume_candidate_ids ?? [];
|
|
178664
|
-
|
|
178665
|
-
args.db.transaction(() => {
|
|
178666
|
-
if (!peekLeaseHolderAndExpiry(args.db, args.holderId, leaseKey)) {
|
|
178667
|
-
log(`[dreamer] user-memories: commit aborted — lease lost (holder ${args.holderId})`);
|
|
178668
|
-
leaseLostAtCommit = true;
|
|
178669
|
-
return;
|
|
178670
|
-
}
|
|
178938
|
+
runLeaseGuardedWrite(args.db, args.holderId, leaseKey, () => {
|
|
178671
178939
|
for (const promotion of promotions) {
|
|
178672
178940
|
insertUserMemory(args.db, promotion.content, promotion.candidateIds);
|
|
178673
178941
|
}
|
|
@@ -178683,10 +178951,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
178683
178951
|
if (promotions.length > 0 || updates.length > 0 || dismissals.length > 0) {
|
|
178684
178952
|
bumpProjectUserProfileVersion(args.db);
|
|
178685
178953
|
}
|
|
178686
|
-
})
|
|
178687
|
-
if (leaseLostAtCommit) {
|
|
178688
|
-
throw new Error("Dream lease lost during user-memory review commit");
|
|
178689
|
-
}
|
|
178954
|
+
});
|
|
178690
178955
|
result.promoted = promotions.length;
|
|
178691
178956
|
result.merged = updates.length;
|
|
178692
178957
|
result.dismissed = dismissals.length;
|
|
@@ -179220,7 +179485,7 @@ init_logger();
|
|
|
179220
179485
|
// ../plugin/src/features/magic-context/smart-notes/capabilities.ts
|
|
179221
179486
|
import { execFile as execFile2 } from "node:child_process";
|
|
179222
179487
|
import { constants as fsConstants } from "node:fs";
|
|
179223
|
-
import { open as open2, realpath } from "node:fs/promises";
|
|
179488
|
+
import { lstat, open as open2, realpath } from "node:fs/promises";
|
|
179224
179489
|
import path8 from "node:path";
|
|
179225
179490
|
import { promisify as promisify2 } from "node:util";
|
|
179226
179491
|
|
|
@@ -179355,16 +179620,19 @@ async function resolveHostToValidatedGlobalAddresses(rawHostname, signal, resolv
|
|
|
179355
179620
|
if (candidates.length === 0) {
|
|
179356
179621
|
throw new SmartNoteSecurityError("DNS resolution returned no addresses");
|
|
179357
179622
|
}
|
|
179358
|
-
const
|
|
179623
|
+
const ipv4Candidates = candidates.filter((candidate) => candidate.family !== 6 && !candidate.address.includes(":"));
|
|
179624
|
+
if (ipv4Candidates.length === 0) {
|
|
179625
|
+
throw new SmartNoteNetworkError("SMART_NOTE_NETWORK: IPv6 destinations are not permitted");
|
|
179626
|
+
}
|
|
179627
|
+
const classified = ipv4Candidates.map((candidate) => {
|
|
179359
179628
|
const parsed = parseIpLiteral(candidate.address);
|
|
179360
|
-
if (
|
|
179361
|
-
throw new SmartNoteSecurityError(`DNS returned an unparsable address: ${candidate.address}`);
|
|
179629
|
+
if (parsed?.family !== 4) {
|
|
179630
|
+
throw new SmartNoteSecurityError(`DNS returned an unparsable IPv4 address: ${candidate.address}`);
|
|
179362
179631
|
}
|
|
179363
|
-
const global = isGlobalAddress(parsed);
|
|
179364
179632
|
return {
|
|
179365
179633
|
address: parsed.address,
|
|
179366
179634
|
family: parsed.family,
|
|
179367
|
-
global
|
|
179635
|
+
global: isGlobalAddress(parsed)
|
|
179368
179636
|
};
|
|
179369
179637
|
});
|
|
179370
179638
|
if (classified.some((candidate) => !candidate.global)) {
|
|
@@ -179387,6 +179655,7 @@ function createPinnedLookup(candidate) {
|
|
|
179387
179655
|
return hook;
|
|
179388
179656
|
}
|
|
179389
179657
|
function requestValidatedAddress(validation, candidate, options) {
|
|
179658
|
+
const agent = createSmartNoteRequestAgent();
|
|
179390
179659
|
return new Promise((resolve, reject) => {
|
|
179391
179660
|
const url2 = validation.url;
|
|
179392
179661
|
const hostHeader = url2.host;
|
|
@@ -179403,6 +179672,7 @@ function requestValidatedAddress(validation, candidate, options) {
|
|
|
179403
179672
|
Accept: "text/plain, application/json;q=0.9, */*;q=0.1"
|
|
179404
179673
|
},
|
|
179405
179674
|
lookup: createPinnedLookup(candidate),
|
|
179675
|
+
agent,
|
|
179406
179676
|
timeout: options.timeoutMs
|
|
179407
179677
|
}, (response) => {
|
|
179408
179678
|
const chunks = [];
|
|
@@ -179447,7 +179717,10 @@ function requestValidatedAddress(validation, candidate, options) {
|
|
|
179447
179717
|
});
|
|
179448
179718
|
request2.on("close", () => options.signal.removeEventListener("abort", onAbort));
|
|
179449
179719
|
request2.end();
|
|
179450
|
-
});
|
|
179720
|
+
}).finally(() => agent.destroy());
|
|
179721
|
+
}
|
|
179722
|
+
function createSmartNoteRequestAgent() {
|
|
179723
|
+
return new https.Agent({ keepAlive: false, maxSockets: 1 });
|
|
179451
179724
|
}
|
|
179452
179725
|
function canonicalDnsName(hostname3) {
|
|
179453
179726
|
const ascii = domainToASCII(hostname3);
|
|
@@ -179630,32 +179903,64 @@ function normalizeRepoPath(repoRelativePath) {
|
|
|
179630
179903
|
}
|
|
179631
179904
|
async function guardedReadFile(projectRoot, repoRelativePath, signal, fileLimitBytes) {
|
|
179632
179905
|
throwIfAborted2(signal);
|
|
179906
|
+
const body = guardedReadFileBody(projectRoot, repoRelativePath, signal, fileLimitBytes);
|
|
179907
|
+
let onAbort;
|
|
179908
|
+
const abort = new Promise((_, reject) => {
|
|
179909
|
+
onAbort = () => reject(abortError(signal));
|
|
179910
|
+
if (signal.aborted)
|
|
179911
|
+
onAbort();
|
|
179912
|
+
else
|
|
179913
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
179914
|
+
});
|
|
179915
|
+
try {
|
|
179916
|
+
return await Promise.race([body, abort]);
|
|
179917
|
+
} finally {
|
|
179918
|
+
if (onAbort)
|
|
179919
|
+
signal.removeEventListener("abort", onAbort);
|
|
179920
|
+
}
|
|
179921
|
+
}
|
|
179922
|
+
async function guardedReadFileBody(projectRoot, repoRelativePath, signal, fileLimitBytes) {
|
|
179633
179923
|
const normalized = normalizeRepoPath(repoRelativePath);
|
|
179634
179924
|
if (!normalized || isSecretDeniedPath(normalized))
|
|
179635
179925
|
return null;
|
|
179636
179926
|
const rootReal = await realpath(projectRoot).catch(() => null);
|
|
179927
|
+
throwIfAborted2(signal);
|
|
179637
179928
|
if (!rootReal)
|
|
179638
179929
|
return null;
|
|
179639
179930
|
const target = path8.resolve(rootReal, normalized);
|
|
179640
179931
|
if (!isPathInside(rootReal, target))
|
|
179641
179932
|
return null;
|
|
179642
179933
|
const parentReal = await realpath(path8.dirname(target)).catch(() => null);
|
|
179934
|
+
throwIfAborted2(signal);
|
|
179643
179935
|
if (!parentReal || !isPathInside(rootReal, parentReal))
|
|
179644
179936
|
return null;
|
|
179937
|
+
const canonicalTarget = path8.join(parentReal, path8.basename(target));
|
|
179938
|
+
const canonicalRelative = normalizeRepoPath(path8.relative(rootReal, canonicalTarget));
|
|
179939
|
+
if (!canonicalRelative || !isPathInside(rootReal, canonicalTarget) || isSecretDeniedPath(canonicalRelative)) {
|
|
179940
|
+
return null;
|
|
179941
|
+
}
|
|
179942
|
+
const targetStat = await lstat(canonicalTarget).catch((error51) => {
|
|
179943
|
+
if (isNoFollowOrMissing(error51))
|
|
179944
|
+
return null;
|
|
179945
|
+
throw error51;
|
|
179946
|
+
});
|
|
179947
|
+
throwIfAborted2(signal);
|
|
179948
|
+
if (!targetStat?.isFile() || targetStat.size > fileLimitBytes)
|
|
179949
|
+
return null;
|
|
179645
179950
|
const noFollow = typeof fsConstants.O_NOFOLLOW === "number" ? fsConstants.O_NOFOLLOW : 0;
|
|
179646
|
-
const
|
|
179951
|
+
const nonBlock = typeof fsConstants.O_NONBLOCK === "number" ? fsConstants.O_NONBLOCK : 0;
|
|
179952
|
+
const openPromise = open2(canonicalTarget, fsConstants.O_RDONLY | noFollow | nonBlock).catch((error51) => {
|
|
179647
179953
|
if (isNoFollowOrMissing(error51))
|
|
179648
179954
|
return null;
|
|
179649
179955
|
throw error51;
|
|
179650
179956
|
});
|
|
179957
|
+
const handle = await closeLateOpenOnAbort(openPromise, signal);
|
|
179651
179958
|
if (!handle)
|
|
179652
179959
|
return null;
|
|
179653
179960
|
try {
|
|
179654
179961
|
throwIfAborted2(signal);
|
|
179655
179962
|
const stat2 = await handle.stat();
|
|
179656
|
-
if (!stat2.isFile())
|
|
179657
|
-
return null;
|
|
179658
|
-
if (stat2.size > fileLimitBytes)
|
|
179963
|
+
if (!stat2.isFile() || stat2.size > fileLimitBytes)
|
|
179659
179964
|
return null;
|
|
179660
179965
|
const buffer2 = Buffer.alloc(stat2.size);
|
|
179661
179966
|
const { bytesRead } = await handle.read(buffer2, 0, stat2.size, 0);
|
|
@@ -179665,6 +179970,17 @@ async function guardedReadFile(projectRoot, repoRelativePath, signal, fileLimitB
|
|
|
179665
179970
|
await handle.close().catch(() => {});
|
|
179666
179971
|
}
|
|
179667
179972
|
}
|
|
179973
|
+
async function closeLateOpenOnAbort(openPromise, signal) {
|
|
179974
|
+
const handle = await openPromise;
|
|
179975
|
+
if (!signal.aborted)
|
|
179976
|
+
return handle;
|
|
179977
|
+
if (handle)
|
|
179978
|
+
handle.close().catch(() => {});
|
|
179979
|
+
throw abortError(signal);
|
|
179980
|
+
}
|
|
179981
|
+
function abortError(signal) {
|
|
179982
|
+
return signal.reason instanceof SmartNoteNetworkError ? signal.reason : new SmartNoteNetworkError("SMART_NOTE_NETWORK: aborted");
|
|
179983
|
+
}
|
|
179668
179984
|
function isPathInside(root, target) {
|
|
179669
179985
|
const relative = path8.relative(root, target);
|
|
179670
179986
|
return relative === "" || !relative.startsWith("..") && !path8.isAbsolute(relative);
|
|
@@ -179787,6 +180103,8 @@ function withSandboxLock(fn) {
|
|
|
179787
180103
|
var DEFAULT_TIMEOUT_MS = 2000;
|
|
179788
180104
|
var DEFAULT_HEAP_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
179789
180105
|
var DEFAULT_STACK_LIMIT_BYTES = 512 * 1024;
|
|
180106
|
+
var MAX_COMPILED_CHECK_BYTES = 64 * 1024;
|
|
180107
|
+
var MAX_SANDBOX_ERROR_CHARS = 2 * 1024;
|
|
179790
180108
|
function resolveCapabilitiesForRun(options, signal) {
|
|
179791
180109
|
if (options.capabilityFactory) {
|
|
179792
180110
|
return options.capabilityFactory(signal);
|
|
@@ -179802,18 +180120,29 @@ function throwIfRunAborted(signal) {
|
|
|
179802
180120
|
}
|
|
179803
180121
|
}
|
|
179804
180122
|
async function runCompiledSmartNoteCheck(options) {
|
|
180123
|
+
if (options.signal?.aborted)
|
|
180124
|
+
return cancelledResult(options.signal.reason);
|
|
180125
|
+
if (Buffer.byteLength(options.compiledCheck, "utf8") > MAX_COMPILED_CHECK_BYTES) {
|
|
180126
|
+
return failureResult("compiled check exceeds 64 KiB", false);
|
|
180127
|
+
}
|
|
179805
180128
|
return withSandboxLock(() => runCompiledSmartNoteCheckLocked(options));
|
|
179806
180129
|
}
|
|
179807
180130
|
async function runCompiledSmartNoteCheckLocked(options) {
|
|
180131
|
+
if (options.signal?.aborted)
|
|
180132
|
+
return cancelledResult(options.signal.reason);
|
|
179808
180133
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
179809
180134
|
const controller = new AbortController;
|
|
179810
|
-
|
|
179811
|
-
|
|
179812
|
-
|
|
179813
|
-
|
|
179814
|
-
options.signal?.
|
|
179815
|
-
}
|
|
179816
|
-
|
|
180135
|
+
let externallyCancelled = false;
|
|
180136
|
+
let executionTimedOut = false;
|
|
180137
|
+
const externalAbort = () => {
|
|
180138
|
+
externallyCancelled = true;
|
|
180139
|
+
controller.abort(options.signal?.reason);
|
|
180140
|
+
};
|
|
180141
|
+
options.signal?.addEventListener("abort", externalAbort, { once: true });
|
|
180142
|
+
const timer = setTimeout(() => {
|
|
180143
|
+
executionTimedOut = true;
|
|
180144
|
+
controller.abort(new Error("smart-note check timed out"));
|
|
180145
|
+
}, timeoutMs);
|
|
179817
180146
|
try {
|
|
179818
180147
|
throwIfRunAborted(controller.signal);
|
|
179819
180148
|
const capabilities = resolveCapabilitiesForRun(options, controller.signal);
|
|
@@ -179830,23 +180159,38 @@ async function runCompiledSmartNoteCheckLocked(options) {
|
|
|
179830
180159
|
const result = await evalCheck(context, options.compiledCheck);
|
|
179831
180160
|
const checkResult = result;
|
|
179832
180161
|
if (!checkResult || typeof checkResult.met !== "boolean") {
|
|
179833
|
-
return
|
|
180162
|
+
return failureResult("check() must return { met: boolean }", false);
|
|
179834
180163
|
}
|
|
179835
180164
|
return { ok: true, result: { met: checkResult.met } };
|
|
179836
180165
|
} finally {
|
|
179837
180166
|
context.dispose();
|
|
179838
180167
|
}
|
|
179839
180168
|
} catch (error51) {
|
|
179840
|
-
|
|
179841
|
-
|
|
179842
|
-
|
|
179843
|
-
network: isSmartNoteNetworkError(error51)
|
|
179844
|
-
};
|
|
180169
|
+
if (externallyCancelled && !executionTimedOut)
|
|
180170
|
+
return cancelledResult(error51);
|
|
180171
|
+
return failureResult(formatSandboxError(error51), isSmartNoteNetworkError(error51));
|
|
179845
180172
|
} finally {
|
|
179846
180173
|
clearTimeout(timer);
|
|
179847
180174
|
options.signal?.removeEventListener("abort", externalAbort);
|
|
179848
180175
|
}
|
|
179849
180176
|
}
|
|
180177
|
+
function failureResult(error51, network) {
|
|
180178
|
+
return { ok: false, cancelled: false, error: truncate(error51), network };
|
|
180179
|
+
}
|
|
180180
|
+
function cancelledResult(reason) {
|
|
180181
|
+
return {
|
|
180182
|
+
ok: false,
|
|
180183
|
+
cancelled: true,
|
|
180184
|
+
error: truncate(reason instanceof Error ? reason.message : String(reason ?? "cancelled")),
|
|
180185
|
+
network: false
|
|
180186
|
+
};
|
|
180187
|
+
}
|
|
180188
|
+
function formatSandboxError(error51) {
|
|
180189
|
+
return error51 instanceof Error ? `${error51.name}: ${error51.message}` : String(error51);
|
|
180190
|
+
}
|
|
180191
|
+
function truncate(value) {
|
|
180192
|
+
return value.slice(0, MAX_SANDBOX_ERROR_CHARS);
|
|
180193
|
+
}
|
|
179850
180194
|
function installCapabilityObject(context, cap) {
|
|
179851
180195
|
const capObject = context.newObject();
|
|
179852
180196
|
try {
|
|
@@ -179922,9 +180266,15 @@ JSON.stringify({ met: __result.met });`;
|
|
|
179922
180266
|
}
|
|
179923
180267
|
|
|
179924
180268
|
// ../plugin/src/features/magic-context/smart-notes/compiler.ts
|
|
180269
|
+
var MAX_COMPILER_OUTPUT_CHARS = 128 * 1024;
|
|
180270
|
+
var MAX_COMPILED_CHECK_BYTES2 = 64 * 1024;
|
|
180271
|
+
var MAX_MANIFEST_ENTRIES = 64;
|
|
180272
|
+
var MAX_CRON_CHARS = 256;
|
|
180273
|
+
var MAX_COMPILER_ERROR_CHARS = 2 * 1024;
|
|
179925
180274
|
async function compileSmartNoteCheck(args) {
|
|
179926
|
-
if (!args.note.surfaceCondition)
|
|
179927
|
-
return { ok: false, error: "note has no surface condition" };
|
|
180275
|
+
if (!args.note.surfaceCondition) {
|
|
180276
|
+
return { ok: false, cancelled: false, error: "note has no surface condition" };
|
|
180277
|
+
}
|
|
179928
180278
|
const prompt = `Compile this smart note condition into a sandbox check.
|
|
179929
180279
|
|
|
179930
180280
|
Project identity: ${args.projectIdentity}
|
|
@@ -179998,6 +180348,7 @@ Remember: output only the JSON object described by the system prompt.`;
|
|
|
179998
180348
|
const response = run.validated;
|
|
179999
180349
|
const compiledCheck = normalizeCompiledCheck(response.compiled_check);
|
|
180000
180350
|
const manifest = normalizeManifest(response.manifest);
|
|
180351
|
+
const checkCron = normalizeCron(response.check_cron);
|
|
180001
180352
|
for (const warning of manifestAdvisoryWarnings(compiledCheck, manifest)) {
|
|
180002
180353
|
log(`[dreamer] smart note #${args.note.id}: manifest advisory — ${warning}`);
|
|
180003
180354
|
}
|
|
@@ -180008,11 +180359,15 @@ Remember: output only the JSON object described by the system prompt.`;
|
|
|
180008
180359
|
timeoutMs: 2000
|
|
180009
180360
|
});
|
|
180010
180361
|
if (!dryRun.ok) {
|
|
180011
|
-
|
|
180012
|
-
|
|
180362
|
+
const error51 = boundedError(`dry-run failed: ${dryRun.error}`);
|
|
180363
|
+
recordInvocation2({
|
|
180364
|
+
status: dryRun.cancelled ? "aborted" : "failed",
|
|
180365
|
+
messages: run.output,
|
|
180366
|
+
error: error51
|
|
180367
|
+
});
|
|
180368
|
+
return { ok: false, cancelled: dryRun.cancelled, error: error51 };
|
|
180013
180369
|
}
|
|
180014
180370
|
recordInvocation2({ status: "completed", messages: run.output });
|
|
180015
|
-
const checkCron = normalizeCron(response.check_cron);
|
|
180016
180371
|
return {
|
|
180017
180372
|
ok: true,
|
|
180018
180373
|
compiledCheck,
|
|
@@ -180022,8 +180377,10 @@ Remember: output only the JSON object described by the system prompt.`;
|
|
|
180022
180377
|
dryRun: dryRun.result
|
|
180023
180378
|
};
|
|
180024
180379
|
} catch (error51) {
|
|
180025
|
-
|
|
180026
|
-
|
|
180380
|
+
const cancelled = args.signal.aborted;
|
|
180381
|
+
const message = boundedError(error51 instanceof Error ? error51.message : String(error51));
|
|
180382
|
+
recordInvocation2({ status: cancelled ? "aborted" : "failed", error: message });
|
|
180383
|
+
return { ok: false, cancelled, error: message };
|
|
180027
180384
|
} finally {
|
|
180028
180385
|
if (childSessionId) {
|
|
180029
180386
|
await args.client.session.delete({ path: { id: childSessionId } }).catch(() => {});
|
|
@@ -180033,6 +180390,9 @@ Remember: output only the JSON object described by the system prompt.`;
|
|
|
180033
180390
|
function parseCompilerOutput(output) {
|
|
180034
180391
|
if (!output)
|
|
180035
180392
|
throw new Error("smart-note compiler returned no output");
|
|
180393
|
+
if (output.length > MAX_COMPILER_OUTPUT_CHARS) {
|
|
180394
|
+
throw new Error("smart-note compiler output exceeds 128 KiB");
|
|
180395
|
+
}
|
|
180036
180396
|
const json2 = extractJsonObject(output);
|
|
180037
180397
|
const parsed = JSON.parse(json2);
|
|
180038
180398
|
if (typeof parsed.compiled_check !== "string")
|
|
@@ -180044,6 +180404,9 @@ function parseCompilerOutput(output) {
|
|
|
180044
180404
|
return parsed;
|
|
180045
180405
|
}
|
|
180046
180406
|
function normalizeCompiledCheck(source) {
|
|
180407
|
+
if (Buffer.byteLength(source, "utf8") > MAX_COMPILED_CHECK_BYTES2) {
|
|
180408
|
+
throw new Error("compiled_check exceeds 64 KiB");
|
|
180409
|
+
}
|
|
180047
180410
|
let code = source.trim();
|
|
180048
180411
|
const fence = code.match(/^```(?:javascript|js)?\s*([\s\S]*?)```$/i);
|
|
180049
180412
|
if (fence)
|
|
@@ -180058,14 +180421,17 @@ function normalizeCompiledCheck(source) {
|
|
|
180058
180421
|
if (/\b(?:import|require)\b/.test(code)) {
|
|
180059
180422
|
throw new Error("compiled_check must not import modules");
|
|
180060
180423
|
}
|
|
180424
|
+
if (Buffer.byteLength(code, "utf8") > MAX_COMPILED_CHECK_BYTES2) {
|
|
180425
|
+
throw new Error("compiled_check exceeds 64 KiB");
|
|
180426
|
+
}
|
|
180061
180427
|
return code;
|
|
180062
180428
|
}
|
|
180063
180429
|
function normalizeManifest(manifest) {
|
|
180064
|
-
const capabilities = Array.isArray(manifest.capabilities) ? unique(manifest.capabilities.filter((cap) => ["readFile", "gitHeadSha", "gitTag", "gitLog", "httpGet"].includes(String(cap)))) : [];
|
|
180430
|
+
const capabilities = Array.isArray(manifest.capabilities) ? unique(manifest.capabilities.slice(0, MAX_MANIFEST_ENTRIES).filter((cap) => ["readFile", "gitHeadSha", "gitTag", "gitLog", "httpGet"].includes(String(cap)))) : [];
|
|
180065
180431
|
return {
|
|
180066
180432
|
capabilities,
|
|
180067
180433
|
readFiles: uniqueStrings(manifest.readFiles),
|
|
180068
|
-
hosts: uniqueStrings(manifest.hosts
|
|
180434
|
+
hosts: uniqueStrings(manifest.hosts, (host) => host.toLowerCase()),
|
|
180069
180435
|
urls: uniqueStrings(manifest.urls),
|
|
180070
180436
|
signals: uniqueStrings(manifest.signals),
|
|
180071
180437
|
summary: typeof manifest.summary === "string" ? manifest.summary.slice(0, 160) : undefined
|
|
@@ -180131,25 +180497,36 @@ function literalCalls(code, method) {
|
|
|
180131
180497
|
return values;
|
|
180132
180498
|
}
|
|
180133
180499
|
function normalizeCron(cron) {
|
|
180134
|
-
|
|
180135
|
-
|
|
180500
|
+
if (cron.length > MAX_CRON_CHARS)
|
|
180501
|
+
throw new Error("check_cron exceeds 256 characters");
|
|
180502
|
+
const normalized = cron.trim() || "0 * * * *";
|
|
180503
|
+
const parsed = parseCron(normalized);
|
|
180504
|
+
if (!parsed.ok)
|
|
180505
|
+
throw new Error(`invalid check_cron: ${parsed.error}`);
|
|
180506
|
+
const next = nextOccurrence(parsed.cron, new Date, undefined, SMART_NOTE_CHECK_CEILING_MS);
|
|
180507
|
+
if (!next)
|
|
180508
|
+
throw new Error("check_cron has no occurrence within the scheduling ceiling");
|
|
180509
|
+
return normalized;
|
|
180136
180510
|
}
|
|
180137
180511
|
function unique(items) {
|
|
180138
180512
|
return [...new Set(items)];
|
|
180139
180513
|
}
|
|
180140
|
-
function uniqueStrings(items) {
|
|
180514
|
+
function uniqueStrings(items, normalize = (value) => value) {
|
|
180141
180515
|
if (!Array.isArray(items))
|
|
180142
180516
|
return;
|
|
180143
|
-
const values = unique(items.filter((item) => typeof item === "string" && item.length > 0));
|
|
180517
|
+
const values = unique(items.slice(0, MAX_MANIFEST_ENTRIES).filter((item) => typeof item === "string" && item.length > 0).map(normalize));
|
|
180144
180518
|
return values.length > 0 ? values : undefined;
|
|
180145
180519
|
}
|
|
180520
|
+
function boundedError(error51) {
|
|
180521
|
+
return error51.slice(0, MAX_COMPILER_ERROR_CHARS);
|
|
180522
|
+
}
|
|
180146
180523
|
|
|
180147
180524
|
// ../plugin/src/features/magic-context/smart-notes/schedule.ts
|
|
180148
180525
|
function nextSmartNoteCheckDueAt(cron, options = {}) {
|
|
180149
180526
|
const now = options.now ?? Date.now();
|
|
180150
180527
|
const floorMs = options.floorMs ?? SMART_NOTE_CHECK_FLOOR_MS;
|
|
180151
180528
|
const ceilingMs = options.ceilingMs ?? SMART_NOTE_CHECK_CEILING_MS;
|
|
180152
|
-
const rawNext = cron?.trim() ? nextDueAtMs(cron, now) : null;
|
|
180529
|
+
const rawNext = cron?.trim() ? nextDueAtMs(cron, now, undefined, ceilingMs) : null;
|
|
180153
180530
|
const rawDelta = rawNext ? rawNext - now : SMART_NOTE_CHECK_DEFAULT_INTERVAL_MS;
|
|
180154
180531
|
const clamped = Math.min(ceilingMs, Math.max(floorMs, rawDelta));
|
|
180155
180532
|
const jittered = clamped + deterministicJitterMs(clamped, options.noteId, options.hash);
|
|
@@ -180171,6 +180548,7 @@ function deterministicJitterMs(intervalMs, noteId, hash2) {
|
|
|
180171
180548
|
}
|
|
180172
180549
|
|
|
180173
180550
|
// ../plugin/src/features/magic-context/smart-notes/storage.ts
|
|
180551
|
+
init_logger();
|
|
180174
180552
|
function toSmartNote(note) {
|
|
180175
180553
|
return {
|
|
180176
180554
|
...note,
|
|
@@ -180183,11 +180561,13 @@ function toSmartNote(note) {
|
|
|
180183
180561
|
function commitSmartNoteState(db, args) {
|
|
180184
180562
|
db.exec("BEGIN IMMEDIATE");
|
|
180185
180563
|
let leaseLost = false;
|
|
180564
|
+
let committed = false;
|
|
180186
180565
|
try {
|
|
180187
180566
|
if (args.leaseHeld && !args.leaseHeld()) {
|
|
180188
180567
|
leaseLost = true;
|
|
180189
|
-
} else {
|
|
180568
|
+
} else if (claimExpectedState(db, args.expected)) {
|
|
180190
180569
|
args.write();
|
|
180570
|
+
committed = true;
|
|
180191
180571
|
}
|
|
180192
180572
|
db.exec("COMMIT");
|
|
180193
180573
|
} catch (error51) {
|
|
@@ -180199,6 +180579,30 @@ function commitSmartNoteState(db, args) {
|
|
|
180199
180579
|
if (leaseLost) {
|
|
180200
180580
|
throw new Error(`Dream lease lost during smart-note ${args.phase} commit`);
|
|
180201
180581
|
}
|
|
180582
|
+
if (!committed) {
|
|
180583
|
+
log(`[debug] smart note #${args.expected.noteId}: discarded stale ${args.phase} result`);
|
|
180584
|
+
}
|
|
180585
|
+
return committed;
|
|
180586
|
+
}
|
|
180587
|
+
function claimExpectedState(db, expected) {
|
|
180588
|
+
if (expected.kind === "compiled-check") {
|
|
180589
|
+
return db.prepare(`UPDATE notes SET id = id
|
|
180590
|
+
WHERE id = ? AND type = 'smart' AND status = 'pending'
|
|
180591
|
+
AND check_status = 'compiled' AND compiled_check = ?
|
|
180592
|
+
AND check_hash IS ? AND check_compiled_at IS ?`).run(expected.noteId, expected.compiledCheck, expected.checkHash, expected.checkCompiledAt).changes > 0;
|
|
180593
|
+
}
|
|
180594
|
+
const statusClause = expected.checkStatus ? " AND check_status = ?" : "";
|
|
180595
|
+
const params = [
|
|
180596
|
+
expected.noteId,
|
|
180597
|
+
expected.content,
|
|
180598
|
+
expected.surfaceCondition,
|
|
180599
|
+
expected.updatedAt
|
|
180600
|
+
];
|
|
180601
|
+
if (expected.checkStatus)
|
|
180602
|
+
params.push(expected.checkStatus);
|
|
180603
|
+
return db.prepare(`UPDATE notes SET id = id
|
|
180604
|
+
WHERE id = ? AND type = 'smart' AND status = 'pending'
|
|
180605
|
+
AND content = ? AND surface_condition IS ? AND updated_at = ?${statusClause}`).run(...params).changes > 0;
|
|
180202
180606
|
}
|
|
180203
180607
|
function getDueCompiledSmartNoteChecks(db, projectPath, now, limit) {
|
|
180204
180608
|
return getPendingSmartNotes(db, projectPath).map(toSmartNote).filter((note) => note.checkStatus === "compiled" && note.compiledCheck !== null && note.policyVersion === SMART_NOTE_CHECK_POLICY_VERSION && (note.checkQuarantinedUntil === null || note.checkQuarantinedUntil <= now) && (note.checkNextDueAt === null || note.checkNextDueAt <= now)).sort((a, b) => (a.checkNextDueAt ?? 0) - (b.checkNextDueAt ?? 0) || a.id - b.id).slice(0, Math.max(1, limit));
|
|
@@ -180316,13 +180720,19 @@ async function runDueCompiledSmartNoteChecks(args) {
|
|
|
180316
180720
|
break;
|
|
180317
180721
|
if (!note.compiledCheck)
|
|
180318
180722
|
continue;
|
|
180723
|
+
const compiledCheck = note.compiledCheck;
|
|
180319
180724
|
ran++;
|
|
180320
180725
|
const controller = new AbortController;
|
|
180726
|
+
const abortFromCaller = () => controller.abort(args.signal?.reason);
|
|
180727
|
+
if (args.signal?.aborted)
|
|
180728
|
+
abortFromCaller();
|
|
180729
|
+
else
|
|
180730
|
+
args.signal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
180321
180731
|
const remaining = Math.max(500, (args.sweepBudgetMs ?? DEFAULT_SWEEP_BUDGET_MS) - (Date.now() - startedAt));
|
|
180322
180732
|
const timer = setTimeout(() => controller.abort(new Error("smart-note sweep budget exhausted")), remaining);
|
|
180323
180733
|
try {
|
|
180324
180734
|
const result = await runCompiledSmartNoteCheck({
|
|
180325
|
-
compiledCheck
|
|
180735
|
+
compiledCheck,
|
|
180326
180736
|
capabilityFactory: (signal) => createSmartNoteCapabilities({
|
|
180327
180737
|
projectRoot: args.projectRoot,
|
|
180328
180738
|
signal
|
|
@@ -180331,48 +180741,67 @@ async function runDueCompiledSmartNoteChecks(args) {
|
|
|
180331
180741
|
timeoutMs: Math.min(2000, remaining)
|
|
180332
180742
|
});
|
|
180333
180743
|
const runFinishedAt = Date.now();
|
|
180744
|
+
const expected = {
|
|
180745
|
+
kind: "compiled-check",
|
|
180746
|
+
noteId: note.id,
|
|
180747
|
+
compiledCheck,
|
|
180748
|
+
checkHash: note.checkHash,
|
|
180749
|
+
checkCompiledAt: note.checkCompiledAt
|
|
180750
|
+
};
|
|
180751
|
+
if (!result.ok && result.cancelled) {
|
|
180752
|
+
continue;
|
|
180753
|
+
}
|
|
180334
180754
|
if (result.ok && result.result.met) {
|
|
180335
|
-
commitSmartNoteState(args.db, {
|
|
180755
|
+
const committed = commitSmartNoteState(args.db, {
|
|
180336
180756
|
phase: "due check",
|
|
180757
|
+
expected,
|
|
180337
180758
|
leaseHeld,
|
|
180338
180759
|
write: () => {
|
|
180339
180760
|
markNoteReady(args.db, note.id, hostGeneratedReadyReason(note.id, note.manifestJson));
|
|
180340
180761
|
}
|
|
180341
180762
|
});
|
|
180342
|
-
|
|
180763
|
+
if (committed)
|
|
180764
|
+
surfaced++;
|
|
180343
180765
|
} else if (result.ok) {
|
|
180766
|
+
const nextDueAt = nextSmartNoteCheckDueAt(note.checkCron, {
|
|
180767
|
+
now: runFinishedAt,
|
|
180768
|
+
noteId: note.id,
|
|
180769
|
+
hash: note.checkHash
|
|
180770
|
+
});
|
|
180344
180771
|
commitSmartNoteState(args.db, {
|
|
180345
180772
|
phase: "due check",
|
|
180773
|
+
expected,
|
|
180346
180774
|
leaseHeld,
|
|
180347
180775
|
write: () => {
|
|
180348
|
-
markCompiledCheckFalse(args.db, note.id,
|
|
180349
|
-
now: runFinishedAt,
|
|
180350
|
-
noteId: note.id,
|
|
180351
|
-
hash: note.checkHash
|
|
180352
|
-
}), runFinishedAt);
|
|
180776
|
+
markCompiledCheckFalse(args.db, note.id, nextDueAt, runFinishedAt);
|
|
180353
180777
|
}
|
|
180354
180778
|
});
|
|
180355
180779
|
} else if (result.network) {
|
|
180356
|
-
commitSmartNoteState(args.db, {
|
|
180780
|
+
const committed = commitSmartNoteState(args.db, {
|
|
180357
180781
|
phase: "network failure",
|
|
180782
|
+
expected,
|
|
180358
180783
|
leaseHeld,
|
|
180359
180784
|
write: () => {
|
|
180360
180785
|
markCompiledCheckNetworkFailure(args.db, note.id, runFinishedAt, MAX_FAILURES_BEFORE_REAUTHOR);
|
|
180361
180786
|
}
|
|
180362
180787
|
});
|
|
180363
|
-
|
|
180788
|
+
if (committed)
|
|
180789
|
+
networkFailed++;
|
|
180364
180790
|
} else {
|
|
180365
|
-
commitSmartNoteState(args.db, {
|
|
180791
|
+
const committed = commitSmartNoteState(args.db, {
|
|
180366
180792
|
phase: "logic failure",
|
|
180793
|
+
expected,
|
|
180367
180794
|
leaseHeld,
|
|
180368
180795
|
write: () => {
|
|
180369
180796
|
markCompiledCheckLogicFailure(args.db, note.id, runFinishedAt, MAX_FAILURES_BEFORE_REAUTHOR);
|
|
180370
180797
|
}
|
|
180371
180798
|
});
|
|
180372
|
-
|
|
180799
|
+
if (committed)
|
|
180800
|
+
failed++;
|
|
180373
180801
|
}
|
|
180374
180802
|
} finally {
|
|
180375
180803
|
clearTimeout(timer);
|
|
180804
|
+
args.signal?.removeEventListener("abort", abortFromCaller);
|
|
180376
180805
|
}
|
|
180377
180806
|
}
|
|
180378
180807
|
return { ran, surfaced, failed, networkFailed };
|
|
@@ -180437,7 +180866,8 @@ async function evaluateSmartNotes(args) {
|
|
|
180437
180866
|
projectRoot,
|
|
180438
180867
|
maxChecks: 10,
|
|
180439
180868
|
sweepBudgetMs: 1e4,
|
|
180440
|
-
leaseHeld
|
|
180869
|
+
leaseHeld,
|
|
180870
|
+
signal: leaseAbortController.signal
|
|
180441
180871
|
});
|
|
180442
180872
|
surfaced += dueRun.surfaced;
|
|
180443
180873
|
didWork ||= dueRun.ran > 0;
|
|
@@ -180457,7 +180887,7 @@ async function evaluateSmartNotes(args) {
|
|
|
180457
180887
|
break;
|
|
180458
180888
|
assertLeaseHeld("liveness start");
|
|
180459
180889
|
didWork = true;
|
|
180460
|
-
const met = await runLivenessCheck(args, note, projectRoot, assertLeaseHeld, leaseHeld);
|
|
180890
|
+
const met = await runLivenessCheck(args, note, projectRoot, assertLeaseHeld, leaseHeld, leaseAbortController.signal);
|
|
180461
180891
|
if (met)
|
|
180462
180892
|
surfaced += 1;
|
|
180463
180893
|
}
|
|
@@ -180470,8 +180900,9 @@ async function evaluateSmartNotes(args) {
|
|
|
180470
180900
|
const met = await confirmReadOnly(args, note.id, note.content, note.surfaceCondition, leaseAbortController.signal);
|
|
180471
180901
|
const now = Date.now();
|
|
180472
180902
|
assertLeaseHeld("fallback commit");
|
|
180473
|
-
commitSmartNoteState(args.db, {
|
|
180903
|
+
const committed = commitSmartNoteState(args.db, {
|
|
180474
180904
|
phase: "fallback",
|
|
180905
|
+
expected: sourceRevisionExpectation(note, "fallback"),
|
|
180475
180906
|
leaseHeld,
|
|
180476
180907
|
write: () => {
|
|
180477
180908
|
if (met) {
|
|
@@ -180482,7 +180913,7 @@ async function evaluateSmartNotes(args) {
|
|
|
180482
180913
|
}
|
|
180483
180914
|
}
|
|
180484
180915
|
});
|
|
180485
|
-
if (met)
|
|
180916
|
+
if (met && committed)
|
|
180486
180917
|
surfaced += 1;
|
|
180487
180918
|
}
|
|
180488
180919
|
assertLeaseHeld("final commit");
|
|
@@ -180512,9 +180943,12 @@ async function compileNote(args, note, projectRoot, assertLeaseHeld, leaseHeld,
|
|
|
180512
180943
|
const now = Date.now();
|
|
180513
180944
|
assertLeaseHeld("compile commit");
|
|
180514
180945
|
if (!result.ok) {
|
|
180946
|
+
if (result.cancelled)
|
|
180947
|
+
return false;
|
|
180515
180948
|
log(`[dreamer] smart note #${note.id}: compile failed — ${result.error}`);
|
|
180516
180949
|
commitSmartNoteState(args.db, {
|
|
180517
180950
|
phase: "compile failure",
|
|
180951
|
+
expected: sourceRevisionExpectation(note),
|
|
180518
180952
|
leaseHeld,
|
|
180519
180953
|
write: () => {
|
|
180520
180954
|
markSmartNoteCompilationFailure(args.db, note.id, now, MAX_COMPILATION_FAILURES);
|
|
@@ -180527,8 +180961,9 @@ async function compileNote(args, note, projectRoot, assertLeaseHeld, leaseHeld,
|
|
|
180527
180961
|
noteId: note.id,
|
|
180528
180962
|
hash: result.checkHash
|
|
180529
180963
|
});
|
|
180530
|
-
commitSmartNoteState(args.db, {
|
|
180964
|
+
const committed = commitSmartNoteState(args.db, {
|
|
180531
180965
|
phase: "compile",
|
|
180966
|
+
expected: sourceRevisionExpectation(note),
|
|
180532
180967
|
leaseHeld,
|
|
180533
180968
|
write: () => {
|
|
180534
180969
|
storeCompiledSmartNoteCheck(args.db, {
|
|
@@ -180547,47 +180982,65 @@ async function compileNote(args, note, projectRoot, assertLeaseHeld, leaseHeld,
|
|
|
180547
180982
|
}
|
|
180548
180983
|
}
|
|
180549
180984
|
});
|
|
180550
|
-
return result.dryRun.met;
|
|
180985
|
+
return result.dryRun.met && committed;
|
|
180551
180986
|
} finally {
|
|
180552
180987
|
promptSignal.cleanup();
|
|
180553
180988
|
}
|
|
180554
180989
|
}
|
|
180555
|
-
async function runLivenessCheck(args, note, projectRoot, assertLeaseHeld, leaseHeld) {
|
|
180990
|
+
async function runLivenessCheck(args, note, projectRoot, assertLeaseHeld, leaseHeld, leaseSignal) {
|
|
180556
180991
|
if (!note.compiledCheck)
|
|
180557
180992
|
return false;
|
|
180558
|
-
const
|
|
180559
|
-
const
|
|
180560
|
-
|
|
180561
|
-
|
|
180562
|
-
|
|
180563
|
-
|
|
180564
|
-
|
|
180565
|
-
|
|
180566
|
-
|
|
180567
|
-
|
|
180568
|
-
|
|
180569
|
-
|
|
180570
|
-
|
|
180571
|
-
|
|
180572
|
-
|
|
180573
|
-
|
|
180574
|
-
|
|
180575
|
-
|
|
180576
|
-
|
|
180577
|
-
|
|
180578
|
-
|
|
180579
|
-
|
|
180580
|
-
|
|
180581
|
-
|
|
180582
|
-
|
|
180583
|
-
|
|
180584
|
-
|
|
180993
|
+
const compiledCheck = note.compiledCheck;
|
|
180994
|
+
const result = await runCompiledSmartNoteCheck({
|
|
180995
|
+
compiledCheck,
|
|
180996
|
+
capabilityFactory: (signal) => createSmartNoteCapabilities({ projectRoot, signal }),
|
|
180997
|
+
signal: leaseSignal,
|
|
180998
|
+
timeoutMs: 2000
|
|
180999
|
+
});
|
|
181000
|
+
if (!result.ok && result.cancelled)
|
|
181001
|
+
return false;
|
|
181002
|
+
const now = Date.now();
|
|
181003
|
+
const nextDueAt = result.ok && !result.result.met ? nextSmartNoteCheckDueAt(note.checkCron, {
|
|
181004
|
+
now,
|
|
181005
|
+
noteId: note.id,
|
|
181006
|
+
hash: note.checkHash
|
|
181007
|
+
}) : null;
|
|
181008
|
+
assertLeaseHeld("liveness commit");
|
|
181009
|
+
const committed = commitSmartNoteState(args.db, {
|
|
181010
|
+
phase: "liveness",
|
|
181011
|
+
expected: compiledCheckExpectation(note, compiledCheck),
|
|
181012
|
+
leaseHeld,
|
|
181013
|
+
write: () => {
|
|
181014
|
+
markSmartNoteLivenessChecked(args.db, note.id, now);
|
|
181015
|
+
if (result.ok && result.result.met) {
|
|
181016
|
+
markNoteReady(args.db, note.id, `Smart note #${note.id}: max-staleness liveness check returned met=true`);
|
|
181017
|
+
} else if (result.ok && nextDueAt !== null) {
|
|
181018
|
+
markCompiledCheckFalse(args.db, note.id, nextDueAt, now);
|
|
181019
|
+
} else if (!result.ok && !result.network) {
|
|
181020
|
+
markSmartNoteCheckStatus(args.db, note.id, "failing", now);
|
|
180585
181021
|
}
|
|
180586
|
-
}
|
|
180587
|
-
|
|
180588
|
-
|
|
180589
|
-
|
|
180590
|
-
|
|
181022
|
+
}
|
|
181023
|
+
});
|
|
181024
|
+
return result.ok && result.result.met && committed;
|
|
181025
|
+
}
|
|
181026
|
+
function sourceRevisionExpectation(note, checkStatus) {
|
|
181027
|
+
return {
|
|
181028
|
+
kind: "source-revision",
|
|
181029
|
+
noteId: note.id,
|
|
181030
|
+
content: note.content,
|
|
181031
|
+
surfaceCondition: note.surfaceCondition,
|
|
181032
|
+
updatedAt: note.updatedAt,
|
|
181033
|
+
...checkStatus ? { checkStatus } : {}
|
|
181034
|
+
};
|
|
181035
|
+
}
|
|
181036
|
+
function compiledCheckExpectation(note, compiledCheck) {
|
|
181037
|
+
return {
|
|
181038
|
+
kind: "compiled-check",
|
|
181039
|
+
noteId: note.id,
|
|
181040
|
+
compiledCheck,
|
|
181041
|
+
checkHash: note.checkHash,
|
|
181042
|
+
checkCompiledAt: note.checkCompiledAt
|
|
181043
|
+
};
|
|
180591
181044
|
}
|
|
180592
181045
|
async function confirmReadOnly(args, noteId, content, surfaceCondition, leaseSignal) {
|
|
180593
181046
|
let childSessionId = null;
|
|
@@ -186664,7 +187117,8 @@ var canonicalReasons = new Set([
|
|
|
186664
187117
|
"pressure_refold",
|
|
186665
187118
|
"upgrade_state",
|
|
186666
187119
|
"cached_m1_missing",
|
|
186667
|
-
"project_change"
|
|
187120
|
+
"project_change",
|
|
187121
|
+
"compartment_render_epoch"
|
|
186668
187122
|
]);
|
|
186669
187123
|
var piReasonAliases = {
|
|
186670
187124
|
project_memory_change: "project_memory_epoch",
|
|
@@ -188914,6 +189368,30 @@ class BoundedSessionMap {
|
|
|
188914
189368
|
// ../plugin/src/hooks/magic-context/inject-compartments.ts
|
|
188915
189369
|
init_logger();
|
|
188916
189370
|
|
|
189371
|
+
// ../plugin/src/hooks/magic-context/compartment-render-epoch.ts
|
|
189372
|
+
var COMPARTMENT_RENDER_EPOCH = "cre2";
|
|
189373
|
+
var EPOCH_COMPONENT_PREFIX = "|compartment-render:";
|
|
189374
|
+
function encodeCachedM0UpgradeIdentity(upgradeState, compartmentRenderEpoch = COMPARTMENT_RENDER_EPOCH) {
|
|
189375
|
+
if (compartmentRenderEpoch === null)
|
|
189376
|
+
return upgradeState;
|
|
189377
|
+
return `${upgradeState ?? ""}${EPOCH_COMPONENT_PREFIX}${compartmentRenderEpoch}`;
|
|
189378
|
+
}
|
|
189379
|
+
function decodeCachedM0UpgradeIdentity(value) {
|
|
189380
|
+
if (value === null) {
|
|
189381
|
+
return { upgradeState: null, compartmentRenderEpoch: null };
|
|
189382
|
+
}
|
|
189383
|
+
const componentIndex = value.lastIndexOf(EPOCH_COMPONENT_PREFIX);
|
|
189384
|
+
if (componentIndex < 0) {
|
|
189385
|
+
return { upgradeState: value, compartmentRenderEpoch: null };
|
|
189386
|
+
}
|
|
189387
|
+
const upgradeState = value.slice(0, componentIndex);
|
|
189388
|
+
const compartmentRenderEpoch = value.slice(componentIndex + EPOCH_COMPONENT_PREFIX.length);
|
|
189389
|
+
return {
|
|
189390
|
+
upgradeState: upgradeState.length > 0 ? upgradeState : null,
|
|
189391
|
+
compartmentRenderEpoch: compartmentRenderEpoch.length > 0 ? compartmentRenderEpoch : null
|
|
189392
|
+
};
|
|
189393
|
+
}
|
|
189394
|
+
|
|
188917
189395
|
// ../plugin/src/hooks/magic-context/decay-curve.ts
|
|
188918
189396
|
var H50 = 24;
|
|
188919
189397
|
var D = 25;
|
|
@@ -188983,10 +189461,13 @@ function formatDateRange(startDate, endDate) {
|
|
|
188983
189461
|
return `${startDate}→${endDate.slice(8)}`;
|
|
188984
189462
|
return `${startDate}→${endDate}`;
|
|
188985
189463
|
}
|
|
189464
|
+
function sanitizeCompartmentTitle(title) {
|
|
189465
|
+
return escapeXmlContent2(title.replace(/[\p{Cc}\p{Zl}\p{Zp}]+/gu, " "));
|
|
189466
|
+
}
|
|
188986
189467
|
function compartmentHeading(c) {
|
|
188987
189468
|
const dateRange = formatDateRange(c.startDate, c.endDate);
|
|
188988
189469
|
const dateSegment = dateRange ? ` · ${dateRange}` : "";
|
|
188989
|
-
return `## ${c.startMessage}-${c.endMessage}${dateSegment} · ${c.title}`;
|
|
189470
|
+
return `## ${c.startMessage}-${c.endMessage}${dateSegment} · ${sanitizeCompartmentTitle(c.title)}`;
|
|
188990
189471
|
}
|
|
188991
189472
|
function guardCompartmentBody(body) {
|
|
188992
189473
|
return body.replace(/^## /gm, " ## ");
|
|
@@ -191157,7 +191638,7 @@ var MAX_FRAGMENTS = 3;
|
|
|
191157
191638
|
var FRAGMENT_CHAR_CAP = 80;
|
|
191158
191639
|
var MAX_HINT_CHARS = 800;
|
|
191159
191640
|
var MS_PER_DAY2 = 24 * 60 * 60 * 1000;
|
|
191160
|
-
function
|
|
191641
|
+
function truncate2(text, limit) {
|
|
191161
191642
|
const normalized = text.replace(/\s+/g, " ").trim();
|
|
191162
191643
|
if (normalized.length <= limit)
|
|
191163
191644
|
return normalized;
|
|
@@ -191186,29 +191667,29 @@ function renderFragment(result, charCap) {
|
|
|
191186
191667
|
switch (result.source) {
|
|
191187
191668
|
case "memory": {
|
|
191188
191669
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
191189
|
-
return
|
|
191670
|
+
return truncate2(compressed, charCap);
|
|
191190
191671
|
}
|
|
191191
191672
|
case "git_commit": {
|
|
191192
191673
|
const subject = result.content.split(/\r?\n/)[0] ?? result.content;
|
|
191193
|
-
const body =
|
|
191674
|
+
const body = truncate2(subject, Math.max(10, charCap - 20));
|
|
191194
191675
|
return `commit ${result.shortSha} ${formatAge(result.committedAtMs)}: ${body}`;
|
|
191195
191676
|
}
|
|
191196
191677
|
case "message": {
|
|
191197
191678
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
191198
|
-
return
|
|
191679
|
+
return truncate2(compressed, charCap);
|
|
191199
191680
|
}
|
|
191200
191681
|
case "compartment": {
|
|
191201
191682
|
const source = result.snippet ?? result.title;
|
|
191202
191683
|
const compressed = cavemanCompress(source, "ultra");
|
|
191203
|
-
return
|
|
191684
|
+
return truncate2(compressed, charCap);
|
|
191204
191685
|
}
|
|
191205
191686
|
case "primer": {
|
|
191206
191687
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
191207
|
-
return
|
|
191688
|
+
return truncate2(compressed, charCap);
|
|
191208
191689
|
}
|
|
191209
191690
|
case "note": {
|
|
191210
191691
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
191211
|
-
return
|
|
191692
|
+
return truncate2(compressed, charCap);
|
|
191212
191693
|
}
|
|
191213
191694
|
}
|
|
191214
191695
|
}
|
|
@@ -191814,8 +192295,8 @@ function resolveToolTier(toolName) {
|
|
|
191814
192295
|
function tagReclaimBytes(tag) {
|
|
191815
192296
|
return tag.byteSize + tag.inputByteSize + tag.reasoningByteSize;
|
|
191816
192297
|
}
|
|
191817
|
-
function
|
|
191818
|
-
return Math.round(
|
|
192298
|
+
function estimateEmergencyDropReclaimTokens(tag) {
|
|
192299
|
+
return Math.round(tagReclaimBytes(tag) * TOKENS_PER_BYTE);
|
|
191819
192300
|
}
|
|
191820
192301
|
function planEmergencyDrop(input) {
|
|
191821
192302
|
const {
|
|
@@ -191847,7 +192328,7 @@ function planEmergencyDrop(input) {
|
|
|
191847
192328
|
for (const tag of floorTags) {
|
|
191848
192329
|
if (tag.status !== "active")
|
|
191849
192330
|
continue;
|
|
191850
|
-
tailTokens +=
|
|
192331
|
+
tailTokens += estimateEmergencyDropReclaimTokens(tag);
|
|
191851
192332
|
}
|
|
191852
192333
|
const fixedFloor = Math.max(currentTotalInputTokens - tailTokens, 0);
|
|
191853
192334
|
const workingSpan = Math.max(ceilingTokens - fixedFloor, 0);
|
|
@@ -191895,7 +192376,7 @@ function planEmergencyDrop(input) {
|
|
|
191895
192376
|
group.sort((a, b) => a.tagNumber - b.tagNumber);
|
|
191896
192377
|
for (const tag of group) {
|
|
191897
192378
|
selected.push(tag.tagNumber);
|
|
191898
|
-
reclaimed +=
|
|
192379
|
+
reclaimed += estimateEmergencyDropReclaimTokens(tag);
|
|
191899
192380
|
if (reclaimed >= reclaimTokens)
|
|
191900
192381
|
break outer;
|
|
191901
192382
|
}
|
|
@@ -192484,6 +192965,7 @@ function getCachedMarkers(db, state, compartmentsForNormalization) {
|
|
|
192484
192965
|
return null;
|
|
192485
192966
|
}
|
|
192486
192967
|
const compartments = compartmentsForNormalization ?? getCompartments(db, state.sessionId);
|
|
192968
|
+
const cachedUpgradeIdentity = decodeCachedM0UpgradeIdentity(meta3.cachedM0UpgradeState);
|
|
192487
192969
|
const maxCompartmentSeq = normalizeCachedMaxCompartmentSeq(meta3.cachedM0MaxCompartmentSeq, compartments);
|
|
192488
192970
|
const cachedBoundary = getCachedBoundary(db, state.sessionId);
|
|
192489
192971
|
const liveBoundary = lastBaselineEndMessageId(compartments);
|
|
@@ -192501,7 +192983,8 @@ function getCachedMarkers(db, state, compartmentsForNormalization) {
|
|
|
192501
192983
|
projectDocsHash: meta3.cachedM0ProjectDocsHash,
|
|
192502
192984
|
sessionFactsVersion: meta3.cachedM0SessionFactsVersion,
|
|
192503
192985
|
materializedAt: meta3.cachedM0MaterializedAt,
|
|
192504
|
-
upgradeState:
|
|
192986
|
+
upgradeState: cachedUpgradeIdentity.upgradeState ?? "",
|
|
192987
|
+
compartmentRenderEpoch: cachedUpgradeIdentity.compartmentRenderEpoch,
|
|
192505
192988
|
lastBaselineEndMessageId: cachedBoundary,
|
|
192506
192989
|
systemHash: meta3.cachedM0SystemHash ?? "",
|
|
192507
192990
|
modelKey: meta3.cachedM0ModelKey ?? "",
|
|
@@ -192533,6 +193016,7 @@ function readCurrentMarkersFromCompartments(db, state, compartments, projectDocs
|
|
|
192533
193016
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
192534
193017
|
materializedAt: Date.now(),
|
|
192535
193018
|
upgradeState: `${PI_M0_UPGRADE_STATE}:${compartments.some((c) => c.legacy === 1) ? "legacy" : "ready"}`,
|
|
193019
|
+
compartmentRenderEpoch: COMPARTMENT_RENDER_EPOCH,
|
|
192536
193020
|
lastBaselineEndMessageId: lastBaselineEndMessageId(compartments),
|
|
192537
193021
|
systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
|
|
192538
193022
|
modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey,
|
|
@@ -192550,9 +193034,13 @@ function mustMaterializePi(state, db, currentCompartmentsOverride) {
|
|
|
192550
193034
|
if (!decodeCachedM0(meta3.cachedM0Bytes)) {
|
|
192551
193035
|
return { value: true, reason: "cache_invalid" };
|
|
192552
193036
|
}
|
|
192553
|
-
|
|
193037
|
+
const cached2 = getCachedMarkers(db, state, currentCompartments);
|
|
193038
|
+
if (cached2 === null) {
|
|
192554
193039
|
return { value: true, reason: "cache_invalid" };
|
|
192555
193040
|
}
|
|
193041
|
+
if (cached2.compartmentRenderEpoch !== current.compartmentRenderEpoch) {
|
|
193042
|
+
return { value: true, reason: "compartment_render_epoch" };
|
|
193043
|
+
}
|
|
192556
193044
|
const hard = state.hardSignals ?? EMPTY_PI_HARD_SIGNALS;
|
|
192557
193045
|
if (hard.modelKey !== "" && hard.modelKey !== (meta3.cachedM0ModelKey ?? "")) {
|
|
192558
193046
|
return { value: true, reason: "model_change" };
|
|
@@ -192566,7 +193054,7 @@ function mustMaterializePi(state, db, currentCompartmentsOverride) {
|
|
|
192566
193054
|
if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (meta3.cachedM0MaterializedAt ?? 0)) {
|
|
192567
193055
|
return { value: true, reason: "ttl_idle" };
|
|
192568
193056
|
}
|
|
192569
|
-
if (
|
|
193057
|
+
if (cached2.upgradeState !== current.upgradeState) {
|
|
192570
193058
|
return { value: true, reason: "renderer_upgrade" };
|
|
192571
193059
|
}
|
|
192572
193060
|
if (current.workspaceFingerprint !== null || (meta3.cachedM0WorkspaceFingerprint ?? null) !== null) {
|
|
@@ -192679,6 +193167,7 @@ function readFrozenM0InputsPi(state, db, docs = readProjectDocsForPiM0(state), m
|
|
|
192679
193167
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
192680
193168
|
materializedAt: memoryCutoff ?? Date.now(),
|
|
192681
193169
|
upgradeState: `${PI_M0_UPGRADE_STATE}:${compartments.some((c) => c.legacy === 1) ? "legacy" : "ready"}`,
|
|
193170
|
+
compartmentRenderEpoch: COMPARTMENT_RENDER_EPOCH,
|
|
192682
193171
|
lastBaselineEndMessageId: lastBaselineEndMessageId(compartments),
|
|
192683
193172
|
systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
|
|
192684
193173
|
modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey,
|
|
@@ -192760,7 +193249,7 @@ function materializeM0Pi(state, db) {
|
|
|
192760
193249
|
projectDocsHash: snapshotMarkers.projectDocsHash,
|
|
192761
193250
|
materializedAt: snapshotMarkers.materializedAt,
|
|
192762
193251
|
sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
|
|
192763
|
-
upgradeState: snapshotMarkers.upgradeState,
|
|
193252
|
+
upgradeState: encodeCachedM0UpgradeIdentity(snapshotMarkers.upgradeState, snapshotMarkers.compartmentRenderEpoch),
|
|
192764
193253
|
systemHash: snapshotMarkers.systemHash,
|
|
192765
193254
|
modelKey: snapshotMarkers.modelKey,
|
|
192766
193255
|
projectIdentity: snapshotMarkers.projectIdentity
|
|
@@ -192930,6 +193419,7 @@ function readCachedPiM0M1Row(db, sessionId) {
|
|
|
192930
193419
|
function markersFromCachedPiRow(row, compartmentsForNormalization) {
|
|
192931
193420
|
if (!row.cached_m0_bytes)
|
|
192932
193421
|
return null;
|
|
193422
|
+
const cachedUpgradeIdentity = decodeCachedM0UpgradeIdentity(row.cached_m0_upgrade_state);
|
|
192933
193423
|
if (row.cached_m0_project_memory_epoch === null)
|
|
192934
193424
|
return null;
|
|
192935
193425
|
if (row.cached_m0_project_user_profile_version === null)
|
|
@@ -192959,7 +193449,8 @@ function markersFromCachedPiRow(row, compartmentsForNormalization) {
|
|
|
192959
193449
|
projectDocsHash: row.cached_m0_project_docs_hash ?? "",
|
|
192960
193450
|
materializedAt: row.cached_m0_materialized_at,
|
|
192961
193451
|
sessionFactsVersion: row.cached_m0_session_facts_version,
|
|
192962
|
-
upgradeState:
|
|
193452
|
+
upgradeState: cachedUpgradeIdentity.upgradeState ?? "",
|
|
193453
|
+
compartmentRenderEpoch: cachedUpgradeIdentity.compartmentRenderEpoch,
|
|
192963
193454
|
lastBaselineEndMessageId: typeof row.cached_m0_last_baseline_end_message_id === "string" && row.cached_m0_last_baseline_end_message_id.length > 0 ? row.cached_m0_last_baseline_end_message_id : null,
|
|
192964
193455
|
systemHash: row.cached_m0_system_hash ?? "",
|
|
192965
193456
|
modelKey: row.cached_m0_model_key ?? "",
|
|
@@ -192970,7 +193461,7 @@ function cachedPiRowMatchesSnapshot(args) {
|
|
|
192970
193461
|
const rowMarkers = markersFromCachedPiRow(args.row, args.compartmentsForNormalization);
|
|
192971
193462
|
if (!rowMarkers)
|
|
192972
193463
|
return false;
|
|
192973
|
-
return bufferEqualsNullable(args.row.cached_m0_bytes, args.m0Bytes) && rowMarkers.projectMemoryEpoch === args.markers.projectMemoryEpoch && rowMarkers.projectUserProfileVersion === args.markers.projectUserProfileVersion && rowMarkers.maxCompartmentSeq === args.markers.maxCompartmentSeq && rowMarkers.maxMemoryId === args.markers.maxMemoryId && rowMarkers.maxMutationId === args.markers.maxMutationId && rowMarkers.maxMemoryMutationId === args.markers.maxMemoryMutationId && rowMarkers.materializedAt === args.markers.materializedAt && rowMarkers.sessionFactsVersion === args.markers.sessionFactsVersion && (rowMarkers.upgradeState ?? null) === (args.markers.upgradeState ?? null) && (rowMarkers.systemHash ?? "") === (args.markers.systemHash ?? "") && (rowMarkers.modelKey ?? "") === (args.markers.modelKey ?? "") && (rowMarkers.projectIdentity ?? null) === (args.markers.projectIdentity ?? null) && (rowMarkers.workspaceFingerprint ?? null) === (args.markers.workspaceFingerprint ?? null);
|
|
193464
|
+
return bufferEqualsNullable(args.row.cached_m0_bytes, args.m0Bytes) && rowMarkers.projectMemoryEpoch === args.markers.projectMemoryEpoch && rowMarkers.projectUserProfileVersion === args.markers.projectUserProfileVersion && rowMarkers.maxCompartmentSeq === args.markers.maxCompartmentSeq && rowMarkers.maxMemoryId === args.markers.maxMemoryId && rowMarkers.maxMutationId === args.markers.maxMutationId && rowMarkers.maxMemoryMutationId === args.markers.maxMemoryMutationId && rowMarkers.materializedAt === args.markers.materializedAt && rowMarkers.sessionFactsVersion === args.markers.sessionFactsVersion && (rowMarkers.upgradeState ?? null) === (args.markers.upgradeState ?? null) && rowMarkers.compartmentRenderEpoch === args.markers.compartmentRenderEpoch && (rowMarkers.systemHash ?? "") === (args.markers.systemHash ?? "") && (rowMarkers.modelKey ?? "") === (args.markers.modelKey ?? "") && (rowMarkers.projectIdentity ?? null) === (args.markers.projectIdentity ?? null) && (rowMarkers.workspaceFingerprint ?? null) === (args.markers.workspaceFingerprint ?? null);
|
|
192974
193465
|
}
|
|
192975
193466
|
function adoptCachedPiProjectIdentity(db, state) {
|
|
192976
193467
|
db.prepare("UPDATE session_meta SET cached_m0_project_identity = ? WHERE session_id = ? AND cached_m0_project_identity IS NULL").run(state.projectIdentity, state.sessionId);
|
|
@@ -193358,7 +193849,7 @@ var COMPARTMENT_AGENT_SYSTEM_PROMPT = `# Historian
|
|
|
193358
193849
|
|
|
193359
193850
|
You are Historian — the hippocampus of a long-running coding agent. You and the primary agent are one mind, working together: the primary agent is doing the active engineering work, and you are the part of that mind that decides what to remember and how to store it.
|
|
193360
193851
|
|
|
193361
|
-
You do not write for some other future reader. You write for **yourself**, later — when this same agent comes back to a topic days or weeks from now, you are the one who will read what you wrote. The wording, the structure, the importance you assign — these are all for your own future self.
|
|
193852
|
+
You do not write for some other future reader. You write for **yourself**, later — when this same agent comes back to a topic days or weeks from now, you are the one who will read what you wrote. The wording, the structure, the importance you assign — these are all for your own future self. So write in the **first person** — as yourself remembering what you did, never as a narrator describing "the agent" from the outside.
|
|
193362
193853
|
|
|
193363
193854
|
A session can run for thousands of messages. Without you, the active prompt would grow until the agent could no longer think. You compact the past so the present can keep working.
|
|
193364
193855
|
|
|
@@ -193520,6 +194011,13 @@ When in doubt about importance, use \`<compartment_examples_from_other_projects>
|
|
|
193520
194011
|
|
|
193521
194012
|
Each compartment contains four paraphrase tiers of the same work unit, ordered from most detailed (P1) to most condensed (P4). As described in the intro, magic-context picks ONE tier per compartment per render pass based on age and importance. Each tier must be self-contained — a future render that shows only P3 must still let a reader understand what happened.
|
|
193522
194013
|
|
|
194014
|
+
**Voice — write every tier in the first person.** These are your own memories. Refer to your own actions as "I" ("I traced the timeout to readLoop", "I first blamed CPU load, then corrected"), and name other actors directly — the user by name or as "the user", peers/subagents/tools by their name. Never narrate yourself in the third person as "the agent". Third-person narration ("The agent investigated X and the user corrected Y") is the single most common voice failure — it reads as a detached report about someone else, when the whole point is that *you* are the one who did this and will read it back later.
|
|
194015
|
+
|
|
194016
|
+
- Wrong (third-person report): "The agent initially blamed CPU load and proposed an epoch-drop theory. The user corrected this framing, and the agent then traced the timeout to readLoop."
|
|
194017
|
+
- Right (first person, actors named): "I first blamed CPU load and floated an epoch-drop theory. The user rejected that (\`U: load shouldn't cause timeouts\`), so I traced the timeout to readLoop pre-computing the deadline before the header arrived."
|
|
194018
|
+
|
|
194019
|
+
The \`U:\` line convention already keeps the user's voice distinct; your prose around it is *yours*, in the first person.
|
|
194020
|
+
|
|
193523
194021
|
Cross-tier rules:
|
|
193524
194022
|
- The compartment opening tag, \`episode_type\`, \`title\`, \`importance\`, and the facts section apply to all tiers — emit them once.
|
|
193525
194023
|
- Each tier covers the same work unit; do not split a tier into a different episode.
|
|
@@ -194464,7 +194962,6 @@ function mapParsedCompartmentsToChunk(compartments, chunk, sequenceOffset) {
|
|
|
194464
194962
|
// ../plugin/src/hooks/magic-context/compartment-runner-validation.ts
|
|
194465
194963
|
var MIN_RECOMP_CHUNK_TOKEN_BUDGET = 20;
|
|
194466
194964
|
function healCompartmentGaps(compartments, toolOnlyRanges = []) {
|
|
194467
|
-
const SAFETY_HEAL_GAP = 15;
|
|
194468
194965
|
for (let i = 1;i < compartments.length; i++) {
|
|
194469
194966
|
const prev = compartments[i - 1];
|
|
194470
194967
|
const curr = compartments[i];
|
|
@@ -194474,7 +194971,7 @@ function healCompartmentGaps(compartments, toolOnlyRanges = []) {
|
|
|
194474
194971
|
if (gapSize <= 0)
|
|
194475
194972
|
continue;
|
|
194476
194973
|
const fullyInsideToolOnly = toolOnlyRanges.some((range) => range.start <= gapStart && range.end >= gapEnd);
|
|
194477
|
-
if (fullyInsideToolOnly
|
|
194974
|
+
if (fullyInsideToolOnly) {
|
|
194478
194975
|
prev.endMessage = gapEnd;
|
|
194479
194976
|
}
|
|
194480
194977
|
}
|
|
@@ -197666,6 +198163,7 @@ function stripPiDroppedPlaceholderMessages(args) {
|
|
|
197666
198163
|
|
|
197667
198164
|
// src/strip-processed-images-pi.ts
|
|
197668
198165
|
init_logger();
|
|
198166
|
+
var STRIPPED_IMAGE_MARKER = "[image stripped]";
|
|
197669
198167
|
function isLargeImagePart(value) {
|
|
197670
198168
|
if (!value || typeof value !== "object")
|
|
197671
198169
|
return false;
|
|
@@ -197721,7 +198219,10 @@ function stripPiProcessedImages(args) {
|
|
|
197721
198219
|
for (let partIndex = 0;partIndex < message.content.length; partIndex++) {
|
|
197722
198220
|
if (!isLargeImagePart(message.content[partIndex]))
|
|
197723
198221
|
continue;
|
|
197724
|
-
message.content[partIndex] = {
|
|
198222
|
+
message.content[partIndex] = {
|
|
198223
|
+
type: "text",
|
|
198224
|
+
text: STRIPPED_IMAGE_MARKER
|
|
198225
|
+
};
|
|
197725
198226
|
stripped++;
|
|
197726
198227
|
}
|
|
197727
198228
|
}
|
|
@@ -199566,7 +200067,8 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
199566
200067
|
const now = Date.now();
|
|
199567
200068
|
if (now - lastNotifiedAt >= EMERGENCY_NOTIFICATION_COOLDOWN_MS) {
|
|
199568
200069
|
lastEmergencyNotificationAtMs.set(sessionId, now);
|
|
199569
|
-
|
|
200070
|
+
sendPiIgnoredNotification(ctx, "Context full — /ctx-flush or /clear to continue.");
|
|
200071
|
+
sessionLog(sessionId, `EMERGENCY: usage=${usagePercentage.toFixed(1)}% — notified user, awaiting in-flight historian + applying drop-all-tools`);
|
|
199570
200072
|
}
|
|
199571
200073
|
const histPromise = inFlightHistorian.get(sessionId);
|
|
199572
200074
|
if (histPromise) {
|
|
@@ -199930,7 +200432,10 @@ function sendPiIgnoredNotification(ctx, message) {
|
|
|
199930
200432
|
const uiNotify = ctx.ui?.notify;
|
|
199931
200433
|
if (typeof uiNotify === "function") {
|
|
199932
200434
|
try {
|
|
199933
|
-
uiNotify.call(ctx.ui, message);
|
|
200435
|
+
const result = uiNotify.call(ctx.ui, message);
|
|
200436
|
+
if (result && typeof result.then === "function") {
|
|
200437
|
+
Promise.resolve(result).catch((error51) => sessionLog("pi", "UI notification rejected:", error51));
|
|
200438
|
+
}
|
|
199934
200439
|
return;
|
|
199935
200440
|
} catch {}
|
|
199936
200441
|
}
|
|
@@ -203471,7 +203976,7 @@ function formatThresholdPercent(value) {
|
|
|
203471
203976
|
// package.json
|
|
203472
203977
|
var package_default = {
|
|
203473
203978
|
name: "@cortexkit/pi-magic-context",
|
|
203474
|
-
version: "0.32.
|
|
203979
|
+
version: "0.32.1",
|
|
203475
203980
|
type: "module",
|
|
203476
203981
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
203477
203982
|
main: "dist/index.js",
|
|
@@ -204472,7 +204977,7 @@ function roleLabel(role) {
|
|
|
204472
204977
|
return "U (user)";
|
|
204473
204978
|
return role;
|
|
204474
204979
|
}
|
|
204475
|
-
function
|
|
204980
|
+
function truncate3(value, max) {
|
|
204476
204981
|
const t = value.trim();
|
|
204477
204982
|
return t.length <= max ? t : `${t.slice(0, max)}…`;
|
|
204478
204983
|
}
|
|
@@ -204482,10 +204987,10 @@ function keyArg(input) {
|
|
|
204482
204987
|
for (const k of ["filePath", "path", "pattern", "query", "symbol", "module", "action"]) {
|
|
204483
204988
|
const v = input[k];
|
|
204484
204989
|
if (typeof v === "string" && v.length > 0)
|
|
204485
|
-
return
|
|
204990
|
+
return truncate3(v, 60);
|
|
204486
204991
|
}
|
|
204487
204992
|
if (typeof input.description === "string")
|
|
204488
|
-
return
|
|
204993
|
+
return truncate3(input.description, 60);
|
|
204489
204994
|
return "";
|
|
204490
204995
|
}
|
|
204491
204996
|
function asToolPart(part) {
|
|
@@ -204541,7 +205046,7 @@ function renderPartPreview(part) {
|
|
|
204541
205046
|
return null;
|
|
204542
205047
|
const text = textOf(part);
|
|
204543
205048
|
if (text !== null) {
|
|
204544
|
-
const t =
|
|
205049
|
+
const t = truncate3(text, 200);
|
|
204545
205050
|
return t.length > 0 ? ` • ${t}` : null;
|
|
204546
205051
|
}
|
|
204547
205052
|
const tool = asToolPart(part);
|
|
@@ -204552,7 +205057,7 @@ function renderPartPreview(part) {
|
|
|
204552
205057
|
}
|
|
204553
205058
|
const reasoning = reasoningOf(part);
|
|
204554
205059
|
if (reasoning !== null)
|
|
204555
|
-
return ` • [reasoning] ${
|
|
205060
|
+
return ` • [reasoning] ${truncate3(reasoning, 120)}`;
|
|
204556
205061
|
const type = typeof part.type === "string" ? part.type : "part";
|
|
204557
205062
|
if (type === "file")
|
|
204558
205063
|
return " • [file]";
|
|
@@ -210352,18 +210857,18 @@ class TodoOverlay {
|
|
|
210352
210857
|
const headingColor = hasInProgress ? "accent" : "dim";
|
|
210353
210858
|
const headingIcon = hasInProgress ? "●" : "○";
|
|
210354
210859
|
const heading = `${theme.fg(headingColor, headingIcon)} ${theme.fg(headingColor, "Todos")} ${theme.fg("muted", "—")} ${theme.fg("dim", formatCounts(counts))}`;
|
|
210355
|
-
const
|
|
210356
|
-
const lines = [
|
|
210860
|
+
const truncate4 = (line) => truncateToWidth2(line, width, "…");
|
|
210861
|
+
const lines = [truncate4(heading)];
|
|
210357
210862
|
const { visible, hiddenCount } = capTodoRows(overlayTodos);
|
|
210358
210863
|
for (const [index, { todo, key }] of visible.entries()) {
|
|
210359
210864
|
const isLast = index === visible.length - 1 && hiddenCount === 0;
|
|
210360
210865
|
const branch = theme.fg("dim", isLast ? "└─" : "├─");
|
|
210361
|
-
lines.push(
|
|
210866
|
+
lines.push(truncate4(`${branch} ${formatTodoLine(todo, theme, { showId: true })}`));
|
|
210362
210867
|
if (todo.status === "completed")
|
|
210363
210868
|
this.completedTaskIdsPendingHide.add(key);
|
|
210364
210869
|
}
|
|
210365
210870
|
if (hiddenCount > 0) {
|
|
210366
|
-
lines.push(
|
|
210871
|
+
lines.push(truncate4(`${theme.fg("dim", "└─")} ${theme.fg("dim", `+${hiddenCount} more`)}`));
|
|
210367
210872
|
}
|
|
210368
210873
|
return lines;
|
|
210369
210874
|
}
|