@cortexkit/pi-magic-context 0.31.3 → 0.31.5
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 +1064 -317
- package/dist/subagent-entry.js +657 -178
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14990,12 +14990,41 @@ function pushNotification(type, payload, sessionId) {
|
|
|
14990
14990
|
queue = kept.sort((a, b) => a.id - b.id);
|
|
14991
14991
|
}
|
|
14992
14992
|
}
|
|
14993
|
-
function
|
|
14993
|
+
function cursor(value) {
|
|
14994
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
14995
|
+
}
|
|
14996
|
+
function drainNotifications(lastReceivedId = 0, sessionId, options = {}) {
|
|
14997
|
+
const sessionCursor = cursor(lastReceivedId);
|
|
14998
|
+
if (options.globalOnly) {
|
|
14999
|
+
queue = queue.filter((notification) => notification.sessionId !== undefined || notification.id > sessionCursor);
|
|
15000
|
+
return queue.filter((notification) => notification.sessionId === undefined && notification.id > sessionCursor);
|
|
15001
|
+
}
|
|
15002
|
+
if (options.sessionOnly) {
|
|
15003
|
+
if (sessionId === undefined)
|
|
15004
|
+
return [];
|
|
15005
|
+
queue = queue.filter((notification) => notification.sessionId !== sessionId || notification.id > sessionCursor);
|
|
15006
|
+
return queue.filter((notification) => notification.sessionId === sessionId && notification.id > sessionCursor);
|
|
15007
|
+
}
|
|
15008
|
+
if (sessionId !== undefined && options.globalLastReceivedId !== undefined) {
|
|
15009
|
+
const globalCursor = cursor(options.globalLastReceivedId);
|
|
15010
|
+
queue = queue.filter((notification) => {
|
|
15011
|
+
if (notification.sessionId === undefined)
|
|
15012
|
+
return notification.id > globalCursor;
|
|
15013
|
+
if (notification.sessionId === sessionId)
|
|
15014
|
+
return notification.id > sessionCursor;
|
|
15015
|
+
return true;
|
|
15016
|
+
});
|
|
15017
|
+
return queue.filter((notification) => {
|
|
15018
|
+
if (notification.sessionId === undefined)
|
|
15019
|
+
return notification.id > globalCursor;
|
|
15020
|
+
return notification.sessionId === sessionId && notification.id > sessionCursor;
|
|
15021
|
+
});
|
|
15022
|
+
}
|
|
14994
15023
|
const matchesClient = (notification) => sessionId === undefined || notification.sessionId === undefined || notification.sessionId === sessionId;
|
|
14995
|
-
if (
|
|
14996
|
-
queue = queue.filter((notification) => !(notification.id <=
|
|
15024
|
+
if (sessionCursor > 0) {
|
|
15025
|
+
queue = queue.filter((notification) => !(notification.id <= sessionCursor && matchesClient(notification)));
|
|
14997
15026
|
}
|
|
14998
|
-
return queue.filter((notification) => notification.id >
|
|
15027
|
+
return queue.filter((notification) => notification.id > sessionCursor && matchesClient(notification));
|
|
14999
15028
|
}
|
|
15000
15029
|
function isTuiConnected(sessionId) {
|
|
15001
15030
|
if (sinks.size === 0)
|
|
@@ -15138,7 +15167,7 @@ var PROMPT_CONTEXT_MESSAGE_LIMIT = 50;
|
|
|
15138
15167
|
|
|
15139
15168
|
// src/index.ts
|
|
15140
15169
|
import { createRequire as createRequire3 } from "node:module";
|
|
15141
|
-
import { join as join13 } from "node:path";
|
|
15170
|
+
import { join as join13, resolve as resolve3 } from "node:path";
|
|
15142
15171
|
|
|
15143
15172
|
// ../plugin/src/config/agent-disable.ts
|
|
15144
15173
|
function isDreamerRunnable(config) {
|
|
@@ -149215,12 +149244,19 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
|
|
|
149215
149244
|
let totalTokens = 0;
|
|
149216
149245
|
let messagesProcessed = 0;
|
|
149217
149246
|
let lastOrdinal = startOrdinal - 1;
|
|
149247
|
+
let highestScannedOrdinal = startOrdinal - 1;
|
|
149218
149248
|
let lastMessageId = "";
|
|
149219
149249
|
let firstMessageId = "";
|
|
149220
149250
|
let currentBlock = null;
|
|
149221
149251
|
let pendingNoiseMeta = [];
|
|
149222
149252
|
let commitClusters = 0;
|
|
149223
149253
|
let lastFlushedRole = "";
|
|
149254
|
+
function recordFilteredNoise(meta) {
|
|
149255
|
+
pendingNoiseMeta.push(meta);
|
|
149256
|
+
if (!currentBlock) {
|
|
149257
|
+
highestScannedOrdinal = Math.max(highestScannedOrdinal, meta.ordinal);
|
|
149258
|
+
}
|
|
149259
|
+
}
|
|
149224
149260
|
function flushCurrentBlock() {
|
|
149225
149261
|
if (!currentBlock)
|
|
149226
149262
|
return true;
|
|
@@ -149236,6 +149272,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
|
|
|
149236
149272
|
if (!firstMessageId)
|
|
149237
149273
|
firstMessageId = currentBlock.meta[0]?.messageId ?? "";
|
|
149238
149274
|
lastOrdinal = currentBlock.meta[currentBlock.meta.length - 1]?.ordinal ?? currentBlock.endOrdinal;
|
|
149275
|
+
highestScannedOrdinal = Math.max(highestScannedOrdinal, lastOrdinal);
|
|
149239
149276
|
lastMessageId = currentBlock.meta[currentBlock.meta.length - 1]?.messageId ?? "";
|
|
149240
149277
|
messagesProcessed += currentBlock.meta.length;
|
|
149241
149278
|
lines.push(blockText);
|
|
@@ -149259,7 +149296,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
|
|
|
149259
149296
|
if (msg.role === "user" && !hasMeaningfulUserText(msg.parts)) {
|
|
149260
149297
|
const tcSummaries = extractToolCallSummaries(msg.parts);
|
|
149261
149298
|
if (tcSummaries.length === 0) {
|
|
149262
|
-
|
|
149299
|
+
recordFilteredNoise(meta);
|
|
149263
149300
|
continue;
|
|
149264
149301
|
}
|
|
149265
149302
|
const tcText = tcSummaries.join(" / ");
|
|
@@ -149291,7 +149328,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
|
|
|
149291
149328
|
const compacted = compactTextForSummary(allParts.join(" / "), msg.role);
|
|
149292
149329
|
const text = compacted.text;
|
|
149293
149330
|
if (!text) {
|
|
149294
|
-
|
|
149331
|
+
recordFilteredNoise(meta);
|
|
149295
149332
|
continue;
|
|
149296
149333
|
}
|
|
149297
149334
|
const msgHasNarrative = textParts.length > 0;
|
|
@@ -149318,7 +149355,9 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
|
|
|
149318
149355
|
};
|
|
149319
149356
|
pendingNoiseMeta = [];
|
|
149320
149357
|
}
|
|
149321
|
-
flushCurrentBlock()
|
|
149358
|
+
if (flushCurrentBlock() && pendingNoiseMeta.length > 0) {
|
|
149359
|
+
highestScannedOrdinal = Math.max(highestScannedOrdinal, pendingNoiseMeta[pendingNoiseMeta.length - 1]?.ordinal ?? highestScannedOrdinal);
|
|
149360
|
+
}
|
|
149322
149361
|
const toolOnlyRanges = [];
|
|
149323
149362
|
for (const range of flushedToolOnlyBlocks) {
|
|
149324
149363
|
const last = toolOnlyRanges[toolOnlyRanges.length - 1];
|
|
@@ -149335,7 +149374,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
|
|
|
149335
149374
|
endMessageId: lastMessageId,
|
|
149336
149375
|
messageCount: messagesProcessed,
|
|
149337
149376
|
tokenEstimate: totalTokens,
|
|
149338
|
-
hasMore: lastOrdinal < (eligibleEndOrdinal !== undefined ? Math.min(eligibleEndOrdinal - 1, totalMessageCount) : totalMessageCount),
|
|
149377
|
+
hasMore: Math.max(lastOrdinal, highestScannedOrdinal) < (eligibleEndOrdinal !== undefined ? Math.min(eligibleEndOrdinal - 1, totalMessageCount) : totalMessageCount),
|
|
149339
149378
|
text: lines.join(`
|
|
149340
149379
|
`),
|
|
149341
149380
|
lines: lineMeta,
|
|
@@ -149370,7 +149409,10 @@ function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
|
|
|
149370
149409
|
var lastIndexedStatements = new WeakMap;
|
|
149371
149410
|
var insertMessageStatements = new WeakMap;
|
|
149372
149411
|
var upsertIndexStatements = new WeakMap;
|
|
149412
|
+
var upsertCleanIndexStatements = new WeakMap;
|
|
149413
|
+
var upsertDirtyFloorStatements = new WeakMap;
|
|
149373
149414
|
var deleteFtsStatements = new WeakMap;
|
|
149415
|
+
var deleteFtsFromOrdinalStatements = new WeakMap;
|
|
149374
149416
|
var deleteIndexStatements = new WeakMap;
|
|
149375
149417
|
var countIndexedMessageStatements = new WeakMap;
|
|
149376
149418
|
function normalizeIndexText(text) {
|
|
@@ -149379,7 +149421,7 @@ function normalizeIndexText(text) {
|
|
|
149379
149421
|
function getLastIndexedStatement(db) {
|
|
149380
149422
|
let stmt = lastIndexedStatements.get(db);
|
|
149381
149423
|
if (!stmt) {
|
|
149382
|
-
stmt = db.prepare("SELECT last_indexed_ordinal FROM message_history_index WHERE session_id = ?");
|
|
149424
|
+
stmt = db.prepare("SELECT last_indexed_ordinal, dirty_floor_ordinal FROM message_history_index WHERE session_id = ?");
|
|
149383
149425
|
lastIndexedStatements.set(db, stmt);
|
|
149384
149426
|
}
|
|
149385
149427
|
return stmt;
|
|
@@ -149400,6 +149442,22 @@ function getUpsertIndexStatement(db) {
|
|
|
149400
149442
|
}
|
|
149401
149443
|
return stmt;
|
|
149402
149444
|
}
|
|
149445
|
+
function getUpsertCleanIndexStatement(db) {
|
|
149446
|
+
let stmt = upsertCleanIndexStatements.get(db);
|
|
149447
|
+
if (!stmt) {
|
|
149448
|
+
stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, dirty_floor_ordinal, updated_at, harness) VALUES (?, ?, 0, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = excluded.last_indexed_ordinal, dirty_floor_ordinal = 0, updated_at = excluded.updated_at");
|
|
149449
|
+
upsertCleanIndexStatements.set(db, stmt);
|
|
149450
|
+
}
|
|
149451
|
+
return stmt;
|
|
149452
|
+
}
|
|
149453
|
+
function getUpsertDirtyFloorStatement(db) {
|
|
149454
|
+
let stmt = upsertDirtyFloorStatements.get(db);
|
|
149455
|
+
if (!stmt) {
|
|
149456
|
+
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 = MAX(message_history_index.last_indexed_ordinal, excluded.last_indexed_ordinal), dirty_floor_ordinal = CASE WHEN message_history_index.dirty_floor_ordinal <= 0 THEN excluded.dirty_floor_ordinal WHEN excluded.dirty_floor_ordinal <= 0 THEN message_history_index.dirty_floor_ordinal ELSE MIN(message_history_index.dirty_floor_ordinal, excluded.dirty_floor_ordinal) END, updated_at = excluded.updated_at");
|
|
149457
|
+
upsertDirtyFloorStatements.set(db, stmt);
|
|
149458
|
+
}
|
|
149459
|
+
return stmt;
|
|
149460
|
+
}
|
|
149403
149461
|
function getDeleteFtsStatement(db) {
|
|
149404
149462
|
let stmt = deleteFtsStatements.get(db);
|
|
149405
149463
|
if (!stmt) {
|
|
@@ -149408,6 +149466,14 @@ function getDeleteFtsStatement(db) {
|
|
|
149408
149466
|
}
|
|
149409
149467
|
return stmt;
|
|
149410
149468
|
}
|
|
149469
|
+
function getDeleteFtsFromOrdinalStatement(db) {
|
|
149470
|
+
let stmt = deleteFtsFromOrdinalStatements.get(db);
|
|
149471
|
+
if (!stmt) {
|
|
149472
|
+
stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ? AND CAST(message_ordinal AS INTEGER) >= ?");
|
|
149473
|
+
deleteFtsFromOrdinalStatements.set(db, stmt);
|
|
149474
|
+
}
|
|
149475
|
+
return stmt;
|
|
149476
|
+
}
|
|
149411
149477
|
function getDeleteIndexStatement(db) {
|
|
149412
149478
|
let stmt = deleteIndexStatements.get(db);
|
|
149413
149479
|
if (!stmt) {
|
|
@@ -149428,6 +149494,14 @@ function getLastIndexedOrdinal(db, sessionId) {
|
|
|
149428
149494
|
const row = getLastIndexedStatement(db).get(sessionId);
|
|
149429
149495
|
return typeof row?.last_indexed_ordinal === "number" ? row.last_indexed_ordinal : 0;
|
|
149430
149496
|
}
|
|
149497
|
+
function getDirtyIndexFloor(db, sessionId) {
|
|
149498
|
+
const row = getLastIndexedStatement(db).get(sessionId);
|
|
149499
|
+
return typeof row?.dirty_floor_ordinal === "number" && row.dirty_floor_ordinal > 0 ? row.dirty_floor_ordinal : null;
|
|
149500
|
+
}
|
|
149501
|
+
function markMessageIndexDirty(db, sessionId, floorOrdinal) {
|
|
149502
|
+
const dirtyFloor = Math.max(1, Math.floor(floorOrdinal));
|
|
149503
|
+
getUpsertDirtyFloorStatement(db).run(sessionId, getLastIndexedOrdinal(db, sessionId), dirtyFloor, Date.now(), getHarness());
|
|
149504
|
+
}
|
|
149431
149505
|
function isMessageAlreadyIndexed(db, sessionId, messageId) {
|
|
149432
149506
|
const row = getCountIndexedMessageStatement(db).get(sessionId, messageId);
|
|
149433
149507
|
return (typeof row?.count === "number" ? row.count : 0) > 0;
|
|
@@ -149495,7 +149569,15 @@ function indexMessagesAfterOrdinal(db, sessionId, messages, lastIndexedOrdinal,
|
|
|
149495
149569
|
db.exec("BEGIN IMMEDIATE");
|
|
149496
149570
|
let committed = false;
|
|
149497
149571
|
try {
|
|
149498
|
-
|
|
149572
|
+
let effectiveWatermark = Math.max(lastIndexedOrdinal, getLastIndexedOrdinal(db, sessionId));
|
|
149573
|
+
const dirtyFloor = getDirtyIndexFloor(db, sessionId);
|
|
149574
|
+
if (dirtyFloor !== null) {
|
|
149575
|
+
const rewindOrdinal = Math.max(1, Math.min(dirtyFloor, finalWatermark + 1));
|
|
149576
|
+
if (rewindOrdinal <= finalWatermark) {
|
|
149577
|
+
getDeleteFtsFromOrdinalStatement(db).run(sessionId, rewindOrdinal);
|
|
149578
|
+
}
|
|
149579
|
+
effectiveWatermark = Math.min(effectiveWatermark, rewindOrdinal - 1);
|
|
149580
|
+
}
|
|
149499
149581
|
const insertMessage = getInsertMessageStatement(db);
|
|
149500
149582
|
for (const message of messages) {
|
|
149501
149583
|
if (message.ordinal <= effectiveWatermark) {
|
|
@@ -149512,7 +149594,7 @@ function indexMessagesAfterOrdinal(db, sessionId, messages, lastIndexedOrdinal,
|
|
|
149512
149594
|
inserted++;
|
|
149513
149595
|
}
|
|
149514
149596
|
const newWatermark = Math.max(effectiveWatermark, finalWatermark);
|
|
149515
|
-
|
|
149597
|
+
getUpsertCleanIndexStatement(db).run(sessionId, newWatermark, now, getHarness());
|
|
149516
149598
|
db.exec("COMMIT");
|
|
149517
149599
|
committed = true;
|
|
149518
149600
|
} finally {
|
|
@@ -149609,8 +149691,9 @@ function scheduleReconciliation(db, sessionId, readMessages) {
|
|
|
149609
149691
|
reconciliationScheduledSessions.add(sessionId);
|
|
149610
149692
|
defer(() => {
|
|
149611
149693
|
reconcileSessionIndex(db, sessionId, readMessages).catch((error) => {
|
|
149612
|
-
reconciliationScheduledSessions.delete(sessionId);
|
|
149613
149694
|
logIndexingError(sessionId, "reconciliation", error);
|
|
149695
|
+
}).finally(() => {
|
|
149696
|
+
reconciliationScheduledSessions.delete(sessionId);
|
|
149614
149697
|
});
|
|
149615
149698
|
});
|
|
149616
149699
|
}
|
|
@@ -149622,13 +149705,17 @@ function scheduleIncrementalIndex(db, sessionId, messageId, readSingleMessage) {
|
|
|
149622
149705
|
const timer = setTimeout(() => {
|
|
149623
149706
|
incrementalTimers.delete(key);
|
|
149624
149707
|
pendingIncrementalKeys.add(key);
|
|
149708
|
+
let attemptedOrdinal = null;
|
|
149625
149709
|
runWithSessionLock(sessionId, () => {
|
|
149626
149710
|
const message = readSingleMessage(sessionId, messageId);
|
|
149627
149711
|
if (!message) {
|
|
149628
149712
|
return;
|
|
149629
149713
|
}
|
|
149714
|
+
attemptedOrdinal = message.ordinal;
|
|
149630
149715
|
indexSingleMessage(db, sessionId, message);
|
|
149631
149716
|
}).catch((error) => {
|
|
149717
|
+
markMessageIndexDirty(db, sessionId, attemptedOrdinal ?? getLastIndexedOrdinal(db, sessionId) + 1);
|
|
149718
|
+
reconciledSessions.delete(sessionId);
|
|
149632
149719
|
logIndexingError(sessionId, `incremental index for ${messageId}`, error);
|
|
149633
149720
|
}).finally(() => {
|
|
149634
149721
|
pendingIncrementalKeys.delete(key);
|
|
@@ -150580,6 +150667,7 @@ function healNullTextColumns(db) {
|
|
|
150580
150667
|
["cache_ttl", ""],
|
|
150581
150668
|
["last_nudge_band", ""],
|
|
150582
150669
|
["last_nudge_level", ""],
|
|
150670
|
+
["channel2_nudge_claim_token", ""],
|
|
150583
150671
|
["last_transform_error", ""],
|
|
150584
150672
|
["nudge_anchor_message_id", ""],
|
|
150585
150673
|
["nudge_anchor_text", ""],
|
|
@@ -150643,6 +150731,7 @@ function healNullIntegerColumns(db) {
|
|
|
150643
150731
|
}
|
|
150644
150732
|
|
|
150645
150733
|
// ../plugin/src/features/magic-context/workspaces.ts
|
|
150734
|
+
init_logger();
|
|
150646
150735
|
import { createHash as createHash2 } from "node:crypto";
|
|
150647
150736
|
|
|
150648
150737
|
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
@@ -150693,6 +150782,7 @@ var CATEGORY_DEFAULT_TTL = {
|
|
|
150693
150782
|
};
|
|
150694
150783
|
// ../plugin/src/features/magic-context/workspaces.ts
|
|
150695
150784
|
var VALID_SHARE_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
150785
|
+
var DEFAULT_WORKSPACE_SHARE_CATEGORIES = ["CONSTRAINTS"];
|
|
150696
150786
|
function tableExists(db, tableName) {
|
|
150697
150787
|
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ? LIMIT 1").get(tableName);
|
|
150698
150788
|
return Boolean(row);
|
|
@@ -150707,23 +150797,39 @@ function uniqueSorted(values) {
|
|
|
150707
150797
|
function placeholders(values) {
|
|
150708
150798
|
return values.map(() => "?").join(", ");
|
|
150709
150799
|
}
|
|
150800
|
+
function defaultWorkspaceShareCategories() {
|
|
150801
|
+
return [...DEFAULT_WORKSPACE_SHARE_CATEGORIES];
|
|
150802
|
+
}
|
|
150803
|
+
function warnInvalidShareCategories(reason, raw) {
|
|
150804
|
+
log("[magic-context] WARN: invalid workspace share_categories; sharing no foreign memory categories", {
|
|
150805
|
+
reason,
|
|
150806
|
+
raw
|
|
150807
|
+
});
|
|
150808
|
+
}
|
|
150710
150809
|
function normalizeShareCategories(raw) {
|
|
150711
|
-
if (raw === null || raw === undefined)
|
|
150712
|
-
return
|
|
150713
|
-
|
|
150714
|
-
|
|
150810
|
+
if (raw === null || raw === undefined) {
|
|
150811
|
+
return defaultWorkspaceShareCategories();
|
|
150812
|
+
}
|
|
150813
|
+
if (typeof raw !== "string") {
|
|
150814
|
+
warnInvalidShareCategories("not a string", raw);
|
|
150815
|
+
return [];
|
|
150816
|
+
}
|
|
150715
150817
|
let parsed;
|
|
150716
150818
|
try {
|
|
150717
150819
|
parsed = JSON.parse(raw);
|
|
150718
150820
|
} catch {
|
|
150719
|
-
|
|
150821
|
+
warnInvalidShareCategories("malformed JSON", raw);
|
|
150822
|
+
return [];
|
|
150823
|
+
}
|
|
150824
|
+
if (!Array.isArray(parsed)) {
|
|
150825
|
+
warnInvalidShareCategories("not a JSON array", raw);
|
|
150826
|
+
return [];
|
|
150720
150827
|
}
|
|
150721
|
-
if (!Array.isArray(parsed))
|
|
150722
|
-
return null;
|
|
150723
150828
|
const categories = [];
|
|
150724
150829
|
for (const value of parsed) {
|
|
150725
150830
|
if (typeof value !== "string" || !VALID_SHARE_CATEGORIES.has(value)) {
|
|
150726
|
-
|
|
150831
|
+
warnInvalidShareCategories("unknown category", raw);
|
|
150832
|
+
return [];
|
|
150727
150833
|
}
|
|
150728
150834
|
if (!categories.includes(value))
|
|
150729
150835
|
categories.push(value);
|
|
@@ -150732,16 +150838,33 @@ function normalizeShareCategories(raw) {
|
|
|
150732
150838
|
}
|
|
150733
150839
|
function selectWorkspaceShareCategories(db, identities) {
|
|
150734
150840
|
const candidates = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
150735
|
-
if (candidates.length === 0 || !tableExists(db, "workspace_members")
|
|
150841
|
+
if (candidates.length === 0 || !tableExists(db, "workspace_members")) {
|
|
150736
150842
|
return null;
|
|
150737
150843
|
}
|
|
150844
|
+
const hasMembership = Boolean(db.prepare(`SELECT 1
|
|
150845
|
+
FROM workspace_members
|
|
150846
|
+
WHERE project_path IN (${placeholders(candidates)})
|
|
150847
|
+
LIMIT 1`).get(...candidates));
|
|
150848
|
+
if (!hasMembership)
|
|
150849
|
+
return null;
|
|
150850
|
+
if (!tableExists(db, "workspaces")) {
|
|
150851
|
+
log("[magic-context] WARN: workspace member has no workspaces table; sharing no foreign memory categories");
|
|
150852
|
+
return [];
|
|
150853
|
+
}
|
|
150854
|
+
if (!columnExists(db, "workspaces", "share_categories")) {
|
|
150855
|
+
return defaultWorkspaceShareCategories();
|
|
150856
|
+
}
|
|
150738
150857
|
const row = db.prepare(`SELECT workspace.share_categories AS shareCategories
|
|
150739
150858
|
FROM workspace_members AS member
|
|
150740
150859
|
JOIN workspaces AS workspace ON workspace.id = member.workspace_id
|
|
150741
150860
|
WHERE member.project_path IN (${placeholders(candidates)})
|
|
150742
150861
|
ORDER BY workspace.id ASC
|
|
150743
150862
|
LIMIT 1`).get(...candidates);
|
|
150744
|
-
|
|
150863
|
+
if (!row) {
|
|
150864
|
+
log("[magic-context] WARN: workspace member has no workspace share_categories row; sharing no foreign memory categories");
|
|
150865
|
+
return [];
|
|
150866
|
+
}
|
|
150867
|
+
return normalizeShareCategories(row.shareCategories);
|
|
150745
150868
|
}
|
|
150746
150869
|
function resolveWorkspaceShareCategories(db, projectIdentity) {
|
|
150747
150870
|
return selectWorkspaceShareCategories(db, [projectIdentity]);
|
|
@@ -150846,7 +150969,7 @@ function computeWorkspaceEpochFingerprint(db, identities) {
|
|
|
150846
150969
|
const hash = createHash2("sha256");
|
|
150847
150970
|
hash.update("share_categories", "utf8");
|
|
150848
150971
|
hash.update("\x00");
|
|
150849
|
-
hash.update(shareCategories === null ? "
|
|
150972
|
+
hash.update(shareCategories === null ? "NO_WORKSPACE" : JSON.stringify(shareCategories), "utf8");
|
|
150850
150973
|
hash.update(`
|
|
150851
150974
|
`);
|
|
150852
150975
|
for (const identity of canonical) {
|
|
@@ -153418,6 +153541,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
153418
153541
|
CREATE TABLE IF NOT EXISTS message_history_index (
|
|
153419
153542
|
session_id TEXT PRIMARY KEY,
|
|
153420
153543
|
last_indexed_ordinal INTEGER NOT NULL DEFAULT 0,
|
|
153544
|
+
dirty_floor_ordinal INTEGER NOT NULL DEFAULT 0,
|
|
153421
153545
|
updated_at INTEGER NOT NULL,
|
|
153422
153546
|
harness TEXT NOT NULL DEFAULT 'opencode'
|
|
153423
153547
|
);
|
|
@@ -153447,6 +153571,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
153447
153571
|
last_nudge_level TEXT DEFAULT '',
|
|
153448
153572
|
channel2_nudge_state TEXT DEFAULT '',
|
|
153449
153573
|
channel2_nudge_claimed_at INTEGER DEFAULT 0,
|
|
153574
|
+
channel2_nudge_claim_token TEXT DEFAULT '',
|
|
153450
153575
|
last_emergency_input_sample INTEGER DEFAULT 0,
|
|
153451
153576
|
last_transform_error TEXT DEFAULT '',
|
|
153452
153577
|
nudge_anchor_message_id TEXT DEFAULT '',
|
|
@@ -153693,6 +153818,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
153693
153818
|
ensureColumn(db, "session_meta", "last_nudge_level", "TEXT DEFAULT ''");
|
|
153694
153819
|
ensureColumn(db, "session_meta", "channel2_nudge_state", "TEXT DEFAULT ''");
|
|
153695
153820
|
ensureColumn(db, "session_meta", "channel2_nudge_claimed_at", "INTEGER DEFAULT 0");
|
|
153821
|
+
ensureColumn(db, "session_meta", "channel2_nudge_claim_token", "TEXT DEFAULT ''");
|
|
153696
153822
|
ensureColumn(db, "session_meta", "last_emergency_input_sample", "INTEGER DEFAULT 0");
|
|
153697
153823
|
ensureColumn(db, "session_meta", "last_transform_error", "TEXT DEFAULT ''");
|
|
153698
153824
|
ensureColumn(db, "session_meta", "nudge_anchor_message_id", "TEXT DEFAULT ''");
|
|
@@ -153905,6 +154031,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
153905
154031
|
ON transform_decisions(session_id, harness);
|
|
153906
154032
|
`);
|
|
153907
154033
|
ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
154034
|
+
ensureColumn(db, "message_history_index", "dirty_floor_ordinal", "INTEGER NOT NULL DEFAULT 0");
|
|
153908
154035
|
ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
153909
154036
|
ensureColumn(db, "source_contents", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
153910
154037
|
ensureColumn(db, "compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
@@ -153920,7 +154047,7 @@ var CHANNEL2_CLAIM_TTL_MS = 120000;
|
|
|
153920
154047
|
function healWedgedChannel2Claims(db) {
|
|
153921
154048
|
try {
|
|
153922
154049
|
const staleBefore = Date.now() - CHANNEL2_CLAIM_TTL_MS;
|
|
153923
|
-
db.prepare("UPDATE session_meta SET channel2_nudge_state = 'pending', channel2_nudge_claimed_at = 0 WHERE channel2_nudge_state = 'claimed' AND (channel2_nudge_claimed_at IS NULL OR channel2_nudge_claimed_at = 0 OR channel2_nudge_claimed_at <= ?)").run(staleBefore);
|
|
154050
|
+
db.prepare("UPDATE session_meta SET channel2_nudge_state = 'pending', channel2_nudge_claimed_at = 0, channel2_nudge_claim_token = '' WHERE channel2_nudge_state = 'claimed' AND (channel2_nudge_claimed_at IS NULL OR channel2_nudge_claimed_at = 0 OR channel2_nudge_claimed_at <= ?)").run(staleBefore);
|
|
153924
154051
|
} catch {}
|
|
153925
154052
|
}
|
|
153926
154053
|
function openDatabase(dbPathOrOptions) {
|
|
@@ -154613,7 +154740,7 @@ function setChannel2NudgeState(db, sessionId, state) {
|
|
|
154613
154740
|
db.transaction(() => {
|
|
154614
154741
|
ensureSessionMetaRow(db, sessionId);
|
|
154615
154742
|
const claimedAt = state === "claimed" ? Date.now() : 0;
|
|
154616
|
-
db.prepare("UPDATE session_meta SET channel2_nudge_state = ?, channel2_nudge_claimed_at =
|
|
154743
|
+
db.prepare("UPDATE session_meta SET channel2_nudge_state = ?, channel2_nudge_claimed_at = ?, channel2_nudge_claim_token = '' WHERE session_id = ?").run(state, claimedAt, sessionId);
|
|
154617
154744
|
})();
|
|
154618
154745
|
}
|
|
154619
154746
|
function casChannel2NudgeState(db, sessionId, from, to) {
|
|
@@ -154621,7 +154748,7 @@ function casChannel2NudgeState(db, sessionId, from, to) {
|
|
|
154621
154748
|
db.transaction(() => {
|
|
154622
154749
|
ensureSessionMetaRow(db, sessionId);
|
|
154623
154750
|
const claimedAt = to === "claimed" ? Date.now() : 0;
|
|
154624
|
-
const result = db.prepare("UPDATE session_meta SET channel2_nudge_state = ?, channel2_nudge_claimed_at =
|
|
154751
|
+
const result = db.prepare("UPDATE session_meta SET channel2_nudge_state = ?, channel2_nudge_claimed_at = ?, channel2_nudge_claim_token = '' WHERE session_id = ? AND channel2_nudge_state = ?").run(to, claimedAt, sessionId, from);
|
|
154625
154752
|
changed = (result.changes ?? 0) > 0;
|
|
154626
154753
|
})();
|
|
154627
154754
|
return changed;
|
|
@@ -156833,8 +156960,31 @@ function clearNoteNudgeTriggerOnly(db, sessionId) {
|
|
|
156833
156960
|
|
|
156834
156961
|
// ../plugin/src/hooks/magic-context/todo-view.ts
|
|
156835
156962
|
import { createHash as createHash5 } from "node:crypto";
|
|
156836
|
-
var
|
|
156837
|
-
var
|
|
156963
|
+
var TODO_STATUS_PENDING = "pending";
|
|
156964
|
+
var TODO_STATUS_IN_PROGRESS = "in_progress";
|
|
156965
|
+
var TODO_STATUS_COMPLETED = "completed";
|
|
156966
|
+
var TODO_STATUS_CANCELLED = "cancelled";
|
|
156967
|
+
var TODO_PRIORITY_HIGH = "high";
|
|
156968
|
+
var TODO_PRIORITY_MEDIUM = "medium";
|
|
156969
|
+
var TODO_PRIORITY_LOW = "low";
|
|
156970
|
+
var TODO_STATUSES = [
|
|
156971
|
+
TODO_STATUS_PENDING,
|
|
156972
|
+
TODO_STATUS_IN_PROGRESS,
|
|
156973
|
+
TODO_STATUS_COMPLETED,
|
|
156974
|
+
TODO_STATUS_CANCELLED
|
|
156975
|
+
];
|
|
156976
|
+
var TODO_PRIORITIES = [
|
|
156977
|
+
TODO_PRIORITY_HIGH,
|
|
156978
|
+
TODO_PRIORITY_MEDIUM,
|
|
156979
|
+
TODO_PRIORITY_LOW
|
|
156980
|
+
];
|
|
156981
|
+
var TODO_STATUS_SET = new Set(TODO_STATUSES);
|
|
156982
|
+
var TODO_PRIORITY_SET = new Set(TODO_PRIORITIES);
|
|
156983
|
+
var TERMINAL_STATUSES = new Set([
|
|
156984
|
+
TODO_STATUS_COMPLETED,
|
|
156985
|
+
TODO_STATUS_CANCELLED
|
|
156986
|
+
]);
|
|
156987
|
+
var TITLE_DONE_STATUSES = new Set([TODO_STATUS_COMPLETED]);
|
|
156838
156988
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
156839
156989
|
function normalizeTodoStateJson(todos) {
|
|
156840
156990
|
if (!Array.isArray(todos))
|
|
@@ -156846,7 +156996,7 @@ function normalizeTodoStateJson(todos) {
|
|
|
156846
156996
|
normalized.push({
|
|
156847
156997
|
content: todo.content,
|
|
156848
156998
|
status: todo.status,
|
|
156849
|
-
priority: todo.priority ??
|
|
156999
|
+
priority: todo.priority ?? TODO_PRIORITY_MEDIUM
|
|
156850
157000
|
});
|
|
156851
157001
|
}
|
|
156852
157002
|
return JSON.stringify(normalized);
|
|
@@ -156890,11 +157040,11 @@ function parseTodoState(stateJson) {
|
|
|
156890
157040
|
const result = [];
|
|
156891
157041
|
for (const item of parsed) {
|
|
156892
157042
|
if (!isTodoItem(item))
|
|
156893
|
-
|
|
157043
|
+
return null;
|
|
156894
157044
|
result.push({
|
|
156895
157045
|
content: item.content,
|
|
156896
157046
|
status: item.status,
|
|
156897
|
-
priority: item.priority ??
|
|
157047
|
+
priority: item.priority ?? TODO_PRIORITY_MEDIUM
|
|
156898
157048
|
});
|
|
156899
157049
|
}
|
|
156900
157050
|
return result;
|
|
@@ -156902,11 +157052,17 @@ function parseTodoState(stateJson) {
|
|
|
156902
157052
|
return null;
|
|
156903
157053
|
}
|
|
156904
157054
|
}
|
|
157055
|
+
function isTodoStatus(value) {
|
|
157056
|
+
return typeof value === "string" && TODO_STATUS_SET.has(value);
|
|
157057
|
+
}
|
|
157058
|
+
function isTodoPriority(value) {
|
|
157059
|
+
return typeof value === "string" && TODO_PRIORITY_SET.has(value);
|
|
157060
|
+
}
|
|
156905
157061
|
function isTodoItem(value) {
|
|
156906
157062
|
if (value === null || typeof value !== "object")
|
|
156907
157063
|
return false;
|
|
156908
157064
|
const todo = value;
|
|
156909
|
-
return typeof todo.content === "string" &&
|
|
157065
|
+
return typeof todo.content === "string" && isTodoStatus(todo.status) && (todo.priority === undefined || isTodoPriority(todo.priority));
|
|
156910
157066
|
}
|
|
156911
157067
|
|
|
156912
157068
|
// ../plugin/src/hooks/magic-context/upgrade-reminder.ts
|
|
@@ -157432,18 +157588,48 @@ function inferAccountingSubagent(agent) {
|
|
|
157432
157588
|
return "recomp";
|
|
157433
157589
|
return "historian";
|
|
157434
157590
|
}
|
|
157591
|
+
var ALREADY_PROCESSING_PREFIX = "Agent is already processing";
|
|
157592
|
+
var ISOLATED_RETRY_MODEL_UNAVAILABLE_MESSAGE = "model unavailable in isolated retry: it is provided by a disabled extension; configure it through models.json or add a built-in/provider-configured fallback";
|
|
157593
|
+
var MODEL_RESOLUTION_ERROR_PATTERNS = [
|
|
157594
|
+
/unknown model/i,
|
|
157595
|
+
/unknown provider/i,
|
|
157596
|
+
/model.+not found/i,
|
|
157597
|
+
/provider.+not found/i,
|
|
157598
|
+
/could not resolve model/i,
|
|
157599
|
+
/no models? (matched|available|configured)/i,
|
|
157600
|
+
/model.+not configured/i
|
|
157601
|
+
];
|
|
157435
157602
|
|
|
157436
157603
|
class PiSubagentRunner {
|
|
157437
157604
|
harness = "pi";
|
|
157438
157605
|
invocation;
|
|
157439
157606
|
spawnImpl;
|
|
157440
157607
|
platform;
|
|
157608
|
+
extraArgs;
|
|
157441
157609
|
constructor(options = {}) {
|
|
157442
157610
|
this.invocation = options.piBinary ? { command: options.piBinary, prefixArgs: [] } : resolvePiInvocation();
|
|
157443
157611
|
this.spawnImpl = options.spawnImpl ?? childProcess.spawn;
|
|
157444
157612
|
this.platform = options.platform ?? process.platform;
|
|
157613
|
+
this.extraArgs = options.extraArgs ?? [];
|
|
157445
157614
|
}
|
|
157446
157615
|
async run(options) {
|
|
157616
|
+
const primaryRunMode = { disableDiscoveredExtensions: false };
|
|
157617
|
+
const primaryResult = await this.runModelChain(options, primaryRunMode);
|
|
157618
|
+
if (this.spawnUsesNoExtensions(primaryRunMode) || !isPiExtensionCollisionFailure(primaryResult)) {
|
|
157619
|
+
return primaryResult;
|
|
157620
|
+
}
|
|
157621
|
+
const sessionId = options.accountingSessionId ?? "pi-subagent";
|
|
157622
|
+
sessionLog(sessionId, "pi subagent: a loaded Pi extension started an agent turn before the child's prompt could run; retrying with an isolated extension set (user extensions disabled for this run)");
|
|
157623
|
+
const isolatedResult = await this.runModelChain(options, {
|
|
157624
|
+
disableDiscoveredExtensions: true
|
|
157625
|
+
});
|
|
157626
|
+
if (!isolatedResult.ok && isIsolatedRetryModelUnavailable(isolatedResult)) {
|
|
157627
|
+
sessionLog(sessionId, ISOLATED_RETRY_MODEL_UNAVAILABLE_MESSAGE);
|
|
157628
|
+
return annotateIsolatedRetryModelUnavailable(isolatedResult);
|
|
157629
|
+
}
|
|
157630
|
+
return isolatedResult;
|
|
157631
|
+
}
|
|
157632
|
+
async runModelChain(options, runMode) {
|
|
157447
157633
|
const models = [options.model, ...options.fallbackModels ?? []].filter((model) => typeof model === "string" && model.length > 0);
|
|
157448
157634
|
const attempts = models.length > 0 ? models : [undefined];
|
|
157449
157635
|
let lastResult = null;
|
|
@@ -157454,17 +157640,23 @@ class PiSubagentRunner {
|
|
|
157454
157640
|
model,
|
|
157455
157641
|
fallbackModels: undefined
|
|
157456
157642
|
};
|
|
157457
|
-
const result = await this.runOnce(attemptOptions);
|
|
157643
|
+
const result = await this.runOnce(attemptOptions, runMode);
|
|
157458
157644
|
if (result.ok)
|
|
157459
157645
|
return result;
|
|
157460
157646
|
lastResult = result;
|
|
157647
|
+
if (!this.spawnUsesNoExtensions(runMode) && isPiExtensionCollisionFailure(result)) {
|
|
157648
|
+
return result;
|
|
157649
|
+
}
|
|
157461
157650
|
if (index >= attempts.length - 1 || !isFallbackEligible(result.reason)) {
|
|
157462
157651
|
return result;
|
|
157463
157652
|
}
|
|
157464
157653
|
}
|
|
157465
|
-
return lastResult ?? this.runOnce({ ...options, fallbackModels: undefined });
|
|
157654
|
+
return lastResult ?? this.runOnce({ ...options, fallbackModels: undefined }, runMode);
|
|
157655
|
+
}
|
|
157656
|
+
spawnUsesNoExtensions(runMode) {
|
|
157657
|
+
return runMode.disableDiscoveredExtensions || hasNoExtensionsArg([...this.invocation.prefixArgs, ...this.extraArgs]);
|
|
157466
157658
|
}
|
|
157467
|
-
async runOnce(options) {
|
|
157659
|
+
async runOnce(options, runMode) {
|
|
157468
157660
|
const startTime = Date.now();
|
|
157469
157661
|
let recordedAccounting = false;
|
|
157470
157662
|
const recordAccounting = (result, messages = []) => {
|
|
@@ -157539,6 +157731,7 @@ class PiSubagentRunner {
|
|
|
157539
157731
|
}
|
|
157540
157732
|
}
|
|
157541
157733
|
const args = buildArgs(options, {
|
|
157734
|
+
disableDiscoveredExtensions: runMode.disableDiscoveredExtensions,
|
|
157542
157735
|
omitPositionalMessage: deliverViaStdin,
|
|
157543
157736
|
systemPromptPath
|
|
157544
157737
|
});
|
|
@@ -157566,7 +157759,7 @@ class PiSubagentRunner {
|
|
|
157566
157759
|
};
|
|
157567
157760
|
let child;
|
|
157568
157761
|
try {
|
|
157569
|
-
child = this.spawnImpl(this.invocation.command, [...this.invocation.prefixArgs, ...args], {
|
|
157762
|
+
child = this.spawnImpl(this.invocation.command, [...this.invocation.prefixArgs, ...this.extraArgs, ...args], {
|
|
157570
157763
|
cwd: options.cwd,
|
|
157571
157764
|
env: {
|
|
157572
157765
|
...process.env,
|
|
@@ -157860,6 +158053,32 @@ class PiSubagentRunner {
|
|
|
157860
158053
|
});
|
|
157861
158054
|
}
|
|
157862
158055
|
}
|
|
158056
|
+
function getResultStderr(result) {
|
|
158057
|
+
const stderr = result.meta?.stderr;
|
|
158058
|
+
return typeof stderr === "string" ? stderr : "";
|
|
158059
|
+
}
|
|
158060
|
+
function hasNoExtensionsArg(args) {
|
|
158061
|
+
return args.includes("--no-extensions");
|
|
158062
|
+
}
|
|
158063
|
+
function isPiExtensionCollisionFailure(result) {
|
|
158064
|
+
return !result.ok && result.reason === "non_zero_exit" && getResultStderr(result).includes(ALREADY_PROCESSING_PREFIX);
|
|
158065
|
+
}
|
|
158066
|
+
function isIsolatedRetryModelUnavailable(result) {
|
|
158067
|
+
if (result.ok)
|
|
158068
|
+
return false;
|
|
158069
|
+
const diagnosticText = `${result.error}
|
|
158070
|
+
${getResultStderr(result)}`;
|
|
158071
|
+
return MODEL_RESOLUTION_ERROR_PATTERNS.some((pattern) => pattern.test(diagnosticText));
|
|
158072
|
+
}
|
|
158073
|
+
function annotateIsolatedRetryModelUnavailable(result) {
|
|
158074
|
+
if (result.error.startsWith(ISOLATED_RETRY_MODEL_UNAVAILABLE_MESSAGE)) {
|
|
158075
|
+
return result;
|
|
158076
|
+
}
|
|
158077
|
+
return {
|
|
158078
|
+
...result,
|
|
158079
|
+
error: `${ISOLATED_RETRY_MODEL_UNAVAILABLE_MESSAGE}. Original failure: ${result.error}`
|
|
158080
|
+
};
|
|
158081
|
+
}
|
|
157863
158082
|
function isFallbackEligible(reason) {
|
|
157864
158083
|
return reason === "model_failed" || reason === "truncated" || reason === "non_zero_exit" || reason === "no_assistant";
|
|
157865
158084
|
}
|
|
@@ -157874,9 +158093,13 @@ function buildArgs(options, opts) {
|
|
|
157874
158093
|
"--no-prompt-templates",
|
|
157875
158094
|
"--no-context-files"
|
|
157876
158095
|
];
|
|
157877
|
-
|
|
158096
|
+
if (opts?.disableDiscoveredExtensions) {
|
|
158097
|
+
args.push("--no-extensions");
|
|
158098
|
+
}
|
|
158099
|
+
const subagentEntryPath = opts?.subagentEntryPath ?? SUBAGENT_ENTRY_PATH;
|
|
158100
|
+
const shouldLoadSubagentExtension = subagentEntryPath && (SEARCH_ONLY_SUBAGENT_TOOL_AGENTS.has(options.agent) || DREAMER_ACTION_AGENTS.has(options.agent));
|
|
157878
158101
|
if (shouldLoadSubagentExtension) {
|
|
157879
|
-
args.push("--extension",
|
|
158102
|
+
args.push("--extension", subagentEntryPath);
|
|
157880
158103
|
if (DREAMER_ACTION_AGENTS.has(options.agent)) {
|
|
157881
158104
|
args.push("--magic-context-dreamer-actions");
|
|
157882
158105
|
}
|
|
@@ -158585,6 +158808,22 @@ function extractLatestAssistantText(messages) {
|
|
|
158585
158808
|
return getTextParts(latest).map((part) => part.text).join(`
|
|
158586
158809
|
`) || null;
|
|
158587
158810
|
}
|
|
158811
|
+
function hasLengthCappedOutput(value) {
|
|
158812
|
+
if (Array.isArray(value))
|
|
158813
|
+
return value.some((item) => hasLengthCappedOutput(item));
|
|
158814
|
+
if (!isRecord(value))
|
|
158815
|
+
return false;
|
|
158816
|
+
if (value.length_capped === true || value.lengthCapped === true)
|
|
158817
|
+
return true;
|
|
158818
|
+
const finishReason = value.finish_reason ?? value.finishReason;
|
|
158819
|
+
if (typeof finishReason === "string") {
|
|
158820
|
+
const normalized = finishReason.toLowerCase();
|
|
158821
|
+
if (normalized === "length" || normalized === "max_tokens" || normalized === "max_output_tokens") {
|
|
158822
|
+
return true;
|
|
158823
|
+
}
|
|
158824
|
+
}
|
|
158825
|
+
return Object.values(value).some((item) => hasLengthCappedOutput(item));
|
|
158826
|
+
}
|
|
158588
158827
|
|
|
158589
158828
|
// ../plugin/src/features/magic-context/dreamer/task-executor.ts
|
|
158590
158829
|
init_logger();
|
|
@@ -174637,6 +174876,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
174637
174876
|
|
|
174638
174877
|
// ../plugin/src/features/magic-context/memory/storage-memory-embeddings.ts
|
|
174639
174878
|
var saveEmbeddingStatements = new WeakMap;
|
|
174879
|
+
var saveEmbeddingIfHashMatchesStatements = new WeakMap;
|
|
174640
174880
|
var loadAllEmbeddingsStatements = new WeakMap;
|
|
174641
174881
|
var deleteEmbeddingStatements = new WeakMap;
|
|
174642
174882
|
var getStoredModelIdStatements = new WeakMap;
|
|
@@ -174667,6 +174907,14 @@ function getSaveEmbeddingStatement(db) {
|
|
|
174667
174907
|
}
|
|
174668
174908
|
return stmt;
|
|
174669
174909
|
}
|
|
174910
|
+
function getSaveEmbeddingIfHashMatchesStatement(db) {
|
|
174911
|
+
let stmt = saveEmbeddingIfHashMatchesStatements.get(db);
|
|
174912
|
+
if (!stmt) {
|
|
174913
|
+
stmt = db.prepare("INSERT INTO memory_embeddings (memory_id, embedding, model_id) SELECT ?, ?, ? FROM memories WHERE id = ? AND normalized_hash = ? ON CONFLICT(memory_id, model_id) DO UPDATE SET embedding = excluded.embedding");
|
|
174914
|
+
saveEmbeddingIfHashMatchesStatements.set(db, stmt);
|
|
174915
|
+
}
|
|
174916
|
+
return stmt;
|
|
174917
|
+
}
|
|
174670
174918
|
function getLoadAllEmbeddingsStatement(db) {
|
|
174671
174919
|
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
174672
174920
|
if (!stmt) {
|
|
@@ -174695,6 +174943,10 @@ function saveEmbedding(db, memoryId, embedding, modelId) {
|
|
|
174695
174943
|
const blob = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
174696
174944
|
getSaveEmbeddingStatement(db).run(memoryId, blob, modelId);
|
|
174697
174945
|
}
|
|
174946
|
+
function saveEmbeddingIfHashMatches(db, memoryId, embedding, modelId, normalizedHash) {
|
|
174947
|
+
const blob = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
174948
|
+
return getSaveEmbeddingIfHashMatchesStatement(db).run(memoryId, blob, modelId, memoryId, normalizedHash).changes > 0;
|
|
174949
|
+
}
|
|
174698
174950
|
function loadAllEmbeddings(db, projectPath, modelId) {
|
|
174699
174951
|
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath, modelId).filter(isEmbeddingRow);
|
|
174700
174952
|
const embeddings = new Map;
|
|
@@ -175555,12 +175807,12 @@ function isUnembeddedMemoryRow(row) {
|
|
|
175555
175807
|
if (row === null || typeof row !== "object")
|
|
175556
175808
|
return false;
|
|
175557
175809
|
const candidate = row;
|
|
175558
|
-
return typeof candidate.id === "number" && typeof candidate.content === "string";
|
|
175810
|
+
return typeof candidate.id === "number" && typeof candidate.content === "string" && typeof candidate.normalized_hash === "string";
|
|
175559
175811
|
}
|
|
175560
175812
|
function getLoadUnembeddedMemoriesStatement(db) {
|
|
175561
175813
|
let stmt = loadUnembeddedMemoriesStatements.get(db);
|
|
175562
175814
|
if (!stmt) {
|
|
175563
|
-
stmt = db.prepare("SELECT m.id AS id, m.content AS content FROM memories m LEFT JOIN memory_embeddings me ON m.id = me.memory_id AND me.model_id = ? WHERE m.project_path = ? AND m.status = 'active' AND me.memory_id IS NULL LIMIT ?");
|
|
175815
|
+
stmt = db.prepare("SELECT m.id AS id, m.content AS content, m.normalized_hash AS normalized_hash FROM memories m LEFT JOIN memory_embeddings me ON m.id = me.memory_id AND me.model_id = ? WHERE m.project_path = ? AND m.status = 'active' AND me.memory_id IS NULL LIMIT ?");
|
|
175564
175816
|
loadUnembeddedMemoriesStatements.set(db, stmt);
|
|
175565
175817
|
}
|
|
175566
175818
|
return stmt;
|
|
@@ -175583,8 +175835,9 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
175583
175835
|
const embedding = result.vectors[index];
|
|
175584
175836
|
if (!embedding)
|
|
175585
175837
|
continue;
|
|
175586
|
-
|
|
175587
|
-
|
|
175838
|
+
if (saveEmbeddingIfHashMatches(db, memory.id, embedding, result.modelId, memory.normalized_hash)) {
|
|
175839
|
+
embeddedCount += 1;
|
|
175840
|
+
}
|
|
175588
175841
|
}
|
|
175589
175842
|
})();
|
|
175590
175843
|
return embeddedCount;
|
|
@@ -176286,25 +176539,33 @@ function getMemoryCountsByStatusStatement(db) {
|
|
|
176286
176539
|
}
|
|
176287
176540
|
return stmt;
|
|
176288
176541
|
}
|
|
176289
|
-
function
|
|
176290
|
-
const now = Date.now();
|
|
176291
|
-
const normalizedHash = computeNormalizedHash(input.content);
|
|
176542
|
+
function buildInsertMemoryValues(input, normalizedHash, now, includeImportance) {
|
|
176292
176543
|
const insertValues = [
|
|
176293
176544
|
input.projectPath,
|
|
176294
176545
|
input.category,
|
|
176295
176546
|
input.content,
|
|
176296
176547
|
normalizedHash
|
|
176297
176548
|
];
|
|
176298
|
-
if (
|
|
176549
|
+
if (includeImportance) {
|
|
176299
176550
|
insertValues.push(input.importance ?? 50);
|
|
176300
176551
|
}
|
|
176301
176552
|
insertValues.push(input.sourceSessionId ?? null, input.sourceType ?? "historian", 1, 0, now, now, now, now, null, "active", input.expiresAt ?? null, "unverified", null, null, null, input.metadataJson ?? null);
|
|
176302
|
-
|
|
176303
|
-
|
|
176304
|
-
|
|
176553
|
+
return insertValues;
|
|
176554
|
+
}
|
|
176555
|
+
function loadInsertedMemory(db, rowid) {
|
|
176556
|
+
const inserted = getMemoryById(db, Number(rowid));
|
|
176305
176557
|
if (!inserted) {
|
|
176306
176558
|
throw new Error("Failed to load inserted memory row");
|
|
176307
176559
|
}
|
|
176560
|
+
return inserted;
|
|
176561
|
+
}
|
|
176562
|
+
function insertMemory(db, input) {
|
|
176563
|
+
const now = Date.now();
|
|
176564
|
+
const normalizedHash = computeNormalizedHash(input.content);
|
|
176565
|
+
const insertValues = buildInsertMemoryValues(input, normalizedHash, now, hasMemoryImportanceColumn(db));
|
|
176566
|
+
const result = getInsertMemoryStatement(db).run(...insertValues);
|
|
176567
|
+
const insertedResult = result;
|
|
176568
|
+
const inserted = loadInsertedMemory(db, insertedResult.lastInsertRowid);
|
|
176308
176569
|
invalidateProject(input.projectPath);
|
|
176309
176570
|
return inserted;
|
|
176310
176571
|
}
|
|
@@ -177098,6 +177359,14 @@ function renewLease(db, holderId, leaseKey = DREAMING_LEASE_KEY) {
|
|
|
177098
177359
|
return true;
|
|
177099
177360
|
});
|
|
177100
177361
|
}
|
|
177362
|
+
function runLeaseGuardedWrite(db, holderId, leaseKey, fn) {
|
|
177363
|
+
return runImmediate2(db, () => {
|
|
177364
|
+
if (!peekLeaseHolderAndExpiry(db, holderId, leaseKey)) {
|
|
177365
|
+
throw new Error("Dream lease lost before guarded write");
|
|
177366
|
+
}
|
|
177367
|
+
return fn();
|
|
177368
|
+
});
|
|
177369
|
+
}
|
|
177101
177370
|
var LEASE_HEARTBEAT_INTERVAL_MS = 60 * 1000;
|
|
177102
177371
|
function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalMs = LEASE_HEARTBEAT_INTERVAL_MS) {
|
|
177103
177372
|
let lost = false;
|
|
@@ -177892,6 +178161,39 @@ function hasShareabilitySensitiveText(text) {
|
|
|
177892
178161
|
}
|
|
177893
178162
|
}
|
|
177894
178163
|
|
|
178164
|
+
// ../plugin/src/features/magic-context/dreamer/manifest-parser.ts
|
|
178165
|
+
function extractCompleteManifestBody(text, rootName) {
|
|
178166
|
+
const escapedRoot = rootName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
178167
|
+
const rootMatch = new RegExp(`<${escapedRoot}\\b[^>]*>([\\s\\S]*?)<\\/${escapedRoot}>`, "i").exec(text);
|
|
178168
|
+
if (rootMatch)
|
|
178169
|
+
return rootMatch[1];
|
|
178170
|
+
const hasOpenRoot = new RegExp(`<${escapedRoot}\\b`, "i").test(text);
|
|
178171
|
+
const hasCloseRoot = new RegExp(`<\\/${escapedRoot}>`, "i").test(text);
|
|
178172
|
+
if (hasOpenRoot && !hasCloseRoot) {
|
|
178173
|
+
throw new Error(`${rootName} manifest missing closing root tag`);
|
|
178174
|
+
}
|
|
178175
|
+
throw new Error(`${rootName} manifest missing complete root element`);
|
|
178176
|
+
}
|
|
178177
|
+
function assertNoDuplicateManifestIds(ids, rootName) {
|
|
178178
|
+
const seen = new Set;
|
|
178179
|
+
for (const id of ids) {
|
|
178180
|
+
if (seen.has(id))
|
|
178181
|
+
throw new Error(`${rootName} manifest contains duplicate id ${id}`);
|
|
178182
|
+
seen.add(id);
|
|
178183
|
+
}
|
|
178184
|
+
}
|
|
178185
|
+
function assertManifestCoversExactly(ids, expectedIds, rootName) {
|
|
178186
|
+
assertNoDuplicateManifestIds(ids, rootName);
|
|
178187
|
+
for (const id of ids) {
|
|
178188
|
+
if (!expectedIds.has(id))
|
|
178189
|
+
throw new Error(`${rootName} manifest contains unknown id ${id}`);
|
|
178190
|
+
}
|
|
178191
|
+
for (const id of expectedIds) {
|
|
178192
|
+
if (!ids.includes(id))
|
|
178193
|
+
throw new Error(`${rootName} manifest missing id ${id}`);
|
|
178194
|
+
}
|
|
178195
|
+
}
|
|
178196
|
+
|
|
177895
178197
|
// ../plugin/src/features/magic-context/dreamer/classify-prompt.ts
|
|
177896
178198
|
var SCORING_GUIDANCE = `### How to score importance (1-100)
|
|
177897
178199
|
Importance decides which memories survive when the injected memory block is over budget: high scores stay in context, low scores drop first. So the score is only useful if it **discriminates** — if most memories land in the same band, you have not classified them, you have just labelled them.
|
|
@@ -177958,14 +178260,15 @@ ${renderPool(args.memories)}`;
|
|
|
177958
178260
|
var SCOPES = new Set(["project", "ecosystem", "universe"]);
|
|
177959
178261
|
function parseClassifyManifest(text) {
|
|
177960
178262
|
const out = [];
|
|
177961
|
-
|
|
178263
|
+
const body = extractCompleteManifestBody(text, "classify");
|
|
178264
|
+
for (const m of body.matchAll(/<memory\b([^>]*)\/?>/g)) {
|
|
177962
178265
|
const attrs = m[1];
|
|
177963
178266
|
const idMatch = attrs.match(/\bid\s*=\s*"(\d+)"/);
|
|
177964
178267
|
if (!idMatch)
|
|
177965
|
-
|
|
178268
|
+
throw new Error("classify manifest entry missing numeric id");
|
|
177966
178269
|
const id = Number.parseInt(idMatch[1], 10);
|
|
177967
178270
|
if (!Number.isInteger(id))
|
|
177968
|
-
|
|
178271
|
+
throw new Error("classify manifest entry missing numeric id");
|
|
177969
178272
|
const entry = { id };
|
|
177970
178273
|
const impMatch = attrs.match(/\bimportance\s*=\s*"(\d+)"/);
|
|
177971
178274
|
if (impMatch) {
|
|
@@ -177974,18 +178277,23 @@ function parseClassifyManifest(text) {
|
|
|
177974
178277
|
entry.importance = Math.max(1, Math.min(100, imp));
|
|
177975
178278
|
}
|
|
177976
178279
|
const scopeMatch = attrs.match(/\bscope\s*=\s*"([a-z]+)"/i);
|
|
177977
|
-
if (scopeMatch
|
|
177978
|
-
|
|
178280
|
+
if (scopeMatch) {
|
|
178281
|
+
const scope = scopeMatch[1].toLowerCase();
|
|
178282
|
+
if (!SCOPES.has(scope))
|
|
178283
|
+
throw new Error(`classify manifest invalid scope ${scope}`);
|
|
178284
|
+
entry.scope = scope;
|
|
177979
178285
|
}
|
|
177980
178286
|
const shareMatch = attrs.match(/\bshareable\s*=\s*"(true|false|1|0)"/i);
|
|
177981
178287
|
if (shareMatch) {
|
|
177982
178288
|
const v = shareMatch[1].toLowerCase();
|
|
177983
178289
|
entry.shareable = v === "true" || v === "1";
|
|
177984
178290
|
}
|
|
177985
|
-
if (entry.importance
|
|
177986
|
-
|
|
178291
|
+
if (entry.importance === undefined && !entry.scope && entry.shareable === undefined) {
|
|
178292
|
+
throw new Error(`classify manifest entry ${id} missing classification fields`);
|
|
177987
178293
|
}
|
|
178294
|
+
out.push(entry);
|
|
177988
178295
|
}
|
|
178296
|
+
assertNoDuplicateManifestIds(out.map((entry) => entry.id), "classify");
|
|
177989
178297
|
return out;
|
|
177990
178298
|
}
|
|
177991
178299
|
|
|
@@ -178120,9 +178428,13 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
178120
178428
|
});
|
|
178121
178429
|
},
|
|
178122
178430
|
validateOutput: (messages) => {
|
|
178431
|
+
if (hasLengthCappedOutput(messages)) {
|
|
178432
|
+
throw new Error("classify returned length-capped output");
|
|
178433
|
+
}
|
|
178123
178434
|
const text = extractLatestAssistantText(messages);
|
|
178124
178435
|
if (!text)
|
|
178125
178436
|
throw new Error("classify returned no output");
|
|
178437
|
+
parseClassifyManifest(text);
|
|
178126
178438
|
return text;
|
|
178127
178439
|
}
|
|
178128
178440
|
});
|
|
@@ -178148,17 +178460,13 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
178148
178460
|
}
|
|
178149
178461
|
function applyClassifications(args, chunk, manifestText) {
|
|
178150
178462
|
const byId = new Map(chunk.map((m) => [m.id, m]));
|
|
178151
|
-
const parsed = parseClassifyManifest(manifestText)
|
|
178463
|
+
const parsed = parseClassifyManifest(manifestText);
|
|
178464
|
+
assertManifestCoversExactly(parsed.map((entry) => entry.id), new Set(byId.keys()), "classify");
|
|
178152
178465
|
if (parsed.length === 0)
|
|
178153
178466
|
return { classified: 0, changed: 0 };
|
|
178154
178467
|
let classified = 0;
|
|
178155
178468
|
let changed = 0;
|
|
178156
|
-
|
|
178157
|
-
args.db.transaction(() => {
|
|
178158
|
-
if (!peekLeaseHolderAndExpiry(args.db, args.holderId, args.leaseKey)) {
|
|
178159
|
-
leaseLost = true;
|
|
178160
|
-
return;
|
|
178161
|
-
}
|
|
178469
|
+
runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
|
|
178162
178470
|
for (const p of parsed) {
|
|
178163
178471
|
const memory = byId.get(p.id);
|
|
178164
178472
|
if (!memory)
|
|
@@ -178173,9 +178481,7 @@ function applyClassifications(args, chunk, manifestText) {
|
|
|
178173
178481
|
if (didChange)
|
|
178174
178482
|
changed += 1;
|
|
178175
178483
|
}
|
|
178176
|
-
})
|
|
178177
|
-
if (leaseLost)
|
|
178178
|
-
throw new Error("Dream lease lost during classify commit");
|
|
178484
|
+
});
|
|
178179
178485
|
return { classified, changed };
|
|
178180
178486
|
}
|
|
178181
178487
|
function recordInvocation(args, startedAt, params) {
|
|
@@ -178223,9 +178529,11 @@ var SMART_NOTE_CHECK_LIVENESS_RECHECK_MS = 24 * 60 * 60 * 1000;
|
|
|
178223
178529
|
|
|
178224
178530
|
class SmartNoteNetworkError extends Error {
|
|
178225
178531
|
isSmartNoteNetworkError = true;
|
|
178226
|
-
|
|
178532
|
+
terminal;
|
|
178533
|
+
constructor(message, options = {}) {
|
|
178227
178534
|
super(message);
|
|
178228
178535
|
this.name = "SmartNoteNetworkError";
|
|
178536
|
+
this.terminal = options.terminal ?? false;
|
|
178229
178537
|
}
|
|
178230
178538
|
}
|
|
178231
178539
|
|
|
@@ -178239,6 +178547,9 @@ class SmartNoteSecurityError extends Error {
|
|
|
178239
178547
|
function isSmartNoteNetworkError(error51) {
|
|
178240
178548
|
return error51 instanceof SmartNoteNetworkError || error51 instanceof Error && (error51.name === "SmartNoteNetworkError" || error51.message.includes("SmartNoteNetworkError") || error51.message.includes("SMART_NOTE_NETWORK"));
|
|
178241
178549
|
}
|
|
178550
|
+
function isTerminalSmartNoteNetworkError(error51) {
|
|
178551
|
+
return error51 instanceof SmartNoteNetworkError && error51.terminal;
|
|
178552
|
+
}
|
|
178242
178553
|
function parseSmartNoteManifest(json2) {
|
|
178243
178554
|
if (!json2)
|
|
178244
178555
|
return { capabilities: [] };
|
|
@@ -178268,6 +178579,7 @@ function stringArray(value) {
|
|
|
178268
178579
|
var DNS_TIMEOUT_MS = 3000;
|
|
178269
178580
|
var DEFAULT_HTTP_TIMEOUT_MS = 5000;
|
|
178270
178581
|
var DEFAULT_HTTP_BODY_LIMIT_BYTES = 64 * 1024;
|
|
178582
|
+
var MAX_HTTP_ADDRESS_CANDIDATES = 4;
|
|
178271
178583
|
var defaultResolver = {
|
|
178272
178584
|
async lookup(hostname3, signal) {
|
|
178273
178585
|
return await withAbortAndTimeout(dnsLookup(hostname3, { all: true, verbatim: true }), signal, DNS_TIMEOUT_MS, "DNS lookup timed out").then((rows) => rows.filter((row) => row.family === 4 || row.family === 6).map((row) => ({ address: row.address, family: row.family })));
|
|
@@ -178304,18 +178616,21 @@ async function guardedSmartNoteHttpGet(input, options) {
|
|
|
178304
178616
|
});
|
|
178305
178617
|
const timeoutMs = options.timeoutMs ?? DEFAULT_HTTP_TIMEOUT_MS;
|
|
178306
178618
|
const bodyLimitBytes = options.bodyLimitBytes ?? DEFAULT_HTTP_BODY_LIMIT_BYTES;
|
|
178619
|
+
const requestAddress = options.requestAddress ?? requestValidatedAddress;
|
|
178620
|
+
const candidates = validation.addresses.slice(0, MAX_HTTP_ADDRESS_CANDIDATES);
|
|
178307
178621
|
let lastError;
|
|
178308
|
-
for (const candidate of
|
|
178622
|
+
for (const candidate of candidates) {
|
|
178309
178623
|
try {
|
|
178310
|
-
return await
|
|
178624
|
+
return await requestAddress(validation, candidate, {
|
|
178311
178625
|
signal: options.signal,
|
|
178312
178626
|
timeoutMs,
|
|
178313
178627
|
bodyLimitBytes
|
|
178314
178628
|
});
|
|
178315
178629
|
} catch (error51) {
|
|
178316
178630
|
lastError = error51;
|
|
178317
|
-
if (error51 instanceof SmartNoteSecurityError || options.signal.aborted)
|
|
178631
|
+
if (error51 instanceof SmartNoteSecurityError || options.signal.aborted || isTerminalSmartNoteNetworkError(error51)) {
|
|
178318
178632
|
throw error51;
|
|
178633
|
+
}
|
|
178319
178634
|
}
|
|
178320
178635
|
}
|
|
178321
178636
|
throw toNetworkError(lastError, "all validated addresses failed");
|
|
@@ -178385,7 +178700,9 @@ function requestValidatedAddress(validation, candidate, options) {
|
|
|
178385
178700
|
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
178386
178701
|
bytes += buf.byteLength;
|
|
178387
178702
|
if (bytes > options.bodyLimitBytes) {
|
|
178388
|
-
|
|
178703
|
+
reject(new SmartNoteNetworkError("SMART_NOTE_NETWORK: response body too large", { terminal: true }));
|
|
178704
|
+
response.destroy();
|
|
178705
|
+
request2.destroy();
|
|
178389
178706
|
return;
|
|
178390
178707
|
}
|
|
178391
178708
|
chunks.push(buf);
|
|
@@ -178402,10 +178719,16 @@ function requestValidatedAddress(validation, candidate, options) {
|
|
|
178402
178719
|
resolve({ status, body: Buffer.concat(chunks).toString("utf8") });
|
|
178403
178720
|
});
|
|
178404
178721
|
});
|
|
178405
|
-
const onAbort = () =>
|
|
178722
|
+
const onAbort = () => {
|
|
178723
|
+
reject(new SmartNoteNetworkError("SMART_NOTE_NETWORK: aborted"));
|
|
178724
|
+
request2.destroy();
|
|
178725
|
+
};
|
|
178406
178726
|
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
178407
178727
|
request2.on("timeout", () => {
|
|
178408
|
-
|
|
178728
|
+
reject(new SmartNoteNetworkError("SMART_NOTE_NETWORK: request timed out", {
|
|
178729
|
+
terminal: true
|
|
178730
|
+
}));
|
|
178731
|
+
request2.destroy();
|
|
178409
178732
|
});
|
|
178410
178733
|
request2.on("error", (error51) => {
|
|
178411
178734
|
options.signal.removeEventListener("abort", onAbort);
|
|
@@ -178753,6 +179076,20 @@ function withSandboxLock(fn) {
|
|
|
178753
179076
|
var DEFAULT_TIMEOUT_MS = 2000;
|
|
178754
179077
|
var DEFAULT_HEAP_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
178755
179078
|
var DEFAULT_STACK_LIMIT_BYTES = 512 * 1024;
|
|
179079
|
+
function resolveCapabilitiesForRun(options, signal) {
|
|
179080
|
+
if (options.capabilityFactory) {
|
|
179081
|
+
return options.capabilityFactory(signal);
|
|
179082
|
+
}
|
|
179083
|
+
if (options.capabilities) {
|
|
179084
|
+
return options.capabilities;
|
|
179085
|
+
}
|
|
179086
|
+
throw new Error("smart-note check requires capabilities");
|
|
179087
|
+
}
|
|
179088
|
+
function throwIfRunAborted(signal) {
|
|
179089
|
+
if (signal.aborted) {
|
|
179090
|
+
throw signal.reason ?? new Error("smart-note check aborted");
|
|
179091
|
+
}
|
|
179092
|
+
}
|
|
178756
179093
|
async function runCompiledSmartNoteCheck(options) {
|
|
178757
179094
|
return withSandboxLock(() => runCompiledSmartNoteCheckLocked(options));
|
|
178758
179095
|
}
|
|
@@ -178760,17 +179097,24 @@ async function runCompiledSmartNoteCheckLocked(options) {
|
|
|
178760
179097
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
178761
179098
|
const controller = new AbortController;
|
|
178762
179099
|
const externalAbort = () => controller.abort(options.signal?.reason);
|
|
178763
|
-
options.signal?.
|
|
179100
|
+
if (options.signal?.aborted) {
|
|
179101
|
+
externalAbort();
|
|
179102
|
+
} else {
|
|
179103
|
+
options.signal?.addEventListener("abort", externalAbort, { once: true });
|
|
179104
|
+
}
|
|
178764
179105
|
const timer = setTimeout(() => controller.abort(new Error("smart-note check timed out")), timeoutMs);
|
|
178765
179106
|
try {
|
|
179107
|
+
throwIfRunAborted(controller.signal);
|
|
179108
|
+
const capabilities = resolveCapabilitiesForRun(options, controller.signal);
|
|
178766
179109
|
const deadline = Date.now() + timeoutMs;
|
|
178767
179110
|
const quickjs = await getAsyncModule();
|
|
179111
|
+
throwIfRunAborted(controller.signal);
|
|
178768
179112
|
const context = quickjs.newContext();
|
|
178769
179113
|
try {
|
|
178770
179114
|
context.runtime.setMemoryLimit(options.heapLimitBytes ?? DEFAULT_HEAP_LIMIT_BYTES);
|
|
178771
179115
|
context.runtime.setMaxStackSize(options.stackLimitBytes ?? DEFAULT_STACK_LIMIT_BYTES);
|
|
178772
179116
|
context.runtime.setInterruptHandler(() => controller.signal.aborted || Date.now() > deadline);
|
|
178773
|
-
installCapabilityObject(context,
|
|
179117
|
+
installCapabilityObject(context, capabilities);
|
|
178774
179118
|
disableAmbientDynamicCode(context);
|
|
178775
179119
|
const result = await evalCheck(context, options.compiledCheck);
|
|
178776
179120
|
const checkResult = result;
|
|
@@ -178923,6 +179267,7 @@ Remember: output only the JSON object described by the system prompt.`;
|
|
|
178923
179267
|
}
|
|
178924
179268
|
}, {
|
|
178925
179269
|
timeoutMs: remainingMs,
|
|
179270
|
+
signal: args.signal,
|
|
178926
179271
|
fallbackModels: args.fallbackModels,
|
|
178927
179272
|
callContext: "dreamer:smart-note-compiler",
|
|
178928
179273
|
fetchOutput: async () => {
|
|
@@ -178947,7 +179292,8 @@ Remember: output only the JSON object described by the system prompt.`;
|
|
|
178947
179292
|
}
|
|
178948
179293
|
const dryRun = await runCompiledSmartNoteCheck({
|
|
178949
179294
|
compiledCheck,
|
|
178950
|
-
|
|
179295
|
+
capabilityFactory: args.capabilityFactory,
|
|
179296
|
+
signal: args.signal,
|
|
178951
179297
|
timeoutMs: 2000
|
|
178952
179298
|
});
|
|
178953
179299
|
if (!dryRun.ok) {
|
|
@@ -179095,7 +179441,9 @@ function nextSmartNoteCheckDueAt(cron, options = {}) {
|
|
|
179095
179441
|
const rawNext = cron?.trim() ? nextDueAtMs(cron, now) : null;
|
|
179096
179442
|
const rawDelta = rawNext ? rawNext - now : SMART_NOTE_CHECK_DEFAULT_INTERVAL_MS;
|
|
179097
179443
|
const clamped = Math.min(ceilingMs, Math.max(floorMs, rawDelta));
|
|
179098
|
-
|
|
179444
|
+
const jittered = clamped + deterministicJitterMs(clamped, options.noteId, options.hash);
|
|
179445
|
+
const bounded = Math.min(ceilingMs, Math.max(floorMs, jittered));
|
|
179446
|
+
return now + bounded;
|
|
179099
179447
|
}
|
|
179100
179448
|
function deterministicJitterMs(intervalMs, noteId, hash2) {
|
|
179101
179449
|
const max = Math.min(60000, Math.floor(intervalMs * 0.1));
|
|
@@ -179264,9 +179612,9 @@ async function runDueCompiledSmartNoteChecks(args) {
|
|
|
179264
179612
|
try {
|
|
179265
179613
|
const result = await runCompiledSmartNoteCheck({
|
|
179266
179614
|
compiledCheck: note.compiledCheck,
|
|
179267
|
-
|
|
179615
|
+
capabilityFactory: (signal) => createSmartNoteCapabilities({
|
|
179268
179616
|
projectRoot: args.projectRoot,
|
|
179269
|
-
signal
|
|
179617
|
+
signal
|
|
179270
179618
|
}),
|
|
179271
179619
|
signal: controller.signal,
|
|
179272
179620
|
timeoutMs: Math.min(2000, remaining)
|
|
@@ -179329,6 +179677,24 @@ var MAX_COMPILE_PER_RUN = 5;
|
|
|
179329
179677
|
var MAX_FALLBACK_PER_RUN = 3;
|
|
179330
179678
|
var MAX_COMPILATION_FAILURES = 3;
|
|
179331
179679
|
var SMART_NOTE_CONFIRMATION_SYSTEM_PROMPT = 'You are a no-tool smart-note confirmation evaluator. Output only JSON shaped as {"met": boolean}. Return true only when the supplied text alone proves the condition is satisfied.';
|
|
179680
|
+
function createPromptAbortSignal(parent, timeoutMs, timeoutMessage) {
|
|
179681
|
+
const controller = new AbortController;
|
|
179682
|
+
const abortFromParent = () => {
|
|
179683
|
+
controller.abort(parent.reason ?? new Error("smart-note prompt aborted by lease loss"));
|
|
179684
|
+
};
|
|
179685
|
+
if (parent.aborted)
|
|
179686
|
+
abortFromParent();
|
|
179687
|
+
else
|
|
179688
|
+
parent.addEventListener("abort", abortFromParent, { once: true });
|
|
179689
|
+
const timer = setTimeout(() => controller.abort(new Error(timeoutMessage)), timeoutMs);
|
|
179690
|
+
return {
|
|
179691
|
+
signal: controller.signal,
|
|
179692
|
+
cleanup: () => {
|
|
179693
|
+
clearTimeout(timer);
|
|
179694
|
+
parent.removeEventListener("abort", abortFromParent);
|
|
179695
|
+
}
|
|
179696
|
+
};
|
|
179697
|
+
}
|
|
179332
179698
|
async function evaluateSmartNotes(args) {
|
|
179333
179699
|
const projectRoot = args.sessionDirectory ?? args.projectIdentity;
|
|
179334
179700
|
const pendingAtStart = getPendingSmartNotes(args.db, args.projectIdentity).length;
|
|
@@ -179337,6 +179703,7 @@ async function evaluateSmartNotes(args) {
|
|
|
179337
179703
|
return { surfaced: 0, pending: 0, ran: false };
|
|
179338
179704
|
}
|
|
179339
179705
|
let leaseLost = false;
|
|
179706
|
+
const leaseAbortController = new AbortController;
|
|
179340
179707
|
const leaseHeld = () => !leaseLost && peekLeaseHolderAndExpiry(args.db, args.holderId, args.leaseKey);
|
|
179341
179708
|
const assertLeaseHeld = (phase) => {
|
|
179342
179709
|
if (!leaseHeld()) {
|
|
@@ -179346,6 +179713,7 @@ async function evaluateSmartNotes(args) {
|
|
|
179346
179713
|
};
|
|
179347
179714
|
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => {
|
|
179348
179715
|
leaseLost = true;
|
|
179716
|
+
leaseAbortController.abort(new Error("Dream lease lost during smart notes"));
|
|
179349
179717
|
log("[dreamer] smart notes: lease lost — aborting");
|
|
179350
179718
|
args.onLeaseLost?.("smart notes");
|
|
179351
179719
|
});
|
|
@@ -179368,7 +179736,7 @@ async function evaluateSmartNotes(args) {
|
|
|
179368
179736
|
break;
|
|
179369
179737
|
assertLeaseHeld("compile start");
|
|
179370
179738
|
didWork = true;
|
|
179371
|
-
const compiled = await compileNote(args, note, projectRoot, assertLeaseHeld, leaseHeld);
|
|
179739
|
+
const compiled = await compileNote(args, note, projectRoot, assertLeaseHeld, leaseHeld, leaseAbortController.signal);
|
|
179372
179740
|
if (compiled)
|
|
179373
179741
|
surfaced += 1;
|
|
179374
179742
|
}
|
|
@@ -179388,7 +179756,7 @@ async function evaluateSmartNotes(args) {
|
|
|
179388
179756
|
break;
|
|
179389
179757
|
assertLeaseHeld("fallback start");
|
|
179390
179758
|
didWork = true;
|
|
179391
|
-
const met = await confirmReadOnly(args, note.id, note.content, note.surfaceCondition);
|
|
179759
|
+
const met = await confirmReadOnly(args, note.id, note.content, note.surfaceCondition, leaseAbortController.signal);
|
|
179392
179760
|
const now = Date.now();
|
|
179393
179761
|
assertLeaseHeld("fallback commit");
|
|
179394
179762
|
commitSmartNoteState(args.db, {
|
|
@@ -179414,9 +179782,8 @@ async function evaluateSmartNotes(args) {
|
|
|
179414
179782
|
heartbeat.stop();
|
|
179415
179783
|
}
|
|
179416
179784
|
}
|
|
179417
|
-
async function compileNote(args, note, projectRoot, assertLeaseHeld, leaseHeld) {
|
|
179418
|
-
const
|
|
179419
|
-
const timer = setTimeout(() => controller.abort(new Error("smart-note compile deadline")), Math.max(1000, args.deadline - Date.now()));
|
|
179785
|
+
async function compileNote(args, note, projectRoot, assertLeaseHeld, leaseHeld, leaseSignal) {
|
|
179786
|
+
const promptSignal = createPromptAbortSignal(leaseSignal, Math.max(1000, args.deadline - Date.now()), "smart-note compile deadline");
|
|
179420
179787
|
try {
|
|
179421
179788
|
const result = await compileSmartNoteCheck({
|
|
179422
179789
|
client: args.client,
|
|
@@ -179425,7 +179792,8 @@ async function compileNote(args, note, projectRoot, assertLeaseHeld, leaseHeld)
|
|
|
179425
179792
|
sessionDirectory: args.sessionDirectory,
|
|
179426
179793
|
projectIdentity: args.projectIdentity,
|
|
179427
179794
|
note,
|
|
179428
|
-
|
|
179795
|
+
capabilityFactory: (signal) => createSmartNoteCapabilities({ projectRoot, signal }),
|
|
179796
|
+
signal: promptSignal.signal,
|
|
179429
179797
|
deadline: args.deadline,
|
|
179430
179798
|
model: args.model,
|
|
179431
179799
|
fallbackModels: args.fallbackModels
|
|
@@ -179470,7 +179838,7 @@ async function compileNote(args, note, projectRoot, assertLeaseHeld, leaseHeld)
|
|
|
179470
179838
|
});
|
|
179471
179839
|
return result.dryRun.met;
|
|
179472
179840
|
} finally {
|
|
179473
|
-
|
|
179841
|
+
promptSignal.cleanup();
|
|
179474
179842
|
}
|
|
179475
179843
|
}
|
|
179476
179844
|
async function runLivenessCheck(args, note, projectRoot, assertLeaseHeld, leaseHeld) {
|
|
@@ -179481,7 +179849,7 @@ async function runLivenessCheck(args, note, projectRoot, assertLeaseHeld, leaseH
|
|
|
179481
179849
|
try {
|
|
179482
179850
|
const result = await runCompiledSmartNoteCheck({
|
|
179483
179851
|
compiledCheck: note.compiledCheck,
|
|
179484
|
-
|
|
179852
|
+
capabilityFactory: (signal) => createSmartNoteCapabilities({ projectRoot, signal }),
|
|
179485
179853
|
signal: controller.signal,
|
|
179486
179854
|
timeoutMs: 2000
|
|
179487
179855
|
});
|
|
@@ -179510,7 +179878,7 @@ async function runLivenessCheck(args, note, projectRoot, assertLeaseHeld, leaseH
|
|
|
179510
179878
|
clearTimeout(timer);
|
|
179511
179879
|
}
|
|
179512
179880
|
}
|
|
179513
|
-
async function confirmReadOnly(args, noteId, content, surfaceCondition) {
|
|
179881
|
+
async function confirmReadOnly(args, noteId, content, surfaceCondition, leaseSignal) {
|
|
179514
179882
|
let childSessionId = null;
|
|
179515
179883
|
const startedAt = Date.now();
|
|
179516
179884
|
let invocationRecorded = false;
|
|
@@ -179553,42 +179921,49 @@ Note content: ${JSON.stringify(content)}
|
|
|
179553
179921
|
Surface condition: ${JSON.stringify(surfaceCondition ?? "")}
|
|
179554
179922
|
|
|
179555
179923
|
Output exactly JSON: {"met": false}`;
|
|
179556
|
-
const
|
|
179557
|
-
|
|
179558
|
-
|
|
179559
|
-
|
|
179560
|
-
|
|
179561
|
-
|
|
179562
|
-
|
|
179563
|
-
|
|
179564
|
-
|
|
179565
|
-
|
|
179566
|
-
|
|
179567
|
-
|
|
179568
|
-
|
|
179569
|
-
|
|
179570
|
-
|
|
179571
|
-
|
|
179572
|
-
|
|
179573
|
-
|
|
179574
|
-
|
|
179575
|
-
|
|
179576
|
-
|
|
179577
|
-
|
|
179578
|
-
|
|
179579
|
-
|
|
179580
|
-
|
|
179581
|
-
|
|
179582
|
-
|
|
179583
|
-
|
|
179584
|
-
|
|
179585
|
-
|
|
179586
|
-
|
|
179587
|
-
|
|
179588
|
-
|
|
179589
|
-
|
|
179590
|
-
|
|
179591
|
-
|
|
179924
|
+
const promptSignal = createPromptAbortSignal(leaseSignal, Math.max(1000, args.deadline - Date.now()), "smart-note confirmation deadline");
|
|
179925
|
+
let run;
|
|
179926
|
+
try {
|
|
179927
|
+
run = await promptSyncWithValidatedOutputRetry(args.client, {
|
|
179928
|
+
path: { id: childSessionId },
|
|
179929
|
+
query: { directory: args.sessionDirectory ?? args.projectIdentity },
|
|
179930
|
+
body: {
|
|
179931
|
+
agent: SMART_NOTE_COMPILER_AGENT,
|
|
179932
|
+
system: SMART_NOTE_CONFIRMATION_SYSTEM_PROMPT,
|
|
179933
|
+
...modelBodyField(args.model),
|
|
179934
|
+
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
179935
|
+
}
|
|
179936
|
+
}, {
|
|
179937
|
+
timeoutMs: Math.max(1000, args.deadline - Date.now()),
|
|
179938
|
+
signal: promptSignal.signal,
|
|
179939
|
+
fallbackModels: args.fallbackModels,
|
|
179940
|
+
callContext: "dreamer:smart-note-read-only-confirm",
|
|
179941
|
+
fetchOutput: async () => {
|
|
179942
|
+
const messagesResponse = await args.client.session.messages({
|
|
179943
|
+
path: { id: childSessionId },
|
|
179944
|
+
query: {
|
|
179945
|
+
directory: args.sessionDirectory ?? args.projectIdentity,
|
|
179946
|
+
limit: 20
|
|
179947
|
+
}
|
|
179948
|
+
});
|
|
179949
|
+
return normalizeSDKResponse(messagesResponse, [], {
|
|
179950
|
+
preferResponseOnMissingData: true
|
|
179951
|
+
});
|
|
179952
|
+
},
|
|
179953
|
+
validateOutput: (messages) => {
|
|
179954
|
+
const text = extractLatestAssistantText(messages) ?? "";
|
|
179955
|
+
const match = text.match(/\{[\s\S]*\}/);
|
|
179956
|
+
if (!match)
|
|
179957
|
+
throw new Error("confirmation evaluator returned no JSON");
|
|
179958
|
+
const parsed = JSON.parse(match[0]);
|
|
179959
|
+
if (typeof parsed.met !== "boolean")
|
|
179960
|
+
throw new Error("confirmation met missing");
|
|
179961
|
+
return parsed.met;
|
|
179962
|
+
}
|
|
179963
|
+
});
|
|
179964
|
+
} finally {
|
|
179965
|
+
promptSignal.cleanup();
|
|
179966
|
+
}
|
|
179592
179967
|
recordInvocation2({ status: "completed", messages: run.output });
|
|
179593
179968
|
return run.validated;
|
|
179594
179969
|
} catch (error51) {
|
|
@@ -179803,19 +180178,21 @@ ${list}
|
|
|
179803
180178
|
}
|
|
179804
180179
|
function parseMapMemoriesManifest(text) {
|
|
179805
180180
|
const out = [];
|
|
179806
|
-
|
|
180181
|
+
const body = extractCompleteManifestBody(text, "mappings");
|
|
180182
|
+
for (const m of body.matchAll(/<memory\b([^>]*)\/?>/g)) {
|
|
179807
180183
|
const attrs = m[1];
|
|
179808
180184
|
const idMatch = attrs.match(/\bid\s*=\s*"(\d+)"/);
|
|
179809
180185
|
if (!idMatch)
|
|
179810
|
-
|
|
180186
|
+
throw new Error("mappings manifest entry missing numeric id");
|
|
179811
180187
|
const id = Number.parseInt(idMatch[1], 10);
|
|
179812
180188
|
if (!Number.isInteger(id))
|
|
179813
|
-
|
|
180189
|
+
throw new Error("mappings manifest entry missing numeric id");
|
|
179814
180190
|
const independent = /\bindependent\s*=\s*"(?:true|1)"/i.test(attrs);
|
|
179815
180191
|
const filesMatch = attrs.match(/\bfiles\s*=\s*"([^"]*)"/);
|
|
179816
180192
|
const files = filesMatch ? filesMatch[1].split(",").map((f) => f.trim()).filter(Boolean) : [];
|
|
179817
180193
|
out.push({ id, files, independent: independent || files.length === 0 });
|
|
179818
180194
|
}
|
|
180195
|
+
assertNoDuplicateManifestIds(out.map((entry) => entry.id), "mappings");
|
|
179819
180196
|
return out;
|
|
179820
180197
|
}
|
|
179821
180198
|
|
|
@@ -179904,9 +180281,13 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
|
|
|
179904
180281
|
});
|
|
179905
180282
|
},
|
|
179906
180283
|
validateOutput: (messages) => {
|
|
180284
|
+
if (hasLengthCappedOutput(messages)) {
|
|
180285
|
+
throw new Error("map-memories returned length-capped output");
|
|
180286
|
+
}
|
|
179907
180287
|
const text = extractLatestAssistantText(messages);
|
|
179908
180288
|
if (!text)
|
|
179909
180289
|
throw new Error("map-memories returned no output");
|
|
180290
|
+
parseMapMemoriesManifest(text);
|
|
179910
180291
|
return text;
|
|
179911
180292
|
}
|
|
179912
180293
|
});
|
|
@@ -179932,7 +180313,8 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
|
|
|
179932
180313
|
}
|
|
179933
180314
|
async function applyBatchMappings(args, batch, manifestText) {
|
|
179934
180315
|
const batchIds = new Set(batch.map((m) => m.id));
|
|
179935
|
-
const parsed = parseMapMemoriesManifest(manifestText)
|
|
180316
|
+
const parsed = parseMapMemoriesManifest(manifestText);
|
|
180317
|
+
assertManifestCoversExactly(parsed.map((entry) => entry.id), batchIds, "mappings");
|
|
179936
180318
|
if (parsed.length === 0)
|
|
179937
180319
|
return { mapped: 0, independent: 0 };
|
|
179938
180320
|
const planned = [];
|
|
@@ -179954,12 +180336,7 @@ async function applyBatchMappings(args, batch, manifestText) {
|
|
|
179954
180336
|
const now = Date.now();
|
|
179955
180337
|
let mapped = 0;
|
|
179956
180338
|
let independent = 0;
|
|
179957
|
-
|
|
179958
|
-
args.db.transaction(() => {
|
|
179959
|
-
if (!peekLeaseHolderAndExpiry(args.db, args.holderId, args.leaseKey)) {
|
|
179960
|
-
leaseLost = true;
|
|
179961
|
-
return;
|
|
179962
|
-
}
|
|
180339
|
+
runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
|
|
179963
180340
|
for (const item of planned) {
|
|
179964
180341
|
recordMemoryMapping(args.db, item.id, item.files, now);
|
|
179965
180342
|
if (item.independent)
|
|
@@ -179967,9 +180344,7 @@ async function applyBatchMappings(args, batch, manifestText) {
|
|
|
179967
180344
|
else
|
|
179968
180345
|
mapped += 1;
|
|
179969
180346
|
}
|
|
179970
|
-
})
|
|
179971
|
-
if (leaseLost)
|
|
179972
|
-
throw new Error("Dream lease lost during map-memories commit");
|
|
180347
|
+
});
|
|
179973
180348
|
return { mapped, independent };
|
|
179974
180349
|
}
|
|
179975
180350
|
function recordInvocation2(args, startedAt, params) {
|
|
@@ -180197,11 +180572,7 @@ async function promotePrimers(args) {
|
|
|
180197
180572
|
activePrimers: primers,
|
|
180198
180573
|
threshold: PRIMER_CLUSTER_THRESHOLD
|
|
180199
180574
|
});
|
|
180200
|
-
args.db.
|
|
180201
|
-
if (!peekLeaseHolderAndExpiry(args.db, args.holderId, args.leaseKey)) {
|
|
180202
|
-
leaseLost = true;
|
|
180203
|
-
return;
|
|
180204
|
-
}
|
|
180575
|
+
runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
|
|
180205
180576
|
for (const cluster of clusters) {
|
|
180206
180577
|
if (cluster.candidates.length === 0)
|
|
180207
180578
|
continue;
|
|
@@ -180232,7 +180603,7 @@ async function promotePrimers(args) {
|
|
|
180232
180603
|
});
|
|
180233
180604
|
result.promoted += 1;
|
|
180234
180605
|
}
|
|
180235
|
-
})
|
|
180606
|
+
});
|
|
180236
180607
|
if (leaseLost)
|
|
180237
180608
|
throw new Error("Dream lease lost during promote-primers commit");
|
|
180238
180609
|
log(`[dreamer] primers: candidates=${result.candidates} promoted=${result.promoted} updated=${result.updated}`);
|
|
@@ -180500,16 +180871,9 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
|
|
|
180500
180871
|
log(`[dreamer] refresh-primers: primer #${primer.id} answer not committed (no investigation tool calls)`);
|
|
180501
180872
|
return false;
|
|
180502
180873
|
}
|
|
180503
|
-
|
|
180504
|
-
args.db.transaction(() => {
|
|
180505
|
-
if (!peekLeaseHolderAndExpiry(args.db, args.holderId, args.leaseKey)) {
|
|
180506
|
-
leaseLost = true;
|
|
180507
|
-
return;
|
|
180508
|
-
}
|
|
180874
|
+
runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
|
|
180509
180875
|
updatePrimerAnswer(args.db, primer.id, answer);
|
|
180510
|
-
})
|
|
180511
|
-
if (leaseLost)
|
|
180512
|
-
throw new Error("Dream lease lost during refresh-primers commit");
|
|
180876
|
+
});
|
|
180513
180877
|
return true;
|
|
180514
180878
|
} catch (error51) {
|
|
180515
180879
|
const desc = describeError(error51);
|
|
@@ -180706,8 +181070,7 @@ class OpenCodeRetrospectiveRawProvider {
|
|
|
180706
181070
|
LEFT JOIN session_meta m ON m.session_id = sp.session_id
|
|
180707
181071
|
WHERE sp.project_path = ? AND sp.harness = 'opencode'
|
|
180708
181072
|
AND COALESCE(m.is_subagent, 0) = 0
|
|
180709
|
-
ORDER BY sp.updated_at
|
|
180710
|
-
LIMIT ?`).all(projectIdentity, RETROSPECTIVE_MAX_SESSIONS_PER_RUN);
|
|
181073
|
+
ORDER BY sp.updated_at ASC, sp.session_id ASC`).all(projectIdentity);
|
|
180711
181074
|
return rows.map((row) => ({
|
|
180712
181075
|
sessionId: row.session_id,
|
|
180713
181076
|
updatedAt: typeof row.updated_at === "number" ? row.updated_at : undefined
|
|
@@ -180732,6 +181095,12 @@ class OpenCodeRetrospectiveRawProvider {
|
|
|
180732
181095
|
return { messages: [], truncated: false };
|
|
180733
181096
|
}
|
|
180734
181097
|
}
|
|
181098
|
+
readOldestMessageTimesSince(sessionIds, sinceMs) {
|
|
181099
|
+
const db = this.resolveDb();
|
|
181100
|
+
if (!db || sessionIds.length === 0)
|
|
181101
|
+
return new Map;
|
|
181102
|
+
return readOpenCodeOldestMessageTimesSince(db, sessionIds, sinceMs);
|
|
181103
|
+
}
|
|
180735
181104
|
readUserMessagesBefore(sessionId, beforeMs, count) {
|
|
180736
181105
|
const db = this.resolveDb();
|
|
180737
181106
|
if (!db)
|
|
@@ -180753,13 +181122,28 @@ class OpenCodeRetrospectiveRawProvider {
|
|
|
180753
181122
|
async function readRetrospectiveScanWindow(provider2, projectIdentity, watermarkMs, overlapUserCount, options) {
|
|
180754
181123
|
const maxMessages = options?.maxMessagesPerRun ?? RETROSPECTIVE_MAX_MESSAGES_PER_RUN;
|
|
180755
181124
|
const capPerSession = options?.capPerSession ?? RETROSPECTIVE_MAX_MESSAGES_PER_SESSION;
|
|
180756
|
-
const
|
|
181125
|
+
const sessionLimit = Math.max(1, Math.floor(options?.maxSessionsPerRun ?? RETROSPECTIVE_MAX_SESSIONS_PER_RUN));
|
|
180757
181126
|
try {
|
|
180758
|
-
const
|
|
181127
|
+
const allSessions = await provider2.listProjectSessions(projectIdentity);
|
|
181128
|
+
const eligibleSessions = allSessions.map((session, index) => ({ session, index })).filter(({ session }) => (session.updatedAt ?? Number.POSITIVE_INFINITY) > watermarkMs);
|
|
181129
|
+
const oldestBySession = provider2.readOldestMessageTimesSince ? await provider2.readOldestMessageTimesSince(eligibleSessions.map(({ session }) => session.sessionId), watermarkMs) : null;
|
|
181130
|
+
const sessions = (oldestBySession ? eligibleSessions.filter(({ session }) => oldestBySession.has(session.sessionId)) : eligibleSessions).sort((a, b) => {
|
|
181131
|
+
const aFrontier = oldestBySession?.get(a.session.sessionId);
|
|
181132
|
+
const bFrontier = oldestBySession?.get(b.session.sessionId);
|
|
181133
|
+
if (aFrontier !== undefined || bFrontier !== undefined) {
|
|
181134
|
+
return (aFrontier ?? Number.POSITIVE_INFINITY) - (bFrontier ?? Number.POSITIVE_INFINITY) || a.index - b.index;
|
|
181135
|
+
}
|
|
181136
|
+
const aUpdated = a.session.updatedAt ?? Number.POSITIVE_INFINITY;
|
|
181137
|
+
const bUpdated = b.session.updatedAt ?? Number.POSITIVE_INFINITY;
|
|
181138
|
+
const byUpdated = aUpdated - bUpdated;
|
|
181139
|
+
return byUpdated || a.index - b.index;
|
|
181140
|
+
});
|
|
181141
|
+
const sessionsToRead = sessions.slice(0, sessionLimit).map(({ session }) => session);
|
|
181142
|
+
const firstExcludedSession = sessions[sessionLimit]?.session;
|
|
181143
|
+
const firstExcludedPendingTs = firstExcludedSession ? oldestBySession?.get(firstExcludedSession.sessionId) : undefined;
|
|
180759
181144
|
const sinceReads = [];
|
|
180760
|
-
|
|
180761
|
-
|
|
180762
|
-
sinceReads.push(...await Promise.all(page.map((session) => provider2.readUserMessagesSince(session.sessionId, watermarkMs, capPerSession))));
|
|
181145
|
+
if (sessionsToRead.length > 0) {
|
|
181146
|
+
sinceReads.push(...await Promise.all(sessionsToRead.map((session) => provider2.readUserMessagesSince(session.sessionId, watermarkMs, capPerSession))));
|
|
180763
181147
|
}
|
|
180764
181148
|
let saturatedFrontier = Number.POSITIVE_INFINITY;
|
|
180765
181149
|
for (const read of sinceReads) {
|
|
@@ -180781,9 +181165,14 @@ async function readRetrospectiveScanWindow(provider2, projectIdentity, watermark
|
|
|
180781
181165
|
if (firstDropped) {
|
|
180782
181166
|
frontier = Math.min(frontier, firstDropped.ts - 1);
|
|
180783
181167
|
}
|
|
181168
|
+
if (typeof firstExcludedPendingTs === "number") {
|
|
181169
|
+
frontier = Math.min(frontier, firstExcludedPendingTs - 1);
|
|
181170
|
+
} else if (typeof firstExcludedSession?.updatedAt === "number") {
|
|
181171
|
+
frontier = Math.min(frontier, firstExcludedSession.updatedAt - 1);
|
|
181172
|
+
}
|
|
180784
181173
|
maxScannedTs = Math.max(watermarkMs, Math.min(maxScannedTs, frontier));
|
|
180785
181174
|
const keptSessionIds = new Set(keptSince.map((message) => message.sessionId));
|
|
180786
|
-
const overlapSessions =
|
|
181175
|
+
const overlapSessions = sessionsToRead.filter((session) => keptSessionIds.has(session.sessionId));
|
|
180787
181176
|
const overlapBatches = overlapUserCount > 0 && watermarkMs > 0 ? await Promise.all(overlapSessions.map((session) => provider2.readUserMessagesBefore(session.sessionId, watermarkMs, overlapUserCount))) : [];
|
|
180788
181177
|
const seen = new Set;
|
|
180789
181178
|
const merged = [];
|
|
@@ -180811,6 +181200,24 @@ function readOpenCodeMessagesSince(db, sessionId, sinceMs, capPerSession) {
|
|
|
180811
181200
|
const kept = truncated ? rows.slice(0, limit) : rows;
|
|
180812
181201
|
return { messages: normalizeOpenCodeRows(db, sessionId, kept), truncated };
|
|
180813
181202
|
}
|
|
181203
|
+
function readOpenCodeOldestMessageTimesSince(db, sessionIds, sinceMs) {
|
|
181204
|
+
const result = new Map;
|
|
181205
|
+
const uniqueIds = Array.from(new Set(sessionIds.filter((id) => id.length > 0)));
|
|
181206
|
+
const chunkSize = 500;
|
|
181207
|
+
for (let i = 0;i < uniqueIds.length; i += chunkSize) {
|
|
181208
|
+
const chunk = uniqueIds.slice(i, i + chunkSize);
|
|
181209
|
+
const placeholders4 = chunk.map(() => "?").join(", ");
|
|
181210
|
+
const rows = db.prepare(`SELECT session_id, MIN(time_created) AS oldest_ts
|
|
181211
|
+
FROM message
|
|
181212
|
+
WHERE time_created > ? AND session_id IN (${placeholders4})
|
|
181213
|
+
GROUP BY session_id`).all(sinceMs, ...chunk);
|
|
181214
|
+
for (const row of rows) {
|
|
181215
|
+
if (typeof row.oldest_ts === "number")
|
|
181216
|
+
result.set(row.session_id, row.oldest_ts);
|
|
181217
|
+
}
|
|
181218
|
+
}
|
|
181219
|
+
return result;
|
|
181220
|
+
}
|
|
180814
181221
|
function readOpenCodeUserMessagesBefore(db, sessionId, beforeMs, count) {
|
|
180815
181222
|
const want = Math.max(1, Math.floor(count));
|
|
180816
181223
|
const window = Math.max(want * 5, 32);
|
|
@@ -181103,7 +181510,7 @@ async function partitionVerifyScope(args) {
|
|
|
181103
181510
|
continue;
|
|
181104
181511
|
}
|
|
181105
181512
|
const files = v?.files ?? [];
|
|
181106
|
-
const needs = files.some((file2) => !verificationFileExists(gitRoot, file2) || uncommitted.has(file2) || (changeTimes.get(file2) ?? 0)
|
|
181513
|
+
const needs = files.some((file2) => !verificationFileExists(gitRoot, file2) || uncommitted.has(file2) || (changeTimes.get(file2) ?? 0) >= verifiedAt - 1000);
|
|
181107
181514
|
if (needs)
|
|
181108
181515
|
inScope.push(toPrompt(m));
|
|
181109
181516
|
else
|
|
@@ -181169,22 +181576,26 @@ function filesOf(s) {
|
|
|
181169
181576
|
}
|
|
181170
181577
|
function parseVerifyManifest(text) {
|
|
181171
181578
|
const out = { verified: [], updated: [], archived: [] };
|
|
181172
|
-
|
|
181579
|
+
const body = extractCompleteManifestBody(text, "verify");
|
|
181580
|
+
for (const m of body.matchAll(/<verified\b([^>]*)\/?>/g)) {
|
|
181173
181581
|
const id = Number.parseInt(attrOf(m[1], "id") ?? "", 10);
|
|
181174
|
-
if (Number.isInteger(id))
|
|
181175
|
-
|
|
181582
|
+
if (!Number.isInteger(id))
|
|
181583
|
+
throw new Error("verify manifest entry missing numeric id");
|
|
181584
|
+
out.verified.push({ id, files: filesOf(m[1]) });
|
|
181176
181585
|
}
|
|
181177
|
-
for (const m of
|
|
181586
|
+
for (const m of body.matchAll(/<update\b([^>]*?)(?:\/>|>([\s\S]*?)<\/update>)/g)) {
|
|
181178
181587
|
const id = Number.parseInt(attrOf(m[1], "id") ?? "", 10);
|
|
181179
|
-
if (Number.isInteger(id))
|
|
181180
|
-
|
|
181181
|
-
}
|
|
181588
|
+
if (!Number.isInteger(id))
|
|
181589
|
+
throw new Error("verify manifest entry missing numeric id");
|
|
181590
|
+
out.updated.push({ id, files: filesOf(m[1]), content: (m[2] ?? "").trim() });
|
|
181182
181591
|
}
|
|
181183
|
-
for (const m of
|
|
181592
|
+
for (const m of body.matchAll(/<archive\b([^>]*)\/?>/g)) {
|
|
181184
181593
|
const id = Number.parseInt(attrOf(m[1], "id") ?? "", 10);
|
|
181185
|
-
if (Number.isInteger(id))
|
|
181186
|
-
|
|
181594
|
+
if (!Number.isInteger(id))
|
|
181595
|
+
throw new Error("verify manifest entry missing numeric id");
|
|
181596
|
+
out.archived.push({ id, reason: attrOf(m[1], "reason") ?? "" });
|
|
181187
181597
|
}
|
|
181598
|
+
assertNoDuplicateManifestIds([...out.verified, ...out.updated, ...out.archived].map((entry) => entry.id), "verify");
|
|
181188
181599
|
return out;
|
|
181189
181600
|
}
|
|
181190
181601
|
|
|
@@ -181277,9 +181688,13 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
181277
181688
|
});
|
|
181278
181689
|
},
|
|
181279
181690
|
validateOutput: (messages) => {
|
|
181691
|
+
if (hasLengthCappedOutput(messages)) {
|
|
181692
|
+
throw new Error("verify returned length-capped output");
|
|
181693
|
+
}
|
|
181280
181694
|
const text = extractLatestAssistantText(messages);
|
|
181281
181695
|
if (!text)
|
|
181282
181696
|
throw new Error("verify returned no output");
|
|
181697
|
+
parseVerifyManifest(text);
|
|
181283
181698
|
return text;
|
|
181284
181699
|
}
|
|
181285
181700
|
});
|
|
@@ -181306,24 +181721,14 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
181306
181721
|
async function applyVerifyManifest(args, batch, manifestText) {
|
|
181307
181722
|
const batchIds = new Set(batch.map((m) => m.id));
|
|
181308
181723
|
const parsed = parseVerifyManifest(manifestText);
|
|
181724
|
+
assertManifestCoversExactly([...parsed.verified, ...parsed.updated, ...parsed.archived].map((entry) => entry.id), batchIds, "verify");
|
|
181309
181725
|
const now = Date.now();
|
|
181310
181726
|
const writes = [];
|
|
181311
|
-
const verdictCounts = new Map;
|
|
181312
|
-
for (const verdict of [...parsed.verified, ...parsed.updated, ...parsed.archived]) {
|
|
181313
|
-
if (!batchIds.has(verdict.id))
|
|
181314
|
-
continue;
|
|
181315
|
-
verdictCounts.set(verdict.id, (verdictCounts.get(verdict.id) ?? 0) + 1);
|
|
181316
|
-
}
|
|
181317
|
-
const conflictingIds = new Set(Array.from(verdictCounts.entries()).filter(([, count]) => count !== 1).map(([id]) => id));
|
|
181318
181727
|
for (const v of parsed.verified) {
|
|
181319
|
-
if (!batchIds.has(v.id) || conflictingIds.has(v.id))
|
|
181320
|
-
continue;
|
|
181321
181728
|
const files = await normalizeFiles(args, v.files);
|
|
181322
181729
|
writes.push({ kind: "verify", id: v.id, files });
|
|
181323
181730
|
}
|
|
181324
181731
|
for (const u of parsed.updated) {
|
|
181325
|
-
if (!batchIds.has(u.id) || conflictingIds.has(u.id))
|
|
181326
|
-
continue;
|
|
181327
181732
|
const content = u.content.trim();
|
|
181328
181733
|
if (!content || content.length > 20000) {
|
|
181329
181734
|
const files2 = await normalizeFiles(args, u.files);
|
|
@@ -181340,8 +181745,6 @@ async function applyVerifyManifest(args, batch, manifestText) {
|
|
|
181340
181745
|
});
|
|
181341
181746
|
}
|
|
181342
181747
|
for (const a of parsed.archived) {
|
|
181343
|
-
if (!batchIds.has(a.id) || conflictingIds.has(a.id))
|
|
181344
|
-
continue;
|
|
181345
181748
|
writes.push({ kind: "archive", id: a.id, reason: a.reason });
|
|
181346
181749
|
}
|
|
181347
181750
|
if (writes.length === 0)
|
|
@@ -181349,12 +181752,7 @@ async function applyVerifyManifest(args, batch, manifestText) {
|
|
|
181349
181752
|
let verified = 0;
|
|
181350
181753
|
let updated = 0;
|
|
181351
181754
|
let archived = 0;
|
|
181352
|
-
|
|
181353
|
-
args.db.transaction(() => {
|
|
181354
|
-
if (!peekLeaseHolderAndExpiry(args.db, args.holderId, args.leaseKey)) {
|
|
181355
|
-
leaseLost = true;
|
|
181356
|
-
return;
|
|
181357
|
-
}
|
|
181755
|
+
runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
|
|
181358
181756
|
for (const w of writes) {
|
|
181359
181757
|
const memory = getMemoryById(args.db, w.id);
|
|
181360
181758
|
if (!isPrimaryMutable(memory))
|
|
@@ -181382,9 +181780,7 @@ async function applyVerifyManifest(args, batch, manifestText) {
|
|
|
181382
181780
|
archived += 1;
|
|
181383
181781
|
}
|
|
181384
181782
|
}
|
|
181385
|
-
})
|
|
181386
|
-
if (leaseLost)
|
|
181387
|
-
throw new Error("Dream lease lost during verify commit");
|
|
181783
|
+
});
|
|
181388
181784
|
return { verified, updated, archived };
|
|
181389
181785
|
}
|
|
181390
181786
|
async function normalizeFiles(args, rawFiles) {
|
|
@@ -181878,11 +182274,7 @@ async function runRetrospectiveTask(config2, ctx, helpers) {
|
|
|
181878
182274
|
throw new Error("Dream lease lost during retrospective");
|
|
181879
182275
|
const sourceSessionId = flagged[0]?.sessionId ?? userMessages[0]?.sessionId ?? "retrospective";
|
|
181880
182276
|
const learnings = parseRetrospectiveLearnings(deepenRun.validated);
|
|
181881
|
-
const applied = db
|
|
181882
|
-
if (!peekLeaseHolderAndExpiry(db, holderId, leaseKey)) {
|
|
181883
|
-
leaseLost = true;
|
|
181884
|
-
return null;
|
|
181885
|
-
}
|
|
182277
|
+
const applied = runLeaseGuardedWrite(db, holderId, leaseKey, () => {
|
|
181886
182278
|
const result = applyRetrospectiveLearnings({
|
|
181887
182279
|
db,
|
|
181888
182280
|
projectIdentity,
|
|
@@ -181893,7 +182285,7 @@ async function runRetrospectiveTask(config2, ctx, helpers) {
|
|
|
181893
182285
|
});
|
|
181894
182286
|
recordRetrospectiveWindowProcessed(db, projectIdentity, windowKey);
|
|
181895
182287
|
return result;
|
|
181896
|
-
})
|
|
182288
|
+
});
|
|
181897
182289
|
if (leaseLost || !applied)
|
|
181898
182290
|
throw new Error("Dream lease lost during retrospective commit");
|
|
181899
182291
|
log(`[dreamer] retrospective: flagged=${flagged.length} learnings=${learnings.length} memory=${applied.memoryWritten} observations=${applied.observationsInserted} dropped=${applied.observationsDropped} rejected=${applied.rejected.length}`);
|
|
@@ -183428,11 +183820,106 @@ function migrateLegacyExperimental(rawConfig, warnings) {
|
|
|
183428
183820
|
|
|
183429
183821
|
// ../plugin/src/config/project-security.ts
|
|
183430
183822
|
var HIDDEN_AGENT_KEYS = ["historian", "dreamer", "sidekick"];
|
|
183823
|
+
var HISTORIAN_USER_ONLY_FIELDS = ["model", "fallback_models"];
|
|
183431
183824
|
var AGENT_ESCALATION_FIELDS = ["prompt", "permission", "tools", "system_prompt"];
|
|
183432
183825
|
var EMBEDDING_DESTINATION_FIELDS = ["endpoint", "provider"];
|
|
183826
|
+
var PERCENTAGE_THRESHOLD_REASON = "security: a repository may only raise compaction thresholds above the user's effective value; it cannot force earlier historian work or cloned-repo cost escalation.";
|
|
183827
|
+
var TOKEN_THRESHOLD_REASON = "security: a repository may only raise execute_threshold_tokens above the user's trusted token threshold; it cannot force earlier historian work or cloned-repo cost escalation.";
|
|
183828
|
+
var TOKEN_THRESHOLD_INTRODUCTION_REASON = "security: a repository cannot introduce a new execute_threshold_tokens override when the user has no trusted token threshold for that key; that could force earlier historian work or cloned-repo cost escalation.";
|
|
183433
183829
|
function isPlainObject3(value) {
|
|
183434
183830
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
183435
183831
|
}
|
|
183832
|
+
function isValidPercentageThreshold(value) {
|
|
183833
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 20 && value <= 80;
|
|
183834
|
+
}
|
|
183835
|
+
function isValidTokenThreshold(value) {
|
|
183836
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 5000 && value <= 2000000;
|
|
183837
|
+
}
|
|
183838
|
+
function normalizeTrustedPercentageThresholds(value) {
|
|
183839
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
183840
|
+
return { defaultValue: value, overrides: new Map };
|
|
183841
|
+
}
|
|
183842
|
+
if (isPlainObject3(value) && typeof value.default === "number" && Number.isFinite(value.default)) {
|
|
183843
|
+
const overrides = new Map;
|
|
183844
|
+
for (const [key, child] of Object.entries(value)) {
|
|
183845
|
+
if (key === "default")
|
|
183846
|
+
continue;
|
|
183847
|
+
if (typeof child === "number" && Number.isFinite(child)) {
|
|
183848
|
+
overrides.set(key, child);
|
|
183849
|
+
}
|
|
183850
|
+
}
|
|
183851
|
+
return { defaultValue: value.default, overrides };
|
|
183852
|
+
}
|
|
183853
|
+
return { defaultValue: DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, overrides: new Map };
|
|
183854
|
+
}
|
|
183855
|
+
function normalizeTrustedTokenThresholds(value) {
|
|
183856
|
+
if (!isPlainObject3(value)) {
|
|
183857
|
+
return { defaultValue: undefined, overrides: new Map };
|
|
183858
|
+
}
|
|
183859
|
+
const overrides = new Map;
|
|
183860
|
+
for (const [key, child] of Object.entries(value)) {
|
|
183861
|
+
if (key === "default")
|
|
183862
|
+
continue;
|
|
183863
|
+
if (typeof child === "number" && Number.isFinite(child)) {
|
|
183864
|
+
overrides.set(key, child);
|
|
183865
|
+
}
|
|
183866
|
+
}
|
|
183867
|
+
return {
|
|
183868
|
+
defaultValue: typeof value.default === "number" && Number.isFinite(value.default) ? value.default : undefined,
|
|
183869
|
+
overrides
|
|
183870
|
+
};
|
|
183871
|
+
}
|
|
183872
|
+
function clonePercentageThresholds(value) {
|
|
183873
|
+
return {
|
|
183874
|
+
defaultValue: value.defaultValue,
|
|
183875
|
+
overrides: new Map(value.overrides)
|
|
183876
|
+
};
|
|
183877
|
+
}
|
|
183878
|
+
function cloneTokenThresholds(value) {
|
|
183879
|
+
return {
|
|
183880
|
+
defaultValue: value.defaultValue,
|
|
183881
|
+
overrides: new Map(value.overrides)
|
|
183882
|
+
};
|
|
183883
|
+
}
|
|
183884
|
+
function percentageThresholdsEqual(left, right) {
|
|
183885
|
+
if (left.defaultValue !== right.defaultValue)
|
|
183886
|
+
return false;
|
|
183887
|
+
if (left.overrides.size !== right.overrides.size)
|
|
183888
|
+
return false;
|
|
183889
|
+
for (const [key, value] of left.overrides) {
|
|
183890
|
+
if (right.overrides.get(key) !== value)
|
|
183891
|
+
return false;
|
|
183892
|
+
}
|
|
183893
|
+
return true;
|
|
183894
|
+
}
|
|
183895
|
+
function setMergedPercentageThreshold(mergedRaw, value) {
|
|
183896
|
+
if (value.overrides.size === 0) {
|
|
183897
|
+
mergedRaw.execute_threshold_percentage = value.defaultValue;
|
|
183898
|
+
return;
|
|
183899
|
+
}
|
|
183900
|
+
const serialized = { default: value.defaultValue };
|
|
183901
|
+
for (const [key, threshold] of value.overrides) {
|
|
183902
|
+
serialized[key] = threshold;
|
|
183903
|
+
}
|
|
183904
|
+
mergedRaw.execute_threshold_percentage = serialized;
|
|
183905
|
+
}
|
|
183906
|
+
function setMergedTokenThreshold(mergedRaw, value) {
|
|
183907
|
+
if (value.defaultValue === undefined && value.overrides.size === 0) {
|
|
183908
|
+
delete mergedRaw.execute_threshold_tokens;
|
|
183909
|
+
return;
|
|
183910
|
+
}
|
|
183911
|
+
const serialized = {};
|
|
183912
|
+
if (value.defaultValue !== undefined) {
|
|
183913
|
+
serialized.default = value.defaultValue;
|
|
183914
|
+
}
|
|
183915
|
+
for (const [key, threshold] of value.overrides) {
|
|
183916
|
+
serialized[key] = threshold;
|
|
183917
|
+
}
|
|
183918
|
+
mergedRaw.execute_threshold_tokens = serialized;
|
|
183919
|
+
}
|
|
183920
|
+
function makeProjectThresholdWarning(field, reason) {
|
|
183921
|
+
return `Ignoring ${field} from project config (${reason})`;
|
|
183922
|
+
}
|
|
183436
183923
|
function stripUnsafeProjectConfigFields(projectRaw) {
|
|
183437
183924
|
const warnings = [];
|
|
183438
183925
|
if ("auto_update" in projectRaw) {
|
|
@@ -183460,6 +183947,19 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
183460
183947
|
warnings.push(`Ignoring embedding.${removed.join("/")} from project config ` + "(security: a repository cannot choose where private text is embedded).");
|
|
183461
183948
|
}
|
|
183462
183949
|
}
|
|
183950
|
+
const historian = projectRaw.historian;
|
|
183951
|
+
if (isPlainObject3(historian)) {
|
|
183952
|
+
const removed = [];
|
|
183953
|
+
for (const field of HISTORIAN_USER_ONLY_FIELDS) {
|
|
183954
|
+
if (field in historian) {
|
|
183955
|
+
delete historian[field];
|
|
183956
|
+
removed.push(field);
|
|
183957
|
+
}
|
|
183958
|
+
}
|
|
183959
|
+
if (removed.length > 0) {
|
|
183960
|
+
warnings.push(`Ignoring historian.${removed.join("/")} from project config ` + "(security: historian model selection is user-level only; a repository cannot force extra compaction cost).");
|
|
183961
|
+
}
|
|
183962
|
+
}
|
|
183463
183963
|
for (const agentKey of HIDDEN_AGENT_KEYS) {
|
|
183464
183964
|
const block = projectRaw[agentKey];
|
|
183465
183965
|
if (!isPlainObject3(block))
|
|
@@ -183477,6 +183977,101 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
183477
183977
|
}
|
|
183478
183978
|
return warnings;
|
|
183479
183979
|
}
|
|
183980
|
+
function constrainProjectThresholdOverrides(args) {
|
|
183981
|
+
const warnings = [];
|
|
183982
|
+
const basePercentage = normalizeTrustedPercentageThresholds(args.trustedBaseConfig.execute_threshold_percentage);
|
|
183983
|
+
const baseTokens = normalizeTrustedTokenThresholds(args.trustedBaseConfig.execute_threshold_tokens);
|
|
183984
|
+
if ("execute_threshold_percentage" in args.projectRaw) {
|
|
183985
|
+
const projectValue = args.projectRaw.execute_threshold_percentage;
|
|
183986
|
+
if (isValidPercentageThreshold(projectValue)) {
|
|
183987
|
+
const constrained = clonePercentageThresholds(basePercentage);
|
|
183988
|
+
constrained.defaultValue = Math.max(basePercentage.defaultValue, projectValue);
|
|
183989
|
+
for (const [modelKey, threshold] of basePercentage.overrides) {
|
|
183990
|
+
const raisedThreshold = Math.max(threshold, projectValue);
|
|
183991
|
+
if (raisedThreshold === constrained.defaultValue) {
|
|
183992
|
+
constrained.overrides.delete(modelKey);
|
|
183993
|
+
} else {
|
|
183994
|
+
constrained.overrides.set(modelKey, raisedThreshold);
|
|
183995
|
+
}
|
|
183996
|
+
}
|
|
183997
|
+
setMergedPercentageThreshold(args.mergedRaw, constrained);
|
|
183998
|
+
if (percentageThresholdsEqual(constrained, basePercentage)) {
|
|
183999
|
+
warnings.push(makeProjectThresholdWarning("execute_threshold_percentage", PERCENTAGE_THRESHOLD_REASON));
|
|
184000
|
+
}
|
|
184001
|
+
} else if (isPlainObject3(projectValue)) {
|
|
184002
|
+
const constrained = clonePercentageThresholds(basePercentage);
|
|
184003
|
+
let touchedValidEntry = false;
|
|
184004
|
+
if (isValidPercentageThreshold(projectValue.default)) {
|
|
184005
|
+
touchedValidEntry = true;
|
|
184006
|
+
if (projectValue.default > basePercentage.defaultValue) {
|
|
184007
|
+
constrained.defaultValue = projectValue.default;
|
|
184008
|
+
} else {
|
|
184009
|
+
warnings.push(makeProjectThresholdWarning("execute_threshold_percentage.default", PERCENTAGE_THRESHOLD_REASON));
|
|
184010
|
+
}
|
|
184011
|
+
}
|
|
184012
|
+
for (const [modelKey, rawValue] of Object.entries(projectValue)) {
|
|
184013
|
+
if (modelKey === "default")
|
|
184014
|
+
continue;
|
|
184015
|
+
if (!isValidPercentageThreshold(rawValue))
|
|
184016
|
+
continue;
|
|
184017
|
+
touchedValidEntry = true;
|
|
184018
|
+
const baseValue = basePercentage.overrides.get(modelKey) ?? basePercentage.defaultValue;
|
|
184019
|
+
if (rawValue > baseValue) {
|
|
184020
|
+
if (rawValue === constrained.defaultValue) {
|
|
184021
|
+
constrained.overrides.delete(modelKey);
|
|
184022
|
+
} else {
|
|
184023
|
+
constrained.overrides.set(modelKey, rawValue);
|
|
184024
|
+
}
|
|
184025
|
+
} else {
|
|
184026
|
+
warnings.push(makeProjectThresholdWarning(`execute_threshold_percentage.${modelKey}`, PERCENTAGE_THRESHOLD_REASON));
|
|
184027
|
+
}
|
|
184028
|
+
}
|
|
184029
|
+
if (touchedValidEntry) {
|
|
184030
|
+
setMergedPercentageThreshold(args.mergedRaw, constrained);
|
|
184031
|
+
}
|
|
184032
|
+
}
|
|
184033
|
+
}
|
|
184034
|
+
if ("execute_threshold_tokens" in args.projectRaw && isPlainObject3(args.projectRaw.execute_threshold_tokens)) {
|
|
184035
|
+
const projectValue = args.projectRaw.execute_threshold_tokens;
|
|
184036
|
+
const constrained = cloneTokenThresholds(baseTokens);
|
|
184037
|
+
let touchedValidEntry = false;
|
|
184038
|
+
if (isValidTokenThreshold(projectValue.default)) {
|
|
184039
|
+
touchedValidEntry = true;
|
|
184040
|
+
if (baseTokens.defaultValue === undefined) {
|
|
184041
|
+
warnings.push(makeProjectThresholdWarning("execute_threshold_tokens.default", TOKEN_THRESHOLD_INTRODUCTION_REASON));
|
|
184042
|
+
} else if (projectValue.default > baseTokens.defaultValue) {
|
|
184043
|
+
constrained.defaultValue = projectValue.default;
|
|
184044
|
+
} else {
|
|
184045
|
+
warnings.push(makeProjectThresholdWarning("execute_threshold_tokens.default", TOKEN_THRESHOLD_REASON));
|
|
184046
|
+
}
|
|
184047
|
+
}
|
|
184048
|
+
for (const [modelKey, rawValue] of Object.entries(projectValue)) {
|
|
184049
|
+
if (modelKey === "default")
|
|
184050
|
+
continue;
|
|
184051
|
+
if (!isValidTokenThreshold(rawValue))
|
|
184052
|
+
continue;
|
|
184053
|
+
touchedValidEntry = true;
|
|
184054
|
+
const baseValue = baseTokens.overrides.get(modelKey) ?? baseTokens.defaultValue;
|
|
184055
|
+
if (baseValue === undefined) {
|
|
184056
|
+
warnings.push(makeProjectThresholdWarning(`execute_threshold_tokens.${modelKey}`, TOKEN_THRESHOLD_INTRODUCTION_REASON));
|
|
184057
|
+
continue;
|
|
184058
|
+
}
|
|
184059
|
+
if (rawValue > baseValue) {
|
|
184060
|
+
if (rawValue === constrained.defaultValue) {
|
|
184061
|
+
constrained.overrides.delete(modelKey);
|
|
184062
|
+
} else {
|
|
184063
|
+
constrained.overrides.set(modelKey, rawValue);
|
|
184064
|
+
}
|
|
184065
|
+
} else {
|
|
184066
|
+
warnings.push(makeProjectThresholdWarning(`execute_threshold_tokens.${modelKey}`, TOKEN_THRESHOLD_REASON));
|
|
184067
|
+
}
|
|
184068
|
+
}
|
|
184069
|
+
if (touchedValidEntry) {
|
|
184070
|
+
setMergedTokenThreshold(args.mergedRaw, constrained);
|
|
184071
|
+
}
|
|
184072
|
+
}
|
|
184073
|
+
return warnings;
|
|
184074
|
+
}
|
|
183480
184075
|
function normalizeEndpoint3(value) {
|
|
183481
184076
|
if (typeof value !== "string")
|
|
183482
184077
|
return;
|
|
@@ -183844,6 +184439,7 @@ function loadPiConfig(opts = {}) {
|
|
|
183844
184439
|
return a.scope === "user" ? -1 : 1;
|
|
183845
184440
|
});
|
|
183846
184441
|
const userRaw = mergeFiles.find((f) => f.scope === "user")?.config;
|
|
184442
|
+
const trustedBaseConfig = parsePiConfig(userRaw ?? {}).config;
|
|
183847
184443
|
for (const loaded of mergeFiles) {
|
|
183848
184444
|
const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
|
|
183849
184445
|
warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
|
|
@@ -183856,6 +184452,13 @@ function loadPiConfig(opts = {}) {
|
|
|
183856
184452
|
for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, userRaw)) {
|
|
183857
184453
|
warnings.push(`${prefix} ${warning}`);
|
|
183858
184454
|
}
|
|
184455
|
+
for (const warning of constrainProjectThresholdOverrides({
|
|
184456
|
+
mergedRaw: rawConfig,
|
|
184457
|
+
projectRaw,
|
|
184458
|
+
trustedBaseConfig
|
|
184459
|
+
})) {
|
|
184460
|
+
warnings.push(`${prefix} ${warning}`);
|
|
184461
|
+
}
|
|
183859
184462
|
} else {
|
|
183860
184463
|
rawConfig = mergeRawConfigs(rawConfig, loaded.config);
|
|
183861
184464
|
}
|
|
@@ -183954,6 +184557,7 @@ function loadPiConfigDetailed(opts = {}) {
|
|
|
183954
184557
|
return a.scope === "user" ? -1 : 1;
|
|
183955
184558
|
});
|
|
183956
184559
|
const userRaw = mergeFiles.find((f) => f.scope === "user")?.config;
|
|
184560
|
+
const trustedBaseConfig = parsePiConfig(userRaw ?? {}).config;
|
|
183957
184561
|
for (const loaded of mergeFiles) {
|
|
183958
184562
|
const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
|
|
183959
184563
|
warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
|
|
@@ -183966,6 +184570,13 @@ function loadPiConfigDetailed(opts = {}) {
|
|
|
183966
184570
|
for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, userRaw)) {
|
|
183967
184571
|
warnings.push(`${prefix} ${warning}`);
|
|
183968
184572
|
}
|
|
184573
|
+
for (const warning of constrainProjectThresholdOverrides({
|
|
184574
|
+
mergedRaw: rawConfig,
|
|
184575
|
+
projectRaw,
|
|
184576
|
+
trustedBaseConfig
|
|
184577
|
+
})) {
|
|
184578
|
+
warnings.push(`${prefix} ${warning}`);
|
|
184579
|
+
}
|
|
183969
184580
|
} else {
|
|
183970
184581
|
rawConfig = mergeRawConfigs(rawConfig, loaded.config);
|
|
183971
184582
|
}
|
|
@@ -184044,6 +184655,8 @@ function isMidTurnPi(event, _sessionId) {
|
|
|
184044
184655
|
}
|
|
184045
184656
|
if (latestAssistant === null)
|
|
184046
184657
|
return false;
|
|
184658
|
+
if (hasRealUserAfter(messages, latestAssistantIndex))
|
|
184659
|
+
return false;
|
|
184047
184660
|
if (latestAssistant.stopReason === "toolUse")
|
|
184048
184661
|
return true;
|
|
184049
184662
|
const toolCallIds = getToolCallIds(latestAssistant.content);
|
|
@@ -184066,6 +184679,15 @@ function isMidTurnPi(event, _sessionId) {
|
|
|
184066
184679
|
}
|
|
184067
184680
|
return false;
|
|
184068
184681
|
}
|
|
184682
|
+
function hasRealUserAfter(messages, latestAssistantIndex) {
|
|
184683
|
+
for (const msg of messages.slice(latestAssistantIndex + 1)) {
|
|
184684
|
+
if (msg === null || typeof msg !== "object")
|
|
184685
|
+
continue;
|
|
184686
|
+
if (msg.role === "user")
|
|
184687
|
+
return true;
|
|
184688
|
+
}
|
|
184689
|
+
return false;
|
|
184690
|
+
}
|
|
184069
184691
|
function getToolCallIds(content) {
|
|
184070
184692
|
const ids = new Set;
|
|
184071
184693
|
if (!Array.isArray(content))
|
|
@@ -184388,7 +185010,7 @@ class PiRetrospectiveRawProvider {
|
|
|
184388
185010
|
updatedAt: typeof info.modified === "number" ? info.modified : undefined
|
|
184389
185011
|
});
|
|
184390
185012
|
}
|
|
184391
|
-
return result.sort((a, b) => (
|
|
185013
|
+
return result.sort((a, b) => (a.updatedAt ?? 0) - (b.updatedAt ?? 0));
|
|
184392
185014
|
}
|
|
184393
185015
|
async readUserMessagesSince(sessionId, sinceMs, capPerSession) {
|
|
184394
185016
|
const all = await this.loadUserEntries(sessionId);
|
|
@@ -184399,6 +185021,15 @@ class PiRetrospectiveRawProvider {
|
|
|
184399
185021
|
truncated: eligible.length > limit
|
|
184400
185022
|
};
|
|
184401
185023
|
}
|
|
185024
|
+
async readOldestMessageTimesSince(sessionIds, sinceMs) {
|
|
185025
|
+
const out = new Map;
|
|
185026
|
+
for (const sessionId of sessionIds) {
|
|
185027
|
+
const oldest = (await this.loadUserEntries(sessionId)).filter((message) => message.ts > sinceMs).sort((a, b) => a.ts - b.ts || a.ordinal - b.ordinal)[0];
|
|
185028
|
+
if (oldest)
|
|
185029
|
+
out.set(sessionId, oldest.ts);
|
|
185030
|
+
}
|
|
185031
|
+
return out;
|
|
185032
|
+
}
|
|
184402
185033
|
async readUserMessagesBefore(sessionId, beforeMs, count) {
|
|
184403
185034
|
const all = await this.loadUserEntries(sessionId);
|
|
184404
185035
|
return all.filter((entry) => entry.ts <= beforeMs).sort((a, b) => a.ts - b.ts || a.ordinal - b.ordinal).slice(-Math.max(1, Math.floor(count)));
|
|
@@ -186158,6 +186789,8 @@ init_logger();
|
|
|
186158
186789
|
// ../plugin/src/hooks/magic-context/read-session-true-raw-tokens.ts
|
|
186159
186790
|
var MAX_MESSAGE_CACHE_ENTRIES = 1e5;
|
|
186160
186791
|
var MAX_MESSAGE_CACHE_KEY_BYTES = 64 * 1024 * 1024;
|
|
186792
|
+
var FNV1A_32_OFFSET = 2166136261;
|
|
186793
|
+
var FNV1A_32_PRIME = 16777619;
|
|
186161
186794
|
var messageEstimateCache = new Map;
|
|
186162
186795
|
var messageEstimateCacheBytes = 0;
|
|
186163
186796
|
var EMPTY_BREAKDOWN = {
|
|
@@ -186260,6 +186893,23 @@ function recursiveByteLength(value) {
|
|
|
186260
186893
|
}
|
|
186261
186894
|
return String(value).length;
|
|
186262
186895
|
}
|
|
186896
|
+
function updateFnv1a32(hash2, text) {
|
|
186897
|
+
let next = hash2;
|
|
186898
|
+
for (let index = 0;index < text.length; index += 1) {
|
|
186899
|
+
next ^= text.charCodeAt(index);
|
|
186900
|
+
next = Math.imul(next, FNV1A_32_PRIME) >>> 0;
|
|
186901
|
+
}
|
|
186902
|
+
return next;
|
|
186903
|
+
}
|
|
186904
|
+
function contentStringsHash(fields) {
|
|
186905
|
+
let hash2 = FNV1A_32_OFFSET;
|
|
186906
|
+
for (const field of fields) {
|
|
186907
|
+
hash2 = updateFnv1a32(hash2, `${field.length}:`);
|
|
186908
|
+
hash2 = updateFnv1a32(hash2, field);
|
|
186909
|
+
hash2 = updateFnv1a32(hash2, "\x00");
|
|
186910
|
+
}
|
|
186911
|
+
return hash2.toString(16).padStart(8, "0");
|
|
186912
|
+
}
|
|
186263
186913
|
function rawPartVersion(part) {
|
|
186264
186914
|
return part.__magicContextPartUpdatedAt ?? part.updated_at ?? part.updatedAt ?? part.version ?? part.revision ?? "";
|
|
186265
186915
|
}
|
|
@@ -186607,13 +187257,12 @@ function buildTrueRawTokenIndex(sessionId, messages, options) {
|
|
|
186607
187257
|
function partContentFingerprint(part) {
|
|
186608
187258
|
if (!isRecord(part))
|
|
186609
187259
|
return `${typeof part}:${recursiveByteLength(part)}`;
|
|
186610
|
-
const type = partType(part);
|
|
186611
187260
|
const tool = toolSignalFromPart(part);
|
|
186612
187261
|
if (tool) {
|
|
186613
|
-
return
|
|
187262
|
+
return contentStringsHash([tool.inputText, tool.outputText]);
|
|
186614
187263
|
}
|
|
186615
187264
|
const text = firstStringField(part, ["text", "thinking", "reasoning", "content", "url"]) ?? "";
|
|
186616
|
-
return
|
|
187265
|
+
return contentStringsHash([text]);
|
|
186617
187266
|
}
|
|
186618
187267
|
function computeRawRangeFingerprint(messages, startInclusive, endExclusive) {
|
|
186619
187268
|
const pieces = [];
|
|
@@ -188870,24 +189519,46 @@ function getMessageSearchStatementWithCutoff(db) {
|
|
|
188870
189519
|
return stmt;
|
|
188871
189520
|
}
|
|
188872
189521
|
var ftsRowCountStatements = new WeakMap;
|
|
189522
|
+
var ftsRowCountStatementsWithCutoff = new WeakMap;
|
|
188873
189523
|
var ftsMatchCountStatements = new WeakMap;
|
|
188874
|
-
|
|
188875
|
-
|
|
188876
|
-
|
|
188877
|
-
|
|
188878
|
-
|
|
188879
|
-
|
|
188880
|
-
|
|
189524
|
+
var ftsMatchCountStatementsWithCutoff = new WeakMap;
|
|
189525
|
+
function getSessionFtsRowCount(db, sessionId, cutoff) {
|
|
189526
|
+
const stmt = cutoff === null ? (() => {
|
|
189527
|
+
let cached2 = ftsRowCountStatements.get(db);
|
|
189528
|
+
if (!cached2) {
|
|
189529
|
+
cached2 = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ?");
|
|
189530
|
+
ftsRowCountStatements.set(db, cached2);
|
|
189531
|
+
}
|
|
189532
|
+
return cached2;
|
|
189533
|
+
})() : (() => {
|
|
189534
|
+
let cached2 = ftsRowCountStatementsWithCutoff.get(db);
|
|
189535
|
+
if (!cached2) {
|
|
189536
|
+
cached2 = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ? AND CAST(message_ordinal AS INTEGER) <= ?");
|
|
189537
|
+
ftsRowCountStatementsWithCutoff.set(db, cached2);
|
|
189538
|
+
}
|
|
189539
|
+
return cached2;
|
|
189540
|
+
})();
|
|
189541
|
+
const row = cutoff === null ? stmt.get(sessionId) : stmt.get(sessionId, cutoff);
|
|
188881
189542
|
return typeof row?.n === "number" ? row.n : 0;
|
|
188882
189543
|
}
|
|
188883
|
-
function countSessionFtsMatches(db, sessionId, ftsQuery) {
|
|
188884
|
-
|
|
188885
|
-
|
|
188886
|
-
|
|
188887
|
-
|
|
188888
|
-
|
|
189544
|
+
function countSessionFtsMatches(db, sessionId, ftsQuery, cutoff) {
|
|
189545
|
+
const stmt = cutoff === null ? (() => {
|
|
189546
|
+
let cached2 = ftsMatchCountStatements.get(db);
|
|
189547
|
+
if (!cached2) {
|
|
189548
|
+
cached2 = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ?");
|
|
189549
|
+
ftsMatchCountStatements.set(db, cached2);
|
|
189550
|
+
}
|
|
189551
|
+
return cached2;
|
|
189552
|
+
})() : (() => {
|
|
189553
|
+
let cached2 = ftsMatchCountStatementsWithCutoff.get(db);
|
|
189554
|
+
if (!cached2) {
|
|
189555
|
+
cached2 = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ? AND CAST(message_ordinal AS INTEGER) <= ?");
|
|
189556
|
+
ftsMatchCountStatementsWithCutoff.set(db, cached2);
|
|
189557
|
+
}
|
|
189558
|
+
return cached2;
|
|
189559
|
+
})();
|
|
188889
189560
|
try {
|
|
188890
|
-
const row = stmt.get(sessionId, ftsQuery);
|
|
189561
|
+
const row = cutoff === null ? stmt.get(sessionId, ftsQuery) : stmt.get(sessionId, ftsQuery, cutoff);
|
|
188891
189562
|
return typeof row?.n === "number" ? row.n : 0;
|
|
188892
189563
|
} catch {
|
|
188893
189564
|
return 0;
|
|
@@ -189137,7 +189808,7 @@ function searchMessages(args) {
|
|
|
189137
189808
|
role: row.role
|
|
189138
189809
|
}));
|
|
189139
189810
|
}
|
|
189140
|
-
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId);
|
|
189811
|
+
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId, cutoff);
|
|
189141
189812
|
const queryLists = [];
|
|
189142
189813
|
if (baseQuery.length > 0) {
|
|
189143
189814
|
queryLists.push({
|
|
@@ -189150,7 +189821,7 @@ function searchMessages(args) {
|
|
|
189150
189821
|
const probeQuery = sanitizeFtsQuery(probe);
|
|
189151
189822
|
if (probeQuery.length === 0)
|
|
189152
189823
|
continue;
|
|
189153
|
-
const df = countSessionFtsMatches(args.db, args.sessionId, probeQuery);
|
|
189824
|
+
const df = countSessionFtsMatches(args.db, args.sessionId, probeQuery, cutoff);
|
|
189154
189825
|
const weight = probeDiscriminationWeight(df, corpusSize);
|
|
189155
189826
|
probeWeights.set(probe, weight);
|
|
189156
189827
|
queryLists.push({
|
|
@@ -200185,6 +200856,15 @@ async function executeContextRecompWithResult(deps, options = {}) {
|
|
|
200185
200856
|
published: false
|
|
200186
200857
|
};
|
|
200187
200858
|
}
|
|
200859
|
+
options.onLeaseAcquired?.();
|
|
200860
|
+
if (isWrapupInProgress(deps.db, sessionId)) {
|
|
200861
|
+
sessionLog(sessionId, "recomp skipped: /ctx-wrapup became active");
|
|
200862
|
+
releaseCompartmentLease(deps.db, sessionId, holderId);
|
|
200863
|
+
return {
|
|
200864
|
+
message: "## Magic Recomp — Skipped\n\n/ctx-wrapup is already compacting this session. Wait for it to finish, then try `/ctx-recomp` again.",
|
|
200865
|
+
published: false
|
|
200866
|
+
};
|
|
200867
|
+
}
|
|
200188
200868
|
const renewal = startLeaseRenewal(deps, holderId);
|
|
200189
200869
|
const runnerDeps = withPublishedCallback({ ...deps, compartmentLeaseHolderId: holderId });
|
|
200190
200870
|
const promise2 = options.range ? executePartialRecompInternal(runnerDeps, options.range) : executeContextRecompInternal(runnerDeps);
|
|
@@ -201310,7 +201990,7 @@ function formatThresholdPercent(value) {
|
|
|
201310
201990
|
// package.json
|
|
201311
201991
|
var package_default = {
|
|
201312
201992
|
name: "@cortexkit/pi-magic-context",
|
|
201313
|
-
version: "0.31.
|
|
201993
|
+
version: "0.31.5",
|
|
201314
201994
|
type: "module",
|
|
201315
201995
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
201316
201996
|
main: "dist/index.js",
|
|
@@ -201860,6 +202540,11 @@ function readHistorianState(db, sessionId, meta3) {
|
|
|
201860
202540
|
import * as crypto4 from "node:crypto";
|
|
201861
202541
|
var DEFAULT_MESSAGES_TO_KEEP = 20;
|
|
201862
202542
|
var LEASE_WAIT_MS = 1000;
|
|
202543
|
+
var MAX_WRAPUP_LEASE_WAIT_MS = 10 * 60 * 1000;
|
|
202544
|
+
function resolveWrapupLeaseWaitTimeout(deps) {
|
|
202545
|
+
const configured = deps.wrapupLeaseWaitTimeoutMs ?? MAX_WRAPUP_LEASE_WAIT_MS;
|
|
202546
|
+
return Number.isFinite(configured) && configured >= 0 ? configured : MAX_WRAPUP_LEASE_WAIT_MS;
|
|
202547
|
+
}
|
|
201863
202548
|
function parseWrapupArgs(raw) {
|
|
201864
202549
|
const trimmed = raw.trim();
|
|
201865
202550
|
if (trimmed === "")
|
|
@@ -202077,11 +202762,12 @@ Eligible history is about ${initialPlan.snapshot.trueRawEligibleTokens.toLocaleS
|
|
|
202077
202762
|
Chunk ${chunkIndex}: wrapping messages ${plan.snapshot.offset}-${plan.snapshot.eligibleEndOrdinal - 1} (~${plan.snapshot.trueRawEligibleTokens.toLocaleString()} eligible tokens remain).`,
|
|
202078
202763
|
level: "info"
|
|
202079
202764
|
});
|
|
202080
|
-
const
|
|
202081
|
-
if (!
|
|
202082
|
-
failure = ownershipLost ? `${ownershipLostReason}; wrapped up through message ${lastEnd}. Run /ctx-wrapup again to continue.` : "Another Magic Context rebuild started while wrapup was waiting. Run /ctx-wrapup again to continue.";
|
|
202765
|
+
const leaseResult = await acquireCompartmentLeaseEventually(deps.db, sessionId, renewWrapupMarker, resolveWrapupLeaseWaitTimeout(deps));
|
|
202766
|
+
if (!leaseResult.ok) {
|
|
202767
|
+
failure = ownershipLost ? `${ownershipLostReason}; wrapped up through message ${lastEnd}. Run /ctx-wrapup again to continue.` : leaseResult.reason === "timeout" ? `Timed out waiting for another process to release the compartment-state lease; wrapped up through message ${lastEnd}. Run /ctx-wrapup again to continue.` : "Another Magic Context rebuild started while wrapup was waiting. Run /ctx-wrapup again to continue.";
|
|
202083
202768
|
break;
|
|
202084
202769
|
}
|
|
202770
|
+
const leaseHolder = leaseResult.holderId;
|
|
202085
202771
|
const leaseRenewal = setInterval(() => {
|
|
202086
202772
|
try {
|
|
202087
202773
|
renewCompartmentLease(deps.db, sessionId, leaseHolder);
|
|
@@ -202185,15 +202871,19 @@ function resolvePiContextLimit(ctx) {
|
|
|
202185
202871
|
}
|
|
202186
202872
|
return 128000;
|
|
202187
202873
|
}
|
|
202188
|
-
async function acquireCompartmentLeaseEventually(db, sessionId, renewWrapupMarker) {
|
|
202874
|
+
async function acquireCompartmentLeaseEventually(db, sessionId, renewWrapupMarker, maxWaitMs) {
|
|
202875
|
+
const waitStartedAt = Date.now();
|
|
202876
|
+
const remainingMs = () => Math.max(0, waitStartedAt + maxWaitMs - Date.now());
|
|
202189
202877
|
for (;; ) {
|
|
202878
|
+
if (remainingMs() <= 0)
|
|
202879
|
+
return { ok: false, reason: "timeout" };
|
|
202190
202880
|
const holderId = crypto4.randomUUID();
|
|
202191
202881
|
const lease = acquireCompartmentLease(db, sessionId, holderId);
|
|
202192
202882
|
if (lease)
|
|
202193
|
-
return holderId;
|
|
202883
|
+
return { ok: true, holderId };
|
|
202194
202884
|
if (!renewWrapupMarker({}))
|
|
202195
|
-
return
|
|
202196
|
-
await new Promise((resolve3) => setTimeout(resolve3, LEASE_WAIT_MS));
|
|
202885
|
+
return { ok: false, reason: "ownership_lost" };
|
|
202886
|
+
await new Promise((resolve3) => setTimeout(resolve3, Math.min(LEASE_WAIT_MS, remainingMs())));
|
|
202197
202887
|
}
|
|
202198
202888
|
}
|
|
202199
202889
|
function estimateChunks(tokens, chunkTokens) {
|
|
@@ -206949,8 +207639,9 @@ function createCtxMemoryTool(deps) {
|
|
|
206949
207639
|
const isOwn = targetIdentityForStoredPath(memory2.projectPath) === projectIdentity;
|
|
206950
207640
|
if (isOwn)
|
|
206951
207641
|
return true;
|
|
206952
|
-
return toolShareCategories
|
|
207642
|
+
return toolShareCategories?.includes(memory2.category) ?? false;
|
|
206953
207643
|
};
|
|
207644
|
+
const memoryOwnedByTool = (memory2) => workspaceIdentitySet.identities.length > 1 ? targetIdentityForStoredPath(memory2.projectPath) === projectIdentity : storedPathBelongsToIdentity(memory2.projectPath, projectIdentity);
|
|
206954
207645
|
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
206955
207646
|
if (snapshot ? !snapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
206956
207647
|
return err2("Cross-session memory is disabled for this project.");
|
|
@@ -206997,7 +207688,8 @@ function createCtxMemoryTool(deps) {
|
|
|
206997
207688
|
return err2("Error: 'content' is required when action is 'update'.");
|
|
206998
207689
|
}
|
|
206999
207690
|
const memory2 = getMemoryById(deps.db, updateId);
|
|
207000
|
-
|
|
207691
|
+
const updateAllowed = memory2 ? dreamerAllowed ? memoryVisibleToTool(memory2) : memoryOwnedByTool(memory2) : false;
|
|
207692
|
+
if (!memory2 || !updateAllowed) {
|
|
207001
207693
|
return err2(`Error: Memory with ID ${updateId} was not found.`);
|
|
207002
207694
|
}
|
|
207003
207695
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
@@ -207044,7 +207736,7 @@ function createCtxMemoryTool(deps) {
|
|
|
207044
207736
|
return err2("Error: One or more source memories were not found.");
|
|
207045
207737
|
}
|
|
207046
207738
|
if (!dreamerAllowed) {
|
|
207047
|
-
const foreign = sourceMemories.find((memory2) => !
|
|
207739
|
+
const foreign = sourceMemories.find((memory2) => !memoryOwnedByTool(memory2));
|
|
207048
207740
|
if (foreign) {
|
|
207049
207741
|
return err2(`Error: Memory with ID ${foreign.id} was not found.`);
|
|
207050
207742
|
}
|
|
@@ -207146,7 +207838,8 @@ function createCtxMemoryTool(deps) {
|
|
|
207146
207838
|
const archiveIds = [...new Set(rawArchiveIds)];
|
|
207147
207839
|
for (const memoryId of archiveIds) {
|
|
207148
207840
|
const memory2 = getMemoryById(deps.db, memoryId);
|
|
207149
|
-
|
|
207841
|
+
const archiveAllowed = memory2 ? dreamerAllowed ? memoryVisibleToTool(memory2) : memoryOwnedByTool(memory2) : false;
|
|
207842
|
+
if (!memory2 || !archiveAllowed) {
|
|
207150
207843
|
return err2(`Error: Memory with ID ${memoryId} was not found.`);
|
|
207151
207844
|
}
|
|
207152
207845
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
@@ -207807,14 +208500,7 @@ import {
|
|
|
207807
208500
|
var TODO_TOOL_NAME = "todowrite";
|
|
207808
208501
|
var TODOS_COMMAND_NAME = "todos";
|
|
207809
208502
|
var WIDGET_KEY = "magic-context-todos";
|
|
207810
|
-
var
|
|
207811
|
-
var TODO_STATUSES = [
|
|
207812
|
-
"pending",
|
|
207813
|
-
"in_progress",
|
|
207814
|
-
"completed",
|
|
207815
|
-
"cancelled"
|
|
207816
|
-
];
|
|
207817
|
-
var TODO_PRIORITIES = ["high", "medium", "low"];
|
|
208503
|
+
var MAX_TODO_CONTENT_ROWS = 12;
|
|
207818
208504
|
var STATUS_GLYPH = {
|
|
207819
208505
|
pending: "○",
|
|
207820
208506
|
in_progress: "◐",
|
|
@@ -207828,10 +208514,10 @@ var STATUS_COLOR = {
|
|
|
207828
208514
|
cancelled: "error"
|
|
207829
208515
|
};
|
|
207830
208516
|
var snapshotsBySession = new Map;
|
|
207831
|
-
function
|
|
208517
|
+
function isTodoStatus2(value) {
|
|
207832
208518
|
return TODO_STATUSES.includes(value);
|
|
207833
208519
|
}
|
|
207834
|
-
function
|
|
208520
|
+
function isTodoPriority2(value) {
|
|
207835
208521
|
return TODO_PRIORITIES.includes(value);
|
|
207836
208522
|
}
|
|
207837
208523
|
function cloneTodos(todos) {
|
|
@@ -207845,14 +208531,14 @@ function parseTodos(input) {
|
|
|
207845
208531
|
if (item === null || typeof item !== "object")
|
|
207846
208532
|
return null;
|
|
207847
208533
|
const raw = item;
|
|
207848
|
-
if (typeof raw.content !== "string" || !
|
|
208534
|
+
if (typeof raw.content !== "string" || !isTodoStatus2(raw.status)) {
|
|
207849
208535
|
return null;
|
|
207850
208536
|
}
|
|
207851
208537
|
const todo = {
|
|
207852
208538
|
content: raw.content,
|
|
207853
208539
|
status: raw.status
|
|
207854
208540
|
};
|
|
207855
|
-
if (
|
|
208541
|
+
if (isTodoPriority2(raw.priority))
|
|
207856
208542
|
todo.priority = raw.priority;
|
|
207857
208543
|
if (typeof raw.id === "string" && raw.id.length > 0)
|
|
207858
208544
|
todo.id = raw.id;
|
|
@@ -207929,7 +208615,7 @@ function countTodos(todos) {
|
|
|
207929
208615
|
return counts;
|
|
207930
208616
|
}
|
|
207931
208617
|
function activeTitleCount(todos) {
|
|
207932
|
-
return todos.filter((todo) => todo.status
|
|
208618
|
+
return todos.filter((todo) => !TITLE_DONE_STATUSES.has(todo.status)).length;
|
|
207933
208619
|
}
|
|
207934
208620
|
function formatCounts(counts) {
|
|
207935
208621
|
if (counts.total === 0)
|
|
@@ -207963,6 +208649,16 @@ function lineComponent(renderLines) {
|
|
|
207963
208649
|
invalidate() {}
|
|
207964
208650
|
};
|
|
207965
208651
|
}
|
|
208652
|
+
function capTodoRows(rows) {
|
|
208653
|
+
if (rows.length <= MAX_TODO_CONTENT_ROWS) {
|
|
208654
|
+
return { visible: [...rows], hiddenCount: 0 };
|
|
208655
|
+
}
|
|
208656
|
+
const visibleCount = Math.max(0, MAX_TODO_CONTENT_ROWS - 1);
|
|
208657
|
+
return {
|
|
208658
|
+
visible: rows.slice(0, visibleCount),
|
|
208659
|
+
hiddenCount: rows.length - visibleCount
|
|
208660
|
+
};
|
|
208661
|
+
}
|
|
207966
208662
|
function renderTodowriteCall(args, theme) {
|
|
207967
208663
|
const todos = parseTodos(args.todos) ?? [];
|
|
207968
208664
|
const active = activeTitleCount(todos);
|
|
@@ -207985,7 +208681,12 @@ function renderTodowriteResult(result, theme) {
|
|
|
207985
208681
|
return lineComponent((width) => {
|
|
207986
208682
|
if (renderedTodos.length === 0)
|
|
207987
208683
|
return [theme.fg("dim", "No todos")];
|
|
207988
|
-
|
|
208684
|
+
const { visible, hiddenCount } = capTodoRows(renderedTodos);
|
|
208685
|
+
const lines = visible.map((todo) => truncateToWidth2(formatTodoLine(todo, theme, { showId: true }), width, "…"));
|
|
208686
|
+
if (hiddenCount > 0) {
|
|
208687
|
+
lines.push(truncateToWidth2(theme.fg("dim", `+${hiddenCount} more`), width, "…"));
|
|
208688
|
+
}
|
|
208689
|
+
return lines;
|
|
207989
208690
|
});
|
|
207990
208691
|
}
|
|
207991
208692
|
function registerTodosCommand(pi) {
|
|
@@ -208015,8 +208716,11 @@ function registerTodosCommand(pi) {
|
|
|
208015
208716
|
if (group.length === 0)
|
|
208016
208717
|
continue;
|
|
208017
208718
|
lines.push(heading);
|
|
208018
|
-
|
|
208719
|
+
const { visible, hiddenCount } = capTodoRows(group);
|
|
208720
|
+
for (const todo of visible)
|
|
208019
208721
|
lines.push(formatCommandLine(todo));
|
|
208722
|
+
if (hiddenCount > 0)
|
|
208723
|
+
lines.push(` +${hiddenCount} more`);
|
|
208020
208724
|
}
|
|
208021
208725
|
ctx.ui.notify(lines.join(`
|
|
208022
208726
|
`), "info");
|
|
@@ -208144,19 +208848,16 @@ class TodoOverlay {
|
|
|
208144
208848
|
const heading = `${theme.fg(headingColor, headingIcon)} ${theme.fg(headingColor, "Todos")} ${theme.fg("muted", "—")} ${theme.fg("dim", formatCounts(counts))}`;
|
|
208145
208849
|
const truncate3 = (line) => truncateToWidth2(line, width, "…");
|
|
208146
208850
|
const lines = [truncate3(heading)];
|
|
208147
|
-
const
|
|
208148
|
-
const visibleRows = hasTruncatedTail ? MAX_OVERLAY_CONTENT_ROWS - 1 : MAX_OVERLAY_CONTENT_ROWS;
|
|
208149
|
-
const truncatedTail = Math.max(0, overlayTodos.length - visibleRows);
|
|
208150
|
-
const visible = overlayTodos.slice(0, visibleRows);
|
|
208851
|
+
const { visible, hiddenCount } = capTodoRows(overlayTodos);
|
|
208151
208852
|
for (const [index, { todo, key }] of visible.entries()) {
|
|
208152
|
-
const isLast = index === visible.length - 1 &&
|
|
208853
|
+
const isLast = index === visible.length - 1 && hiddenCount === 0;
|
|
208153
208854
|
const branch = theme.fg("dim", isLast ? "└─" : "├─");
|
|
208154
208855
|
lines.push(truncate3(`${branch} ${formatTodoLine(todo, theme, { showId: true })}`));
|
|
208155
208856
|
if (todo.status === "completed")
|
|
208156
208857
|
this.completedTaskIdsPendingHide.add(key);
|
|
208157
208858
|
}
|
|
208158
|
-
if (
|
|
208159
|
-
lines.push(truncate3(`${theme.fg("dim", "└─")} ${theme.fg("dim", `+${
|
|
208859
|
+
if (hiddenCount > 0) {
|
|
208860
|
+
lines.push(truncate3(`${theme.fg("dim", "└─")} ${theme.fg("dim", `+${hiddenCount} more`)}`));
|
|
208160
208861
|
}
|
|
208161
208862
|
return lines;
|
|
208162
208863
|
}
|
|
@@ -208212,17 +208913,10 @@ function registerTodoStateLifecycle(pi, deps) {
|
|
|
208212
208913
|
}
|
|
208213
208914
|
|
|
208214
208915
|
// src/tools/todowrite.ts
|
|
208215
|
-
var STATUS_VALUES = [
|
|
208216
|
-
"pending",
|
|
208217
|
-
"in_progress",
|
|
208218
|
-
"completed",
|
|
208219
|
-
"cancelled"
|
|
208220
|
-
];
|
|
208221
|
-
var PRIORITY_VALUES = ["high", "medium", "low"];
|
|
208222
208916
|
var TodoItem = exports_typebox.Object({
|
|
208223
208917
|
content: exports_typebox.String({ description: "Brief description of the task" }),
|
|
208224
|
-
status: exports_typebox.Union(
|
|
208225
|
-
priority: exports_typebox.Optional(exports_typebox.Union(
|
|
208918
|
+
status: exports_typebox.Union(TODO_STATUSES.map((v) => exports_typebox.Literal(v))),
|
|
208919
|
+
priority: exports_typebox.Optional(exports_typebox.Union(TODO_PRIORITIES.map((v) => exports_typebox.Literal(v)))),
|
|
208226
208920
|
id: exports_typebox.Optional(exports_typebox.String({ description: "Optional stable id for the todo" }))
|
|
208227
208921
|
});
|
|
208228
208922
|
var TodowriteParams = exports_typebox.Object({
|
|
@@ -208247,8 +208941,7 @@ function createTodowriteTool() {
|
|
|
208247
208941
|
parameters: TodowriteParams,
|
|
208248
208942
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
208249
208943
|
const todos = params.todos ?? [];
|
|
208250
|
-
const
|
|
208251
|
-
const active = todos.length - completed;
|
|
208944
|
+
const active = todos.filter((todo) => !TITLE_DONE_STATUSES.has(todo.status)).length;
|
|
208252
208945
|
return {
|
|
208253
208946
|
content: [
|
|
208254
208947
|
{
|
|
@@ -208339,6 +209032,55 @@ function persistPiMessageEndModelMeta(args) {
|
|
|
208339
209032
|
updateSessionMeta(args.db, args.sessionId, { cacheTtl });
|
|
208340
209033
|
}
|
|
208341
209034
|
}
|
|
209035
|
+
function getCompatiblePiTodoCapture(todos) {
|
|
209036
|
+
if (!Array.isArray(todos))
|
|
209037
|
+
return null;
|
|
209038
|
+
const normalized = normalizeTodoStateJson(todos);
|
|
209039
|
+
if (normalized === null)
|
|
209040
|
+
return null;
|
|
209041
|
+
return { normalized, todos };
|
|
209042
|
+
}
|
|
209043
|
+
function applyCompatiblePiTodoCapture(args) {
|
|
209044
|
+
if (args.todowriteEnabled) {
|
|
209045
|
+
setTodoSnapshot(args.sessionId, args.capture.todos);
|
|
209046
|
+
args.todoOverlay?.update(args.sessionId);
|
|
209047
|
+
}
|
|
209048
|
+
if (args.persist) {
|
|
209049
|
+
updateSessionMeta(args.db, args.sessionId, {
|
|
209050
|
+
lastTodoState: args.capture.normalized
|
|
209051
|
+
});
|
|
209052
|
+
}
|
|
209053
|
+
}
|
|
209054
|
+
function capturePiTodowriteArgsIfCompatible(args) {
|
|
209055
|
+
const capture = getCompatiblePiTodoCapture(args.todos);
|
|
209056
|
+
if (capture === null)
|
|
209057
|
+
return false;
|
|
209058
|
+
applyCompatiblePiTodoCapture({ ...args, capture });
|
|
209059
|
+
return true;
|
|
209060
|
+
}
|
|
209061
|
+
function capturePiTodowriteMessageIfCompatible(args) {
|
|
209062
|
+
const msg = args.message;
|
|
209063
|
+
if (msg?.role !== "assistant" || !Array.isArray(msg.content)) {
|
|
209064
|
+
return false;
|
|
209065
|
+
}
|
|
209066
|
+
for (const block of msg.content) {
|
|
209067
|
+
if (!block || typeof block !== "object")
|
|
209068
|
+
continue;
|
|
209069
|
+
const b = block;
|
|
209070
|
+
if (b.type !== "toolCall")
|
|
209071
|
+
continue;
|
|
209072
|
+
if (typeof b.name !== "string")
|
|
209073
|
+
continue;
|
|
209074
|
+
if (b.name !== "todowrite")
|
|
209075
|
+
continue;
|
|
209076
|
+
const capture = getCompatiblePiTodoCapture(b.arguments?.todos);
|
|
209077
|
+
if (capture === null)
|
|
209078
|
+
continue;
|
|
209079
|
+
applyCompatiblePiTodoCapture({ ...args, capture });
|
|
209080
|
+
return true;
|
|
209081
|
+
}
|
|
209082
|
+
return false;
|
|
209083
|
+
}
|
|
208342
209084
|
function info(message, data) {
|
|
208343
209085
|
log(`${PREFIX} ${message}`, data);
|
|
208344
209086
|
}
|
|
@@ -208346,6 +209088,7 @@ function warn(message, data) {
|
|
|
208346
209088
|
log(`${PREFIX} WARN ${message}`, data);
|
|
208347
209089
|
}
|
|
208348
209090
|
var migratedConfigDirs = new Set;
|
|
209091
|
+
var loggedPiConfigDirs = new Set;
|
|
208349
209092
|
function ensureConfigLocationsMigrated(dir) {
|
|
208350
209093
|
if (migratedConfigDirs.has(dir))
|
|
208351
209094
|
return;
|
|
@@ -208355,6 +209098,28 @@ function ensureConfigLocationsMigrated(dir) {
|
|
|
208355
209098
|
info: (m) => info(m)
|
|
208356
209099
|
});
|
|
208357
209100
|
}
|
|
209101
|
+
function logPiConfigLoad(args) {
|
|
209102
|
+
const key = resolve3(args.dir);
|
|
209103
|
+
if (args.dedupe && loggedPiConfigDirs.has(key))
|
|
209104
|
+
return;
|
|
209105
|
+
if (args.dedupe) {
|
|
209106
|
+
loggedPiConfigDirs.add(key);
|
|
209107
|
+
}
|
|
209108
|
+
if (args.loadedFromPaths.length > 0) {
|
|
209109
|
+
info(`config loaded from: ${args.loadedFromPaths.join(", ")}`);
|
|
209110
|
+
} else {
|
|
209111
|
+
info("config: no magic-context.jsonc found, using schema defaults");
|
|
209112
|
+
}
|
|
209113
|
+
for (const warning of args.warnings) {
|
|
209114
|
+
warn(`config: ${warning}`);
|
|
209115
|
+
}
|
|
209116
|
+
}
|
|
209117
|
+
var __test = {
|
|
209118
|
+
logPiConfigLoad,
|
|
209119
|
+
resetLoggedPiConfigDirs() {
|
|
209120
|
+
loggedPiConfigDirs.clear();
|
|
209121
|
+
}
|
|
209122
|
+
};
|
|
208358
209123
|
function formatTokens(value) {
|
|
208359
209124
|
return value.toLocaleString();
|
|
208360
209125
|
}
|
|
@@ -208541,14 +209306,12 @@ async function src_default2(pi) {
|
|
|
208541
209306
|
const { config: config2, warnings, loadedFromPaths } = loadPiConfig({
|
|
208542
209307
|
cwd: projectDir
|
|
208543
209308
|
});
|
|
208544
|
-
|
|
208545
|
-
|
|
208546
|
-
|
|
208547
|
-
|
|
208548
|
-
|
|
208549
|
-
|
|
208550
|
-
warn(`config: ${w}`);
|
|
208551
|
-
}
|
|
209309
|
+
logPiConfigLoad({
|
|
209310
|
+
dir: projectDir,
|
|
209311
|
+
loadedFromPaths,
|
|
209312
|
+
warnings,
|
|
209313
|
+
dedupe: true
|
|
209314
|
+
});
|
|
208552
209315
|
setSqlitePragmaConfig({
|
|
208553
209316
|
cacheSizeMb: config2.sqlite.cache_size_mb,
|
|
208554
209317
|
mmapSizeMb: config2.sqlite.mmap_size_mb
|
|
@@ -208630,7 +209393,14 @@ async function src_default2(pi) {
|
|
|
208630
209393
|
if (cached2)
|
|
208631
209394
|
return cached2;
|
|
208632
209395
|
ensureConfigLocationsMigrated(dir);
|
|
208633
|
-
const
|
|
209396
|
+
const switchedLoad = loadPiConfig({ cwd: dir });
|
|
209397
|
+
logPiConfigLoad({
|
|
209398
|
+
dir,
|
|
209399
|
+
loadedFromPaths: switchedLoad.loadedFromPaths,
|
|
209400
|
+
warnings: switchedLoad.warnings,
|
|
209401
|
+
dedupe: true
|
|
209402
|
+
});
|
|
209403
|
+
const switchedConfig = switchedLoad.config;
|
|
208634
209404
|
const switchedIdentity = identityOverride ?? resolveProjectIdentityOrFallback(dir);
|
|
208635
209405
|
const built = buildProjectDeps(dir, switchedIdentity, switchedConfig);
|
|
208636
209406
|
projectDepsByDir.set(dir, built);
|
|
@@ -209001,18 +209771,14 @@ ${block}` : event.systemPrompt;
|
|
|
209001
209771
|
const todoArgs = event.args;
|
|
209002
209772
|
const todos = todoArgs?.todos;
|
|
209003
209773
|
const sessionMeta = Array.isArray(todos) ? getOrCreateSessionMeta(db, sessionId) : null;
|
|
209004
|
-
|
|
209005
|
-
|
|
209006
|
-
|
|
209007
|
-
|
|
209008
|
-
|
|
209009
|
-
|
|
209010
|
-
|
|
209011
|
-
|
|
209012
|
-
lastTodoState: normalizedTodos
|
|
209013
|
-
});
|
|
209014
|
-
}
|
|
209015
|
-
}
|
|
209774
|
+
capturePiTodowriteArgsIfCompatible({
|
|
209775
|
+
db,
|
|
209776
|
+
sessionId,
|
|
209777
|
+
todos,
|
|
209778
|
+
todowriteEnabled,
|
|
209779
|
+
todoOverlay,
|
|
209780
|
+
persist: Boolean(sessionMeta && !sessionMeta.isSubagent)
|
|
209781
|
+
});
|
|
209016
209782
|
if (Array.isArray(todos) && todos.length > 0 && todos.every((t) => t.status === "completed" || t.status === "cancelled")) {
|
|
209017
209783
|
if (sessionMeta && !sessionMeta.isSubagent) {
|
|
209018
209784
|
onNoteTrigger(db, sessionId, "todos_complete");
|
|
@@ -209115,36 +209881,14 @@ ${block}` : event.systemPrompt;
|
|
|
209115
209881
|
try {
|
|
209116
209882
|
const sessionMetaForTodo = getOrCreateSessionMeta(db, sessionId);
|
|
209117
209883
|
if (!sessionMetaForTodo.isSubagent) {
|
|
209118
|
-
|
|
209119
|
-
|
|
209120
|
-
|
|
209121
|
-
|
|
209122
|
-
|
|
209123
|
-
|
|
209124
|
-
|
|
209125
|
-
|
|
209126
|
-
if (typeof b.name !== "string")
|
|
209127
|
-
continue;
|
|
209128
|
-
if (b.name !== "todowrite") {
|
|
209129
|
-
continue;
|
|
209130
|
-
}
|
|
209131
|
-
const args = b.arguments;
|
|
209132
|
-
const todos = args?.todos;
|
|
209133
|
-
if (!Array.isArray(todos))
|
|
209134
|
-
continue;
|
|
209135
|
-
const normalized = normalizeTodoStateJson(todos);
|
|
209136
|
-
if (normalized === null)
|
|
209137
|
-
continue;
|
|
209138
|
-
if (todowriteEnabled) {
|
|
209139
|
-
setTodoSnapshot(sessionId, todos);
|
|
209140
|
-
todoOverlay?.update(sessionId);
|
|
209141
|
-
}
|
|
209142
|
-
updateSessionMeta(db, sessionId, {
|
|
209143
|
-
lastTodoState: normalized
|
|
209144
|
-
});
|
|
209145
|
-
break;
|
|
209146
|
-
}
|
|
209147
|
-
}
|
|
209884
|
+
capturePiTodowriteMessageIfCompatible({
|
|
209885
|
+
db,
|
|
209886
|
+
sessionId,
|
|
209887
|
+
message: event.message,
|
|
209888
|
+
todowriteEnabled,
|
|
209889
|
+
todoOverlay,
|
|
209890
|
+
persist: true
|
|
209891
|
+
});
|
|
209148
209892
|
}
|
|
209149
209893
|
} catch (err5) {
|
|
209150
209894
|
warn("message_end: synthetic todowrite capture failed:", err5);
|
|
@@ -209236,5 +209980,8 @@ export {
|
|
|
209236
209980
|
resolveDreamerFromConfig,
|
|
209237
209981
|
persistPiPressureFromMessageEnd,
|
|
209238
209982
|
persistPiMessageEndModelMeta,
|
|
209239
|
-
src_default2 as default
|
|
209983
|
+
src_default2 as default,
|
|
209984
|
+
capturePiTodowriteMessageIfCompatible,
|
|
209985
|
+
capturePiTodowriteArgsIfCompatible,
|
|
209986
|
+
__test
|
|
209240
209987
|
};
|