@cortexkit/pi-magic-context 0.40.1 → 0.41.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/historian-calibration-extension.js +64 -0
- package/dist/{index-fre7qcqg.js → index-0jgz8yja.js} +833 -499
- package/dist/index-q2vgz0j1.js +463 -0
- package/dist/index.js +1380 -493
- package/dist/{safe-notification-target-q00qgjm6.js → safe-notification-target-hjcb423r.js} +1 -1
- package/dist/subagent-entry.js +2 -2
- package/dist/transformers-web.js +24570 -0
- package/dist/transformers.node-b1wa0hgx.js +28808 -0
- package/package.json +92 -87
- package/dist/index-hk6sj7dn.js +0 -147
- /package/dist/{index-8sseka65.js → index-y63nbvkk.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
bumpProjectUserProfileVersion,
|
|
53
53
|
byteSize,
|
|
54
54
|
canonicalizeInMemoryChunkTextForEmbedding,
|
|
55
|
+
captureChannel1PostReduceGraceBaseline,
|
|
55
56
|
casChannel2NudgeClaim,
|
|
56
57
|
casChannel2NudgeState,
|
|
57
58
|
chunkCanonicalText,
|
|
@@ -100,6 +101,7 @@ import {
|
|
|
100
101
|
deriveTagLoadFloor,
|
|
101
102
|
deriveWindowGeometry,
|
|
102
103
|
describeError,
|
|
104
|
+
describeProtectedTailDrainBudgetSkip,
|
|
103
105
|
dismissUserMemory,
|
|
104
106
|
drainCommitBacklogForProject,
|
|
105
107
|
effectiveTailHygiene,
|
|
@@ -124,6 +126,7 @@ import {
|
|
|
124
126
|
extractM0Block,
|
|
125
127
|
extractTexts,
|
|
126
128
|
extractToolCallSummaries,
|
|
129
|
+
fenceBoundaryForCompletedToolArcs,
|
|
127
130
|
fenceBoundaryForToolArcs,
|
|
128
131
|
findAdoptableFallbackTags,
|
|
129
132
|
findLastModelKeyFromBranch,
|
|
@@ -187,6 +190,7 @@ import {
|
|
|
187
190
|
getOverflowState,
|
|
188
191
|
getPendingCompactionMarkerState,
|
|
189
192
|
getPendingOps,
|
|
193
|
+
getPendingOpsCount,
|
|
190
194
|
getPendingPiCompactionMarkerState,
|
|
191
195
|
getPendingSmartNotes,
|
|
192
196
|
getPersistedNoteNudge,
|
|
@@ -230,7 +234,6 @@ import {
|
|
|
230
234
|
hasMuralCueColumns,
|
|
231
235
|
hasPiFallbackMessageTags,
|
|
232
236
|
hasPiFallbackToolOwnerTags,
|
|
233
|
-
hasShareabilitySensitiveText,
|
|
234
237
|
incrementHistorianFailure,
|
|
235
238
|
indexCommitsForProject,
|
|
236
239
|
indexMessagesAfterOrdinal,
|
|
@@ -256,6 +259,8 @@ import {
|
|
|
256
259
|
isWrapupInProgress,
|
|
257
260
|
loadPiConfig,
|
|
258
261
|
loadProtectedTailMeta,
|
|
262
|
+
logSlowWriteTransaction,
|
|
263
|
+
markChannel1PostReduceGracePending,
|
|
259
264
|
markGitSweepSuccessAndRelease,
|
|
260
265
|
markNoteChecked,
|
|
261
266
|
markNoteReady,
|
|
@@ -298,9 +303,11 @@ import {
|
|
|
298
303
|
readGitFileChangeTimesSince,
|
|
299
304
|
readGitHead,
|
|
300
305
|
readPiSessionMessages,
|
|
306
|
+
readPiSessionSnapshot,
|
|
301
307
|
readProjectDocsCanonical,
|
|
302
308
|
readRawSessionMessages,
|
|
303
309
|
readSessionChunk,
|
|
310
|
+
reclaimableToolOutputCount,
|
|
304
311
|
recordHistorianDrainFailure,
|
|
305
312
|
recordMemoryMapping,
|
|
306
313
|
recordMemoryVerifications,
|
|
@@ -327,8 +334,6 @@ import {
|
|
|
327
334
|
replaceCompartmentChunkEmbeddings,
|
|
328
335
|
replaceSourceContent,
|
|
329
336
|
reserveProtectedTailDrainTokens,
|
|
330
|
-
resetLastNudgeCycle,
|
|
331
|
-
resetLastNudgeCycleIfTailShrank,
|
|
332
337
|
resolveCompactionModeRecord,
|
|
333
338
|
resolveGitTopLevel,
|
|
334
339
|
resolveModelConfigOrDefault,
|
|
@@ -368,7 +373,6 @@ import {
|
|
|
368
373
|
setStoragePrivatePermissionEnforcement,
|
|
369
374
|
setTodoSnapshot,
|
|
370
375
|
shouldBypassFailClosedBlock,
|
|
371
|
-
shouldUseStickyChannel1Reminder,
|
|
372
376
|
sourceNameForMemory,
|
|
373
377
|
stripChannel1ReminderSpans,
|
|
374
378
|
stripMemoryMuralBlock,
|
|
@@ -403,7 +407,7 @@ import {
|
|
|
403
407
|
withMigrationLanguageDirective,
|
|
404
408
|
withRawMessageProvider,
|
|
405
409
|
withRawSessionMessageCache
|
|
406
|
-
} from "./index-
|
|
410
|
+
} from "./index-0jgz8yja.js";
|
|
407
411
|
import {
|
|
408
412
|
pushNotification
|
|
409
413
|
} from "./index-hw34xmzk.js";
|
|
@@ -411,19 +415,22 @@ import {
|
|
|
411
415
|
ensureCortexKitArtifactGitignore,
|
|
412
416
|
getHarness,
|
|
413
417
|
getMagicContextStorageDir,
|
|
418
|
+
getMagicContextStorageResolution,
|
|
414
419
|
getProjectMagicContextHistorianDir,
|
|
420
|
+
hasShareabilitySensitiveText,
|
|
415
421
|
log,
|
|
416
422
|
sessionLog,
|
|
417
423
|
setHarness
|
|
418
|
-
} from "./index-
|
|
424
|
+
} from "./index-q2vgz0j1.js";
|
|
419
425
|
import {
|
|
420
426
|
__require,
|
|
421
427
|
__toESM
|
|
422
428
|
} from "./index-1yh8g550.js";
|
|
423
429
|
|
|
424
430
|
// src/index.ts
|
|
425
|
-
import {
|
|
426
|
-
import {
|
|
431
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
432
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
433
|
+
import { join as join6, resolve as resolve3 } from "node:path";
|
|
427
434
|
|
|
428
435
|
// ../plugin/src/shared/model-resolution.ts
|
|
429
436
|
function asRecord(value) {
|
|
@@ -1432,7 +1439,7 @@ function resolveHistorianContextLimit(historianModelOverride) {
|
|
|
1432
1439
|
}
|
|
1433
1440
|
|
|
1434
1441
|
// ../plugin/src/hooks/magic-context/event-resolvers.ts
|
|
1435
|
-
var DEFAULT_CONTEXT_LIMIT =
|
|
1442
|
+
var DEFAULT_CONTEXT_LIMIT = 200000;
|
|
1436
1443
|
function resolveCacheTtl(cacheTtl, modelKey) {
|
|
1437
1444
|
if (typeof cacheTtl === "string") {
|
|
1438
1445
|
return cacheTtl;
|
|
@@ -2065,7 +2072,9 @@ import {
|
|
|
2065
2072
|
existsSync as existsSync3,
|
|
2066
2073
|
mkdtempSync,
|
|
2067
2074
|
readFileSync as readFileSync2,
|
|
2075
|
+
realpathSync as realpathSync2,
|
|
2068
2076
|
rmSync,
|
|
2077
|
+
statSync,
|
|
2069
2078
|
writeFileSync as writeFileSync2
|
|
2070
2079
|
} from "node:fs";
|
|
2071
2080
|
import { createRequire } from "node:module";
|
|
@@ -2075,7 +2084,8 @@ import {
|
|
|
2075
2084
|
dirname,
|
|
2076
2085
|
isAbsolute,
|
|
2077
2086
|
join as join2,
|
|
2078
|
-
resolve as resolvePath
|
|
2087
|
+
resolve as resolvePath,
|
|
2088
|
+
sep
|
|
2079
2089
|
} from "node:path";
|
|
2080
2090
|
import { createInterface } from "node:readline";
|
|
2081
2091
|
import { fileURLToPath } from "node:url";
|
|
@@ -2223,48 +2233,235 @@ function recordChildInvocation(input) {
|
|
|
2223
2233
|
}
|
|
2224
2234
|
|
|
2225
2235
|
// src/subagent-runner.ts
|
|
2226
|
-
|
|
2236
|
+
var PI_CODING_AGENT_MODULE = "@earendil-works/pi-coding-agent";
|
|
2237
|
+
var PI_CODING_AGENT_PACKAGE_NAMES = new Set([
|
|
2238
|
+
PI_CODING_AGENT_MODULE,
|
|
2239
|
+
"@oh-my-pi/pi-coding-agent"
|
|
2240
|
+
]);
|
|
2241
|
+
var BUN_VIRTUAL_SCRIPT_PREFIX = "/$bunfs/root/";
|
|
2242
|
+
var WINDOWS_PI_EXTENSIONS = [".EXE", ".COM", ".CMD", ".BAT", ".PS1"];
|
|
2243
|
+
var DEFAULT_PI_RESOLUTION_FS = {
|
|
2244
|
+
existsSync: existsSync3,
|
|
2245
|
+
statSync,
|
|
2246
|
+
realpathSync: realpathSync2,
|
|
2247
|
+
readFileSync: readFileSync2
|
|
2248
|
+
};
|
|
2249
|
+
function readPiManifest(packageJsonPath, fs2) {
|
|
2227
2250
|
try {
|
|
2228
|
-
const
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2251
|
+
const manifest = JSON.parse(fs2.readFileSync(packageJsonPath, "utf8"));
|
|
2252
|
+
return manifest && typeof manifest === "object" ? manifest : null;
|
|
2253
|
+
} catch {
|
|
2254
|
+
return null;
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
function findPiPackageRoot(startDir, fs2) {
|
|
2258
|
+
let dir = startDir;
|
|
2259
|
+
while (dir !== dirname(dir)) {
|
|
2260
|
+
const manifest = readPiManifest(join2(dir, "package.json"), fs2);
|
|
2261
|
+
if (manifest?.name && typeof manifest.name === "string" && PI_CODING_AGENT_PACKAGE_NAMES.has(manifest.name)) {
|
|
2262
|
+
if (basename(dir) === "dist") {
|
|
2263
|
+
const parentDir = dirname(dir);
|
|
2264
|
+
const parentManifest = readPiManifest(join2(parentDir, "package.json"), fs2);
|
|
2265
|
+
if (typeof parentManifest?.name === "string" && parentManifest.name === manifest.name) {
|
|
2266
|
+
return { dir: parentDir, manifest: parentManifest };
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
return { dir, manifest };
|
|
2270
|
+
}
|
|
2271
|
+
dir = dirname(dir);
|
|
2272
|
+
}
|
|
2273
|
+
return null;
|
|
2274
|
+
}
|
|
2275
|
+
function pathIsInside(root, candidate) {
|
|
2276
|
+
return candidate !== root && candidate.startsWith(`${root}${sep}`);
|
|
2277
|
+
}
|
|
2278
|
+
function resolvePiBin(found, fs2, checkedPaths) {
|
|
2279
|
+
const bin = found.manifest.bin;
|
|
2280
|
+
const binEntry = typeof bin === "string" ? bin : bin && typeof bin === "object" && typeof bin.pi === "string" ? bin.pi : undefined;
|
|
2281
|
+
if (!binEntry)
|
|
2233
2282
|
return null;
|
|
2283
|
+
const packageRoot = resolvePath(found.dir);
|
|
2284
|
+
const candidate = resolvePath(packageRoot, binEntry);
|
|
2285
|
+
checkedPaths.push(candidate);
|
|
2286
|
+
if (isAbsolute(binEntry) || !pathIsInside(packageRoot, candidate)) {
|
|
2287
|
+
return null;
|
|
2288
|
+
}
|
|
2289
|
+
try {
|
|
2290
|
+
if (!fs2.existsSync(candidate) || !fs2.statSync(candidate).isFile()) {
|
|
2291
|
+
return null;
|
|
2292
|
+
}
|
|
2293
|
+
const realRoot = fs2.realpathSync(packageRoot);
|
|
2294
|
+
const realCandidate = fs2.realpathSync(candidate);
|
|
2295
|
+
return pathIsInside(realRoot, realCandidate) ? realCandidate : null;
|
|
2234
2296
|
} catch {
|
|
2235
2297
|
return null;
|
|
2236
2298
|
}
|
|
2237
2299
|
}
|
|
2238
|
-
function
|
|
2239
|
-
|
|
2240
|
-
const
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2300
|
+
function resolvePiCliFromPackageJson(packageJsonPath, fs2, checkedPaths) {
|
|
2301
|
+
checkedPaths.push(packageJsonPath);
|
|
2302
|
+
const manifest = readPiManifest(packageJsonPath, fs2);
|
|
2303
|
+
if (typeof manifest?.name !== "string" || !PI_CODING_AGENT_PACKAGE_NAMES.has(manifest.name)) {
|
|
2304
|
+
return null;
|
|
2305
|
+
}
|
|
2306
|
+
return resolvePiBin({ dir: dirname(packageJsonPath), manifest }, fs2, checkedPaths);
|
|
2307
|
+
}
|
|
2308
|
+
function resolvePiCliFromRunningEntry(entry, fs2) {
|
|
2309
|
+
const checkedPaths = [entry ?? "process.argv[1] (missing)"];
|
|
2310
|
+
if (!entry || entry.startsWith(BUN_VIRTUAL_SCRIPT_PREFIX)) {
|
|
2311
|
+
return { cliPath: null, checkedPaths };
|
|
2244
2312
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2313
|
+
try {
|
|
2314
|
+
if (!fs2.existsSync(entry) || !fs2.statSync(entry).isFile()) {
|
|
2315
|
+
return { cliPath: null, checkedPaths };
|
|
2316
|
+
}
|
|
2317
|
+
const realEntry = fs2.realpathSync(entry);
|
|
2318
|
+
if (realEntry !== entry)
|
|
2319
|
+
checkedPaths.push(realEntry);
|
|
2320
|
+
const found = findPiPackageRoot(dirname(realEntry), fs2);
|
|
2321
|
+
if (!found)
|
|
2322
|
+
return { cliPath: null, checkedPaths };
|
|
2323
|
+
return {
|
|
2324
|
+
cliPath: resolvePiBin(found, fs2, checkedPaths),
|
|
2325
|
+
checkedPaths
|
|
2326
|
+
};
|
|
2327
|
+
} catch {
|
|
2328
|
+
return { cliPath: null, checkedPaths };
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
function defaultResolvePiPackageJson(from) {
|
|
2332
|
+
const requesters = [from, import.meta.url];
|
|
2333
|
+
for (const requester of requesters) {
|
|
2334
|
+
try {
|
|
2335
|
+
const require_ = requester ? createRequire(requester.startsWith("file:") ? requester : resolvePath(requester)) : createRequire(import.meta.url);
|
|
2336
|
+
return require_.resolve(`${PI_CODING_AGENT_MODULE}/package.json`);
|
|
2337
|
+
} catch {}
|
|
2338
|
+
}
|
|
2339
|
+
return null;
|
|
2340
|
+
}
|
|
2341
|
+
function resolveBundledPiCli(from, fs2, resolvePackageJson, checkedPaths) {
|
|
2342
|
+
const packageJsonPath = resolvePackageJson(from);
|
|
2343
|
+
if (!packageJsonPath) {
|
|
2344
|
+
checkedPaths.push(`${PI_CODING_AGENT_MODULE}/package.json (unresolvable from running module paths)`);
|
|
2345
|
+
return null;
|
|
2346
|
+
}
|
|
2347
|
+
return resolvePiCliFromPackageJson(packageJsonPath, fs2, checkedPaths);
|
|
2348
|
+
}
|
|
2349
|
+
function resolveWindowsPiCommand(env, fs2) {
|
|
2350
|
+
const pathValue = env.PATH ?? env.Path;
|
|
2351
|
+
if (!pathValue)
|
|
2352
|
+
return { path: null, extension: null, checkedPaths: [] };
|
|
2353
|
+
const pathExt = env.PATHEXT ?? env.PathExt ?? "";
|
|
2354
|
+
const extensions = [];
|
|
2355
|
+
for (const value of pathExt.split(";")) {
|
|
2356
|
+
const extension = value.trim().toUpperCase();
|
|
2357
|
+
if (WINDOWS_PI_EXTENSIONS.includes(extension) && !extensions.includes(extension)) {
|
|
2358
|
+
extensions.push(extension);
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
for (const extension of WINDOWS_PI_EXTENSIONS) {
|
|
2362
|
+
if (!extensions.includes(extension))
|
|
2363
|
+
extensions.push(extension);
|
|
2364
|
+
}
|
|
2365
|
+
const checkedPaths = [];
|
|
2366
|
+
for (const rawDir of pathValue.split(";")) {
|
|
2367
|
+
const dir = rawDir.trim().replace(/^"(.*)"$/, "$1");
|
|
2368
|
+
if (!dir)
|
|
2369
|
+
continue;
|
|
2370
|
+
for (const extension of extensions) {
|
|
2371
|
+
const candidate = join2(dir, `pi${extension.toLowerCase()}`);
|
|
2372
|
+
checkedPaths.push(candidate);
|
|
2373
|
+
try {
|
|
2374
|
+
if (fs2.existsSync(candidate) && fs2.statSync(candidate).isFile()) {
|
|
2375
|
+
return { path: candidate, extension, checkedPaths };
|
|
2376
|
+
}
|
|
2377
|
+
} catch {}
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
return { path: null, extension: null, checkedPaths };
|
|
2381
|
+
}
|
|
2382
|
+
function isGenericRuntimeExecutable(execPath) {
|
|
2383
|
+
return /^(node(?:js)?\d*|bun)(\.exe)?$/.test(basename(execPath).toLowerCase());
|
|
2384
|
+
}
|
|
2385
|
+
function formatCheckedPaths(checkedPaths) {
|
|
2386
|
+
const unique = [...new Set(checkedPaths)];
|
|
2387
|
+
const visible = unique.slice(0, 12);
|
|
2388
|
+
return unique.length > visible.length ? `${visible.join(", ")} (+${unique.length - visible.length} more)` : visible.join(", ");
|
|
2389
|
+
}
|
|
2390
|
+
function resolvePiInvocation(options = {}) {
|
|
2391
|
+
const fs2 = { ...DEFAULT_PI_RESOLUTION_FS, ...options.fs };
|
|
2392
|
+
const execPath = options.execPath ?? process.execPath;
|
|
2393
|
+
const currentScript = options.argv1 ?? process.argv[1];
|
|
2394
|
+
const platform = options.platform ?? process.platform;
|
|
2395
|
+
const env = options.env ?? process.env;
|
|
2396
|
+
const resolvePackageJson = options.resolvePackageJson ?? defaultResolvePiPackageJson;
|
|
2397
|
+
const running = resolvePiCliFromRunningEntry(currentScript, fs2);
|
|
2398
|
+
const checkedPaths = [...running.checkedPaths];
|
|
2399
|
+
if (running.cliPath) {
|
|
2400
|
+
return { command: execPath, prefixArgs: [running.cliPath] };
|
|
2401
|
+
}
|
|
2402
|
+
if (!isGenericRuntimeExecutable(execPath)) {
|
|
2248
2403
|
return { command: execPath, prefixArgs: [] };
|
|
2249
2404
|
}
|
|
2250
|
-
const bundled = resolveBundledPiCli();
|
|
2405
|
+
const bundled = resolveBundledPiCli(currentScript, fs2, resolvePackageJson, checkedPaths);
|
|
2251
2406
|
if (bundled) {
|
|
2252
2407
|
return { command: execPath, prefixArgs: [bundled] };
|
|
2253
2408
|
}
|
|
2254
|
-
|
|
2409
|
+
const detectionMiss = `script-detection miss on ${formatCheckedPaths(checkedPaths)}`;
|
|
2410
|
+
if (platform === "win32") {
|
|
2411
|
+
const resolved = resolveWindowsPiCommand(env, fs2);
|
|
2412
|
+
if (resolved.path && resolved.extension) {
|
|
2413
|
+
const diagnostic = `${detectionMiss}; Windows PATHEXT resolved ${resolved.path}`;
|
|
2414
|
+
if (resolved.extension === ".CMD" || resolved.extension === ".BAT") {
|
|
2415
|
+
const command = env.ComSpec?.trim() || env.COMSPEC?.trim() || "cmd.exe";
|
|
2416
|
+
return {
|
|
2417
|
+
command,
|
|
2418
|
+
prefixArgs: ["/d", "/s", "/c", resolved.path],
|
|
2419
|
+
fallbackDiagnostic: diagnostic
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
if (resolved.extension === ".PS1") {
|
|
2423
|
+
const command = env.SystemRoot ? join2(env.SystemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : "powershell.exe";
|
|
2424
|
+
return {
|
|
2425
|
+
command,
|
|
2426
|
+
prefixArgs: [
|
|
2427
|
+
"-NoLogo",
|
|
2428
|
+
"-NoProfile",
|
|
2429
|
+
"-NonInteractive",
|
|
2430
|
+
"-File",
|
|
2431
|
+
resolved.path
|
|
2432
|
+
],
|
|
2433
|
+
fallbackDiagnostic: diagnostic
|
|
2434
|
+
};
|
|
2435
|
+
}
|
|
2436
|
+
return {
|
|
2437
|
+
command: resolved.path,
|
|
2438
|
+
prefixArgs: [],
|
|
2439
|
+
fallbackDiagnostic: diagnostic
|
|
2440
|
+
};
|
|
2441
|
+
}
|
|
2442
|
+
checkedPaths.push(...resolved.checkedPaths);
|
|
2443
|
+
}
|
|
2444
|
+
return {
|
|
2445
|
+
command: "pi",
|
|
2446
|
+
prefixArgs: [],
|
|
2447
|
+
fallbackDiagnostic: `script-detection miss on ${formatCheckedPaths(checkedPaths)}`
|
|
2448
|
+
};
|
|
2255
2449
|
}
|
|
2256
|
-
function
|
|
2450
|
+
function describeSpawnFailure(error, invocation) {
|
|
2451
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2452
|
+
return invocation.fallbackDiagnostic ? `${message} after ${invocation.fallbackDiagnostic}` : message;
|
|
2453
|
+
}
|
|
2454
|
+
function resolveSiblingEntryPath(fileName) {
|
|
2257
2455
|
try {
|
|
2258
2456
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
2259
|
-
const candidate = resolvePath(here,
|
|
2260
|
-
|
|
2261
|
-
return candidate;
|
|
2262
|
-
return;
|
|
2457
|
+
const candidate = resolvePath(here, fileName);
|
|
2458
|
+
return existsSync3(candidate) ? candidate : undefined;
|
|
2263
2459
|
} catch {
|
|
2264
2460
|
return;
|
|
2265
2461
|
}
|
|
2266
2462
|
}
|
|
2267
|
-
var SUBAGENT_ENTRY_PATH =
|
|
2463
|
+
var SUBAGENT_ENTRY_PATH = resolveSiblingEntryPath("subagent-entry.js");
|
|
2464
|
+
var HISTORIAN_CALIBRATION_ENTRY_PATH = resolveSiblingEntryPath("historian-calibration-extension.js");
|
|
2268
2465
|
var TERMINAL_DRAIN_GRACE_MS = 2000;
|
|
2269
2466
|
var MAGIC_CONTEXT_PI_SUBAGENT_ENV = "MAGIC_CONTEXT_PI_SUBAGENT";
|
|
2270
2467
|
function packageRootIsOmp(packageRoot) {
|
|
@@ -2338,6 +2535,12 @@ var DREAMER_ACTION_AGENTS = new Set([
|
|
|
2338
2535
|
"dreamer",
|
|
2339
2536
|
"magic-context-dreamer"
|
|
2340
2537
|
]);
|
|
2538
|
+
var HISTORIAN_AGENTS = new Set([
|
|
2539
|
+
"magic-context-historian",
|
|
2540
|
+
"historian",
|
|
2541
|
+
"historian-recomp",
|
|
2542
|
+
"historian-editor"
|
|
2543
|
+
]);
|
|
2341
2544
|
var SEARCH_ONLY_SUBAGENT_TOOL_AGENTS = new Set([
|
|
2342
2545
|
"sidekick",
|
|
2343
2546
|
"dreamer-retrospective",
|
|
@@ -2429,7 +2632,7 @@ class PiSubagentRunner {
|
|
|
2429
2632
|
extraArgs;
|
|
2430
2633
|
subagentExtensions;
|
|
2431
2634
|
constructor(options = {}) {
|
|
2432
|
-
this.invocation = options.piBinary ? { command: options.piBinary, prefixArgs: [] } : resolvePiInvocation();
|
|
2635
|
+
this.invocation = options.invocation ?? (options.piBinary ? { command: options.piBinary, prefixArgs: [] } : resolvePiInvocation({ platform: options.platform }));
|
|
2433
2636
|
this.spawnImpl = options.spawnImpl ?? childProcess.spawn;
|
|
2434
2637
|
this.platform = options.platform ?? process.platform;
|
|
2435
2638
|
this.extraArgs = options.extraArgs ?? [];
|
|
@@ -2644,7 +2847,13 @@ class PiSubagentRunner {
|
|
|
2644
2847
|
cwd: options.cwd,
|
|
2645
2848
|
env: {
|
|
2646
2849
|
...process.env,
|
|
2647
|
-
[MAGIC_CONTEXT_PI_SUBAGENT_ENV]: "1"
|
|
2850
|
+
[MAGIC_CONTEXT_PI_SUBAGENT_ENV]: "1",
|
|
2851
|
+
...options.temperature !== undefined ? {
|
|
2852
|
+
MAGIC_CONTEXT_HISTORIAN_TEMPERATURE: String(options.temperature)
|
|
2853
|
+
} : {},
|
|
2854
|
+
...options.maxOutputTokens !== undefined ? {
|
|
2855
|
+
MAGIC_CONTEXT_HISTORIAN_MAX_OUTPUT_TOKENS: String(options.maxOutputTokens)
|
|
2856
|
+
} : {}
|
|
2648
2857
|
},
|
|
2649
2858
|
stdio: [deliverViaStdin ? "pipe" : "ignore", "pipe", "pipe"]
|
|
2650
2859
|
});
|
|
@@ -2653,7 +2862,7 @@ class PiSubagentRunner {
|
|
|
2653
2862
|
settle({
|
|
2654
2863
|
ok: false,
|
|
2655
2864
|
reason: "spawn_failed",
|
|
2656
|
-
error: error
|
|
2865
|
+
error: describeSpawnFailure(error, this.invocation),
|
|
2657
2866
|
durationMs: Date.now() - startTime
|
|
2658
2867
|
});
|
|
2659
2868
|
return;
|
|
@@ -2842,7 +3051,7 @@ class PiSubagentRunner {
|
|
|
2842
3051
|
settle({
|
|
2843
3052
|
ok: false,
|
|
2844
3053
|
reason: "spawn_failed",
|
|
2845
|
-
error: error
|
|
3054
|
+
error: describeSpawnFailure(error, this.invocation),
|
|
2846
3055
|
durationMs: Date.now() - startTime
|
|
2847
3056
|
});
|
|
2848
3057
|
});
|
|
@@ -2863,10 +3072,11 @@ class PiSubagentRunner {
|
|
|
2863
3072
|
if (sawAgentEnd) {
|
|
2864
3073
|
const trimmedAssistantText = finalAssistantText?.trim() ?? null;
|
|
2865
3074
|
if (trimmedAssistantText === null || trimmedAssistantText.length === 0) {
|
|
3075
|
+
const emptyAssistantReason = trimmedAssistantText === null ? "pi agent_end did not include an assistant message" : "pi assistant produced empty text";
|
|
2866
3076
|
settle({
|
|
2867
3077
|
ok: false,
|
|
2868
3078
|
reason: "no_assistant",
|
|
2869
|
-
error:
|
|
3079
|
+
error: finalErrorMessage ? `${emptyAssistantReason} (provider error: ${finalErrorMessage})` : emptyAssistantReason,
|
|
2870
3080
|
durationMs: Date.now() - startTime,
|
|
2871
3081
|
meta: {
|
|
2872
3082
|
stderr: stderr.length > 0 ? stderr : undefined,
|
|
@@ -3036,6 +3246,10 @@ function buildArgs(options, opts) {
|
|
|
3036
3246
|
args.push("--magic-context-dreamer-actions");
|
|
3037
3247
|
}
|
|
3038
3248
|
}
|
|
3249
|
+
const historianCalibrationEntryPath = opts?.historianCalibrationEntryPath === undefined ? HISTORIAN_CALIBRATION_ENTRY_PATH : opts.historianCalibrationEntryPath;
|
|
3250
|
+
if (HISTORIAN_AGENTS.has(options.agent) && historianCalibrationEntryPath) {
|
|
3251
|
+
args.push("--extension", historianCalibrationEntryPath);
|
|
3252
|
+
}
|
|
3039
3253
|
const strictTools = STRICT_TOOL_ALLOWLIST.get(options.agent);
|
|
3040
3254
|
if (strictTools === undefined) {
|
|
3041
3255
|
sessionLog(options.accountingSessionId ?? "pi-subagent", `Pi subagent agent "${options.agent}" has no strict tool allow-list; forcing --no-tools`);
|
|
@@ -3772,7 +3986,7 @@ async function sendIgnoredMessageNow(client, sessionId, text, params, forcePersi
|
|
|
3772
3986
|
queueIgnoredNotification({ client, sessionId, text, params, forcePersist });
|
|
3773
3987
|
return "queued";
|
|
3774
3988
|
}
|
|
3775
|
-
const { waitForSafeNotificationTarget } = await import("./safe-notification-target-
|
|
3989
|
+
const { waitForSafeNotificationTarget } = await import("./safe-notification-target-hjcb423r.js");
|
|
3776
3990
|
if (await waitForSafeNotificationTarget(client, sessionId) === "skip") {
|
|
3777
3991
|
sessionLog(sessionId, "notification skipped (session not titled yet)");
|
|
3778
3992
|
return "skipped";
|
|
@@ -4380,13 +4594,17 @@ function peekLeaseHolderAndExpiry(db, expectedHolder, leaseKey = DREAMING_LEASE_
|
|
|
4380
4594
|
function leaseOwnershipMatches(db, expectedHolder, expectedGeneration, leaseKey = DREAMING_LEASE_KEY) {
|
|
4381
4595
|
return getLeaseGeneration(db, leaseKey) === expectedGeneration && peekLeaseHolderAndExpiry(db, expectedHolder, leaseKey);
|
|
4382
4596
|
}
|
|
4383
|
-
function runImmediate(db, body) {
|
|
4597
|
+
function runImmediate(db, body, site, slowWriteThresholdMs) {
|
|
4598
|
+
const transactionStartedAt = site === undefined ? undefined : performance.now();
|
|
4384
4599
|
db.exec("BEGIN IMMEDIATE");
|
|
4385
4600
|
let committed = false;
|
|
4386
4601
|
try {
|
|
4387
4602
|
const result = body();
|
|
4388
4603
|
db.exec("COMMIT");
|
|
4389
4604
|
committed = true;
|
|
4605
|
+
if (site !== undefined && transactionStartedAt !== undefined) {
|
|
4606
|
+
logSlowWriteTransaction(site, transactionStartedAt, slowWriteThresholdMs);
|
|
4607
|
+
}
|
|
4390
4608
|
return result;
|
|
4391
4609
|
} finally {
|
|
4392
4610
|
if (!committed) {
|
|
@@ -4428,13 +4646,13 @@ function renewLease(db, holderId, leaseKey = DREAMING_LEASE_KEY, expectedGenerat
|
|
|
4428
4646
|
return true;
|
|
4429
4647
|
});
|
|
4430
4648
|
}
|
|
4431
|
-
function runLeaseGuardedWrite(db, holderId, leaseKey, fn) {
|
|
4649
|
+
function runLeaseGuardedWrite(db, holderId, leaseKey, fn, slowWriteThresholdMs) {
|
|
4432
4650
|
return runImmediate(db, () => {
|
|
4433
4651
|
if (!peekLeaseHolderAndExpiry(db, holderId, leaseKey)) {
|
|
4434
4652
|
throw new Error("Dream lease lost before guarded write");
|
|
4435
4653
|
}
|
|
4436
4654
|
return fn();
|
|
4437
|
-
});
|
|
4655
|
+
}, `lease-guarded-write:${leaseKey}`, slowWriteThresholdMs);
|
|
4438
4656
|
}
|
|
4439
4657
|
var LEASE_HEARTBEAT_INTERVAL_MS = 60 * 1000;
|
|
4440
4658
|
function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisition = LEASE_HEARTBEAT_INTERVAL_MS) {
|
|
@@ -5966,7 +6184,7 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
5966
6184
|
query: { directory: args.sessionDirectory },
|
|
5967
6185
|
body: {
|
|
5968
6186
|
agent: DREAMER_CLASSIFIER_AGENT,
|
|
5969
|
-
system: CLASSIFY_SYSTEM_PROMPT,
|
|
6187
|
+
system: withContentLanguageDirective(CLASSIFY_SYSTEM_PROMPT, args.language),
|
|
5970
6188
|
...modelBodyField(args.model),
|
|
5971
6189
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
5972
6190
|
}
|
|
@@ -6029,6 +6247,8 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
6029
6247
|
memories: chunk.map(toPromptMemory2),
|
|
6030
6248
|
anchors
|
|
6031
6249
|
});
|
|
6250
|
+
const modelChain = [args.model, ...args.fallbackModels ?? []].map(toModelEntry).filter((entry) => entry !== undefined).map((entry) => entry.model);
|
|
6251
|
+
const resolvedModelChain = [...new Set(modelChain)];
|
|
6032
6252
|
const response = await args.moduleClient?.call({
|
|
6033
6253
|
sessionId: args.moduleSessionId,
|
|
6034
6254
|
projectRoot: args.moduleProjectRoot,
|
|
@@ -6040,6 +6260,7 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
6040
6260
|
task: "classify",
|
|
6041
6261
|
command_id: `classify:${args.moduleCommandId ?? Date.now()}:${createHash4("sha256").update(chunk.map((candidate) => candidate.id).join(",")).digest("hex").slice(0, 24)}`,
|
|
6042
6262
|
authority_generation: args.moduleAuthorityGeneration,
|
|
6263
|
+
...resolvedModelChain.length > 0 ? { model_chain: resolvedModelChain } : {},
|
|
6043
6264
|
payload: {
|
|
6044
6265
|
prompt_body: prompt,
|
|
6045
6266
|
items: chunk.map((candidate) => ({
|
|
@@ -6713,7 +6934,7 @@ function getAsyncModule() {
|
|
|
6713
6934
|
asyncModulePromise ??= (async () => {
|
|
6714
6935
|
const [{ default: singlefileAsyncifyVariant }, { newQuickJSAsyncWASMModuleFromVariant }] = await Promise.all([
|
|
6715
6936
|
import("./index-rgdqj8nj.js").then((m)=>__toESM(m.default,1)),
|
|
6716
|
-
import("./index-
|
|
6937
|
+
import("./index-y63nbvkk.js")
|
|
6717
6938
|
]);
|
|
6718
6939
|
return newQuickJSAsyncWASMModuleFromVariant(singlefileAsyncifyVariant);
|
|
6719
6940
|
})();
|
|
@@ -7843,7 +8064,7 @@ function enforceMaintainDocsProtectedRegions(args) {
|
|
|
7843
8064
|
import { createHash as createHash6 } from "node:crypto";
|
|
7844
8065
|
|
|
7845
8066
|
// ../plugin/src/features/magic-context/dreamer/map-memories-prompt.ts
|
|
7846
|
-
import { existsSync as existsSync6, statSync } from "node:fs";
|
|
8067
|
+
import { existsSync as existsSync6, statSync as statSync2 } from "node:fs";
|
|
7847
8068
|
import path4 from "node:path";
|
|
7848
8069
|
var MAP_MEMORIES_SYSTEM_PROMPT = `You are a memory mapper for the magic-context system. You map project memories to the repository files that back them.
|
|
7849
8070
|
|
|
@@ -7853,7 +8074,7 @@ Tools (read-only): read, grep, glob, aft_search, aft_outline, aft_zoom. Each mem
|
|
|
7853
8074
|
|
|
7854
8075
|
For each memory decide ONE of:
|
|
7855
8076
|
- Backing files found → the COMPLETE set of repo-relative paths whose code the memory is about.
|
|
7856
|
-
- File-independent → the memory describes EXTERNAL behavior (a provider / API / platform / protocol limit, e.g. "Anthropic returns 400 on empty content"), or a pure process / workflow / philosophy rule, with NO specific local file that backs it.
|
|
8077
|
+
- File-independent → the memory describes EXTERNAL behavior (a provider / API / platform / protocol limit, e.g. "Anthropic returns 400 on empty content"), or a pure process / workflow / philosophy rule, with NO specific local file that backs it. A BEHAVIORAL claim (when to act, how to work, who decides, or tool-usage discipline) is file-independent even when it cites file paths or commands as examples: a named file is not the file backing the rule.
|
|
7857
8078
|
|
|
7858
8079
|
Output ONE XML manifest at the very end and NOTHING else — no narration, no per-memory commentary, no reasoning:
|
|
7859
8080
|
<mappings>
|
|
@@ -7864,7 +8085,7 @@ Output ONE XML manifest at the very end and NOTHING else — no narration, no pe
|
|
|
7864
8085
|
Rules:
|
|
7865
8086
|
- Every input memory id MUST appear exactly once.
|
|
7866
8087
|
- files: repo-relative, comma-separated, no spaces inside a path. Only files that actually exist and genuinely back the memory.
|
|
7867
|
-
- A BACKING FILE is CODE that implements or handles the claim — not a file that merely mentions it. A markdown doc (.md), a PARITY/notes file, or a test that only DESCRIBES an external fact is NOT a backing file. If the only place a memory's fact appears is prose/docs/a test (no code implements or handles it), mark it independent="true".
|
|
8088
|
+
- A BACKING FILE is CODE that implements or handles the claim — not a file that merely mentions it. A path named inside a process directive is an action target or example, not evidence that the file backs the directive. A markdown doc (.md), a PARITY/notes file, or a test that only DESCRIBES an external fact is NOT a backing file. If the only place a memory's fact appears is prose/docs/a test (no code implements or handles it), mark it independent="true".
|
|
7868
8089
|
- Many CONSTRAINTS are HYBRID: "external system does X, and OUR code handles it here." Map those to the HANDLING code (you can verify the handling, even though you can't verify the external behavior). Only mark independent when there is NO local code that implements or handles the fact.
|
|
7869
8090
|
- Prefer the most specific file(s); do not pad with tangential files. Most memories map to one file; some to a few.
|
|
7870
8091
|
- When you genuinely cannot find any local backing and it is not clearly external, still emit the memory with independent="true" (do not drop it).`;
|
|
@@ -7881,7 +8102,7 @@ function extractMemoryCandidatePaths(content, repoDir) {
|
|
|
7881
8102
|
if (!abs.startsWith(`${root}/`))
|
|
7882
8103
|
continue;
|
|
7883
8104
|
try {
|
|
7884
|
-
if (existsSync6(abs) &&
|
|
8105
|
+
if (existsSync6(abs) && statSync2(abs).isFile())
|
|
7885
8106
|
found.add(rel);
|
|
7886
8107
|
} catch {}
|
|
7887
8108
|
if (found.size >= MAX_SEED_PATHS_PER_MEMORY)
|
|
@@ -7902,7 +8123,7 @@ ${m.content}${seed}`;
|
|
|
7902
8123
|
|
|
7903
8124
|
Project: ${projectPath}
|
|
7904
8125
|
|
|
7905
|
-
For each memory below, find the repo file(s) it makes a claim about, or mark it file-independent. When "Likely files" are listed, those paths are named in the memory and confirmed to exist — START there: confirm each actually backs the claim (a quick read/outline), drop any that don't, add others only if genuinely needed. Search from scratch only when no likely files are given. Then output ONE <mappings> manifest covering every id.
|
|
8126
|
+
For each memory below, find the repo file(s) it makes a claim about, or mark it file-independent. Behavioral process/workflow directives stay file-independent even when they name files. When "Likely files" are listed, those paths are named in the memory and confirmed to exist — START there only for code claims: confirm each actually backs the claim (a quick read/outline), drop any that don't, add others only if genuinely needed. Search from scratch only when no likely files are given. Then output ONE <mappings> manifest covering every id.
|
|
7906
8127
|
|
|
7907
8128
|
<memories>
|
|
7908
8129
|
${list}
|
|
@@ -7967,6 +8188,21 @@ function validateMapMemoriesManifest(text, expectedIds) {
|
|
|
7967
8188
|
return parsed;
|
|
7968
8189
|
}
|
|
7969
8190
|
|
|
8191
|
+
// ../plugin/src/features/magic-context/dreamer/memory-claim-safety.ts
|
|
8192
|
+
var POLICY_SENTENCE_START = /(?:^|[.!?]\s+|\n\s*)(?:[-*]\s+|\d+[.)]\s+)?(?:you\s+|we\s+)?(?:must(?:\s+not)?|never|always|do\s+not|don't|shall\s+not)\b/i;
|
|
8193
|
+
var ACTOR_POLICY = /\b(?:you|we|agents?|masons?|workers?|operators?|users?|maintainers?)\s+(?:must(?:\s+not)?|should(?:\s+not)?|need\s+to|shall(?:\s+not)?|cannot|can't|may\s+not)\b/i;
|
|
8194
|
+
var BEHAVIORAL_WHEN_CLAUSE = /\bwhen\s+(?:you(?:'re|\s+are)?|we(?:'re|\s+are)?|told|asked|requested|working|debugging|reviewing|checking|verifying|investigating|using|running|editing|changing)\b/i;
|
|
8195
|
+
var WORKFLOW_IMPERATIVE = /(?:^|[.!?]\s+|\n\s*)(?:[-*]\s+|\d+[.)]\s+)?(?:please\s+)?(?:run|use|check|ask|avoid|prefer|ensure|keep|follow|brief|report|inspect|search|open|read|review|validate|confirm|delegate|stop|start|remember)\b/i;
|
|
8196
|
+
var DECISION_AUTHORITY = /\b(?:the\s+)?(?:user|operator|maintainer|owner)\s+(?:decides|chooses|approves|has\s+(?:the\s+)?final\s+say)\b/i;
|
|
8197
|
+
function isDirectiveShapedProjectRule(category, content) {
|
|
8198
|
+
if (category !== "PROJECT_RULES")
|
|
8199
|
+
return false;
|
|
8200
|
+
const text = content.trim();
|
|
8201
|
+
if (!text)
|
|
8202
|
+
return false;
|
|
8203
|
+
return POLICY_SENTENCE_START.test(text) || ACTOR_POLICY.test(text) || BEHAVIORAL_WHEN_CLAUSE.test(text) || WORKFLOW_IMPERATIVE.test(text) || DECISION_AUTHORITY.test(text);
|
|
8204
|
+
}
|
|
8205
|
+
|
|
7970
8206
|
// ../plugin/src/features/magic-context/dreamer/map-memories.ts
|
|
7971
8207
|
var MAP_BATCH_SIZE = 80;
|
|
7972
8208
|
var MAP_BATCH_FLOOR_MS = 240000;
|
|
@@ -7981,6 +8217,8 @@ function isTimeoutClassError2(error) {
|
|
|
7981
8217
|
function shouldRequeueIndependentMapping(state2, content, repoDir) {
|
|
7982
8218
|
if (!state2.hasSentinel || state2.files.length > 0)
|
|
7983
8219
|
return false;
|
|
8220
|
+
if (state2.mappingOrigin === "host_rejected_fallback")
|
|
8221
|
+
return false;
|
|
7984
8222
|
return extractMemoryCandidatePaths(content, repoDir).length > 0;
|
|
7985
8223
|
}
|
|
7986
8224
|
function toMapInput(memory, repoDir) {
|
|
@@ -8187,9 +8425,26 @@ async function applyParsedBatchMappings(args, batch, parsed) {
|
|
|
8187
8425
|
if (valid.length === 0)
|
|
8188
8426
|
return { mapped: 0, independent: 0 };
|
|
8189
8427
|
const planned = [];
|
|
8428
|
+
const batchById = new Map(batch.map((memory) => [memory.id, memory]));
|
|
8190
8429
|
for (const p of valid) {
|
|
8430
|
+
const memory = batchById.get(p.id);
|
|
8431
|
+
if (!p.independent && p.files.length > 0 && memory && isDirectiveShapedProjectRule(memory.category, memory.content)) {
|
|
8432
|
+
log(`[dreamer] map-memories safety override: memory_id=${p.id} verdict=file-mapping replacement=independent mapping_origin=host_rejected_fallback reason=directive-shaped-project-rule`);
|
|
8433
|
+
planned.push({
|
|
8434
|
+
id: p.id,
|
|
8435
|
+
files: [],
|
|
8436
|
+
independent: true,
|
|
8437
|
+
mappingOrigin: "host_rejected_fallback"
|
|
8438
|
+
});
|
|
8439
|
+
continue;
|
|
8440
|
+
}
|
|
8191
8441
|
if (p.independent) {
|
|
8192
|
-
planned.push({
|
|
8442
|
+
planned.push({
|
|
8443
|
+
id: p.id,
|
|
8444
|
+
files: [],
|
|
8445
|
+
independent: true,
|
|
8446
|
+
mappingOrigin: "mapper"
|
|
8447
|
+
});
|
|
8193
8448
|
continue;
|
|
8194
8449
|
}
|
|
8195
8450
|
if (p.files.length === 0) {
|
|
@@ -8199,9 +8454,22 @@ async function applyParsedBatchMappings(args, batch, parsed) {
|
|
|
8199
8454
|
cwd: args.sessionDirectory,
|
|
8200
8455
|
files: p.files
|
|
8201
8456
|
});
|
|
8202
|
-
if (normalized.files.length === 0)
|
|
8457
|
+
if (normalized.files.length === 0) {
|
|
8458
|
+
log(`[dreamer] map-memories: all ${p.files.length} path(s) for memory ${p.id} were rejected; recording host_rejected_fallback`);
|
|
8459
|
+
planned.push({
|
|
8460
|
+
id: p.id,
|
|
8461
|
+
files: [],
|
|
8462
|
+
independent: true,
|
|
8463
|
+
mappingOrigin: "host_rejected_fallback"
|
|
8464
|
+
});
|
|
8203
8465
|
continue;
|
|
8204
|
-
|
|
8466
|
+
}
|
|
8467
|
+
planned.push({
|
|
8468
|
+
id: p.id,
|
|
8469
|
+
files: normalized.files,
|
|
8470
|
+
independent: false,
|
|
8471
|
+
mappingOrigin: "mapper"
|
|
8472
|
+
});
|
|
8205
8473
|
}
|
|
8206
8474
|
if (planned.length === 0)
|
|
8207
8475
|
return { mapped: 0, independent: 0 };
|
|
@@ -8216,7 +8484,8 @@ async function applyParsedBatchMappings(args, batch, parsed) {
|
|
|
8216
8484
|
return {
|
|
8217
8485
|
memory_id: identity.moduleId,
|
|
8218
8486
|
content_hash_at_prompt: identity.normalizedHash,
|
|
8219
|
-
mapped_files: item.independent ? null : item.files
|
|
8487
|
+
mapped_files: item.independent ? null : item.files,
|
|
8488
|
+
mapping_origin: item.mappingOrigin
|
|
8220
8489
|
};
|
|
8221
8490
|
});
|
|
8222
8491
|
let response;
|
|
@@ -8253,7 +8522,7 @@ async function applyParsedBatchMappings(args, batch, parsed) {
|
|
|
8253
8522
|
const now = Date.now();
|
|
8254
8523
|
runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
|
|
8255
8524
|
for (const item of planned) {
|
|
8256
|
-
recordMemoryMapping(args.db, item.id, item.files, now);
|
|
8525
|
+
recordMemoryMapping(args.db, item.id, item.files, now, item.mappingOrigin);
|
|
8257
8526
|
item.independent ? independent += 1 : mapped += 1;
|
|
8258
8527
|
}
|
|
8259
8528
|
});
|
|
@@ -9414,24 +9683,29 @@ Each memory below comes with its backing file(s) — the code it makes a claim a
|
|
|
9414
9683
|
|
|
9415
9684
|
Tools (read-only): read, grep, glob, aft_search, aft_outline, aft_zoom. You read code to check claims; you change nothing.
|
|
9416
9685
|
|
|
9417
|
-
Decide ONE of
|
|
9686
|
+
Decide ONE of four outcomes per memory:
|
|
9418
9687
|
- VERIFIED — still accurate. Keep it as-is.
|
|
9419
|
-
- UPDATE —
|
|
9420
|
-
- ARCHIVE — the code
|
|
9688
|
+
- UPDATE — a CODE FACT is still true but a file-falsifiable DETAIL drifted (a renamed symbol, moved file, changed number/name). Provide corrected content in terse present tense ("X uses Y", not "X was changed to Y"). Only update for genuine drift, not style. If a legitimate update intentionally consolidates the old claim into much shorter content, set consolidation="true" explicitly.
|
|
9689
|
+
- ARCHIVE — a CODE FACT is positively falsified: the code clearly contradicts it, or the API/symbol/path it describes no longer exists.
|
|
9690
|
+
- SKIP — the claim is not a code fact, or code cannot decide it. Keep it unchanged and do not claim verification.
|
|
9691
|
+
|
|
9692
|
+
UPDATE and ARCHIVE are ONLY for claims a repository file can falsify, such as an API that no longer exists, a path that moved, or a constant that changed. Behavioral directives (when to act, how to work, who decides, tool-usage discipline) can only be VERIFIED or SKIPPED. A named path inside a directive does not make the directive a code fact, and a file's failure to corroborate a behavioral rule is never grounds to update or archive it.
|
|
9421
9693
|
|
|
9422
|
-
BE CONSERVATIVE ABOUT ARCHIVING. Wrong archival of a TRUE memory is the worst possible outcome — far worse than leaving a slightly-stale memory. If you cannot find the code, or you are unsure, or it might still be true somewhere you didn't look: mark it VERIFIED, never archived. Archive ONLY when you have positive evidence the code contradicts
|
|
9694
|
+
BE CONSERVATIVE ABOUT ARCHIVING. Wrong archival of a TRUE memory is the worst possible outcome — far worse than leaving a slightly-stale memory. If you cannot find the code, or you are unsure, or it might still be true somewhere you didn't look: mark it VERIFIED or SKIPPED, never archived. Archive ONLY when you have positive evidence the code contradicts a code fact.
|
|
9423
9695
|
|
|
9424
9696
|
Output ONE XML manifest at the very end and NOTHING else — no narration, no per-memory commentary, no reasoning:
|
|
9425
9697
|
<verify>
|
|
9426
9698
|
<verified id="N" files="path/a.ts,path/b.ts"/>
|
|
9427
9699
|
<update id="M" files="path/c.ts">corrected present-tense content</update>
|
|
9700
|
+
<update id="C" files="path/d.ts" consolidation="true">intentionally consolidated content</update>
|
|
9428
9701
|
<archive id="K" reason="specific evidence the code contradicts it"/>
|
|
9702
|
+
<skip id="S" reason="behavioral directive; code cannot decide it"/>
|
|
9429
9703
|
</verify>
|
|
9430
9704
|
|
|
9431
9705
|
Rules:
|
|
9432
|
-
- Every input memory id MUST appear exactly once, in exactly one of verified/update/archive.
|
|
9706
|
+
- Every input memory id MUST appear exactly once, in exactly one of verified/update/archive/skip.
|
|
9433
9707
|
- files = the COMPLETE current backing set (repo-relative, comma-separated). It may differ from the given mapping if a file moved — record what you actually verified against.
|
|
9434
|
-
- Default to VERIFIED. update and archive are the exceptions, not the norm.`;
|
|
9708
|
+
- Default to VERIFIED. skip when code cannot decide the claim. update and archive are the exceptions, not the norm.`;
|
|
9435
9709
|
function buildVerifyPrompt(projectPath, memories) {
|
|
9436
9710
|
const list = memories.map((m) => `[${m.id}] ${m.category}
|
|
9437
9711
|
Content: ${m.content}
|
|
@@ -9442,7 +9716,7 @@ Backing files: ${m.mappedFiles.join(", ")}`).join(`
|
|
|
9442
9716
|
|
|
9443
9717
|
Project: ${projectPath}
|
|
9444
9718
|
|
|
9445
|
-
Read each memory's backing files, decide verified / update / archive (default verified;
|
|
9719
|
+
Read each memory's backing files, decide verified / update / archive / skip (default verified; behavioral directives only permit verified or skip), then output ONE <verify> manifest covering every id.
|
|
9446
9720
|
|
|
9447
9721
|
<memories>
|
|
9448
9722
|
${list}
|
|
@@ -9456,7 +9730,7 @@ function filesOf(s) {
|
|
|
9456
9730
|
return (attrOf(s, "files") ?? "").split(",").map((f) => f.trim()).filter(Boolean);
|
|
9457
9731
|
}
|
|
9458
9732
|
function verifyIds(parsed) {
|
|
9459
|
-
return [...parsed.verified, ...parsed.updated, ...parsed.archived].map((entry) => entry.id);
|
|
9733
|
+
return [...parsed.verified, ...parsed.updated, ...parsed.archived, ...parsed.skipped].map((entry) => entry.id);
|
|
9460
9734
|
}
|
|
9461
9735
|
function verifyBody(text) {
|
|
9462
9736
|
try {
|
|
@@ -9469,7 +9743,7 @@ function verifyBody(text) {
|
|
|
9469
9743
|
}
|
|
9470
9744
|
}
|
|
9471
9745
|
function parseVerifyManifest(text) {
|
|
9472
|
-
const out = { verified: [], updated: [], archived: [] };
|
|
9746
|
+
const out = { verified: [], updated: [], archived: [], skipped: [] };
|
|
9473
9747
|
const body = verifyBody(text);
|
|
9474
9748
|
for (const m of body.matchAll(/<verified\b([^>]*)\/?>/g)) {
|
|
9475
9749
|
const id = Number.parseInt(attrOf(m[1], "id") ?? "", 10);
|
|
@@ -9481,7 +9755,12 @@ function parseVerifyManifest(text) {
|
|
|
9481
9755
|
const id = Number.parseInt(attrOf(m[1], "id") ?? "", 10);
|
|
9482
9756
|
if (!Number.isInteger(id))
|
|
9483
9757
|
throw new Error("verify manifest entry missing numeric id");
|
|
9484
|
-
out.updated.push({
|
|
9758
|
+
out.updated.push({
|
|
9759
|
+
id,
|
|
9760
|
+
files: filesOf(m[1]),
|
|
9761
|
+
content: (m[2] ?? "").trim(),
|
|
9762
|
+
consolidation: attrOf(m[1], "consolidation")?.toLowerCase() === "true"
|
|
9763
|
+
});
|
|
9485
9764
|
}
|
|
9486
9765
|
for (const m of body.matchAll(/<archive\b([^>]*)\/?>/g)) {
|
|
9487
9766
|
const id = Number.parseInt(attrOf(m[1], "id") ?? "", 10);
|
|
@@ -9489,6 +9768,12 @@ function parseVerifyManifest(text) {
|
|
|
9489
9768
|
throw new Error("verify manifest entry missing numeric id");
|
|
9490
9769
|
out.archived.push({ id, reason: attrOf(m[1], "reason") ?? "" });
|
|
9491
9770
|
}
|
|
9771
|
+
for (const m of body.matchAll(/<skip\b([^>]*)\/?>/g)) {
|
|
9772
|
+
const id = Number.parseInt(attrOf(m[1], "id") ?? "", 10);
|
|
9773
|
+
if (!Number.isInteger(id))
|
|
9774
|
+
throw new Error("verify manifest entry missing numeric id");
|
|
9775
|
+
out.skipped.push({ id, reason: attrOf(m[1], "reason") ?? "" });
|
|
9776
|
+
}
|
|
9492
9777
|
if (verifyIds(out).length === 0 && body.trim().length > 0) {
|
|
9493
9778
|
throw new Error(describeUnrecognizedManifestShape(text, "verify", "verified"));
|
|
9494
9779
|
}
|
|
@@ -9528,6 +9813,8 @@ async function runVerify(args) {
|
|
|
9528
9813
|
verified: 0,
|
|
9529
9814
|
updated: 0,
|
|
9530
9815
|
archived: 0,
|
|
9816
|
+
skipped: 0,
|
|
9817
|
+
refused: 0,
|
|
9531
9818
|
batches: 0,
|
|
9532
9819
|
inScope: 0,
|
|
9533
9820
|
remaining: 0,
|
|
@@ -9572,9 +9859,12 @@ async function runVerify(args) {
|
|
|
9572
9859
|
result.verified += counts.verified;
|
|
9573
9860
|
result.updated += counts.updated;
|
|
9574
9861
|
result.archived += counts.archived;
|
|
9575
|
-
result.
|
|
9862
|
+
result.skipped += counts.skipped;
|
|
9863
|
+
result.refused += counts.refused;
|
|
9864
|
+
const batchProcessed = counts.verified + counts.updated + counts.archived + counts.skipped + counts.refused;
|
|
9865
|
+
result.remaining -= batchProcessed;
|
|
9576
9866
|
result.batches += 1;
|
|
9577
|
-
args.onProgress?.(result.verified + result.updated + result.archived);
|
|
9867
|
+
args.onProgress?.(result.verified + result.updated + result.archived + result.skipped + result.refused, result.refused);
|
|
9578
9868
|
if (counts.providerFailure) {
|
|
9579
9869
|
lastProviderFailure = counts.providerFailure;
|
|
9580
9870
|
if (counts.providerFailure.fingerprint === priorProviderFailureFingerprint) {
|
|
@@ -9597,7 +9887,7 @@ async function runVerify(args) {
|
|
|
9597
9887
|
result.complete = result.remaining === 0;
|
|
9598
9888
|
if (result.complete)
|
|
9599
9889
|
closeBroadCycle(args, gate.broadCycleStartAt);
|
|
9600
|
-
log(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: verified=${result.verified} updated=${result.updated} archived=${result.archived} batches=${result.batches} remaining=${result.remaining} complete=${result.complete}`);
|
|
9890
|
+
log(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: verified=${result.verified} updated=${result.updated} archived=${result.archived} skipped=${result.skipped} refused=${result.refused} batches=${result.batches} remaining=${result.remaining} complete=${result.complete}`);
|
|
9601
9891
|
return result;
|
|
9602
9892
|
} finally {
|
|
9603
9893
|
heartbeat.stop();
|
|
@@ -9666,7 +9956,14 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
9666
9956
|
recordInvocation4(args, startedAt, { status: "failed", error });
|
|
9667
9957
|
if (error instanceof DreamerModuleFailureError || signal.aborted)
|
|
9668
9958
|
throw error;
|
|
9669
|
-
return {
|
|
9959
|
+
return {
|
|
9960
|
+
verified: 0,
|
|
9961
|
+
updated: 0,
|
|
9962
|
+
archived: 0,
|
|
9963
|
+
skipped: 0,
|
|
9964
|
+
refused: 0,
|
|
9965
|
+
providerFailure
|
|
9966
|
+
};
|
|
9670
9967
|
} finally {
|
|
9671
9968
|
if (agentSessionId && !shouldKeepSubagents()) {
|
|
9672
9969
|
await args.client.session.delete({
|
|
@@ -9680,35 +9977,59 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
9680
9977
|
}
|
|
9681
9978
|
async function applyParsedVerifyManifest(args, batch, parsed) {
|
|
9682
9979
|
const batchIds = new Set(batch.map((m) => m.id));
|
|
9980
|
+
const batchById = new Map(batch.map((memory) => [memory.id, memory]));
|
|
9683
9981
|
const valid = {
|
|
9684
9982
|
verified: parsed.verified.filter((entry) => batchIds.has(entry.id)),
|
|
9685
9983
|
updated: parsed.updated.filter((entry) => batchIds.has(entry.id)),
|
|
9686
|
-
archived: parsed.archived.filter((entry) => batchIds.has(entry.id))
|
|
9984
|
+
archived: parsed.archived.filter((entry) => batchIds.has(entry.id)),
|
|
9985
|
+
skipped: parsed.skipped.filter((entry) => batchIds.has(entry.id))
|
|
9687
9986
|
};
|
|
9688
|
-
const unknown = [
|
|
9987
|
+
const unknown = [
|
|
9988
|
+
...parsed.verified,
|
|
9989
|
+
...parsed.updated,
|
|
9990
|
+
...parsed.archived,
|
|
9991
|
+
...parsed.skipped
|
|
9992
|
+
].filter((entry) => !batchIds.has(entry.id));
|
|
9689
9993
|
if (unknown.length > 0) {
|
|
9690
9994
|
log(`[dreamer] verify warning: dropping ${unknown.length} unknown verification entr${unknown.length === 1 ? "y" : "ies"} outside the current batch (${unknown.map((entry) => entry.id).join(", ")})`);
|
|
9691
9995
|
}
|
|
9692
|
-
const validIds = [...valid.verified, ...valid.updated, ...valid.archived].map((entry) => entry.id);
|
|
9996
|
+
const validIds = [...valid.verified, ...valid.updated, ...valid.archived, ...valid.skipped].map((entry) => entry.id);
|
|
9693
9997
|
assertNoDuplicateManifestIds(validIds, "verify");
|
|
9694
9998
|
if (validIds.length * 2 < batch.length) {
|
|
9695
9999
|
throw new Error(`verify manifest covers ${validIds.length}/${batch.length} batch ids after filtering unknown entries; rejecting mostly-wrong manifest`);
|
|
9696
10000
|
}
|
|
9697
|
-
if (validIds.length === 0)
|
|
9698
|
-
return { verified: 0, updated: 0, archived: 0 };
|
|
10001
|
+
if (validIds.length === 0) {
|
|
10002
|
+
return { verified: 0, updated: 0, archived: 0, skipped: 0, refused: 0 };
|
|
10003
|
+
}
|
|
9699
10004
|
const now = Date.now();
|
|
9700
10005
|
const writes = [];
|
|
10006
|
+
let refused = 0;
|
|
10007
|
+
const skipped = valid.skipped.length;
|
|
9701
10008
|
for (const v of valid.verified) {
|
|
9702
10009
|
const files = await normalizeFiles(args, v.files);
|
|
9703
10010
|
writes.push({ kind: "verify", id: v.id, files });
|
|
9704
10011
|
}
|
|
9705
10012
|
for (const u of valid.updated) {
|
|
10013
|
+
const original = batchById.get(u.id);
|
|
10014
|
+
if (!original)
|
|
10015
|
+
continue;
|
|
10016
|
+
if (isDirectiveShapedProjectRule(original.category, original.content)) {
|
|
10017
|
+
log(`[dreamer] verify safety refusal: memory_id=${u.id} verdict=update reason=directive-shaped-project-rule`);
|
|
10018
|
+
refused += 1;
|
|
10019
|
+
continue;
|
|
10020
|
+
}
|
|
9706
10021
|
const content = u.content.trim();
|
|
9707
10022
|
if (!content || content.length > 20000) {
|
|
9708
10023
|
const files2 = await normalizeFiles(args, u.files);
|
|
9709
10024
|
writes.push({ kind: "verify", id: u.id, files: files2 });
|
|
9710
10025
|
continue;
|
|
9711
10026
|
}
|
|
10027
|
+
const originalLength = original.content.trim().length;
|
|
10028
|
+
if (!u.consolidation && content.length * 2 < originalLength) {
|
|
10029
|
+
log(`[dreamer] verify safety refusal: memory_id=${u.id} verdict=update reason=content-loss original_chars=${originalLength} replacement_chars=${content.length}`);
|
|
10030
|
+
refused += 1;
|
|
10031
|
+
continue;
|
|
10032
|
+
}
|
|
9712
10033
|
const files = await normalizeFiles(args, u.files);
|
|
9713
10034
|
writes.push({
|
|
9714
10035
|
kind: "update",
|
|
@@ -9719,13 +10040,21 @@ async function applyParsedVerifyManifest(args, batch, parsed) {
|
|
|
9719
10040
|
});
|
|
9720
10041
|
}
|
|
9721
10042
|
for (const a of valid.archived) {
|
|
10043
|
+
const original = batchById.get(a.id);
|
|
10044
|
+
if (!original)
|
|
10045
|
+
continue;
|
|
10046
|
+
if (isDirectiveShapedProjectRule(original.category, original.content)) {
|
|
10047
|
+
log(`[dreamer] verify safety refusal: memory_id=${a.id} verdict=archive reason=directive-shaped-project-rule`);
|
|
10048
|
+
refused += 1;
|
|
10049
|
+
continue;
|
|
10050
|
+
}
|
|
9722
10051
|
writes.push({ kind: "archive", id: a.id, reason: a.reason });
|
|
9723
10052
|
}
|
|
9724
|
-
if (writes.length === 0)
|
|
9725
|
-
return { verified: 0, updated: 0, archived: 0 };
|
|
9726
10053
|
let verified = 0;
|
|
9727
10054
|
let updated = 0;
|
|
9728
10055
|
let archived = 0;
|
|
10056
|
+
if (writes.length === 0)
|
|
10057
|
+
return { verified, updated, archived, skipped, refused };
|
|
9729
10058
|
if (args.moduleRoute) {
|
|
9730
10059
|
const identities = getModuleMemoryIdentities(args.db, args.projectIdentity, writes.map((write) => write.id));
|
|
9731
10060
|
const rows = writes.map((write) => {
|
|
@@ -9775,7 +10104,7 @@ async function applyParsedVerifyManifest(args, batch, parsed) {
|
|
|
9775
10104
|
else
|
|
9776
10105
|
archived += 1;
|
|
9777
10106
|
}
|
|
9778
|
-
return { verified, updated, archived };
|
|
10107
|
+
return { verified, updated, archived, skipped, refused };
|
|
9779
10108
|
}
|
|
9780
10109
|
runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
|
|
9781
10110
|
for (const w of writes) {
|
|
@@ -9806,7 +10135,7 @@ async function applyParsedVerifyManifest(args, batch, parsed) {
|
|
|
9806
10135
|
}
|
|
9807
10136
|
}
|
|
9808
10137
|
});
|
|
9809
|
-
return { verified, updated, archived };
|
|
10138
|
+
return { verified, updated, archived, skipped, refused };
|
|
9810
10139
|
}
|
|
9811
10140
|
async function normalizeFiles(args, rawFiles) {
|
|
9812
10141
|
if (rawFiles.length === 0)
|
|
@@ -9919,12 +10248,13 @@ function createDreamTaskExecutor(deps) {
|
|
|
9919
10248
|
})();
|
|
9920
10249
|
const deadline = startedAt + config.timeoutMinutes * 60 * 1000;
|
|
9921
10250
|
const backlogAtStart = getDreamTaskBacklog(db, projectIdentity, config.task);
|
|
9922
|
-
const reportProgress = (processed) => {
|
|
10251
|
+
const reportProgress = (processed, refused) => {
|
|
9923
10252
|
deps.onProgress?.({
|
|
9924
10253
|
task: config.task,
|
|
9925
10254
|
processed: Math.max(0, processed),
|
|
9926
10255
|
total: backlogAtStart.pending,
|
|
9927
|
-
startedAt
|
|
10256
|
+
startedAt,
|
|
10257
|
+
...refused === undefined ? {} : { refused: Math.max(0, refused) }
|
|
9928
10258
|
});
|
|
9929
10259
|
};
|
|
9930
10260
|
reportProgress(0);
|
|
@@ -10111,10 +10441,11 @@ function createDreamTaskExecutor(deps) {
|
|
|
10111
10441
|
fallbackModels: config.fallbackModels,
|
|
10112
10442
|
language: config.language ?? deps.language,
|
|
10113
10443
|
moduleRoute,
|
|
10114
|
-
onProgress: (processed2) => reportProgress(processed2)
|
|
10444
|
+
onProgress: (processed2, refused) => reportProgress(processed2, refused)
|
|
10115
10445
|
});
|
|
10116
|
-
const processed = result.verified + result.updated + result.archived;
|
|
10117
|
-
const
|
|
10446
|
+
const processed = result.verified + result.updated + result.archived + result.skipped + result.refused;
|
|
10447
|
+
const verificationProgress = `${config.task}${config.task === "verify-broad" ? ` cycle ${result.broadCycleStartAt ?? "open"}` : ""}: processed ${processed} (verified ${result.verified}, updated ${result.updated}, archived ${result.archived}, skipped ${result.skipped}, refused ${result.refused}); ${result.remaining} remain`;
|
|
10448
|
+
const broadProgress = config.task === "verify-broad" ? verificationProgress : null;
|
|
10118
10449
|
const backlogAfter = config.task === "verify-broad" ? { pending: result.remaining, total: backlogAtStart.total } : undefined;
|
|
10119
10450
|
if (!result.complete) {
|
|
10120
10451
|
if (broadProgress && processed > 0) {
|
|
@@ -10127,13 +10458,14 @@ function createDreamTaskExecutor(deps) {
|
|
|
10127
10458
|
}
|
|
10128
10459
|
const error = incompleteMessage(result.remaining);
|
|
10129
10460
|
recordRun("failed", error, {
|
|
10461
|
+
progress: verificationProgress,
|
|
10130
10462
|
memoryChanges: computeMemoryDelta(memoryBefore),
|
|
10131
10463
|
backlogAfter
|
|
10132
10464
|
});
|
|
10133
10465
|
return { status: "failed", transient: true, error };
|
|
10134
10466
|
}
|
|
10135
10467
|
recordRun("completed", null, {
|
|
10136
|
-
progress:
|
|
10468
|
+
progress: verificationProgress,
|
|
10137
10469
|
memoryChanges: computeMemoryDelta(memoryBefore),
|
|
10138
10470
|
backlogAfter
|
|
10139
10471
|
});
|
|
@@ -10163,6 +10495,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
10163
10495
|
leaseAcquisition,
|
|
10164
10496
|
model: config.model,
|
|
10165
10497
|
fallbackModels: config.fallbackModels,
|
|
10498
|
+
language: config.language ?? deps.language,
|
|
10166
10499
|
...moduleArgs,
|
|
10167
10500
|
onProgress: (processed) => reportProgress(processed)
|
|
10168
10501
|
});
|
|
@@ -10910,7 +11243,7 @@ async function runDueTasksForProject(deps) {
|
|
|
10910
11243
|
}
|
|
10911
11244
|
|
|
10912
11245
|
// ../plugin/src/plugin/dream-timer.ts
|
|
10913
|
-
import { statSync as
|
|
11246
|
+
import { statSync as statSync3 } from "node:fs";
|
|
10914
11247
|
|
|
10915
11248
|
// ../plugin/src/features/magic-context/dreamer/retrospective-orphan-sweep.ts
|
|
10916
11249
|
var HISTORIAN_CHILD_TITLE = "magic-context-compartment";
|
|
@@ -11014,12 +11347,13 @@ var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
|
|
|
11014
11347
|
var GIT_COMMIT_BACKLOG_DRAIN_MAX_MS = 5 * 60 * 1000;
|
|
11015
11348
|
var BOOT_PROJECT_JITTER_SLOT_MS = 1000;
|
|
11016
11349
|
var activeTimer = null;
|
|
11350
|
+
var startupTickTimer = null;
|
|
11017
11351
|
var startupTimers = new Map;
|
|
11018
11352
|
var startupJitters = new Map;
|
|
11019
11353
|
var nextStartupJitterSlot = 0;
|
|
11020
11354
|
function directoryStillExists(directory) {
|
|
11021
11355
|
try {
|
|
11022
|
-
return
|
|
11356
|
+
return statSync3(directory).isDirectory();
|
|
11023
11357
|
} catch {
|
|
11024
11358
|
return false;
|
|
11025
11359
|
}
|
|
@@ -11039,6 +11373,23 @@ function openTimerDatabaseOrNull(context) {
|
|
|
11039
11373
|
return db;
|
|
11040
11374
|
}
|
|
11041
11375
|
var registeredProjects = new Map;
|
|
11376
|
+
function stopDreamScheduleTimerIfIdle() {
|
|
11377
|
+
if (registeredProjects.size !== 0)
|
|
11378
|
+
return;
|
|
11379
|
+
const stopped = activeTimer !== null || startupTickTimer !== null;
|
|
11380
|
+
if (activeTimer) {
|
|
11381
|
+
clearInterval(activeTimer);
|
|
11382
|
+
activeTimer = null;
|
|
11383
|
+
}
|
|
11384
|
+
if (startupTickTimer) {
|
|
11385
|
+
clearTimeout(startupTickTimer);
|
|
11386
|
+
startupTickTimer = null;
|
|
11387
|
+
}
|
|
11388
|
+
startupJitters.clear();
|
|
11389
|
+
nextStartupJitterSlot = 0;
|
|
11390
|
+
if (stopped)
|
|
11391
|
+
log("[dreamer] stopped dream schedule timer (no projects left)");
|
|
11392
|
+
}
|
|
11042
11393
|
async function startDreamScheduleTimer(args) {
|
|
11043
11394
|
beginBootQuietPeriod();
|
|
11044
11395
|
const db = openTimerDatabaseOrNull("schedule timer registration");
|
|
@@ -11062,7 +11413,10 @@ async function startDreamScheduleTimer(args) {
|
|
|
11062
11413
|
}
|
|
11063
11414
|
if (!activeTimer) {
|
|
11064
11415
|
log(`[dreamer] started independent schedule timer (every ${DREAM_TIMER_INTERVAL_MS / 60000}m)`);
|
|
11065
|
-
scheduleAfterBootQuiet(() =>
|
|
11416
|
+
startupTickTimer = scheduleAfterBootQuiet(() => {
|
|
11417
|
+
startupTickTimer = null;
|
|
11418
|
+
runTick("startup");
|
|
11419
|
+
});
|
|
11066
11420
|
const timer = setInterval(() => runTick("interval"), DREAM_TIMER_INTERVAL_MS);
|
|
11067
11421
|
if (typeof timer === "object" && "unref" in timer) {
|
|
11068
11422
|
timer.unref();
|
|
@@ -11072,6 +11426,10 @@ async function startDreamScheduleTimer(args) {
|
|
|
11072
11426
|
scheduleInitialProjectRun(args, db);
|
|
11073
11427
|
}
|
|
11074
11428
|
return () => {
|
|
11429
|
+
if (registeredProjects.get(args.directory) !== args) {
|
|
11430
|
+
stopDreamScheduleTimerIfIdle();
|
|
11431
|
+
return;
|
|
11432
|
+
}
|
|
11075
11433
|
registeredProjects.delete(args.directory);
|
|
11076
11434
|
const startupTimer = startupTimers.get(args.directory);
|
|
11077
11435
|
if (startupTimer) {
|
|
@@ -11079,13 +11437,7 @@ async function startDreamScheduleTimer(args) {
|
|
|
11079
11437
|
startupTimers.delete(args.directory);
|
|
11080
11438
|
}
|
|
11081
11439
|
log(`[dreamer] unregistered project ${args.projectIdentity} (remaining=${registeredProjects.size})`);
|
|
11082
|
-
|
|
11083
|
-
clearInterval(activeTimer);
|
|
11084
|
-
activeTimer = null;
|
|
11085
|
-
startupJitters.clear();
|
|
11086
|
-
nextStartupJitterSlot = 0;
|
|
11087
|
-
log("[dreamer] stopped dream schedule timer (no projects left)");
|
|
11088
|
-
}
|
|
11440
|
+
stopDreamScheduleTimerIfIdle();
|
|
11089
11441
|
};
|
|
11090
11442
|
}
|
|
11091
11443
|
function runTick(origin) {
|
|
@@ -11170,7 +11522,15 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
11170
11522
|
log(`[dreamer] orphan schedule GC failed for ${reg.projectIdentity}:`, error);
|
|
11171
11523
|
}
|
|
11172
11524
|
}
|
|
11173
|
-
registeredProjects.
|
|
11525
|
+
if (registeredProjects.get(reg.directory) === reg) {
|
|
11526
|
+
registeredProjects.delete(reg.directory);
|
|
11527
|
+
const startupTimer = startupTimers.get(reg.directory);
|
|
11528
|
+
if (startupTimer) {
|
|
11529
|
+
clearTimeout(startupTimer);
|
|
11530
|
+
startupTimers.delete(reg.directory);
|
|
11531
|
+
}
|
|
11532
|
+
}
|
|
11533
|
+
stopDreamScheduleTimerIfIdle();
|
|
11174
11534
|
return;
|
|
11175
11535
|
}
|
|
11176
11536
|
await reg.ensureRegistered(reg.directory, db);
|
|
@@ -11350,25 +11710,145 @@ async function sweepGitCommits(args) {
|
|
|
11350
11710
|
}
|
|
11351
11711
|
|
|
11352
11712
|
// src/dreamer/pi-session-api.ts
|
|
11353
|
-
import { readFileSync as readFileSync4 } from "node:fs";
|
|
11354
|
-
import {
|
|
11713
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4, realpathSync as realpathSync3, statSync as statSync4 } from "node:fs";
|
|
11714
|
+
import {
|
|
11715
|
+
basename as basename2,
|
|
11716
|
+
dirname as dirname2,
|
|
11717
|
+
extname,
|
|
11718
|
+
join as join4,
|
|
11719
|
+
relative,
|
|
11720
|
+
resolve,
|
|
11721
|
+
sep as sep2
|
|
11722
|
+
} from "node:path";
|
|
11355
11723
|
import { pathToFileURL } from "node:url";
|
|
11356
|
-
var
|
|
11724
|
+
var PI_CODING_AGENT_MODULE2 = "@earendil-works/pi-coding-agent";
|
|
11725
|
+
var SCRIPT_ENTRY_PATTERN = /\.(mjs|cjs|mts|cts|js|ts|tsx|jsx)$/i;
|
|
11726
|
+
var TS_ENTRY_PATTERN = /\.(mts|cts|ts|tsx)$/i;
|
|
11727
|
+
function isScriptEntry(filePath) {
|
|
11728
|
+
return SCRIPT_ENTRY_PATTERN.test(filePath) || extname(filePath) === "";
|
|
11729
|
+
}
|
|
11730
|
+
function readManifest(pkgJsonPath) {
|
|
11731
|
+
try {
|
|
11732
|
+
const pkg = JSON.parse(readFileSync4(pkgJsonPath, "utf8"));
|
|
11733
|
+
return pkg && typeof pkg === "object" ? pkg : null;
|
|
11734
|
+
} catch {
|
|
11735
|
+
return null;
|
|
11736
|
+
}
|
|
11737
|
+
}
|
|
11738
|
+
function isCompiledBunBinary() {
|
|
11739
|
+
if (!process.versions.bun) {
|
|
11740
|
+
return false;
|
|
11741
|
+
}
|
|
11742
|
+
const exe = basename2(process.execPath).toLowerCase();
|
|
11743
|
+
return exe !== "bun" && exe !== "bun.exe";
|
|
11744
|
+
}
|
|
11745
|
+
function resolveRunningEntry() {
|
|
11746
|
+
const argv1 = process.argv[1];
|
|
11747
|
+
if (argv1 && existsSync8(argv1) && statSync4(argv1).isFile()) {
|
|
11748
|
+
const real = realpathSync3(argv1);
|
|
11749
|
+
if (isScriptEntry(real)) {
|
|
11750
|
+
return real;
|
|
11751
|
+
}
|
|
11752
|
+
}
|
|
11753
|
+
return null;
|
|
11754
|
+
}
|
|
11755
|
+
function findPackageRoot(startDir) {
|
|
11756
|
+
let dir = startDir;
|
|
11757
|
+
while (dir !== dirname2(dir)) {
|
|
11758
|
+
const pkg = readManifest(join4(dir, "package.json"));
|
|
11759
|
+
if (pkg?.name === PI_CODING_AGENT_MODULE2) {
|
|
11760
|
+
if (basename2(dir) === "dist") {
|
|
11761
|
+
const parentDir = dirname2(dir);
|
|
11762
|
+
const parentPkg = readManifest(join4(parentDir, "package.json"));
|
|
11763
|
+
if (parentPkg?.name === PI_CODING_AGENT_MODULE2) {
|
|
11764
|
+
return { dir: parentDir, pkg: parentPkg };
|
|
11765
|
+
}
|
|
11766
|
+
}
|
|
11767
|
+
return { dir, pkg };
|
|
11768
|
+
}
|
|
11769
|
+
dir = dirname2(dir);
|
|
11770
|
+
}
|
|
11771
|
+
return null;
|
|
11772
|
+
}
|
|
11773
|
+
function resolveExportsTarget(target) {
|
|
11774
|
+
if (typeof target === "string") {
|
|
11775
|
+
return target;
|
|
11776
|
+
}
|
|
11777
|
+
if (Array.isArray(target)) {
|
|
11778
|
+
for (const item of target) {
|
|
11779
|
+
const resolved = resolveExportsTarget(item);
|
|
11780
|
+
if (resolved !== undefined) {
|
|
11781
|
+
return resolved;
|
|
11782
|
+
}
|
|
11783
|
+
}
|
|
11784
|
+
return;
|
|
11785
|
+
}
|
|
11786
|
+
if (target && typeof target === "object") {
|
|
11787
|
+
const conditions = target;
|
|
11788
|
+
for (const condition of ["import", "node", "default"]) {
|
|
11789
|
+
if (condition in conditions) {
|
|
11790
|
+
const resolved = resolveExportsTarget(conditions[condition]);
|
|
11791
|
+
if (resolved !== undefined) {
|
|
11792
|
+
return resolved;
|
|
11793
|
+
}
|
|
11794
|
+
}
|
|
11795
|
+
}
|
|
11796
|
+
}
|
|
11797
|
+
return;
|
|
11798
|
+
}
|
|
11799
|
+
function resolveManifestEntry(found) {
|
|
11800
|
+
const pkg = found.pkg;
|
|
11801
|
+
const entryRel = resolveExportsTarget(pkg.exports?.["."]) ?? (typeof pkg.module === "string" ? pkg.module : undefined) ?? (typeof pkg.main === "string" ? pkg.main : undefined);
|
|
11802
|
+
if (!entryRel) {
|
|
11803
|
+
throw new Error(`No ESM entry found in ${found.dir}/package.json`);
|
|
11804
|
+
}
|
|
11805
|
+
if (!entryRel.startsWith("./")) {
|
|
11806
|
+
throw new Error(`Invalid entry "${entryRel}" in ${found.dir}/package.json: targets must start with "./"`);
|
|
11807
|
+
}
|
|
11808
|
+
const root = resolve(found.dir);
|
|
11809
|
+
const resolved = resolve(root, entryRel);
|
|
11810
|
+
if (resolved !== root && !resolved.startsWith(root + sep2)) {
|
|
11811
|
+
throw new Error(`Invalid entry "${entryRel}" in ${found.dir}/package.json: target escapes the package root`);
|
|
11812
|
+
}
|
|
11813
|
+
return resolved;
|
|
11814
|
+
}
|
|
11815
|
+
function toSourceEntry(entryPath, pkgDir) {
|
|
11816
|
+
const rel = relative(pkgDir, entryPath);
|
|
11817
|
+
const srcRel = rel.replace(/^dist[/\\]/, "src/").replace(/\.mjs$/, ".mts").replace(/\.cjs$/, ".cts").replace(/\.jsx$/, ".tsx").replace(/\.js$/, ".ts");
|
|
11818
|
+
if (srcRel === rel) {
|
|
11819
|
+
return null;
|
|
11820
|
+
}
|
|
11821
|
+
return join4(pkgDir, srcRel);
|
|
11822
|
+
}
|
|
11357
11823
|
var defaultLoaders = [
|
|
11358
|
-
{
|
|
11359
|
-
name: "Bare import",
|
|
11360
|
-
load: async () => await import(PI_CODING_AGENT_MODULE)
|
|
11361
|
-
},
|
|
11362
11824
|
{
|
|
11363
11825
|
name: "Resolve from running Pi binary entry",
|
|
11364
11826
|
load: async () => {
|
|
11365
|
-
if (
|
|
11366
|
-
throw new Error("
|
|
11827
|
+
if (isCompiledBunBinary()) {
|
|
11828
|
+
throw new Error("Running inside a compiled Bun binary: pi-coding-agent is embedded in the executable and argv[1] is a user CLI argument, so there is no on-disk package entry to resolve");
|
|
11829
|
+
}
|
|
11830
|
+
const entry = resolveRunningEntry() ?? process.execPath;
|
|
11831
|
+
if (!entry) {
|
|
11832
|
+
throw new Error("Neither process.argv[1] nor process.execPath is available");
|
|
11833
|
+
}
|
|
11834
|
+
const found = findPackageRoot(dirname2(entry));
|
|
11835
|
+
if (!found) {
|
|
11836
|
+
throw new Error(`Could not locate ${PI_CODING_AGENT_MODULE2} package.json from ${entry}`);
|
|
11837
|
+
}
|
|
11838
|
+
const entryPath = resolveManifestEntry(found);
|
|
11839
|
+
if (TS_ENTRY_PATTERN.test(entry)) {
|
|
11840
|
+
const srcEntry = toSourceEntry(entryPath, found.dir);
|
|
11841
|
+
if (srcEntry && existsSync8(srcEntry)) {
|
|
11842
|
+
return await import(pathToFileURL(srcEntry).href);
|
|
11843
|
+
}
|
|
11844
|
+
throw new Error(`Pi is running from TypeScript source (${entry}) but no source counterpart of ${entryPath} exists; refusing to load possibly stale build output`);
|
|
11367
11845
|
}
|
|
11368
|
-
|
|
11369
|
-
const resolved = require2.resolve(PI_CODING_AGENT_MODULE);
|
|
11370
|
-
return await import(pathToFileURL(resolved).href);
|
|
11846
|
+
return await import(pathToFileURL(entryPath).href);
|
|
11371
11847
|
}
|
|
11848
|
+
},
|
|
11849
|
+
{
|
|
11850
|
+
name: "Bare import",
|
|
11851
|
+
load: async () => await import(PI_CODING_AGENT_MODULE2)
|
|
11372
11852
|
}
|
|
11373
11853
|
];
|
|
11374
11854
|
var cachedModulePromise = null;
|
|
@@ -11386,7 +11866,7 @@ async function resolvePiCodingAgentModule(loaders) {
|
|
|
11386
11866
|
errors.push(err);
|
|
11387
11867
|
}
|
|
11388
11868
|
}
|
|
11389
|
-
throw new Error(`Failed to resolve ${
|
|
11869
|
+
throw new Error(`Failed to resolve ${PI_CODING_AGENT_MODULE2} via all strategies:
|
|
11390
11870
|
` + errors.map((e, i) => ` - ${activeLoaders[i].name}: ${e.message || e}`).join(`
|
|
11391
11871
|
`) + `
|
|
11392
11872
|
Likely cause: symlinked or nonstandard install layout.`);
|
|
@@ -11454,7 +11934,7 @@ function createPiPrimerRawProviderFactory(deps = {}) {
|
|
|
11454
11934
|
}
|
|
11455
11935
|
|
|
11456
11936
|
// src/dreamer/retrospective-raw-provider-pi.ts
|
|
11457
|
-
import { resolve } from "node:path";
|
|
11937
|
+
import { resolve as resolve2 } from "node:path";
|
|
11458
11938
|
class PiRetrospectiveRawProvider {
|
|
11459
11939
|
deps;
|
|
11460
11940
|
sessionPathById = new Map;
|
|
@@ -11465,7 +11945,7 @@ class PiRetrospectiveRawProvider {
|
|
|
11465
11945
|
async listProjectSessions(_projectIdentity) {
|
|
11466
11946
|
const deps = await this.resolveDeps();
|
|
11467
11947
|
const sessions = await deps.listSessions(this.deps.sessionDir);
|
|
11468
|
-
const projectCwd =
|
|
11948
|
+
const projectCwd = resolve2(this.deps.projectCwd);
|
|
11469
11949
|
const result = [];
|
|
11470
11950
|
this.sessionPathById.clear();
|
|
11471
11951
|
for (const raw of sessions) {
|
|
@@ -11474,7 +11954,7 @@ class PiRetrospectiveRawProvider {
|
|
|
11474
11954
|
continue;
|
|
11475
11955
|
if (typeof info.id !== "string" || typeof info.path !== "string")
|
|
11476
11956
|
continue;
|
|
11477
|
-
if (typeof info.cwd !== "string" ||
|
|
11957
|
+
if (typeof info.cwd !== "string" || resolve2(info.cwd) !== projectCwd)
|
|
11478
11958
|
continue;
|
|
11479
11959
|
this.sessionPathById.set(info.id, info.path);
|
|
11480
11960
|
result.push({
|
|
@@ -11568,9 +12048,30 @@ function extractPiTextContent(content) {
|
|
|
11568
12048
|
}
|
|
11569
12049
|
|
|
11570
12050
|
// src/dreamer/index.ts
|
|
11571
|
-
var
|
|
12051
|
+
var PI_DREAMER_PROJECTS = Symbol.for("magic-context.pi.dreamer-registered-projects");
|
|
12052
|
+
function getRegisteredProjects() {
|
|
12053
|
+
const globals = globalThis;
|
|
12054
|
+
const existing = globals[PI_DREAMER_PROJECTS];
|
|
12055
|
+
if (existing instanceof Map) {
|
|
12056
|
+
return existing;
|
|
12057
|
+
}
|
|
12058
|
+
const projects = new Map;
|
|
12059
|
+
globals[PI_DREAMER_PROJECTS] = projects;
|
|
12060
|
+
return projects;
|
|
12061
|
+
}
|
|
12062
|
+
var registeredProjects2 = getRegisteredProjects();
|
|
11572
12063
|
var sessionsById = new Map;
|
|
11573
|
-
var
|
|
12064
|
+
var PI_DREAMER_IN_FLIGHT = Symbol.for("magic-context.pi.dreamer-in-flight");
|
|
12065
|
+
var inFlightDreams = (() => {
|
|
12066
|
+
const globals = globalThis;
|
|
12067
|
+
const existing = globals[PI_DREAMER_IN_FLIGHT];
|
|
12068
|
+
if (existing instanceof Map) {
|
|
12069
|
+
return existing;
|
|
12070
|
+
}
|
|
12071
|
+
const dreams = new Map;
|
|
12072
|
+
globals[PI_DREAMER_IN_FLIGHT] = dreams;
|
|
12073
|
+
return dreams;
|
|
12074
|
+
})();
|
|
11574
12075
|
var sessionCounter = 0;
|
|
11575
12076
|
var piSubagentRunnerFactory = () => new PiSubagentRunner;
|
|
11576
12077
|
var startDreamScheduleTimerFn = startDreamScheduleTimer;
|
|
@@ -11579,14 +12080,26 @@ function registerPiDreamerProject(opts) {
|
|
|
11579
12080
|
return;
|
|
11580
12081
|
}
|
|
11581
12082
|
const existing = registeredProjects2.get(opts.projectIdentity);
|
|
12083
|
+
const owners = existing?.owners ?? new Map;
|
|
12084
|
+
owners.delete(opts.registrationOwner);
|
|
12085
|
+
owners.set(opts.registrationOwner, opts);
|
|
12086
|
+
const notifyOwnersOfAdjunctRefresh = (projectIdentity) => {
|
|
12087
|
+
const callbacks = new Set([...owners.values()].map((owner) => owner.onAdjunctsRefreshNeeded).filter((callback) => callback !== undefined));
|
|
12088
|
+
for (const callback of callbacks)
|
|
12089
|
+
callback(projectIdentity);
|
|
12090
|
+
};
|
|
11582
12091
|
if (existing) {
|
|
11583
|
-
if (existing.projectDir === opts.projectDir) {
|
|
12092
|
+
if (existing.generation && existing.projectDir === opts.projectDir) {
|
|
11584
12093
|
return;
|
|
11585
12094
|
}
|
|
11586
12095
|
existing.cleanup();
|
|
11587
12096
|
registeredProjects2.delete(opts.projectIdentity);
|
|
11588
12097
|
}
|
|
11589
|
-
const
|
|
12098
|
+
const generation = {};
|
|
12099
|
+
const client = createPiDreamerClient(opts, notifyOwnersOfAdjunctRefresh, () => {
|
|
12100
|
+
const current = registeredProjects2.get(opts.projectIdentity);
|
|
12101
|
+
return current?.generation === generation && current.owners.get(opts.registrationOwner)?.projectDir === opts.projectDir;
|
|
12102
|
+
});
|
|
11590
12103
|
let cleanup;
|
|
11591
12104
|
let cancelled = false;
|
|
11592
12105
|
startDreamScheduleTimerFn({
|
|
@@ -11597,6 +12110,8 @@ function registerPiDreamerProject(opts) {
|
|
|
11597
12110
|
dreamerConfig: opts.config,
|
|
11598
12111
|
language: opts.language,
|
|
11599
12112
|
gitCommitIndexing: opts.gitCommitIndexing,
|
|
12113
|
+
memoryEnabled: opts.memoryEnabled,
|
|
12114
|
+
embeddingConfig: opts.embeddingConfig,
|
|
11600
12115
|
retinaHandoff: opts.retinaHandoff,
|
|
11601
12116
|
mural: opts.mural,
|
|
11602
12117
|
ensureRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
@@ -11604,32 +12119,50 @@ function registerPiDreamerProject(opts) {
|
|
|
11604
12119
|
primerRawProviderFactory: createPiPrimerRawProviderFactory()
|
|
11605
12120
|
}).then((timerCleanup) => {
|
|
11606
12121
|
if (cancelled) {
|
|
11607
|
-
|
|
12122
|
+
if (registeredProjects2.get(opts.projectIdentity)?.generation !== generation) {
|
|
12123
|
+
timerCleanup?.();
|
|
12124
|
+
}
|
|
11608
12125
|
return;
|
|
11609
12126
|
}
|
|
11610
12127
|
cleanup = timerCleanup;
|
|
11611
12128
|
});
|
|
11612
|
-
const runManual = async (task) =>
|
|
11613
|
-
|
|
11614
|
-
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
12129
|
+
const runManual = async (task, registrationOwner) => {
|
|
12130
|
+
const manualOpts = owners.get(registrationOwner);
|
|
12131
|
+
if (!manualOpts) {
|
|
12132
|
+
throw new Error(`Pi dreamer registration owner is no longer active for project ${opts.projectIdentity}`);
|
|
12133
|
+
}
|
|
12134
|
+
const manualClient = createPiDreamerClient(manualOpts, notifyOwnersOfAdjunctRefresh, () => owners.get(manualOpts.registrationOwner)?.projectDir === manualOpts.projectDir);
|
|
12135
|
+
const manualRun = runManualDream({
|
|
12136
|
+
db: manualOpts.db,
|
|
12137
|
+
projectIdentity: manualOpts.projectIdentity,
|
|
12138
|
+
tasks: buildDreamTaskRuntimeConfigs(manualOpts.config, "pi", manualOpts.language, manualOpts.mural?.model),
|
|
12139
|
+
executor: createDreamTaskExecutor({
|
|
12140
|
+
client: manualClient,
|
|
12141
|
+
sessionDirectory: manualOpts.projectDir,
|
|
12142
|
+
openOpenCodeDb,
|
|
12143
|
+
retrospectiveRawProvider: new PiRetrospectiveRawProvider({
|
|
12144
|
+
projectCwd: manualOpts.projectDir
|
|
12145
|
+
}),
|
|
12146
|
+
primerRawProviderFactory: createPiPrimerRawProviderFactory(),
|
|
12147
|
+
userMemoryCollectionEnabled: userMemoryCollectionEnabled(manualOpts.config),
|
|
12148
|
+
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
12149
|
+
language: manualOpts.language,
|
|
12150
|
+
retinaHandoff: manualOpts.retinaHandoff,
|
|
12151
|
+
mural: manualOpts.mural
|
|
11622
12152
|
}),
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
|
|
11628
|
-
|
|
11629
|
-
|
|
11630
|
-
|
|
11631
|
-
}
|
|
12153
|
+
task
|
|
12154
|
+
});
|
|
12155
|
+
inFlightDreams.set(manualRun, manualOpts.registrationOwner);
|
|
12156
|
+
try {
|
|
12157
|
+
return await manualRun;
|
|
12158
|
+
} finally {
|
|
12159
|
+
inFlightDreams.delete(manualRun);
|
|
12160
|
+
}
|
|
12161
|
+
};
|
|
11632
12162
|
registeredProjects2.set(opts.projectIdentity, {
|
|
12163
|
+
generation,
|
|
12164
|
+
activeOwner: opts.registrationOwner,
|
|
12165
|
+
owners,
|
|
11633
12166
|
cleanup: () => {
|
|
11634
12167
|
cancelled = true;
|
|
11635
12168
|
cleanup?.();
|
|
@@ -11638,31 +12171,55 @@ function registerPiDreamerProject(opts) {
|
|
|
11638
12171
|
projectDir: opts.projectDir
|
|
11639
12172
|
});
|
|
11640
12173
|
}
|
|
11641
|
-
async function runPiDreamForProject(projectIdentity, task) {
|
|
12174
|
+
async function runPiDreamForProject(projectIdentity, task, registrationOwner) {
|
|
11642
12175
|
const registration = registeredProjects2.get(projectIdentity);
|
|
11643
12176
|
if (!registration) {
|
|
11644
12177
|
throw new Error(`Pi dreamer not registered for project ${projectIdentity}; call registerPiDreamerProject() first`);
|
|
11645
12178
|
}
|
|
11646
|
-
return registration.runManual(task);
|
|
12179
|
+
return registration.runManual(task, registrationOwner);
|
|
11647
12180
|
}
|
|
11648
12181
|
function unregisterPiDreamerProject(opts) {
|
|
11649
12182
|
const registration = registeredProjects2.get(opts.projectIdentity);
|
|
11650
|
-
if (!registration) {
|
|
12183
|
+
if (!registration?.owners.delete(opts.registrationOwner)) {
|
|
12184
|
+
return;
|
|
12185
|
+
}
|
|
12186
|
+
if (registration.owners.size > 0) {
|
|
12187
|
+
if (registration.activeOwner !== opts.registrationOwner)
|
|
12188
|
+
return;
|
|
12189
|
+
const remaining = [...registration.owners.values()];
|
|
12190
|
+
const replacementOptions = remaining[remaining.length - 1];
|
|
12191
|
+
if (!replacementOptions)
|
|
12192
|
+
return;
|
|
12193
|
+
registration.cleanup();
|
|
12194
|
+
registeredProjects2.delete(opts.projectIdentity);
|
|
12195
|
+
registerPiDreamerProject(replacementOptions);
|
|
12196
|
+
const replacement = registeredProjects2.get(opts.projectIdentity);
|
|
12197
|
+
if (replacement) {
|
|
12198
|
+
for (const remainingOptions of remaining) {
|
|
12199
|
+
replacement.owners.set(remainingOptions.registrationOwner, remainingOptions);
|
|
12200
|
+
}
|
|
12201
|
+
}
|
|
11651
12202
|
return;
|
|
11652
12203
|
}
|
|
11653
12204
|
registration.cleanup();
|
|
11654
12205
|
registeredProjects2.delete(opts.projectIdentity);
|
|
11655
12206
|
}
|
|
11656
|
-
async function awaitInFlightDreamers() {
|
|
11657
|
-
|
|
12207
|
+
async function awaitInFlightDreamers(registrationOwner) {
|
|
12208
|
+
const runs = registrationOwner === undefined ? [...inFlightDreams.keys()] : [...inFlightDreams.entries()].filter(([, owner]) => owner === registrationOwner).map(([run]) => run);
|
|
12209
|
+
if (runs.length === 0)
|
|
11658
12210
|
return;
|
|
11659
|
-
|
|
11660
|
-
await Promise.allSettled(Array.from(inFlightDreams));
|
|
12211
|
+
await Promise.allSettled(runs);
|
|
11661
12212
|
}
|
|
11662
|
-
function createPiDreamerClient(opts) {
|
|
12213
|
+
function createPiDreamerClient(opts, onAdjunctsRefreshNeeded = opts.onAdjunctsRefreshNeeded, isRegistrationOwnerActive = () => true) {
|
|
11663
12214
|
const runner = piSubagentRunnerFactory();
|
|
12215
|
+
const assertRegistrationOwnerActive = () => {
|
|
12216
|
+
if (!isRegistrationOwnerActive()) {
|
|
12217
|
+
throw new Error(`Pi dreamer registration is no longer active for project ${opts.projectIdentity}`);
|
|
12218
|
+
}
|
|
12219
|
+
};
|
|
11664
12220
|
const session = {
|
|
11665
12221
|
create: async (args) => {
|
|
12222
|
+
assertRegistrationOwnerActive();
|
|
11666
12223
|
const sessionId = `magic-context-pi-dream-${++sessionCounter}`;
|
|
11667
12224
|
sessionsById.set(sessionId, {
|
|
11668
12225
|
id: sessionId,
|
|
@@ -11679,6 +12236,7 @@ function createPiDreamerClient(opts) {
|
|
|
11679
12236
|
if (!dreamSession) {
|
|
11680
12237
|
throw new Error(`Pi dreamer session not found: ${sessionId}`);
|
|
11681
12238
|
}
|
|
12239
|
+
assertRegistrationOwnerActive();
|
|
11682
12240
|
const userMessage = extractUserMessage(args);
|
|
11683
12241
|
const systemPrompt = extractSystemPrompt(args);
|
|
11684
12242
|
const perTaskModel = extractBodyModel(args);
|
|
@@ -11694,9 +12252,10 @@ function createPiDreamerClient(opts) {
|
|
|
11694
12252
|
signal: args.signal ?? undefined,
|
|
11695
12253
|
thinkingLevel: extractBodyVariant(args)
|
|
11696
12254
|
});
|
|
11697
|
-
inFlightDreams.
|
|
12255
|
+
inFlightDreams.set(runPromise, opts.registrationOwner);
|
|
11698
12256
|
try {
|
|
11699
12257
|
const result = await runPromise;
|
|
12258
|
+
assertRegistrationOwnerActive();
|
|
11700
12259
|
if (!result.ok) {
|
|
11701
12260
|
const error = new Error(`Pi dreamer subagent failed (${result.reason}): ${result.error}`);
|
|
11702
12261
|
if (result.transient) {
|
|
@@ -11711,12 +12270,13 @@ function createPiDreamerClient(opts) {
|
|
|
11711
12270
|
{ type: "text", text: result.assistantText }
|
|
11712
12271
|
])
|
|
11713
12272
|
];
|
|
11714
|
-
|
|
12273
|
+
onAdjunctsRefreshNeeded?.(opts.projectIdentity);
|
|
11715
12274
|
} finally {
|
|
11716
12275
|
inFlightDreams.delete(runPromise);
|
|
11717
12276
|
}
|
|
11718
12277
|
},
|
|
11719
12278
|
messages: async (args) => {
|
|
12279
|
+
assertRegistrationOwnerActive();
|
|
11720
12280
|
const dreamSession = sessionsById.get(args.path.id);
|
|
11721
12281
|
return { data: dreamSession?.messages ?? [] };
|
|
11722
12282
|
},
|
|
@@ -11816,8 +12376,15 @@ function makeMessage(role, parts) {
|
|
|
11816
12376
|
}
|
|
11817
12377
|
|
|
11818
12378
|
// src/commands/pi-command-utils.ts
|
|
11819
|
-
import { Box, Text } from "@earendil-works/pi-tui";
|
|
12379
|
+
import { Box, matchesKey, Text } from "@earendil-works/pi-tui";
|
|
11820
12380
|
var CTX_STATUS_CUSTOM_TYPE = "ctx-status";
|
|
12381
|
+
var statusLifecycleSignals = new WeakMap;
|
|
12382
|
+
function registerCtxStatusLifecycleSignal(pi, signal) {
|
|
12383
|
+
statusLifecycleSignals.set(pi, signal);
|
|
12384
|
+
}
|
|
12385
|
+
function shouldShowCtxStatusDialog(content) {
|
|
12386
|
+
return content.rpcDisplay === "dialog" || content.rpcDisplay !== "notification" && content.level !== undefined && content.level !== "info";
|
|
12387
|
+
}
|
|
11821
12388
|
function resolveSessionId(ctx) {
|
|
11822
12389
|
const sm = ctx.sessionManager;
|
|
11823
12390
|
const getSessionId = sm.getSessionId;
|
|
@@ -11830,6 +12397,41 @@ function resolveSessionId(ctx) {
|
|
|
11830
12397
|
return;
|
|
11831
12398
|
}
|
|
11832
12399
|
}
|
|
12400
|
+
async function showCtxStatusDialog(ctx, content) {
|
|
12401
|
+
let factoryInvoked = false;
|
|
12402
|
+
await ctx.ui.custom((_tui, theme, _keybindings, done) => {
|
|
12403
|
+
factoryInvoked = true;
|
|
12404
|
+
return new CtxStatusDialog(content, theme, done);
|
|
12405
|
+
}, { overlay: true, overlayOptions: { anchor: "center", width: 92 } });
|
|
12406
|
+
return factoryInvoked;
|
|
12407
|
+
}
|
|
12408
|
+
|
|
12409
|
+
class CtxStatusDialog {
|
|
12410
|
+
content;
|
|
12411
|
+
theme;
|
|
12412
|
+
done;
|
|
12413
|
+
constructor(content, theme, done) {
|
|
12414
|
+
this.content = content;
|
|
12415
|
+
this.theme = theme;
|
|
12416
|
+
this.done = done;
|
|
12417
|
+
}
|
|
12418
|
+
handleInput(data) {
|
|
12419
|
+
if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c") || matchesKey(data, "return")) {
|
|
12420
|
+
this.done(undefined);
|
|
12421
|
+
}
|
|
12422
|
+
}
|
|
12423
|
+
invalidate() {}
|
|
12424
|
+
render(_width) {
|
|
12425
|
+
return [
|
|
12426
|
+
this.theme.bold(this.theme.fg(statusTitleColor(this.content.level), `[${this.content.title}]`)),
|
|
12427
|
+
"",
|
|
12428
|
+
...this.content.text.split(`
|
|
12429
|
+
`),
|
|
12430
|
+
"",
|
|
12431
|
+
this.theme.fg("dim", "Press Enter or Escape to close")
|
|
12432
|
+
];
|
|
12433
|
+
}
|
|
12434
|
+
}
|
|
11833
12435
|
function statusTitleColor(level) {
|
|
11834
12436
|
switch (level) {
|
|
11835
12437
|
case "success":
|
|
@@ -11864,7 +12466,37 @@ function registerCtxStatusEntryRenderer(pi) {
|
|
|
11864
12466
|
return false;
|
|
11865
12467
|
}
|
|
11866
12468
|
}
|
|
11867
|
-
function
|
|
12469
|
+
async function presentCtxStatusMessage(ctx, content, signal) {
|
|
12470
|
+
if (ctx.mode !== "rpc" || signal?.aborted)
|
|
12471
|
+
return;
|
|
12472
|
+
const type = content.level === "error" || content.level === "warning" ? content.level : "info";
|
|
12473
|
+
if (!shouldShowCtxStatusDialog(content)) {
|
|
12474
|
+
if (!signal?.aborted)
|
|
12475
|
+
ctx.ui.notify(content.text, type);
|
|
12476
|
+
return;
|
|
12477
|
+
}
|
|
12478
|
+
try {
|
|
12479
|
+
const shown = await showCtxStatusDialog(ctx, content);
|
|
12480
|
+
if (!shown && !signal?.aborted)
|
|
12481
|
+
ctx.ui.notify(content.text, type);
|
|
12482
|
+
} catch (err) {
|
|
12483
|
+
if (signal?.aborted)
|
|
12484
|
+
return;
|
|
12485
|
+
sessionLog("pi-status", `ctx status dialog failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
12486
|
+
ctx.ui.notify(content.text, type);
|
|
12487
|
+
}
|
|
12488
|
+
}
|
|
12489
|
+
function createCtxStatusSender(pi, ctx, signal) {
|
|
12490
|
+
const lifecycleSignal = statusLifecycleSignals.get(pi);
|
|
12491
|
+
const effectiveSignal = signal && lifecycleSignal ? AbortSignal.any([signal, lifecycleSignal]) : signal ?? lifecycleSignal;
|
|
12492
|
+
return (content, details) => {
|
|
12493
|
+
if (!effectiveSignal?.aborted)
|
|
12494
|
+
sendCtxStatusMessage(pi, content, details, ctx, effectiveSignal);
|
|
12495
|
+
};
|
|
12496
|
+
}
|
|
12497
|
+
function sendCtxStatusMessage(pi, content, details, ctx, signal) {
|
|
12498
|
+
if (signal?.aborted)
|
|
12499
|
+
return;
|
|
11868
12500
|
const data = {
|
|
11869
12501
|
...content,
|
|
11870
12502
|
details: details ?? content.details
|
|
@@ -11872,6 +12504,8 @@ function sendCtxStatusMessage(pi, content, details) {
|
|
|
11872
12504
|
if (typeof pi.appendEntry === "function") {
|
|
11873
12505
|
pi.appendEntry(CTX_STATUS_CUSTOM_TYPE, data);
|
|
11874
12506
|
}
|
|
12507
|
+
if (ctx)
|
|
12508
|
+
presentCtxStatusMessage(ctx, data, signal);
|
|
11875
12509
|
sessionLog("pi-status", `${content.title}: ${content.text}`);
|
|
11876
12510
|
}
|
|
11877
12511
|
|
|
@@ -11880,6 +12514,7 @@ function registerCtxDreamCommand(pi, deps) {
|
|
|
11880
12514
|
pi.registerCommand("ctx-dream", {
|
|
11881
12515
|
description: "Run Magic Context dreamer tasks for this project now",
|
|
11882
12516
|
handler: async (args, ctx) => {
|
|
12517
|
+
const sendStatus = createCtxStatusSender(pi, ctx);
|
|
11883
12518
|
const project = deps.resolveProject?.(ctx) ?? {
|
|
11884
12519
|
projectDir: deps.projectDir,
|
|
11885
12520
|
projectIdentity: deps.projectIdentity
|
|
@@ -11890,7 +12525,7 @@ function registerCtxDreamCommand(pi, deps) {
|
|
|
11890
12525
|
let task;
|
|
11891
12526
|
if (requested) {
|
|
11892
12527
|
if (!isCanonicalDreamTask(requested)) {
|
|
11893
|
-
|
|
12528
|
+
sendStatus({
|
|
11894
12529
|
title: "/ctx-dream",
|
|
11895
12530
|
text: `## /ctx-dream
|
|
11896
12531
|
|
|
@@ -11905,7 +12540,7 @@ Unknown task "${requested}".`,
|
|
|
11905
12540
|
task = requested;
|
|
11906
12541
|
}
|
|
11907
12542
|
if (dreamerEnabled === false) {
|
|
11908
|
-
|
|
12543
|
+
sendStatus({
|
|
11909
12544
|
title: "/ctx-dream",
|
|
11910
12545
|
text: "## /ctx-dream\n\nDreamer is disabled for this project (`dreamer.disable=true`).",
|
|
11911
12546
|
level: "info"
|
|
@@ -11917,7 +12552,7 @@ Unknown task "${requested}".`,
|
|
|
11917
12552
|
}
|
|
11918
12553
|
const backlogTasks = task ? [task] : CANONICAL_DREAM_TASKS;
|
|
11919
12554
|
const backlogBefore = getDreamTaskBacklogs(deps.db, project.projectIdentity, backlogTasks);
|
|
11920
|
-
|
|
12555
|
+
sendStatus({
|
|
11921
12556
|
title: "/ctx-dream",
|
|
11922
12557
|
text: [
|
|
11923
12558
|
"## /ctx-dream",
|
|
@@ -11935,7 +12570,8 @@ Unknown task "${requested}".`,
|
|
|
11935
12570
|
projectIdentity: project.projectIdentity
|
|
11936
12571
|
});
|
|
11937
12572
|
try {
|
|
11938
|
-
|
|
12573
|
+
await deps.ensureRegistered?.(ctx);
|
|
12574
|
+
const result = await runPiDreamForProject(project.projectIdentity, task, deps.registrationOwner);
|
|
11939
12575
|
const lines = [];
|
|
11940
12576
|
if (result.ran.length > 0)
|
|
11941
12577
|
lines.push(`Ran: ${result.ran.join(", ")}`);
|
|
@@ -11953,11 +12589,12 @@ Unknown task "${requested}".`,
|
|
|
11953
12589
|
}
|
|
11954
12590
|
if (lines.length === 0)
|
|
11955
12591
|
lines.push("No enabled dream tasks to run.");
|
|
11956
|
-
|
|
12592
|
+
sendStatus({
|
|
11957
12593
|
title: "/ctx-dream",
|
|
11958
12594
|
text: ["## /ctx-dream", "", ...lines].join(`
|
|
11959
12595
|
`),
|
|
11960
|
-
level: result.ran.length > 0 ? "success" : "info"
|
|
12596
|
+
level: result.ran.length > 0 ? "success" : "info",
|
|
12597
|
+
rpcDisplay: "dialog"
|
|
11961
12598
|
}, {
|
|
11962
12599
|
projectDir: project.projectDir,
|
|
11963
12600
|
projectIdentity: project.projectIdentity
|
|
@@ -11965,7 +12602,7 @@ Unknown task "${requested}".`,
|
|
|
11965
12602
|
} catch (error) {
|
|
11966
12603
|
const message = error instanceof Error ? error.message : String(error);
|
|
11967
12604
|
sessionLog(project.projectIdentity, `/ctx-dream failed: ${message}`);
|
|
11968
|
-
|
|
12605
|
+
sendStatus({
|
|
11969
12606
|
title: "/ctx-dream",
|
|
11970
12607
|
text: [
|
|
11971
12608
|
"## /ctx-dream",
|
|
@@ -12005,6 +12642,10 @@ function formatEmbedFailureSummary(embedded, remaining, failure) {
|
|
|
12005
12642
|
}
|
|
12006
12643
|
case "invalid_envelope":
|
|
12007
12644
|
return `Embedded ${embedded} ${compartment}; ${remaining} failed: ${failure.reason}. Fix: configure an OpenAI-compatible embedding endpoint that returns data[].embedding.`;
|
|
12645
|
+
case "certification_refusal":
|
|
12646
|
+
return `Embedded ${embedded} ${compartment}; ${remaining} rejected: ${failure.reason}. Fix: recertify SYNAPSE or configure embedding.fallback_provider, then run /ctx-embed start again.`;
|
|
12647
|
+
case "credential_required":
|
|
12648
|
+
return `Embedded ${embedded} ${compartment}; ${remaining} rejected: ${failure.reason}. Fix: reauthenticate SYNAPSE, then run /ctx-embed start again.`;
|
|
12008
12649
|
case "empty_result":
|
|
12009
12650
|
case "transport_error":
|
|
12010
12651
|
return `Embedded ${embedded} ${compartment}; ${remaining} failed: ${failure.reason}.${failure.retryable ? retry : ""}`;
|
|
@@ -12176,9 +12817,10 @@ function registerCtxEmbedCommand(pi, deps) {
|
|
|
12176
12817
|
pi.registerCommand("ctx-embed", {
|
|
12177
12818
|
description: "Embedding status, or start/pause history compartment embedding (start | pause)",
|
|
12178
12819
|
handler: async (args, ctx) => {
|
|
12820
|
+
const sendStatus = createCtxStatusSender(pi, ctx);
|
|
12179
12821
|
const sessionId = resolveSessionId(ctx);
|
|
12180
12822
|
if (!sessionId) {
|
|
12181
|
-
|
|
12823
|
+
sendStatus({
|
|
12182
12824
|
title: "/ctx-embed",
|
|
12183
12825
|
text: `## /ctx-embed
|
|
12184
12826
|
|
|
@@ -12199,7 +12841,7 @@ No active Pi session is available.`,
|
|
|
12199
12841
|
if (ctrl)
|
|
12200
12842
|
ctrl.abort();
|
|
12201
12843
|
const cov = getEmbeddingCoverageStatus(deps.db, project.projectIdentity, sessionId);
|
|
12202
|
-
|
|
12844
|
+
sendStatus({
|
|
12203
12845
|
title: "/ctx-embed",
|
|
12204
12846
|
text: `## /ctx-embed
|
|
12205
12847
|
|
|
@@ -12209,7 +12851,7 @@ Paused at ${cov.session.embedded}/${cov.session.total} compartments embedded.`,
|
|
|
12209
12851
|
return;
|
|
12210
12852
|
}
|
|
12211
12853
|
if (memoryEnabled === false) {
|
|
12212
|
-
|
|
12854
|
+
sendStatus({
|
|
12213
12855
|
title: "/ctx-embed",
|
|
12214
12856
|
text: `## /ctx-embed
|
|
12215
12857
|
|
|
@@ -12221,16 +12863,16 @@ Memory is disabled for this project, so there is no semantic embedding to backfi
|
|
|
12221
12863
|
await ensureProjectRegisteredFromPiDirectory(project.projectDir, deps.db);
|
|
12222
12864
|
if (sub === "start") {
|
|
12223
12865
|
const { text, level } = await runEmbedDrain(deps.db, project.projectIdentity, sessionId, {
|
|
12224
|
-
onStatus: (status) =>
|
|
12866
|
+
onStatus: (status) => sendStatus({
|
|
12225
12867
|
title: "/ctx-embed",
|
|
12226
12868
|
...status
|
|
12227
12869
|
})
|
|
12228
12870
|
});
|
|
12229
|
-
|
|
12871
|
+
sendStatus({ title: "/ctx-embed", text, level });
|
|
12230
12872
|
return;
|
|
12231
12873
|
}
|
|
12232
12874
|
if (sub !== "") {
|
|
12233
|
-
|
|
12875
|
+
sendStatus({
|
|
12234
12876
|
title: "/ctx-embed",
|
|
12235
12877
|
text: "## /ctx-embed\n\nUsage: `/ctx-embed` (status), `/ctx-embed start`, or `/ctx-embed pause`.",
|
|
12236
12878
|
level: "info"
|
|
@@ -12239,12 +12881,13 @@ Memory is disabled for this project, so there is no semantic embedding to backfi
|
|
|
12239
12881
|
}
|
|
12240
12882
|
const coverage = getEmbeddingCoverageStatus(deps.db, project.projectIdentity, sessionId);
|
|
12241
12883
|
const statusText = formatEmbedStatusText(coverage, { status: "idle" });
|
|
12242
|
-
|
|
12884
|
+
sendStatus({
|
|
12243
12885
|
title: "/ctx-embed",
|
|
12244
12886
|
text: `## Embedding Status
|
|
12245
12887
|
|
|
12246
12888
|
${statusText}`,
|
|
12247
|
-
level: "info"
|
|
12889
|
+
level: "info",
|
|
12890
|
+
rpcDisplay: "dialog"
|
|
12248
12891
|
});
|
|
12249
12892
|
}
|
|
12250
12893
|
});
|
|
@@ -12260,7 +12903,7 @@ function maybeAutoEmbedPiSession(deps, sessionId, projectDir, projectIdentity, n
|
|
|
12260
12903
|
(async () => {
|
|
12261
12904
|
let completedDrainWithWork = false;
|
|
12262
12905
|
try {
|
|
12263
|
-
await new Promise((
|
|
12906
|
+
await new Promise((resolve3) => setTimeout(resolve3, 0));
|
|
12264
12907
|
await ensureProjectRegisteredFromPiDirectory(projectDir, deps.db);
|
|
12265
12908
|
const coverage = getEmbeddingCoverageStatus(deps.db, projectIdentity, sessionId);
|
|
12266
12909
|
if (!coverage.enabled)
|
|
@@ -13151,15 +13794,31 @@ function detectMidTurnBypassReason(input) {
|
|
|
13151
13794
|
}
|
|
13152
13795
|
function applyMidTurnDeferral(input) {
|
|
13153
13796
|
if (input.base === "defer") {
|
|
13154
|
-
return {
|
|
13797
|
+
return {
|
|
13798
|
+
midTurnAdjustedSchedulerDecision: "defer",
|
|
13799
|
+
sideEffect: "none",
|
|
13800
|
+
deferReason: "scheduler_defer"
|
|
13801
|
+
};
|
|
13155
13802
|
}
|
|
13156
13803
|
if (input.bypassReason !== "none") {
|
|
13157
|
-
return {
|
|
13804
|
+
return {
|
|
13805
|
+
midTurnAdjustedSchedulerDecision: "execute",
|
|
13806
|
+
sideEffect: "none",
|
|
13807
|
+
deferReason: null
|
|
13808
|
+
};
|
|
13158
13809
|
}
|
|
13159
13810
|
if (input.midTurn) {
|
|
13160
|
-
return {
|
|
13811
|
+
return {
|
|
13812
|
+
midTurnAdjustedSchedulerDecision: "defer",
|
|
13813
|
+
sideEffect: "set-flag",
|
|
13814
|
+
deferReason: "mid_turn_boundary"
|
|
13815
|
+
};
|
|
13161
13816
|
}
|
|
13162
|
-
return {
|
|
13817
|
+
return {
|
|
13818
|
+
midTurnAdjustedSchedulerDecision: "execute",
|
|
13819
|
+
sideEffect: "none",
|
|
13820
|
+
deferReason: null
|
|
13821
|
+
};
|
|
13163
13822
|
}
|
|
13164
13823
|
|
|
13165
13824
|
// ../plugin/src/hooks/magic-context/caveman.ts
|
|
@@ -13649,23 +14308,33 @@ function fenceWrapupBoundaryForToolArcs(args) {
|
|
|
13649
14308
|
return boundary;
|
|
13650
14309
|
}
|
|
13651
14310
|
function applyHeadCap(args) {
|
|
13652
|
-
const {
|
|
14311
|
+
const {
|
|
14312
|
+
index,
|
|
14313
|
+
protectedTailStart,
|
|
14314
|
+
offset,
|
|
14315
|
+
arcs,
|
|
14316
|
+
lastCompartmentEndOrdinal,
|
|
14317
|
+
capTokens,
|
|
14318
|
+
recentOpenArcCutoff
|
|
14319
|
+
} = args;
|
|
13653
14320
|
if (offset >= protectedTailStart)
|
|
13654
14321
|
return { eligibleEndOrdinal: offset, oversizeAtomicUnit: false };
|
|
13655
14322
|
let end = index.findHeadEndForCap(offset, protectedTailStart, capTokens);
|
|
13656
14323
|
let oversizeAtomicUnit = end === offset + 1 && index.tokenForOrdinal(offset) > capTokens;
|
|
14324
|
+
const completedFence = fenceBoundaryForCompletedToolArcs(end, arcs, lastCompartmentEndOrdinal + 1);
|
|
14325
|
+
if (completedFence > end) {
|
|
14326
|
+
end = Math.min(protectedTailStart, completedFence);
|
|
14327
|
+
if (index.rangeTokens(offset, end) > capTokens)
|
|
14328
|
+
oversizeAtomicUnit = true;
|
|
14329
|
+
} else {
|
|
14330
|
+
end = completedFence;
|
|
14331
|
+
}
|
|
13657
14332
|
for (const arc of arcs) {
|
|
13658
14333
|
const resOrdinal = arc.resOrdinal;
|
|
13659
14334
|
if (resOrdinal === null) {
|
|
13660
14335
|
if (arc.invOrdinal >= recentOpenArcCutoff && arc.invOrdinal >= offset && arc.invOrdinal < end) {
|
|
13661
14336
|
end = Math.min(end, arc.invOrdinal);
|
|
13662
14337
|
}
|
|
13663
|
-
continue;
|
|
13664
|
-
}
|
|
13665
|
-
if (arc.invOrdinal < end && end <= resOrdinal) {
|
|
13666
|
-
end = Math.min(protectedTailStart, resOrdinal + 1);
|
|
13667
|
-
if (index.rangeTokens(Math.max(offset, arc.invOrdinal), end) > capTokens)
|
|
13668
|
-
oversizeAtomicUnit = true;
|
|
13669
14338
|
}
|
|
13670
14339
|
}
|
|
13671
14340
|
if (end <= offset && offset < protectedTailStart) {
|
|
@@ -14267,6 +14936,9 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
|
|
|
14267
14936
|
}
|
|
14268
14937
|
});
|
|
14269
14938
|
}
|
|
14939
|
+
function formatProjectedPostDropPercentage(value) {
|
|
14940
|
+
return value === null ? "none" : `${value.toFixed(1)}%`;
|
|
14941
|
+
}
|
|
14270
14942
|
function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride, reasoningProjection) {
|
|
14271
14943
|
if (sessionMeta.compartmentInProgress) {
|
|
14272
14944
|
sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
|
|
@@ -14327,10 +14999,10 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
|
|
|
14327
14999
|
const forceMaterializationPercentage = escalationBands(executeThresholdPercentage).forceMaterializationPercentage;
|
|
14328
15000
|
if (usage.percentage >= forceMaterializationPercentage) {
|
|
14329
15001
|
if (projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
|
|
14330
|
-
sessionLog(sessionId, `
|
|
15002
|
+
sessionLog(sessionId, `historian redundancy skip: summarizer not needed this pass — force band is ${forceMaterializationPercentage}%; queued/automatic drops are projected to reclaim to ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%) on the next eligible execute pass`);
|
|
14331
15003
|
return { shouldFire: false };
|
|
14332
15004
|
}
|
|
14333
|
-
sessionLog(sessionId, `compartment trigger: force-firing at ${usage.percentage.toFixed(1)}% (projected post-drop ${projectedPostDropPercentage
|
|
15005
|
+
sessionLog(sessionId, `compartment trigger: force-firing at ${usage.percentage.toFixed(1)}% (projected post-drop ${formatProjectedPostDropPercentage(projectedPostDropPercentage)})`);
|
|
14334
15006
|
if (tailInfo.boundarySnapshot && hasRunnableCompartmentWindow(tailInfo.boundarySnapshot)) {
|
|
14335
15007
|
return {
|
|
14336
15008
|
shouldFire: true,
|
|
@@ -14388,14 +15060,14 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
|
|
|
14388
15060
|
return { shouldFire: false };
|
|
14389
15061
|
}
|
|
14390
15062
|
if (projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
|
|
14391
|
-
sessionLog(sessionId, `
|
|
15063
|
+
sessionLog(sessionId, `historian redundancy skip: summarizer not needed this pass — usage is ${usage.percentage.toFixed(1)}%; queued/automatic drops are projected to reclaim to ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%) on the next eligible execute pass`);
|
|
14392
15064
|
return { shouldFire: false };
|
|
14393
15065
|
}
|
|
14394
15066
|
if (!tailInfo.hasProtectedEligibleHead || !tailInfo.isMeaningful) {
|
|
14395
15067
|
sessionLog(sessionId, `compartment trigger: not firing at ${usage.percentage.toFixed(1)}% because unsummarized tail from ${tailInfo.nextStartOrdinal} is too small`);
|
|
14396
15068
|
return { shouldFire: false };
|
|
14397
15069
|
}
|
|
14398
|
-
sessionLog(sessionId, `compartment trigger: proactive fire at ${usage.percentage.toFixed(1)}% (floor=${proactiveTriggerPercentage}% projected post-drop=${projectedPostDropPercentage
|
|
15070
|
+
sessionLog(sessionId, `compartment trigger: proactive fire at ${usage.percentage.toFixed(1)}% (floor=${proactiveTriggerPercentage}% projected post-drop=${formatProjectedPostDropPercentage(projectedPostDropPercentage)} target=${relativePostDropTarget.toFixed(1)}%)`);
|
|
14399
15071
|
return {
|
|
14400
15072
|
shouldFire: true,
|
|
14401
15073
|
reason: "projected_headroom",
|
|
@@ -14436,8 +15108,9 @@ function buildSupersessionReclaimOps(input) {
|
|
|
14436
15108
|
const action = input.targets.get(tag.tagNumber)?.readInput?.()?.action;
|
|
14437
15109
|
isTarget = typeof action === "string" && CTX_NOTE_ZERO_VALUE_ACTIONS.has(action);
|
|
14438
15110
|
}
|
|
14439
|
-
if (isTarget)
|
|
15111
|
+
if (isTarget && (!input.recentMessageIds || tag.toolOwnerMessageId !== null && !input.recentMessageIds.has(tag.toolOwnerMessageId))) {
|
|
14440
15112
|
dropTagIds.push(tag.tagNumber);
|
|
15113
|
+
}
|
|
14441
15114
|
}
|
|
14442
15115
|
const synthetic = [];
|
|
14443
15116
|
for (const tagId of dropTagIds) {
|
|
@@ -14470,6 +15143,9 @@ function buildEditSupersessionReclaim(input) {
|
|
|
14470
15143
|
seenFile.add(filePath);
|
|
14471
15144
|
continue;
|
|
14472
15145
|
}
|
|
15146
|
+
if (input.recentMessageIds && (tag.toolOwnerMessageId === null || input.recentMessageIds.has(tag.toolOwnerMessageId))) {
|
|
15147
|
+
continue;
|
|
15148
|
+
}
|
|
14473
15149
|
if (realPendingTagIds.has(tag.tagNumber))
|
|
14474
15150
|
continue;
|
|
14475
15151
|
if (input.targets.get(tag.tagNumber)?.canDrop?.() !== true)
|
|
@@ -15258,10 +15934,10 @@ var DEFAULT_MIN_PROMPT_CHARS = 20;
|
|
|
15258
15934
|
async function unifiedSearchWithTimeout(db, sessionId, projectPath, prompt, options, timeoutMs) {
|
|
15259
15935
|
const controller = new AbortController;
|
|
15260
15936
|
let timer;
|
|
15261
|
-
const timeoutPromise = new Promise((
|
|
15937
|
+
const timeoutPromise = new Promise((resolve3) => {
|
|
15262
15938
|
timer = setTimeout(() => {
|
|
15263
15939
|
controller.abort();
|
|
15264
|
-
|
|
15940
|
+
resolve3(null);
|
|
15265
15941
|
}, timeoutMs);
|
|
15266
15942
|
});
|
|
15267
15943
|
try {
|
|
@@ -16334,7 +17010,7 @@ function measurePiTailHygiene(input) {
|
|
|
16334
17010
|
}
|
|
16335
17011
|
continue;
|
|
16336
17012
|
}
|
|
16337
|
-
const content = part.text;
|
|
17013
|
+
const content = stripChannel1ReminderSpans(part.text);
|
|
16338
17014
|
const tag = parseVisibleTag(content, tagsByNumber) ?? messageTags.get(`${messageKey}:p${textOrdinal}`);
|
|
16339
17015
|
textOrdinal += 1;
|
|
16340
17016
|
if (!content || isDropSentinel(content)) {
|
|
@@ -16437,7 +17113,8 @@ function refreshPiTailHygieneBaseline(input) {
|
|
|
16437
17113
|
evaluable: true,
|
|
16438
17114
|
generationInvalidated: false,
|
|
16439
17115
|
baselineParts: measured.parts,
|
|
16440
|
-
contentSignature: measured.contentSignature
|
|
17116
|
+
contentSignature: measured.contentSignature,
|
|
17117
|
+
channel1PostReduceGrace: input.previous?.channel1PostReduceGrace
|
|
16441
17118
|
};
|
|
16442
17119
|
}
|
|
16443
17120
|
const prefix = sameMeasuredPrefix(input.previous.baselineParts, measured.parts);
|
|
@@ -16511,8 +17188,15 @@ function markPiChannel1Reduced(sessionId, db) {
|
|
|
16511
17188
|
state2.evaluable = false;
|
|
16512
17189
|
state2.generationInvalidated = true;
|
|
16513
17190
|
}
|
|
16514
|
-
if (db)
|
|
16515
|
-
|
|
17191
|
+
if (!db)
|
|
17192
|
+
return;
|
|
17193
|
+
const grace = markChannel1PostReduceGracePending(db, sessionId);
|
|
17194
|
+
if (state2) {
|
|
17195
|
+
state2.channel1PostReduceGrace = {
|
|
17196
|
+
pending: true,
|
|
17197
|
+
preReduceLevel: grace.postReduceGracePreLevel ?? grace.level
|
|
17198
|
+
};
|
|
17199
|
+
}
|
|
16516
17200
|
}
|
|
16517
17201
|
function isPiTextContent(c) {
|
|
16518
17202
|
return c !== null && typeof c === "object" && c.type === "text" && typeof c.text === "string";
|
|
@@ -16531,10 +17215,7 @@ function maybeChannel1ReminderForToolResult(args) {
|
|
|
16531
17215
|
if (!state2)
|
|
16532
17216
|
return null;
|
|
16533
17217
|
if (toolName === "ctx_reduce") {
|
|
16534
|
-
|
|
16535
|
-
state2.evaluable = false;
|
|
16536
|
-
state2.generationInvalidated = true;
|
|
16537
|
-
resetLastNudgeCycle(db, sessionId);
|
|
17218
|
+
markPiChannel1Reduced(sessionId, db);
|
|
16538
17219
|
return null;
|
|
16539
17220
|
}
|
|
16540
17221
|
const text = toolResultText(args.content);
|
|
@@ -16551,28 +17232,32 @@ function maybeChannel1ReminderForToolResult(args) {
|
|
|
16551
17232
|
...state2,
|
|
16552
17233
|
lastNudgeUndropped: getLastNudgeUndropped(db, sessionId),
|
|
16553
17234
|
lastNudgeLevel: nudgeState.level,
|
|
16554
|
-
|
|
17235
|
+
lastFireOrdinal: nudgeState.ordinal,
|
|
17236
|
+
currentRealUserTurnCount: state2.realUserTurnCount,
|
|
17237
|
+
hasRecentReduce: state2.reducedSinceRefresh,
|
|
17238
|
+
postReduceGracePending: nudgeState.postReduceGracePending,
|
|
17239
|
+
postReduceGraceBaselineU: nudgeState.postReduceGraceBaselineU,
|
|
17240
|
+
postReduceGracePreLevel: nudgeState.postReduceGracePreLevel
|
|
16555
17241
|
});
|
|
16556
17242
|
setLastNudgeUndropped(db, sessionId, decision.nextLastNudge);
|
|
17243
|
+
const nextNudgeState = {
|
|
17244
|
+
...nudgeState,
|
|
17245
|
+
level: decision.nextLastNudgeLevel,
|
|
17246
|
+
ordinal: decision.nextLastNudgeLevel === "" ? 0 : nudgeState.ordinal,
|
|
17247
|
+
postReduceGracePending: decision.clearPostReduceGrace ? undefined : nudgeState.postReduceGracePending,
|
|
17248
|
+
postReduceGraceBaselineU: decision.clearPostReduceGrace ? undefined : nudgeState.postReduceGraceBaselineU,
|
|
17249
|
+
postReduceGracePreLevel: decision.clearPostReduceGrace ? undefined : nudgeState.postReduceGracePreLevel
|
|
17250
|
+
};
|
|
16557
17251
|
if (!decision.fire) {
|
|
16558
|
-
setChannel1NudgeState(db, sessionId,
|
|
16559
|
-
level: decision.nextLastNudgeLevel,
|
|
16560
|
-
ordinal: decision.nextLastNudgeLevel === "" ? 0 : nudgeState.ordinal
|
|
16561
|
-
});
|
|
17252
|
+
setChannel1NudgeState(db, sessionId, nextNudgeState);
|
|
16562
17253
|
return null;
|
|
16563
17254
|
}
|
|
16564
|
-
const sticky = shouldUseStickyChannel1Reminder({
|
|
16565
|
-
lastLevel: nudgeState.level,
|
|
16566
|
-
lastOrdinal: nudgeState.ordinal,
|
|
16567
|
-
level: decision.level,
|
|
16568
|
-
currentRealUserTurnCount: state2.realUserTurnCount
|
|
16569
|
-
});
|
|
16570
17255
|
const block = {
|
|
16571
17256
|
type: "text",
|
|
16572
|
-
text: buildChannel1Reminder(decision.level, decision.undroppedTokens, state2.
|
|
17257
|
+
text: buildChannel1Reminder(decision.level, decision.undroppedTokens, reclaimableToolOutputCount(state2.baselineParts), state2.oldestReclaimableToolTags, decision.sticky)
|
|
16573
17258
|
};
|
|
16574
17259
|
setChannel1NudgeState(db, sessionId, {
|
|
16575
|
-
|
|
17260
|
+
...nextNudgeState,
|
|
16576
17261
|
ordinal: state2.realUserTurnCount
|
|
16577
17262
|
});
|
|
16578
17263
|
return block;
|
|
@@ -16606,7 +17291,7 @@ function maybeDeliverChannel2Pi(pi, db, sessionId) {
|
|
|
16606
17291
|
try {
|
|
16607
17292
|
const message = {
|
|
16608
17293
|
customType: CHANNEL2_NUDGE_CUSTOM_TYPE,
|
|
16609
|
-
content: buildChannel2Reminder(undropped, baseline.
|
|
17294
|
+
content: buildChannel2Reminder(undropped, reclaimableToolOutputCount(baseline.baselineParts), baseline.oldestReclaimableToolTags),
|
|
16610
17295
|
display: false,
|
|
16611
17296
|
details: { kind: "channel-2-ceiling-nudge" }
|
|
16612
17297
|
};
|
|
@@ -16896,6 +17581,8 @@ function piImageFromDataUrl(dataUrl) {
|
|
|
16896
17581
|
return { type: "image", mimeType: match[1], data: match[2] };
|
|
16897
17582
|
}
|
|
16898
17583
|
function resolveMuralForM0Pi(state2, db, modelKey, budgetTokens) {
|
|
17584
|
+
if (state2.memoryEnabled === false)
|
|
17585
|
+
return;
|
|
16899
17586
|
if (state2.mural)
|
|
16900
17587
|
return state2.mural;
|
|
16901
17588
|
if (!state2.muralEnabled)
|
|
@@ -17107,7 +17794,7 @@ function renderM0Pi(state2, db, projectDocs = readProjectDocsForPiM0(state2).ren
|
|
|
17107
17794
|
const sections = [];
|
|
17108
17795
|
if (projectDocs.length > 0)
|
|
17109
17796
|
sections.push(projectDocs);
|
|
17110
|
-
const trimmedProfile = trimUserMemoriesToBudget(userProfileOverride ?? safeGetActiveUserMemoriesPi(db), state2.userProfileBudgetTokens ?? DEFAULT_USER_PROFILE_BUDGET_TOKENS);
|
|
17797
|
+
const trimmedProfile = trimUserMemoriesToBudget(state2.memoryEnabled === false ? [] : userProfileOverride ?? safeGetActiveUserMemoriesPi(db), state2.userProfileBudgetTokens ?? DEFAULT_USER_PROFILE_BUDGET_TOKENS);
|
|
17111
17798
|
const userProfile = renderUserProfileBlock(db, "user-profile", trimmedProfile);
|
|
17112
17799
|
if (userProfile.length > 0)
|
|
17113
17800
|
sections.push(userProfile);
|
|
@@ -17167,7 +17854,7 @@ function readFrozenM0InputsPi(state2, db, docs = readProjectDocsForPiM0(state2),
|
|
|
17167
17854
|
const workspace = resolveWorkspaceRenderContextPi(state2, db);
|
|
17168
17855
|
const compartments = getRenderableCompartmentsPi(db, state2);
|
|
17169
17856
|
const memories = memPath ? workspace.isWorkspaced ? getMemoriesByProjects(db, workspace.expandedIdentities, ["active", "permanent"], memoryCutoff, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(db, memPath, ["active", "permanent"], memoryCutoff) : [];
|
|
17170
|
-
const userProfile = safeGetActiveUserMemoriesPi(db);
|
|
17857
|
+
const userProfile = state2.memoryEnabled === false ? [] : safeGetActiveUserMemoriesPi(db);
|
|
17171
17858
|
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
17172
17859
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
17173
17860
|
const markers = {
|
|
@@ -17187,7 +17874,7 @@ function readFrozenM0InputsPi(state2, db, docs = readProjectDocsForPiM0(state2),
|
|
|
17187
17874
|
systemHash: (state2.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
|
|
17188
17875
|
modelKey: piModelRefToCanonical((state2.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey),
|
|
17189
17876
|
projectIdentity: state2.projectIdentity,
|
|
17190
|
-
muralEnabled: state2.muralEnabled === true,
|
|
17877
|
+
muralEnabled: state2.memoryEnabled !== false && state2.muralEnabled === true,
|
|
17191
17878
|
renderBudgetIdentity: renderBudgetIdentityPi(state2)
|
|
17192
17879
|
};
|
|
17193
17880
|
return { docs, markers, compartments, memories, userProfile, workspace };
|
|
@@ -17409,7 +18096,7 @@ ${body}
|
|
|
17409
18096
|
if (newMemoriesBlock)
|
|
17410
18097
|
sections.push(newMemoriesBlock);
|
|
17411
18098
|
const currentUserProfileVersion = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH)?.projectUserProfileVersion ?? 0;
|
|
17412
|
-
if (currentUserProfileVersion !== markers.projectUserProfileVersion) {
|
|
18099
|
+
if (state2.memoryEnabled !== false && currentUserProfileVersion !== markers.projectUserProfileVersion) {
|
|
17413
18100
|
const profileBudget = state2.userProfileBudgetTokens ?? DEFAULT_USER_PROFILE_BUDGET_TOKENS;
|
|
17414
18101
|
const trimmedProfile = trimUserMemoriesToBudget(safeGetActiveUserMemoriesPi(db), Math.max(1, Math.floor(profileBudget * 0.25)));
|
|
17415
18102
|
const profileBlock = renderUserProfileBlock(db, "new-user-profile", trimmedProfile);
|
|
@@ -20994,7 +21681,7 @@ async function sleepWithAbort(ms, signal) {
|
|
|
20994
21681
|
return true;
|
|
20995
21682
|
if (ms <= 0)
|
|
20996
21683
|
return signal?.aborted === true;
|
|
20997
|
-
return new Promise((
|
|
21684
|
+
return new Promise((resolve3) => {
|
|
20998
21685
|
let settled = false;
|
|
20999
21686
|
let timeout;
|
|
21000
21687
|
const finish = (aborted) => {
|
|
@@ -21004,7 +21691,7 @@ async function sleepWithAbort(ms, signal) {
|
|
|
21004
21691
|
if (timeout)
|
|
21005
21692
|
clearTimeout(timeout);
|
|
21006
21693
|
signal?.removeEventListener("abort", onAbort);
|
|
21007
|
-
|
|
21694
|
+
resolve3(aborted);
|
|
21008
21695
|
};
|
|
21009
21696
|
const onAbort = () => finish(true);
|
|
21010
21697
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -21123,6 +21810,8 @@ async function runPiHistorian(deps) {
|
|
|
21123
21810
|
refreshBoundarySnapshot,
|
|
21124
21811
|
currentContextLimit,
|
|
21125
21812
|
historianTimeoutMs = DEFAULT_HISTORIAN_TIMEOUT_MS2,
|
|
21813
|
+
temperature,
|
|
21814
|
+
maxOutputTokens = 32000,
|
|
21126
21815
|
signal,
|
|
21127
21816
|
retryBackoffMs,
|
|
21128
21817
|
twoPass,
|
|
@@ -21235,9 +21924,9 @@ async function runPiHistorian(deps) {
|
|
|
21235
21924
|
executeThresholdPercentage: boundarySnapshot.executeThresholdPercentage
|
|
21236
21925
|
});
|
|
21237
21926
|
if (!reserve.ok) {
|
|
21238
|
-
sessionLog(sessionId,
|
|
21927
|
+
sessionLog(sessionId, describeProtectedTailDrainBudgetSkip(reserve));
|
|
21239
21928
|
telemetry.status = "noop";
|
|
21240
|
-
telemetry.failureReason = "protected-tail drain
|
|
21929
|
+
telemetry.failureReason = "internal protected-tail drain budget spent";
|
|
21241
21930
|
return;
|
|
21242
21931
|
}
|
|
21243
21932
|
drainReservation = reserve.reservation;
|
|
@@ -21350,6 +22039,8 @@ ${chunkText}`,
|
|
|
21350
22039
|
cwd: directory,
|
|
21351
22040
|
signal,
|
|
21352
22041
|
thinkingLevel,
|
|
22042
|
+
temperature,
|
|
22043
|
+
maxOutputTokens,
|
|
21353
22044
|
onProgress: buildProgressLogger("first"),
|
|
21354
22045
|
accountingSessionId: sessionId,
|
|
21355
22046
|
accountingSubagent: "historian"
|
|
@@ -21374,6 +22065,8 @@ ${chunkText}`,
|
|
|
21374
22065
|
cwd: directory,
|
|
21375
22066
|
signal,
|
|
21376
22067
|
thinkingLevel,
|
|
22068
|
+
temperature,
|
|
22069
|
+
maxOutputTokens,
|
|
21377
22070
|
onProgress: buildProgressLogger("repair"),
|
|
21378
22071
|
accountingSessionId: sessionId,
|
|
21379
22072
|
accountingSubagent: "historian"
|
|
@@ -21403,6 +22096,8 @@ ${chunkText}`,
|
|
|
21403
22096
|
cwd: directory,
|
|
21404
22097
|
signal,
|
|
21405
22098
|
thinkingLevel: candidate.entry.qualifier,
|
|
22099
|
+
temperature,
|
|
22100
|
+
maxOutputTokens,
|
|
21406
22101
|
onProgress: buildProgressLogger("fallback"),
|
|
21407
22102
|
accountingSessionId: sessionId,
|
|
21408
22103
|
accountingSubagent: "historian"
|
|
@@ -21449,6 +22144,8 @@ ${chunkText}`,
|
|
|
21449
22144
|
cwd: directory,
|
|
21450
22145
|
signal,
|
|
21451
22146
|
thinkingLevel,
|
|
22147
|
+
temperature,
|
|
22148
|
+
maxOutputTokens,
|
|
21452
22149
|
onProgress: buildProgressLogger("editor"),
|
|
21453
22150
|
accountingSessionId: sessionId,
|
|
21454
22151
|
accountingSubagent: "historian_editor"
|
|
@@ -21759,6 +22456,62 @@ function findFirstKeptEntryId(entries, lastCompactedOrdinal) {
|
|
|
21759
22456
|
return boundary.id;
|
|
21760
22457
|
}
|
|
21761
22458
|
|
|
22459
|
+
// src/pi-pressure.ts
|
|
22460
|
+
function extractAssistantUsage(message) {
|
|
22461
|
+
if (!message || typeof message !== "object")
|
|
22462
|
+
return null;
|
|
22463
|
+
const m = message;
|
|
22464
|
+
if (m.role !== "assistant")
|
|
22465
|
+
return null;
|
|
22466
|
+
if (!m.usage || typeof m.usage !== "object")
|
|
22467
|
+
return null;
|
|
22468
|
+
const u = m.usage;
|
|
22469
|
+
const result = {};
|
|
22470
|
+
if (typeof u.input === "number")
|
|
22471
|
+
result.input = u.input;
|
|
22472
|
+
if (typeof u.output === "number")
|
|
22473
|
+
result.output = u.output;
|
|
22474
|
+
if (typeof u.cacheRead === "number")
|
|
22475
|
+
result.cacheRead = u.cacheRead;
|
|
22476
|
+
if (typeof u.cacheWrite === "number")
|
|
22477
|
+
result.cacheWrite = u.cacheWrite;
|
|
22478
|
+
if (typeof u.totalTokens === "number")
|
|
22479
|
+
result.totalTokens = u.totalTokens;
|
|
22480
|
+
return result;
|
|
22481
|
+
}
|
|
22482
|
+
function computePiPressure(usage, contextLimit) {
|
|
22483
|
+
if (!usage)
|
|
22484
|
+
return null;
|
|
22485
|
+
const input = usage.input ?? 0;
|
|
22486
|
+
const cacheRead = usage.cacheRead ?? 0;
|
|
22487
|
+
const cacheWrite = usage.cacheWrite ?? 0;
|
|
22488
|
+
const inputTokens = input + cacheRead + cacheWrite;
|
|
22489
|
+
if (inputTokens === 0)
|
|
22490
|
+
return null;
|
|
22491
|
+
const percentage = contextLimit > 0 ? inputTokens / contextLimit * 100 : 0;
|
|
22492
|
+
return { inputTokens, percentage };
|
|
22493
|
+
}
|
|
22494
|
+
function resolvePiPressureSnapshot(args) {
|
|
22495
|
+
const persistedInputTokens = Number.isFinite(args.persistedInputTokens) && args.persistedInputTokens > 0 ? args.persistedInputTokens : 0;
|
|
22496
|
+
const liveInputTokens = typeof args.liveInputTokens === "number" && Number.isFinite(args.liveInputTokens) && args.liveInputTokens > 0 ? args.liveInputTokens : 0;
|
|
22497
|
+
const inputTokens = Math.max(persistedInputTokens, liveInputTokens);
|
|
22498
|
+
const contextLimit = typeof args.usableContextLimit === "number" && Number.isFinite(args.usableContextLimit) && args.usableContextLimit > 0 ? args.usableContextLimit : undefined;
|
|
22499
|
+
if (contextLimit !== undefined) {
|
|
22500
|
+
return {
|
|
22501
|
+
inputTokens,
|
|
22502
|
+
percentage: inputTokens > 0 ? inputTokens / contextLimit * 100 : 0,
|
|
22503
|
+
contextLimit
|
|
22504
|
+
};
|
|
22505
|
+
}
|
|
22506
|
+
return {
|
|
22507
|
+
inputTokens: persistedInputTokens,
|
|
22508
|
+
percentage: Number.isFinite(args.persistedPercentage) && args.persistedPercentage > 0 ? args.persistedPercentage : 0
|
|
22509
|
+
};
|
|
22510
|
+
}
|
|
22511
|
+
function formatPiPressureForLog(snapshot) {
|
|
22512
|
+
return `usage=${snapshot.percentage.toFixed(1)}% (${snapshot.inputTokens} tokens, limit=${snapshot.contextLimit ?? "?"})`;
|
|
22513
|
+
}
|
|
22514
|
+
|
|
21762
22515
|
// src/pi-todo-inject.ts
|
|
21763
22516
|
function getMessageId(message) {
|
|
21764
22517
|
if (typeof message.responseId === "string" && message.responseId.length > 0) {
|
|
@@ -22585,8 +23338,8 @@ function injectPiTemporalMarkers(messages) {
|
|
|
22585
23338
|
// src/timeout.ts
|
|
22586
23339
|
function withTimeout(p, ms) {
|
|
22587
23340
|
let handle;
|
|
22588
|
-
const timeout = new Promise((
|
|
22589
|
-
handle = setTimeout(() =>
|
|
23341
|
+
const timeout = new Promise((resolve3) => {
|
|
23342
|
+
handle = setTimeout(() => resolve3(undefined), ms);
|
|
22590
23343
|
handle.unref?.();
|
|
22591
23344
|
});
|
|
22592
23345
|
return Promise.race([p, timeout]).finally(() => {
|
|
@@ -23300,26 +24053,14 @@ function extractStableId(msg, index, entryIds) {
|
|
|
23300
24053
|
|
|
23301
24054
|
// src/context-handler.ts
|
|
23302
24055
|
var EMERGENCY_BLOCK_PERCENTAGE = 95;
|
|
23303
|
-
var FORWARD_PRESSURE_LIMIT_FACTOR = 0.85;
|
|
23304
24056
|
function isPiHardCacheExpired(lastResponseTime, ttlMs, now) {
|
|
23305
24057
|
return lastResponseTime > 0 && now - lastResponseTime > ttlMs;
|
|
23306
24058
|
}
|
|
23307
|
-
function applyForwardPressureFloor(trailingPercentage, trailingInputTokens, piUsageTokens, correctedLimit) {
|
|
23308
|
-
const forwardTokens = typeof piUsageTokens === "number" && piUsageTokens > 0 ? piUsageTokens : 0;
|
|
23309
|
-
if (forwardTokens === 0 || !isSaneLimit(correctedLimit)) {
|
|
23310
|
-
return { percentage: trailingPercentage, inputTokens: trailingInputTokens };
|
|
23311
|
-
}
|
|
23312
|
-
const forwardPressureLimit = correctedLimit * FORWARD_PRESSURE_LIMIT_FACTOR;
|
|
23313
|
-
const forwardPercentage = forwardTokens / forwardPressureLimit * 100;
|
|
23314
|
-
return forwardPercentage > trailingPercentage ? {
|
|
23315
|
-
percentage: forwardPercentage,
|
|
23316
|
-
inputTokens: Math.max(trailingInputTokens, forwardTokens)
|
|
23317
|
-
} : { percentage: trailingPercentage, inputTokens: trailingInputTokens };
|
|
23318
|
-
}
|
|
23319
24059
|
var injectM0M1PiForRun = injectM0M1Pi;
|
|
23320
24060
|
var persistReasoningWatermarkForRun = updateSessionMeta;
|
|
23321
24061
|
var persistStableIdSchemeForRun = updateSessionMeta;
|
|
23322
24062
|
var afterFallbackAdoptionForTests;
|
|
24063
|
+
var pendingDecisionLogObserverForTests;
|
|
23323
24064
|
var mutationGateObserverForTests;
|
|
23324
24065
|
var DEFAULT_CLEAR_REASONING_AGE = 50;
|
|
23325
24066
|
var PI_STABLE_ID_SCHEME = 1;
|
|
@@ -24255,7 +24996,12 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
24255
24996
|
if (!usedPersistedUsage && isSaneLimit(usageContextLimit) && usageInputTokens > 0) {
|
|
24256
24997
|
usagePercentage = usageInputTokens / usageContextLimit * 100;
|
|
24257
24998
|
}
|
|
24258
|
-
({ percentage: usagePercentage, inputTokens: usageInputTokens } =
|
|
24999
|
+
({ percentage: usagePercentage, inputTokens: usageInputTokens } = resolvePiPressureSnapshot({
|
|
25000
|
+
persistedPercentage: usagePercentage,
|
|
25001
|
+
persistedInputTokens: usageInputTokens,
|
|
25002
|
+
liveInputTokens: piUsage?.tokens,
|
|
25003
|
+
usableContextLimit: usageContextLimit
|
|
25004
|
+
}));
|
|
24259
25005
|
const realUsagePercentageBeforeEmergencyBump = usagePercentage;
|
|
24260
25006
|
if (needsEmergencyBump) {
|
|
24261
25007
|
sessionLog(sessionId, `transform: overflow recovery flag set — bumping percentage to 95% (detectedLimit=${usageContextLimit ?? "unknown"})`);
|
|
@@ -24298,9 +25044,14 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
24298
25044
|
sessionId,
|
|
24299
25045
|
effectiveExecuteThresholdPercentage
|
|
24300
25046
|
});
|
|
24301
|
-
const {
|
|
25047
|
+
const {
|
|
25048
|
+
midTurnAdjustedSchedulerDecision,
|
|
25049
|
+
sideEffect,
|
|
25050
|
+
deferReason: schedulerDeferReason
|
|
25051
|
+
} = options.compactionOff ? {
|
|
24302
25052
|
midTurnAdjustedSchedulerDecision: "defer",
|
|
24303
|
-
sideEffect: "none"
|
|
25053
|
+
sideEffect: "none",
|
|
25054
|
+
deferReason: "scheduler_defer"
|
|
24304
25055
|
} : applyMidTurnDeferral({
|
|
24305
25056
|
base: schedulerDecisionEarly,
|
|
24306
25057
|
bypassReason,
|
|
@@ -24317,6 +25068,9 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
24317
25068
|
schedulerDecision = midTurnAdjustedSchedulerDecision;
|
|
24318
25069
|
sessionLog(sessionId, `[boundary-exec] base=${schedulerDecisionEarly} bypass=${bypassReason} midTurn=${midTurn} effective=${midTurnAdjustedSchedulerDecision} sideEffect=${sideEffect}`);
|
|
24319
25070
|
const forceMaterialization = !options.compactionOff && usagePercentage >= forceMaterializationPercentage;
|
|
25071
|
+
if (!forceMaterialization && getEmergencyInputSample(options.db, sessionId) > 0) {
|
|
25072
|
+
clearEmergencyDropSample(options.db, sessionId);
|
|
25073
|
+
}
|
|
24320
25074
|
const hardUsagePercentage = needsEmergencyBump ? Math.max(EMERGENCY_BLOCK_PERCENTAGE, usagePercentage) : windowGeometry?.usableHard && usageInputTokens > 0 ? usageInputTokens / windowGeometry.usableHard * 100 : usagePercentage;
|
|
24321
25075
|
const emergencyPercentage = ctx.model ? hardUsagePercentage : usagePercentage;
|
|
24322
25076
|
const isEmergency = !options.compactionOff && emergencyPercentage >= EMERGENCY_BLOCK_PERCENTAGE;
|
|
@@ -24346,7 +25100,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
24346
25100
|
}
|
|
24347
25101
|
const isCacheBusting = historyRefreshSessions.has(sessionId);
|
|
24348
25102
|
logTransformTiming(sessionId, "boundaryTriggerChecks", tBoundaryChecks);
|
|
24349
|
-
sessionLog(sessionId, `transform:
|
|
25103
|
+
sessionLog(sessionId, `transform: ${formatPiPressureForLog({ percentage: usagePercentage, inputTokens: usageInputTokens, contextLimit: usageContextLimit })} decision=${schedulerDecision}${forceMaterialization ? " force=true" : ""}${isEmergency ? " EMERGENCY=true" : ""}${isCacheBusting ? " busting=true" : ""}`);
|
|
24350
25104
|
logTransformTiming(sessionId, "emergencyRecoveryBlock", tEmergencyRecovery);
|
|
24351
25105
|
const entryIds = strictEntryIds ?? undefined;
|
|
24352
25106
|
const emergencyCeilingTokens = usageContextLimit && usageContextLimit > 0 ? Math.floor(usageContextLimit * (resolveExecuteThreshold(schedulerConfig.executeThresholdPercentage ?? 65, liveModelBySession.get(sessionId), 65, {
|
|
@@ -24386,6 +25140,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
24386
25140
|
reusableMessageIds,
|
|
24387
25141
|
stableIdSchemeCutover,
|
|
24388
25142
|
schedulerDecision,
|
|
25143
|
+
schedulerDeferReason,
|
|
24389
25144
|
forceMaterialization: forceMaterialization || isEmergency,
|
|
24390
25145
|
forceMaterializationPercentage,
|
|
24391
25146
|
contextUsage: {
|
|
@@ -24524,7 +25279,12 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
24524
25279
|
previous: getPiChannel1Baseline(sessionId)
|
|
24525
25280
|
});
|
|
24526
25281
|
const effective = effectivePiTailHygiene(baseline);
|
|
24527
|
-
|
|
25282
|
+
const durableGrace = baseline.evaluable && !baseline.generationInvalidated ? captureChannel1PostReduceGraceBaseline(options.db, sessionId, effective.u) : getChannel1NudgeState(options.db, sessionId);
|
|
25283
|
+
baseline.channel1PostReduceGrace = durableGrace.postReduceGracePending || durableGrace.postReduceGraceBaselineU !== undefined ? {
|
|
25284
|
+
pending: durableGrace.postReduceGracePending === true,
|
|
25285
|
+
baselineU: durableGrace.postReduceGraceBaselineU,
|
|
25286
|
+
preReduceLevel: durableGrace.postReduceGracePreLevel ?? durableGrace.level
|
|
25287
|
+
} : undefined;
|
|
24528
25288
|
const oldestReclaimableToolTags = getOldestActiveUnprotectedToolTags(options.db, sessionId, protectedTags);
|
|
24529
25289
|
const channelState = {
|
|
24530
25290
|
...baseline,
|
|
@@ -24631,10 +25391,11 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
24631
25391
|
log("[magic-context][pi] registered context handler (tagging + drops + nudges)");
|
|
24632
25392
|
}
|
|
24633
25393
|
var inFlightHistorian = new Map;
|
|
24634
|
-
async function awaitInFlightHistorians() {
|
|
24635
|
-
|
|
25394
|
+
async function awaitInFlightHistorians(sessionId) {
|
|
25395
|
+
const runs = sessionId ? [inFlightHistorian.get(sessionId)].filter((run) => run !== undefined) : [...inFlightHistorian.values()];
|
|
25396
|
+
if (runs.length === 0)
|
|
24636
25397
|
return;
|
|
24637
|
-
await Promise.allSettled(
|
|
25398
|
+
await Promise.allSettled(runs);
|
|
24638
25399
|
}
|
|
24639
25400
|
function resolvePiHistorianTriggerInputs(args) {
|
|
24640
25401
|
const contextLimit = typeof args.usageContextLimit === "number" && Number.isFinite(args.usageContextLimit) && args.usageContextLimit > 0 ? args.usageContextLimit : DEFAULT_CONTEXT_LIMIT;
|
|
@@ -24771,6 +25532,8 @@ function spawnPiHistorianRun(args) {
|
|
|
24771
25532
|
refreshBoundarySnapshot,
|
|
24772
25533
|
currentContextLimit,
|
|
24773
25534
|
historianTimeoutMs: historian.timeoutMs,
|
|
25535
|
+
temperature: historian.temperature,
|
|
25536
|
+
maxOutputTokens: historian.maxOutputTokens,
|
|
24774
25537
|
twoPass: historian.twoPass,
|
|
24775
25538
|
thinkingLevel: historian.thinkingLevel,
|
|
24776
25539
|
memoryEnabled: historian.memoryEnabled,
|
|
@@ -24889,7 +25652,12 @@ function maybeFireHistorian(args) {
|
|
|
24889
25652
|
};
|
|
24890
25653
|
usageSource = "piUsage fallback";
|
|
24891
25654
|
}
|
|
24892
|
-
usage =
|
|
25655
|
+
usage = resolvePiPressureSnapshot({
|
|
25656
|
+
persistedPercentage: usage.percentage,
|
|
25657
|
+
persistedInputTokens: usage.inputTokens,
|
|
25658
|
+
liveInputTokens: piUsage?.tokens,
|
|
25659
|
+
usableContextLimit: usageContextLimit
|
|
25660
|
+
});
|
|
24893
25661
|
sessionLog(sessionId, `historian trigger eval: usage=${usage.percentage.toFixed(1)}% (${usage.inputTokens} tokens) [${usageSource}], checking trigger...`);
|
|
24894
25662
|
} catch (err) {
|
|
24895
25663
|
sessionLog(sessionId, `historian trigger eval: getContextUsage threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -25270,7 +26038,10 @@ async function runPipeline(args) {
|
|
|
25270
26038
|
});
|
|
25271
26039
|
if (shouldApplyPendingOps) {
|
|
25272
26040
|
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : foldExecutedThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
25273
|
-
|
|
26041
|
+
const pendingOpsDepth = getPendingOpsCount(args.db, args.sessionId);
|
|
26042
|
+
const pendingDecisionLog = `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOpsDepth === null ? "not loaded (deferred pass)" : pendingOpsDepth} context=${args.contextUsage.percentage.toFixed(1)}%`;
|
|
26043
|
+
sessionLog(args.sessionId, pendingDecisionLog);
|
|
26044
|
+
pendingDecisionLogObserverForTests?.(pendingDecisionLog);
|
|
25274
26045
|
try {
|
|
25275
26046
|
const tApplyPending = performance.now();
|
|
25276
26047
|
pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, targets, args.protectedTags, pendingOperationTags, pendingOps);
|
|
@@ -25291,7 +26062,11 @@ async function runPipeline(args) {
|
|
|
25291
26062
|
throw err;
|
|
25292
26063
|
}
|
|
25293
26064
|
} else {
|
|
25294
|
-
|
|
26065
|
+
const pendingOpsDepth = getPendingOpsCount(args.db, args.sessionId);
|
|
26066
|
+
const refusalReason = args.schedulerDeferReason ?? (historianRunning ? "historian_in_flight" : "scheduler_defer");
|
|
26067
|
+
const pendingDecisionLog = `pending ops WILL NOT APPLY — reason=${refusalReason} pendingOps=${pendingOpsDepth === null ? "not loaded (deferred pass)" : pendingOpsDepth} context=${args.contextUsage.percentage.toFixed(1)}%`;
|
|
26068
|
+
sessionLog(args.sessionId, pendingDecisionLog);
|
|
26069
|
+
pendingDecisionLogObserverForTests?.(pendingDecisionLog);
|
|
25295
26070
|
}
|
|
25296
26071
|
const targetTagNumbers = [...targets.keys()];
|
|
25297
26072
|
const tGetTags = performance.now();
|
|
@@ -25348,14 +26123,22 @@ async function runPipeline(args) {
|
|
|
25348
26123
|
logTransformTiming(args.sessionId, "getActiveTagsBySession", tActiveTags, `count=${activeTags.length}`);
|
|
25349
26124
|
if (shouldRunHeuristics) {
|
|
25350
26125
|
const reason = args.forceMaterialization ? "force_materialization" : foldExecutedThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
25351
|
-
|
|
26126
|
+
const heuristicsDecisionLog = `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=n/a`;
|
|
26127
|
+
sessionLog(args.sessionId, heuristicsDecisionLog);
|
|
26128
|
+
pendingDecisionLogObserverForTests?.(heuristicsDecisionLog);
|
|
25352
26129
|
} else {
|
|
25353
|
-
const reason = args.heuristics === undefined ? "disabled" : "scheduler_defer";
|
|
25354
|
-
|
|
26130
|
+
const reason = args.heuristics === undefined ? "disabled" : args.schedulerDeferReason ?? (historianRunning ? "historian_in_flight" : alreadyRanHeuristicsThisTurn ? "already_ran_this_turn" : "scheduler_defer");
|
|
26131
|
+
const heuristicsDecisionLog = `heuristics WILL NOT RUN — reason=${reason}`;
|
|
26132
|
+
sessionLog(args.sessionId, heuristicsDecisionLog);
|
|
26133
|
+
pendingDecisionLogObserverForTests?.(heuristicsDecisionLog);
|
|
25355
26134
|
}
|
|
25356
26135
|
if (shouldRunHeuristics && args.heuristics) {
|
|
25357
26136
|
try {
|
|
25358
26137
|
const tHeuristic = performance.now();
|
|
26138
|
+
const independentMutationBeforeHeuristics = pendingOpsDidMutate || foldExecutedThisPass;
|
|
26139
|
+
if (args.forceMaterialization === true && independentMutationBeforeHeuristics && getEmergencyInputSample(args.db, args.sessionId) > 0) {
|
|
26140
|
+
clearEmergencyDropSample(args.db, args.sessionId);
|
|
26141
|
+
}
|
|
25359
26142
|
heuristicsResult = applyPiHeuristicCleanup(args.sessionId, args.db, targets, args.messages, {
|
|
25360
26143
|
protectedTags: args.protectedTags,
|
|
25361
26144
|
staleReduceStripEnabled: args.canUseEmptySentinels,
|
|
@@ -25875,9 +26658,10 @@ function registerCtxFlushCommand(pi, deps) {
|
|
|
25875
26658
|
pi.registerCommand("ctx-flush", {
|
|
25876
26659
|
description: "Force pending Magic Context drops to materialize on the next provider call",
|
|
25877
26660
|
handler: async (_args, ctx) => {
|
|
26661
|
+
const sendStatus = createCtxStatusSender(pi, ctx);
|
|
25878
26662
|
const sessionId = resolveSessionId(ctx);
|
|
25879
26663
|
if (!sessionId) {
|
|
25880
|
-
|
|
26664
|
+
sendStatus({
|
|
25881
26665
|
title: "/ctx-flush",
|
|
25882
26666
|
text: `## /ctx-flush
|
|
25883
26667
|
|
|
@@ -25887,7 +26671,7 @@ No active Pi session is available.`,
|
|
|
25887
26671
|
return;
|
|
25888
26672
|
}
|
|
25889
26673
|
if (deps.compactionOff) {
|
|
25890
|
-
|
|
26674
|
+
sendStatus({
|
|
25891
26675
|
title: "/ctx-flush",
|
|
25892
26676
|
text: COMPACTION_OFF_COMMAND_UNAVAILABLE,
|
|
25893
26677
|
level: "warning"
|
|
@@ -25906,7 +26690,7 @@ Flushed ${pendingBefore} pending ops; next provider call will materialize.
|
|
|
25906
26690
|
${result}` : `## /ctx-flush
|
|
25907
26691
|
|
|
25908
26692
|
${result}`;
|
|
25909
|
-
|
|
26693
|
+
sendStatus({
|
|
25910
26694
|
title: "/ctx-flush",
|
|
25911
26695
|
text,
|
|
25912
26696
|
level: result.startsWith("Error:") ? "error" : "success"
|
|
@@ -25926,7 +26710,7 @@ function cleanupHistorianStateFile(path6) {
|
|
|
25926
26710
|
}
|
|
25927
26711
|
// ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
|
|
25928
26712
|
import { mkdirSync as mkdirSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
25929
|
-
import { join as
|
|
26713
|
+
import { join as join5 } from "node:path";
|
|
25930
26714
|
|
|
25931
26715
|
// ../plugin/src/agents/historian.ts
|
|
25932
26716
|
var HISTORIAN_AGENT = "historian";
|
|
@@ -26263,8 +27047,8 @@ function isTransientHistorianPromptError2(message) {
|
|
|
26263
27047
|
].some((token) => normalized.includes(token));
|
|
26264
27048
|
}
|
|
26265
27049
|
function sleep(ms) {
|
|
26266
|
-
return new Promise((
|
|
26267
|
-
setTimeout(
|
|
27050
|
+
return new Promise((resolve3) => {
|
|
27051
|
+
setTimeout(resolve3, ms);
|
|
26268
27052
|
});
|
|
26269
27053
|
}
|
|
26270
27054
|
function cleanupHistorianDump(sessionId, dumpPath) {
|
|
@@ -26286,7 +27070,7 @@ function dumpHistorianResponse(sessionId, directory, label, text) {
|
|
|
26286
27070
|
ensureCortexKitArtifactGitignore(directory);
|
|
26287
27071
|
const safeSessionId = sanitizeDumpName(sessionId);
|
|
26288
27072
|
const safeLabel = sanitizeDumpName(label);
|
|
26289
|
-
const dumpPath =
|
|
27073
|
+
const dumpPath = join5(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
|
|
26290
27074
|
writeFileSync5(dumpPath, text, "utf8");
|
|
26291
27075
|
sessionLog(sessionId, "compartment agent: historian response dumped", {
|
|
26292
27076
|
label,
|
|
@@ -26319,6 +27103,7 @@ function insertRecompCompartmentRows(db, sessionId, compartments, now) {
|
|
|
26319
27103
|
}
|
|
26320
27104
|
function promoteRecompStagingWithM0Mutation(db, sessionId, holderId) {
|
|
26321
27105
|
const now = Date.now();
|
|
27106
|
+
const transactionStartedAt = performance.now();
|
|
26322
27107
|
db.exec("BEGIN IMMEDIATE");
|
|
26323
27108
|
let finished = false;
|
|
26324
27109
|
try {
|
|
@@ -26347,6 +27132,7 @@ function promoteRecompStagingWithM0Mutation(db, sessionId, holderId) {
|
|
|
26347
27132
|
clearCachedM0M1(db, sessionId);
|
|
26348
27133
|
db.exec("COMMIT");
|
|
26349
27134
|
finished = true;
|
|
27135
|
+
logSlowWriteTransaction("historian-publish:recomp", transactionStartedAt);
|
|
26350
27136
|
return { compartments: staging.compartments, facts: staging.facts };
|
|
26351
27137
|
} finally {
|
|
26352
27138
|
if (!finished) {
|
|
@@ -27130,6 +27916,8 @@ function createPiHistorianClient(args) {
|
|
|
27130
27916
|
const sessions = new Map;
|
|
27131
27917
|
let counter = 0;
|
|
27132
27918
|
async function prompt(input) {
|
|
27919
|
+
if (args.signal?.aborted)
|
|
27920
|
+
throw new Error("prompt aborted by external signal");
|
|
27133
27921
|
const body = readBody(input);
|
|
27134
27922
|
const sessionId = readPathId(input);
|
|
27135
27923
|
if (body.noReply) {
|
|
@@ -27150,8 +27938,11 @@ function createPiHistorianClient(args) {
|
|
|
27150
27938
|
cwd: args.directory,
|
|
27151
27939
|
thinkingLevel: modelOverride ? modelOverride.qualifier : args.thinkingLevel,
|
|
27152
27940
|
accountingSessionId: args.accountingSessionId,
|
|
27153
|
-
accountingSubagent: "recomp"
|
|
27941
|
+
accountingSubagent: "recomp",
|
|
27942
|
+
signal: args.signal
|
|
27154
27943
|
});
|
|
27944
|
+
if (args.signal?.aborted)
|
|
27945
|
+
throw new Error("prompt aborted by external signal");
|
|
27155
27946
|
if (!result.ok) {
|
|
27156
27947
|
throw new Error(`Pi recomp historian failed (${result.reason}): ${result.error}`);
|
|
27157
27948
|
}
|
|
@@ -27162,6 +27953,8 @@ function createPiHistorianClient(args) {
|
|
|
27162
27953
|
session: {
|
|
27163
27954
|
get: async () => ({ directory: args.directory }),
|
|
27164
27955
|
create: async () => {
|
|
27956
|
+
if (args.signal?.aborted)
|
|
27957
|
+
throw new Error("prompt aborted by external signal");
|
|
27165
27958
|
const id = `magic-context-pi-recomp-${++counter}`;
|
|
27166
27959
|
sessions.set(id, []);
|
|
27167
27960
|
return { id };
|
|
@@ -27218,16 +28011,13 @@ function makeMessage2(role, text) {
|
|
|
27218
28011
|
|
|
27219
28012
|
// src/pi-recomp-marker.ts
|
|
27220
28013
|
function stagePiRecompMarker(args) {
|
|
27221
|
-
const readBranchEntries = resolvePiReadBranchEntries2(args.ctx);
|
|
27222
|
-
if (!readBranchEntries)
|
|
27223
|
-
return;
|
|
27224
28014
|
const compartments = getCompartments(args.db, args.sessionId);
|
|
27225
28015
|
const last = compartments[compartments.length - 1];
|
|
27226
28016
|
if (!last)
|
|
27227
28017
|
return;
|
|
27228
28018
|
let firstKeptEntryId = null;
|
|
27229
28019
|
try {
|
|
27230
|
-
firstKeptEntryId = findFirstKeptEntryId(
|
|
28020
|
+
firstKeptEntryId = findFirstKeptEntryId(args.branchEntries, last.endMessage);
|
|
27231
28021
|
} catch {
|
|
27232
28022
|
firstKeptEntryId = null;
|
|
27233
28023
|
}
|
|
@@ -27243,19 +28033,6 @@ function stagePiRecompMarker(args) {
|
|
|
27243
28033
|
});
|
|
27244
28034
|
signalPiDeferredHistoryRefresh(args.sessionId);
|
|
27245
28035
|
}
|
|
27246
|
-
function resolvePiReadBranchEntries2(ctx) {
|
|
27247
|
-
const sm = ctx?.sessionManager;
|
|
27248
|
-
if (typeof sm?.getBranch !== "function")
|
|
27249
|
-
return;
|
|
27250
|
-
return () => {
|
|
27251
|
-
try {
|
|
27252
|
-
const entries = sm.getBranch?.call(sm);
|
|
27253
|
-
return Array.isArray(entries) ? entries : [];
|
|
27254
|
-
} catch {
|
|
27255
|
-
return [];
|
|
27256
|
-
}
|
|
27257
|
-
};
|
|
27258
|
-
}
|
|
27259
28036
|
|
|
27260
28037
|
// src/status-line.ts
|
|
27261
28038
|
var STATUS_KEY = "magic-context";
|
|
@@ -27301,7 +28078,6 @@ function renderStatusText(ctx, db, sessionId) {
|
|
|
27301
28078
|
const meta = readSessionMetaStatus(db, sessionId);
|
|
27302
28079
|
const liveInputTokens = typeof usage?.tokens === "number" && Number.isFinite(usage.tokens) ? usage.tokens : undefined;
|
|
27303
28080
|
const persistedInputTokens = typeof meta?.last_input_tokens === "number" && Number.isFinite(meta.last_input_tokens) && meta.last_input_tokens >= 0 ? meta.last_input_tokens : undefined;
|
|
27304
|
-
const inputTokens = liveInputTokens ?? persistedInputTokens;
|
|
27305
28081
|
const windowGeometry = resolvePiWindowGeometry({
|
|
27306
28082
|
rawContextWindow: usage?.contextWindow ?? ctx.model?.contextWindow,
|
|
27307
28083
|
model: ctx.model,
|
|
@@ -27309,8 +28085,14 @@ function renderStatusText(ctx, db, sessionId) {
|
|
|
27309
28085
|
persistedInputTokens,
|
|
27310
28086
|
persistedPercentage: typeof meta?.last_context_percentage === "number" ? meta.last_context_percentage : undefined
|
|
27311
28087
|
});
|
|
27312
|
-
const
|
|
27313
|
-
|
|
28088
|
+
const pressure = liveInputTokens !== undefined || persistedInputTokens !== undefined ? resolvePiPressureSnapshot({
|
|
28089
|
+
persistedPercentage: meta?.last_context_percentage ?? 0,
|
|
28090
|
+
persistedInputTokens: persistedInputTokens ?? 0,
|
|
28091
|
+
liveInputTokens,
|
|
28092
|
+
usableContextLimit: windowGeometry?.usableSoft
|
|
28093
|
+
}) : undefined;
|
|
28094
|
+
const inputTokens = pressure?.inputTokens;
|
|
28095
|
+
const pct = pressure?.percentage;
|
|
27314
28096
|
const state2 = renderHistorianState(meta, recompSessions.has(sessionId));
|
|
27315
28097
|
return `mc: ${inputTokens === undefined ? "--" : fmt(inputTokens)} (${pct === undefined ? "--" : `${Math.round(pct)}%`}) · ${state2}`;
|
|
27316
28098
|
}
|
|
@@ -27367,29 +28149,41 @@ var inFlightRecomp = new Map;
|
|
|
27367
28149
|
function isPiRecompInFlight(sessionId) {
|
|
27368
28150
|
return inFlightRecomp.has(sessionId);
|
|
27369
28151
|
}
|
|
27370
|
-
async function awaitInFlightRecomps() {
|
|
27371
|
-
|
|
28152
|
+
async function awaitInFlightRecomps(sessionId) {
|
|
28153
|
+
const runs = sessionId ? [inFlightRecomp.get(sessionId)?.promise].filter((run) => run !== undefined) : [...inFlightRecomp.values()].map((run) => run.promise);
|
|
28154
|
+
if (runs.length === 0)
|
|
27372
28155
|
return;
|
|
27373
|
-
await Promise.allSettled(
|
|
28156
|
+
await Promise.allSettled(runs);
|
|
28157
|
+
}
|
|
28158
|
+
function abortInFlightRecomps(sessionId) {
|
|
28159
|
+
inFlightRecomp.get(sessionId)?.controller.abort();
|
|
27374
28160
|
}
|
|
27375
28161
|
function spawnPiRecompRun(args) {
|
|
27376
28162
|
const { sessionId, provider, onStatusChange, work } = args;
|
|
28163
|
+
const controller = new AbortController;
|
|
27377
28164
|
const unregister = setRawMessageProvider(sessionId, provider);
|
|
27378
28165
|
setMagicContextRecompActive(sessionId, true);
|
|
27379
|
-
|
|
27380
|
-
const runPromise = (async () => {
|
|
28166
|
+
let run;
|
|
28167
|
+
const runPromise = Promise.resolve().then(async () => {
|
|
27381
28168
|
try {
|
|
27382
|
-
await work();
|
|
28169
|
+
await work(controller.signal);
|
|
27383
28170
|
} catch (err) {
|
|
27384
|
-
|
|
28171
|
+
if (!controller.signal.aborted) {
|
|
28172
|
+
sessionLog(sessionId, `pi recomp run failed (detached): ${err instanceof Error ? err.message : String(err)}`);
|
|
28173
|
+
}
|
|
28174
|
+
}
|
|
28175
|
+
}).finally(() => {
|
|
28176
|
+
if (inFlightRecomp.get(sessionId) === run) {
|
|
28177
|
+
inFlightRecomp.delete(sessionId);
|
|
27385
28178
|
}
|
|
27386
|
-
})().finally(() => {
|
|
27387
|
-
inFlightRecomp.delete(sessionId);
|
|
27388
28179
|
setMagicContextRecompActive(sessionId, false);
|
|
27389
28180
|
unregister();
|
|
27390
|
-
|
|
28181
|
+
if (!controller.signal.aborted)
|
|
28182
|
+
onStatusChange();
|
|
27391
28183
|
});
|
|
27392
|
-
|
|
28184
|
+
run = { promise: runPromise, controller };
|
|
28185
|
+
inFlightRecomp.set(sessionId, run);
|
|
28186
|
+
onStatusChange();
|
|
27393
28187
|
}
|
|
27394
28188
|
|
|
27395
28189
|
// src/commands/ctx-recomp.ts
|
|
@@ -27406,9 +28200,10 @@ function registerCtxRecompCommand(pi, deps) {
|
|
|
27406
28200
|
pi.registerCommand("ctx-recomp", {
|
|
27407
28201
|
description: "Rebuild Magic Context compartments from raw Pi session history",
|
|
27408
28202
|
handler: async (args, ctx) => {
|
|
28203
|
+
const sendStatus = createCtxStatusSender(pi, ctx);
|
|
27409
28204
|
const sessionId = resolveSessionId(ctx);
|
|
27410
28205
|
if (!sessionId) {
|
|
27411
|
-
|
|
28206
|
+
sendStatus({
|
|
27412
28207
|
title: "/ctx-recomp",
|
|
27413
28208
|
text: `## Magic Recomp
|
|
27414
28209
|
|
|
@@ -27419,7 +28214,7 @@ No active Pi session is available.`,
|
|
|
27419
28214
|
}
|
|
27420
28215
|
const currentDeps = deps.resolveRuntimeDeps?.(ctx) ?? deps;
|
|
27421
28216
|
if (currentDeps.compactionOff) {
|
|
27422
|
-
|
|
28217
|
+
sendStatus({
|
|
27423
28218
|
title: "/ctx-recomp",
|
|
27424
28219
|
text: COMPACTION_OFF_COMMAND_UNAVAILABLE,
|
|
27425
28220
|
level: "warning"
|
|
@@ -27428,7 +28223,7 @@ No active Pi session is available.`,
|
|
|
27428
28223
|
}
|
|
27429
28224
|
const parsed = parseRecompArgs(args);
|
|
27430
28225
|
if (parsed.kind === "error") {
|
|
27431
|
-
|
|
28226
|
+
sendStatus({
|
|
27432
28227
|
title: "/ctx-recomp",
|
|
27433
28228
|
text: `## Magic Recomp — Invalid Arguments
|
|
27434
28229
|
|
|
@@ -27438,15 +28233,16 @@ ${parsed.message}`,
|
|
|
27438
28233
|
return;
|
|
27439
28234
|
}
|
|
27440
28235
|
if (parsed.kind === "upgrade") {
|
|
27441
|
-
|
|
28236
|
+
sendStatus({
|
|
27442
28237
|
title: "/ctx-recomp",
|
|
27443
28238
|
text: executeRecompUpgradeStub(currentDeps.db, sessionId),
|
|
27444
|
-
level: "info"
|
|
28239
|
+
level: "info",
|
|
28240
|
+
rpcDisplay: "dialog"
|
|
27445
28241
|
});
|
|
27446
28242
|
return;
|
|
27447
28243
|
}
|
|
27448
28244
|
if (!currentDeps.historianModel) {
|
|
27449
|
-
|
|
28245
|
+
sendStatus({
|
|
27450
28246
|
title: "/ctx-recomp",
|
|
27451
28247
|
text: "## Magic Recomp\n\n/ctx-recomp is unavailable because `historian.model` is not configured.",
|
|
27452
28248
|
level: "error"
|
|
@@ -27463,7 +28259,7 @@ ${parsed.message}`,
|
|
|
27463
28259
|
confirmationBySession.delete(sessionId);
|
|
27464
28260
|
else
|
|
27465
28261
|
confirmationBySession.set(sessionId, { timestamp: now, argsKey });
|
|
27466
|
-
|
|
28262
|
+
sendStatus({
|
|
27467
28263
|
title: "/ctx-recomp",
|
|
27468
28264
|
text: warning.text,
|
|
27469
28265
|
level: warning.confirmable ? "warning" : "error"
|
|
@@ -27471,7 +28267,7 @@ ${parsed.message}`,
|
|
|
27471
28267
|
return;
|
|
27472
28268
|
}
|
|
27473
28269
|
if (isWrapupInProgress(currentDeps.db, sessionId)) {
|
|
27474
|
-
|
|
28270
|
+
sendStatus({
|
|
27475
28271
|
title: "/ctx-recomp",
|
|
27476
28272
|
text: "## Magic Recomp\n\n/ctx-wrapup is already compacting this session. Wait for it to finish, then try `/ctx-recomp` again.",
|
|
27477
28273
|
level: "warning"
|
|
@@ -27479,7 +28275,7 @@ ${parsed.message}`,
|
|
|
27479
28275
|
return;
|
|
27480
28276
|
}
|
|
27481
28277
|
if (isPiRecompInFlight(sessionId)) {
|
|
27482
|
-
|
|
28278
|
+
sendStatus({
|
|
27483
28279
|
title: "/ctx-recomp",
|
|
27484
28280
|
text: `## Magic Recomp
|
|
27485
28281
|
|
|
@@ -27489,7 +28285,7 @@ A recomp or upgrade is already running for this session in the background. Wait
|
|
|
27489
28285
|
return;
|
|
27490
28286
|
}
|
|
27491
28287
|
confirmationBySession.delete(sessionId);
|
|
27492
|
-
|
|
28288
|
+
sendStatus({
|
|
27493
28289
|
title: "/ctx-recomp",
|
|
27494
28290
|
text: parsed.kind === "partial" ? `## Magic Recomp
|
|
27495
28291
|
|
|
@@ -27498,17 +28294,21 @@ Partial recomp started for range ${parsed.range.start}-${parsed.range.end}.` : `
|
|
|
27498
28294
|
Historian recomp started. Rebuilding compartments and facts from raw Pi session history now.`,
|
|
27499
28295
|
level: "info"
|
|
27500
28296
|
});
|
|
28297
|
+
const cwd = ctx.cwd;
|
|
28298
|
+
const fallbackModelId = ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined;
|
|
28299
|
+
const snapshot = readPiSessionSnapshot(ctx);
|
|
27501
28300
|
const provider = {
|
|
27502
|
-
readMessages: () =>
|
|
28301
|
+
readMessages: () => snapshot.rawMessages
|
|
27503
28302
|
};
|
|
27504
28303
|
spawnPiRecompRun({
|
|
27505
28304
|
sessionId,
|
|
27506
28305
|
provider,
|
|
27507
28306
|
onStatusChange: () => updateStatusLine(ctx, {
|
|
27508
28307
|
db: currentDeps.db,
|
|
27509
|
-
projectIdentity:
|
|
28308
|
+
projectIdentity: cwd
|
|
27510
28309
|
}),
|
|
27511
|
-
work: async () => {
|
|
28310
|
+
work: async (signal) => {
|
|
28311
|
+
const detachedSendStatus = createCtxStatusSender(pi, ctx, signal);
|
|
27512
28312
|
const result = await executeContextRecompWithResult({
|
|
27513
28313
|
client: createPiHistorianClient({
|
|
27514
28314
|
runner: currentDeps.runner,
|
|
@@ -27517,10 +28317,11 @@ Historian recomp started. Rebuilding compartments and facts from raw Pi session
|
|
|
27517
28317
|
fallbackModels: currentDeps.historianFallbacks,
|
|
27518
28318
|
timeoutMs: currentDeps.historianTimeoutMs,
|
|
27519
28319
|
thinkingLevel: currentDeps.historianThinkingLevel,
|
|
27520
|
-
directory:
|
|
28320
|
+
directory: cwd,
|
|
27521
28321
|
accountingSessionId: sessionId,
|
|
28322
|
+
signal,
|
|
27522
28323
|
notify: (text) => {
|
|
27523
|
-
|
|
28324
|
+
detachedSendStatus({
|
|
27524
28325
|
title: "/ctx-recomp",
|
|
27525
28326
|
text,
|
|
27526
28327
|
level: inferLevel(text)
|
|
@@ -27530,15 +28331,17 @@ Historian recomp started. Rebuilding compartments and facts from raw Pi session
|
|
|
27530
28331
|
db: currentDeps.db,
|
|
27531
28332
|
sessionId,
|
|
27532
28333
|
historianChunkTokens: currentDeps.historianChunkTokens,
|
|
27533
|
-
directory:
|
|
28334
|
+
directory: cwd,
|
|
27534
28335
|
historianTimeoutMs: currentDeps.historianTimeoutMs,
|
|
27535
28336
|
memoryEnabled: currentDeps.memoryEnabled,
|
|
27536
28337
|
autoPromote: currentDeps.autoPromote,
|
|
27537
28338
|
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
27538
28339
|
fallbackModels: currentDeps.historianFallbacks,
|
|
27539
28340
|
language: currentDeps.language,
|
|
27540
|
-
fallbackModelId
|
|
28341
|
+
fallbackModelId
|
|
27541
28342
|
}, parsed.kind === "partial" ? { range: parsed.range } : {});
|
|
28343
|
+
if (signal.aborted)
|
|
28344
|
+
return;
|
|
27542
28345
|
if (result.published) {
|
|
27543
28346
|
try {
|
|
27544
28347
|
clearEmergencyRecovery(currentDeps.db, sessionId);
|
|
@@ -27546,14 +28349,18 @@ Historian recomp started. Rebuilding compartments and facts from raw Pi session
|
|
|
27546
28349
|
sessionLog(sessionId, `/ctx-recomp: clearEmergencyRecovery failed (continuing): ${describeError(recoveryError).brief}`);
|
|
27547
28350
|
}
|
|
27548
28351
|
try {
|
|
27549
|
-
stagePiRecompMarker({
|
|
28352
|
+
stagePiRecompMarker({
|
|
28353
|
+
db: currentDeps.db,
|
|
28354
|
+
sessionId,
|
|
28355
|
+
branchEntries: snapshot.branchEntries
|
|
28356
|
+
});
|
|
27550
28357
|
} catch (markerError) {
|
|
27551
28358
|
sessionLog(sessionId, `/ctx-recomp: marker staging failed (recomp already published; continuing): ${describeError(markerError).brief}`);
|
|
27552
28359
|
}
|
|
27553
28360
|
signalPiDeferredHistoryRefresh(sessionId);
|
|
27554
28361
|
signalPiDeferredMaterialization(sessionId);
|
|
27555
28362
|
}
|
|
27556
|
-
|
|
28363
|
+
detachedSendStatus({
|
|
27557
28364
|
title: "/ctx-recomp",
|
|
27558
28365
|
text: result.message,
|
|
27559
28366
|
level: inferLevel(result.message)
|
|
@@ -27785,7 +28592,13 @@ function contextualizeUpgradeReason(reason) {
|
|
|
27785
28592
|
|
|
27786
28593
|
// src/pi-memory-migration.ts
|
|
27787
28594
|
var MIGRATION_SYSTEM_PROMPT2 = "You re-organize a software project's long-term memory into a stricter taxonomy. " + "Follow the user instructions exactly. Output ONLY the requested XML blocks, nothing else.";
|
|
28595
|
+
var CANCELLED_OUTCOME = {
|
|
28596
|
+
ran: false,
|
|
28597
|
+
summary: "Memory migration cancelled during session shutdown."
|
|
28598
|
+
};
|
|
27788
28599
|
async function runPiMemoryMigration(deps) {
|
|
28600
|
+
if (deps.signal?.aborted)
|
|
28601
|
+
return CANCELLED_OUTCOME;
|
|
27789
28602
|
const projectPath = resolveProjectIdentityForSession(deps.directory, deps.allowHomeProject);
|
|
27790
28603
|
if (!projectPath) {
|
|
27791
28604
|
return {
|
|
@@ -27823,6 +28636,8 @@ async function runPiMemoryMigration(deps) {
|
|
|
27823
28636
|
let parsed = null;
|
|
27824
28637
|
let lastFailReason = "no output";
|
|
27825
28638
|
for (let i = 0;i < modelChain.length; i += 1) {
|
|
28639
|
+
if (deps.signal?.aborted)
|
|
28640
|
+
return CANCELLED_OUTCOME;
|
|
27826
28641
|
const model = modelChain[i];
|
|
27827
28642
|
if (i > 0) {
|
|
27828
28643
|
sessionLog(deps.sessionId, `memory-migration: escalating to configured fallback model ${model.model} (${i}/${modelChain.length - 1})`);
|
|
@@ -27837,8 +28652,11 @@ async function runPiMemoryMigration(deps) {
|
|
|
27837
28652
|
cwd: deps.directory,
|
|
27838
28653
|
thinkingLevel: model.qualifier,
|
|
27839
28654
|
accountingSessionId: deps.sessionId,
|
|
27840
|
-
accountingSubagent: "recomp"
|
|
28655
|
+
accountingSubagent: "recomp",
|
|
28656
|
+
signal: deps.signal
|
|
27841
28657
|
});
|
|
28658
|
+
if (deps.signal?.aborted)
|
|
28659
|
+
return CANCELLED_OUTCOME;
|
|
27842
28660
|
if (!result.ok) {
|
|
27843
28661
|
lastFailReason = `historian ${result.reason}`;
|
|
27844
28662
|
continue;
|
|
@@ -27869,6 +28687,8 @@ async function runPiMemoryMigration(deps) {
|
|
|
27869
28687
|
summary: "Memory migration skipped: the model extracted user traits but user memories are disabled. Enable `dreamer.user_memories` so they can be preserved, then re-run /ctx-session-upgrade."
|
|
27870
28688
|
};
|
|
27871
28689
|
}
|
|
28690
|
+
if (deps.signal?.aborted)
|
|
28691
|
+
return CANCELLED_OUTCOME;
|
|
27872
28692
|
let routed = 0;
|
|
27873
28693
|
if (deps.userMemoriesEnabled && parsed.userObservations.length > 0) {
|
|
27874
28694
|
insertUserMemoryCandidates(deps.db, parsed.userObservations.map((content) => ({
|
|
@@ -27893,9 +28713,10 @@ function registerCtxSessionUpgradeCommand(pi, deps) {
|
|
|
27893
28713
|
pi.registerCommand("ctx-session-upgrade", {
|
|
27894
28714
|
description: "Upgrade this session to the current Magic Context history format and re-organize project memories",
|
|
27895
28715
|
handler: async (_args, ctx) => {
|
|
28716
|
+
const sendStatus = createCtxStatusSender(pi, ctx);
|
|
27896
28717
|
const sessionId = resolveSessionId(ctx);
|
|
27897
28718
|
if (!sessionId) {
|
|
27898
|
-
|
|
28719
|
+
sendStatus({
|
|
27899
28720
|
title: "/ctx-session-upgrade",
|
|
27900
28721
|
text: `## Session Upgrade
|
|
27901
28722
|
|
|
@@ -27906,7 +28727,7 @@ No active Pi session is available.`,
|
|
|
27906
28727
|
}
|
|
27907
28728
|
const currentDeps = deps.resolveRuntimeDeps?.(ctx) ?? deps;
|
|
27908
28729
|
if (currentDeps.compactionOff) {
|
|
27909
|
-
|
|
28730
|
+
sendStatus({
|
|
27910
28731
|
title: "/ctx-session-upgrade",
|
|
27911
28732
|
text: COMPACTION_OFF_COMMAND_UNAVAILABLE,
|
|
27912
28733
|
level: "warning"
|
|
@@ -27914,7 +28735,7 @@ No active Pi session is available.`,
|
|
|
27914
28735
|
return;
|
|
27915
28736
|
}
|
|
27916
28737
|
if (!currentDeps.historianModel) {
|
|
27917
|
-
|
|
28738
|
+
sendStatus({
|
|
27918
28739
|
title: "/ctx-session-upgrade",
|
|
27919
28740
|
text: "## Session Upgrade\n\nUnavailable because `historian.model` is not configured.",
|
|
27920
28741
|
level: "error"
|
|
@@ -27922,7 +28743,7 @@ No active Pi session is available.`,
|
|
|
27922
28743
|
return;
|
|
27923
28744
|
}
|
|
27924
28745
|
if (isWrapupInProgress(currentDeps.db, sessionId)) {
|
|
27925
|
-
|
|
28746
|
+
sendStatus({
|
|
27926
28747
|
title: "/ctx-session-upgrade",
|
|
27927
28748
|
text: `## Session Upgrade
|
|
27928
28749
|
|
|
@@ -27932,7 +28753,7 @@ No active Pi session is available.`,
|
|
|
27932
28753
|
return;
|
|
27933
28754
|
}
|
|
27934
28755
|
if (isPiRecompInFlight(sessionId)) {
|
|
27935
|
-
|
|
28756
|
+
sendStatus({
|
|
27936
28757
|
title: "/ctx-session-upgrade",
|
|
27937
28758
|
text: `## Session Upgrade
|
|
27938
28759
|
|
|
@@ -27943,9 +28764,10 @@ An upgrade or recomp is already running for this session in the background. Wait
|
|
|
27943
28764
|
}
|
|
27944
28765
|
const compartments = getCompartments(currentDeps.db, sessionId);
|
|
27945
28766
|
const upgradableCount = compartments.filter((c) => c.legacy === 1 || !c.p1 || c.p1.trim() === "").length;
|
|
28767
|
+
const cwd = ctx.cwd;
|
|
27946
28768
|
const sessionMainModel = ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined;
|
|
27947
28769
|
const migrationEnabled = currentDeps.memoryEnabled;
|
|
27948
|
-
const runMigration = async () => {
|
|
28770
|
+
const runMigration = async (signal) => {
|
|
27949
28771
|
if (!migrationEnabled) {
|
|
27950
28772
|
return "Memory migration skipped (memory disabled).";
|
|
27951
28773
|
}
|
|
@@ -27958,24 +28780,27 @@ An upgrade or recomp is already running for this session in the background. Wait
|
|
|
27958
28780
|
fallbackModels: currentDeps.historianFallbacks,
|
|
27959
28781
|
timeoutMs: currentDeps.historianTimeoutMs,
|
|
27960
28782
|
thinkingLevel: currentDeps.historianThinkingLevel,
|
|
27961
|
-
directory:
|
|
28783
|
+
directory: cwd,
|
|
27962
28784
|
allowHomeProject: currentDeps.allowHomeProject,
|
|
27963
28785
|
sessionId,
|
|
27964
28786
|
userMemoriesEnabled: currentDeps.userMemoriesEnabled,
|
|
27965
|
-
language: currentDeps.language
|
|
28787
|
+
language: currentDeps.language,
|
|
28788
|
+
signal
|
|
27966
28789
|
});
|
|
27967
28790
|
return outcome.summary;
|
|
27968
28791
|
} catch (error) {
|
|
28792
|
+
if (signal.aborted)
|
|
28793
|
+
return "Memory migration cancelled.";
|
|
27969
28794
|
return `Memory migration skipped (error): ${describeError(error).brief}`;
|
|
27970
28795
|
}
|
|
27971
28796
|
};
|
|
27972
28797
|
if (upgradableCount === 0) {
|
|
27973
|
-
const projectPath = resolveProjectIdentityForSession(
|
|
28798
|
+
const projectPath = resolveProjectIdentityForSession(cwd, currentDeps.allowHomeProject);
|
|
27974
28799
|
if (!projectPath)
|
|
27975
28800
|
return;
|
|
27976
28801
|
const migrationPending = migrationEnabled && !isMemoryMigrationDone(currentDeps.db, projectPath);
|
|
27977
28802
|
if (!migrationPending) {
|
|
27978
|
-
|
|
28803
|
+
sendStatus({
|
|
27979
28804
|
title: "/ctx-session-upgrade",
|
|
27980
28805
|
text: [
|
|
27981
28806
|
"## Session Upgrade — Already Up To Date",
|
|
@@ -27983,56 +28808,64 @@ An upgrade or recomp is already running for this session in the background. Wait
|
|
|
27983
28808
|
compartments.length === 0 ? "This session has no compartment history to upgrade yet." : "This session's compartments are already in the current format."
|
|
27984
28809
|
].join(`
|
|
27985
28810
|
`),
|
|
27986
|
-
level: "info"
|
|
28811
|
+
level: "info",
|
|
28812
|
+
rpcDisplay: "dialog"
|
|
27987
28813
|
});
|
|
27988
28814
|
return;
|
|
27989
28815
|
}
|
|
27990
|
-
|
|
28816
|
+
sendStatus({
|
|
27991
28817
|
title: "/ctx-session-upgrade",
|
|
27992
28818
|
text: `## Session Upgrade
|
|
27993
28819
|
|
|
27994
28820
|
Compartments are already current. Re-organizing project memories. This may take a while.`,
|
|
27995
28821
|
level: "info"
|
|
27996
28822
|
});
|
|
28823
|
+
const snapshot2 = readPiSessionSnapshot(ctx);
|
|
27997
28824
|
spawnPiRecompRun({
|
|
27998
28825
|
sessionId,
|
|
27999
28826
|
provider: {
|
|
28000
|
-
readMessages: () =>
|
|
28827
|
+
readMessages: () => snapshot2.rawMessages
|
|
28001
28828
|
},
|
|
28002
28829
|
onStatusChange: () => updateStatusLine(ctx, {
|
|
28003
28830
|
db: currentDeps.db,
|
|
28004
|
-
projectIdentity:
|
|
28831
|
+
projectIdentity: cwd
|
|
28005
28832
|
}),
|
|
28006
|
-
work: async () => {
|
|
28007
|
-
const
|
|
28008
|
-
|
|
28833
|
+
work: async (signal) => {
|
|
28834
|
+
const detachedSendStatus = createCtxStatusSender(pi, ctx, signal);
|
|
28835
|
+
const summary = await runMigration(signal);
|
|
28836
|
+
if (signal.aborted)
|
|
28837
|
+
return;
|
|
28838
|
+
detachedSendStatus({
|
|
28009
28839
|
title: "/ctx-session-upgrade",
|
|
28010
28840
|
text: ["## Session Upgrade — Complete", "", summary].join(`
|
|
28011
28841
|
`),
|
|
28012
|
-
level: "info"
|
|
28842
|
+
level: "info",
|
|
28843
|
+
rpcDisplay: "dialog"
|
|
28013
28844
|
});
|
|
28014
28845
|
}
|
|
28015
28846
|
});
|
|
28016
28847
|
return;
|
|
28017
28848
|
}
|
|
28018
|
-
|
|
28849
|
+
sendStatus({
|
|
28019
28850
|
title: "/ctx-session-upgrade",
|
|
28020
28851
|
text: `## Session Upgrade
|
|
28021
28852
|
|
|
28022
28853
|
Rebuilding compartments into the v2 format and re-organizing project memories. This may take a while.`,
|
|
28023
28854
|
level: "info"
|
|
28024
28855
|
});
|
|
28856
|
+
const snapshot = readPiSessionSnapshot(ctx);
|
|
28025
28857
|
const provider = {
|
|
28026
|
-
readMessages: () =>
|
|
28858
|
+
readMessages: () => snapshot.rawMessages
|
|
28027
28859
|
};
|
|
28028
28860
|
spawnPiRecompRun({
|
|
28029
28861
|
sessionId,
|
|
28030
28862
|
provider,
|
|
28031
28863
|
onStatusChange: () => updateStatusLine(ctx, {
|
|
28032
28864
|
db: currentDeps.db,
|
|
28033
|
-
projectIdentity:
|
|
28865
|
+
projectIdentity: cwd
|
|
28034
28866
|
}),
|
|
28035
|
-
work: async () => {
|
|
28867
|
+
work: async (signal) => {
|
|
28868
|
+
const detachedSendStatus = createCtxStatusSender(pi, ctx, signal);
|
|
28036
28869
|
const recompResult = await executeContextRecompWithResult({
|
|
28037
28870
|
client: createPiHistorianClient({
|
|
28038
28871
|
runner: currentDeps.runner,
|
|
@@ -28040,10 +28873,11 @@ Rebuilding compartments into the v2 format and re-organizing project memories. T
|
|
|
28040
28873
|
fallbackModels: currentDeps.historianFallbacks,
|
|
28041
28874
|
timeoutMs: currentDeps.historianTimeoutMs,
|
|
28042
28875
|
thinkingLevel: currentDeps.historianThinkingLevel,
|
|
28043
|
-
directory:
|
|
28876
|
+
directory: cwd,
|
|
28044
28877
|
accountingSessionId: sessionId,
|
|
28878
|
+
signal,
|
|
28045
28879
|
systemPrompt: withContentLanguageDirective(COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, currentDeps.language, { preserveUserQuotes: true }),
|
|
28046
|
-
notify: (text) =>
|
|
28880
|
+
notify: (text) => detachedSendStatus({
|
|
28047
28881
|
title: "/ctx-session-upgrade",
|
|
28048
28882
|
text,
|
|
28049
28883
|
level: "info"
|
|
@@ -28052,7 +28886,7 @@ Rebuilding compartments into the v2 format and re-organizing project memories. T
|
|
|
28052
28886
|
db: currentDeps.db,
|
|
28053
28887
|
sessionId,
|
|
28054
28888
|
historianChunkTokens: currentDeps.historianChunkTokens,
|
|
28055
|
-
directory:
|
|
28889
|
+
directory: cwd,
|
|
28056
28890
|
historianTimeoutMs: currentDeps.historianTimeoutMs,
|
|
28057
28891
|
memoryEnabled: currentDeps.memoryEnabled,
|
|
28058
28892
|
autoPromote: currentDeps.autoPromote,
|
|
@@ -28061,9 +28895,11 @@ Rebuilding compartments into the v2 format and re-organizing project memories. T
|
|
|
28061
28895
|
fallbackModelId: sessionMainModel,
|
|
28062
28896
|
language: currentDeps.language
|
|
28063
28897
|
}, {});
|
|
28898
|
+
if (signal.aborted)
|
|
28899
|
+
return;
|
|
28064
28900
|
if (!recompResult.published || !isRecompComplete(recompResult.message)) {
|
|
28065
28901
|
const reason = contextualizeUpgradeReason(isRecompFailure(recompResult.message) ? extractRecompReason(recompResult.message) : `Compartments were not fully rebuilt: ${extractRecompReason(recompResult.message)}`);
|
|
28066
|
-
|
|
28902
|
+
detachedSendStatus({
|
|
28067
28903
|
title: "/ctx-session-upgrade",
|
|
28068
28904
|
text: `## Session Upgrade — Incomplete
|
|
28069
28905
|
|
|
@@ -28073,14 +28909,20 @@ ${reason}`,
|
|
|
28073
28909
|
return;
|
|
28074
28910
|
}
|
|
28075
28911
|
try {
|
|
28076
|
-
stagePiRecompMarker({
|
|
28912
|
+
stagePiRecompMarker({
|
|
28913
|
+
db: currentDeps.db,
|
|
28914
|
+
sessionId,
|
|
28915
|
+
branchEntries: snapshot.branchEntries
|
|
28916
|
+
});
|
|
28077
28917
|
} catch (markerError) {
|
|
28078
28918
|
sessionLog(sessionId, `pi /ctx-session-upgrade marker staging failed (non-fatal, recomp already published): ${describeError(markerError).brief}`);
|
|
28079
28919
|
}
|
|
28080
28920
|
signalPiDeferredHistoryRefresh(sessionId);
|
|
28081
28921
|
signalPiDeferredMaterialization(sessionId);
|
|
28082
|
-
const migrationSummary = await runMigration();
|
|
28083
|
-
|
|
28922
|
+
const migrationSummary = await runMigration(signal);
|
|
28923
|
+
if (signal.aborted)
|
|
28924
|
+
return;
|
|
28925
|
+
detachedSendStatus({
|
|
28084
28926
|
title: "/ctx-session-upgrade",
|
|
28085
28927
|
text: [
|
|
28086
28928
|
"## Session Upgrade — Complete",
|
|
@@ -28092,7 +28934,8 @@ ${migrationSummary}` : "",
|
|
|
28092
28934
|
recompResult.message
|
|
28093
28935
|
].join(`
|
|
28094
28936
|
`),
|
|
28095
|
-
level: "info"
|
|
28937
|
+
level: "info",
|
|
28938
|
+
rpcDisplay: "dialog"
|
|
28096
28939
|
});
|
|
28097
28940
|
}
|
|
28098
28941
|
});
|
|
@@ -28118,6 +28961,9 @@ function formatThresholdClampNote(opts) {
|
|
|
28118
28961
|
return ` [clamped: ${opts.configuredValue}% > ${opts.maxPercentage}%]`;
|
|
28119
28962
|
}
|
|
28120
28963
|
|
|
28964
|
+
// ../plugin/src/shared/rust-mode-status.ts
|
|
28965
|
+
var RUST_MODE_HOST_PATHS_LINE = "Host backends → MODULE: ctx_memory, ctx_note; historian: module-side";
|
|
28966
|
+
|
|
28121
28967
|
// ../plugin/src/shared/tail-hygiene-status.ts
|
|
28122
28968
|
function finiteNumber(value, fallback = 0) {
|
|
28123
28969
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
@@ -28184,7 +29030,7 @@ function formatExecuteThreshold(detail, contextLimit) {
|
|
|
28184
29030
|
}
|
|
28185
29031
|
return `${percentage}%${clampNote}`;
|
|
28186
29032
|
}
|
|
28187
|
-
function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageConfig = DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, liveModelKey, historyBudgetPercentage, commitClusterTrigger, executeThresholdTokens, contextLimit, dreamer, windowGeometry, tailHygiene) {
|
|
29033
|
+
function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageConfig = DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, liveModelKey, historyBudgetPercentage, commitClusterTrigger, executeThresholdTokens, contextLimit, dreamer, windowGeometry, tailHygiene, contextUsage, rustMode = false) {
|
|
28188
29034
|
const thresholdDetail = resolveExecuteThresholdDetail(executeThresholdPercentageConfig, liveModelKey, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, {
|
|
28189
29035
|
tokensConfig: executeThresholdTokens,
|
|
28190
29036
|
contextLimit,
|
|
@@ -28209,7 +29055,9 @@ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageC
|
|
|
28209
29055
|
const remainingMs = Math.max(0, ttlMs - elapsed);
|
|
28210
29056
|
const cacheExpired = remainingMs === 0 && meta.lastResponseTime > 0;
|
|
28211
29057
|
const proactiveCompartmentTrigger = getProactiveCompartmentTriggerPercentage(executeThresholdPercentage);
|
|
28212
|
-
const
|
|
29058
|
+
const displayInputTokens = contextUsage?.inputTokens ?? meta.lastInputTokens;
|
|
29059
|
+
const displayPercentage = contextUsage?.percentage ?? meta.lastContextPercentage;
|
|
29060
|
+
const displayContextLimit = contextLimit && contextLimit > 0 ? contextLimit : displayPercentage > 0 ? Math.round(displayInputTokens / (displayPercentage / 100)) : 0;
|
|
28213
29061
|
const lines = [
|
|
28214
29062
|
"## Magic Status",
|
|
28215
29063
|
"",
|
|
@@ -28234,11 +29082,15 @@ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageC
|
|
|
28234
29082
|
"",
|
|
28235
29083
|
"### Execute Threshold",
|
|
28236
29084
|
`- Execute threshold: ${formatExecuteThreshold(thresholdDetail, displayContextLimit)}`,
|
|
28237
|
-
`- Last input tokens: ${
|
|
29085
|
+
`- Last input tokens: ${displayInputTokens.toLocaleString()} tokens`,
|
|
28238
29086
|
"",
|
|
28239
29087
|
`**Protected tags:** ${protectedTags}`,
|
|
28240
29088
|
`**Subagent session:** ${meta.isSubagent}`
|
|
28241
29089
|
];
|
|
29090
|
+
const storage = getMagicContextStorageResolution();
|
|
29091
|
+
lines.push("", `**Storage:** ${storage.path} (${storage.source})`);
|
|
29092
|
+
if (rustMode)
|
|
29093
|
+
lines.push("", "### Rust Mode", `- ${RUST_MODE_HOST_PATHS_LINE}`);
|
|
28242
29094
|
if (tailHygiene !== undefined) {
|
|
28243
29095
|
lines.push("", "### Tail Hygiene", `- Reclaimable / eligible: ${formatTailHygiene(tailHygiene)}`, "- Reasoning is excluded from both terms.");
|
|
28244
29096
|
}
|
|
@@ -28247,8 +29099,8 @@ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageC
|
|
|
28247
29099
|
`- Running: ${dreamer.progress.task} — ${dreamer.progress.processed}/${dreamer.progress.total} processed`
|
|
28248
29100
|
] : [], ...formatDreamTaskBacklogs(dreamer.backlog).split("\\n"));
|
|
28249
29101
|
}
|
|
28250
|
-
if (
|
|
28251
|
-
lines.push("", "### Context Usage", `- Last percentage: ${
|
|
29102
|
+
if (displayPercentage > 0 || displayInputTokens > 0) {
|
|
29103
|
+
lines.push("", "### Context Usage", `- Last percentage: ${displayPercentage.toFixed(1)}%`, `- Last input tokens: ${displayInputTokens.toLocaleString()}`, `- Resolved context limit: ${displayContextLimit > 0 ? displayContextLimit.toLocaleString() : "unknown"}`, ...windowGeometry ? [`- ${formatWindowDerivationLine(displayInputTokens, windowGeometry)}`] : [], `- Proactive compartment evaluation: ${proactiveCompartmentTrigger}%`, `- Post-drop target for historian: ${(executeThresholdPercentage * POST_DROP_TARGET_RATIO).toFixed(0)}% (${executeThresholdPercentage}% * ${POST_DROP_TARGET_RATIO})`, `- Commit cluster trigger: ${commitClusterTrigger?.enabled !== false ? `enabled (min ${commitClusterTrigger?.min_clusters ?? 3} clusters)` : "disabled"}, tail-size trigger: > 3x compartment budget`);
|
|
28252
29104
|
}
|
|
28253
29105
|
const compartments = getCompartments(db, sessionId);
|
|
28254
29106
|
let historyBlockTokens = 0;
|
|
@@ -28285,7 +29137,7 @@ ${c.content}
|
|
|
28285
29137
|
|
|
28286
29138
|
// src/dialogs/status-dialog.ts
|
|
28287
29139
|
import {
|
|
28288
|
-
matchesKey,
|
|
29140
|
+
matchesKey as matchesKey2,
|
|
28289
29141
|
truncateToWidth,
|
|
28290
29142
|
visibleWidth
|
|
28291
29143
|
} from "@earendil-works/pi-tui";
|
|
@@ -28349,7 +29201,7 @@ ${c.content}
|
|
|
28349
29201
|
// package.json
|
|
28350
29202
|
var package_default = {
|
|
28351
29203
|
name: "@cortexkit/pi-magic-context",
|
|
28352
|
-
version: "0.
|
|
29204
|
+
version: "0.41.1",
|
|
28353
29205
|
type: "module",
|
|
28354
29206
|
description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
|
|
28355
29207
|
main: "dist/index.js",
|
|
@@ -28377,7 +29229,7 @@ var package_default = {
|
|
|
28377
29229
|
"README.md"
|
|
28378
29230
|
],
|
|
28379
29231
|
scripts: {
|
|
28380
|
-
build: "tsc -p ../retina-local-fs/tsconfig.build.json && rm -f dist/index.js dist/subagent-entry.js dist/*-*.js && bun build src/index.ts src/subagent-entry.ts --outdir dist --target node --format esm --splitting --external @earendil-works/pi-coding-agent --external @earendil-works/pi-tui --external
|
|
29232
|
+
build: "tsc -p ../retina-local-fs/tsconfig.build.json && rm -f dist/index.js dist/subagent-entry.js dist/historian-calibration-extension.js dist/transformers-web.js dist/*-*.js && bun build ../plugin/src/features/magic-context/memory/transformers-web-entry.ts --outfile dist/transformers-web.js --target browser --format esm --external onnxruntime-web && bun build src/index.ts src/subagent-entry.ts src/historian-calibration-extension.ts --outdir dist --target node --format esm --splitting --external @earendil-works/pi-coding-agent --external @earendil-works/pi-tui --external onnxruntime-node --external onnxruntime-web --external sharp --external node:sqlite",
|
|
28381
29233
|
"build:e2e-argv": "bun build src/subagent-runner.ts --outfile ../../tests/docker/.generated/subagent-runner-e2e.mjs --target node --format esm --external node:sqlite",
|
|
28382
29234
|
typecheck: "tsc -p ../retina-local-fs/tsconfig.build.json && tsc --noEmit",
|
|
28383
29235
|
test: "bun install --frozen-lockfile && bun test",
|
|
@@ -28390,16 +29242,21 @@ var package_default = {
|
|
|
28390
29242
|
},
|
|
28391
29243
|
dependencies: {
|
|
28392
29244
|
"@cortexkit/subc-client": "0.4.1",
|
|
28393
|
-
"@huggingface/transformers": "^4.1.0",
|
|
28394
29245
|
"@jitl/quickjs-singlefile-cjs-release-asyncify": "0.32.0",
|
|
28395
29246
|
"ai-tokenizer": "^1.0.6",
|
|
28396
29247
|
"comment-json": "^5.0.0",
|
|
29248
|
+
"onnxruntime-web": "1.26.0-dev.20260416-b7804b056c",
|
|
28397
29249
|
"quickjs-emscripten": "^0.32.0",
|
|
28398
29250
|
typebox: "^1.3.1",
|
|
28399
29251
|
zod: "^4.1.8"
|
|
28400
29252
|
},
|
|
29253
|
+
optionalDependencies: {
|
|
29254
|
+
"onnxruntime-node": "1.24.3",
|
|
29255
|
+
sharp: "^0.34.5"
|
|
29256
|
+
},
|
|
28401
29257
|
devDependencies: {
|
|
28402
29258
|
"@biomejs/biome": "^2.5.1",
|
|
29259
|
+
"@huggingface/transformers": "^4.1.0",
|
|
28403
29260
|
"@earendil-works/pi-ai": "0.83.0",
|
|
28404
29261
|
"@earendil-works/pi-coding-agent": "0.83.0",
|
|
28405
29262
|
"@earendil-works/pi-tui": "0.83.0",
|
|
@@ -28485,7 +29342,7 @@ class StatusDialogComponent {
|
|
|
28485
29342
|
}, REFRESH_INTERVAL_MS);
|
|
28486
29343
|
}
|
|
28487
29344
|
handleInput(data) {
|
|
28488
|
-
if (
|
|
29345
|
+
if (matchesKey2(data, "escape") || matchesKey2(data, "ctrl+c") || matchesKey2(data, "return")) {
|
|
28489
29346
|
this.close();
|
|
28490
29347
|
}
|
|
28491
29348
|
}
|
|
@@ -28586,8 +29443,6 @@ function drawBorder(inner, width, theme) {
|
|
|
28586
29443
|
function buildPiStatusDetail(pi, ctx, deps, sessionId) {
|
|
28587
29444
|
const usage = ctx.getContextUsage?.();
|
|
28588
29445
|
const meta = getOrCreateSessionMeta(deps.db, sessionId);
|
|
28589
|
-
const hasPersistedPressure = meta.lastInputTokens > 0 && meta.lastContextPercentage > 0;
|
|
28590
|
-
const inputTokens = hasPersistedPressure ? meta.lastInputTokens : typeof usage?.tokens === "number" ? usage.tokens : 0;
|
|
28591
29446
|
let detectedContextLimit;
|
|
28592
29447
|
try {
|
|
28593
29448
|
const detected = getOverflowState(deps.db, sessionId).detectedContextLimit;
|
|
@@ -28601,8 +29456,15 @@ function buildPiStatusDetail(pi, ctx, deps, sessionId) {
|
|
|
28601
29456
|
persistedInputTokens: meta.lastInputTokens,
|
|
28602
29457
|
persistedPercentage: meta.lastContextPercentage
|
|
28603
29458
|
});
|
|
28604
|
-
const
|
|
28605
|
-
|
|
29459
|
+
const pressure = resolvePiPressureSnapshot({
|
|
29460
|
+
persistedPercentage: meta.lastContextPercentage,
|
|
29461
|
+
persistedInputTokens: meta.lastInputTokens,
|
|
29462
|
+
liveInputTokens: usage?.tokens,
|
|
29463
|
+
usableContextLimit: windowGeometry?.usableSoft
|
|
29464
|
+
});
|
|
29465
|
+
const inputTokens = pressure.inputTokens;
|
|
29466
|
+
const contextLimit = pressure.contextLimit ?? 0;
|
|
29467
|
+
const usagePercentage = pressure.percentage;
|
|
28606
29468
|
const compartments = getCompartments(deps.db, sessionId);
|
|
28607
29469
|
const metaRow = readSessionMetaRow(deps.db, sessionId);
|
|
28608
29470
|
const memoryBlockCount = Number(metaRow?.memory_block_count ?? 0);
|
|
@@ -28859,12 +29721,13 @@ function registerCtxStatusCommand(pi, deps) {
|
|
|
28859
29721
|
pi.registerCommand("ctx-status", {
|
|
28860
29722
|
description: "Show Magic Context status for the current Pi session",
|
|
28861
29723
|
handler: async (_args, ctx) => {
|
|
29724
|
+
const sendStatus = createCtxStatusSender(pi, ctx);
|
|
28862
29725
|
const runtimeDeps = deps.resolveStatusDeps?.(ctx) ?? deps;
|
|
28863
29726
|
const projectIdentity = runtimeDeps.resolveProject?.(ctx).projectIdentity ?? runtimeDeps.projectIdentity;
|
|
28864
29727
|
const currentDeps = { ...runtimeDeps, projectIdentity };
|
|
28865
29728
|
const sessionId = resolveSessionId(ctx);
|
|
28866
29729
|
if (!sessionId) {
|
|
28867
|
-
|
|
29730
|
+
sendStatus({
|
|
28868
29731
|
title: "/ctx-status",
|
|
28869
29732
|
text: `## Magic Status
|
|
28870
29733
|
|
|
@@ -28895,20 +29758,30 @@ No active Pi session is available.`,
|
|
|
28895
29758
|
persistedPercentage: meta.lastContextPercentage
|
|
28896
29759
|
});
|
|
28897
29760
|
const usableContextLimit = windowGeometry?.usableSoft;
|
|
29761
|
+
const pressure = resolvePiPressureSnapshot({
|
|
29762
|
+
persistedPercentage: meta.lastContextPercentage,
|
|
29763
|
+
persistedInputTokens: meta.lastInputTokens,
|
|
29764
|
+
liveInputTokens: usage?.tokens,
|
|
29765
|
+
usableContextLimit
|
|
29766
|
+
});
|
|
28898
29767
|
const statusText = executeStatus(currentDeps.db, sessionId, currentDeps.protectedTags ?? 20, currentDeps.executeThresholdPercentage, modelKey, currentDeps.historyBudgetPercentage, currentDeps.commitClusterTrigger, currentDeps.executeThresholdTokens, usableContextLimit, {
|
|
28899
29768
|
backlog: getDreamTaskBacklogs(currentDeps.db, currentDeps.projectIdentity, CANONICAL_DREAM_TASKS)
|
|
28900
|
-
}, windowGeometry, resolveTailHygieneStatus(getPiChannel1Baseline(sessionId)));
|
|
29769
|
+
}, windowGeometry, resolveTailHygieneStatus(getPiChannel1Baseline(sessionId)), pressure);
|
|
28901
29770
|
const details = buildStatusDetails(currentDeps, sessionId);
|
|
28902
29771
|
const profileStatus = currentDeps.activeProfile ?? "none";
|
|
28903
|
-
|
|
29772
|
+
const storage = getMagicContextStorageResolution();
|
|
29773
|
+
sendStatus({
|
|
28904
29774
|
title: "/ctx-status",
|
|
28905
29775
|
text: `${statusText}
|
|
28906
29776
|
|
|
28907
|
-
Active profile: ${profileStatus}
|
|
28908
|
-
|
|
29777
|
+
Active profile: ${profileStatus}
|
|
29778
|
+
|
|
29779
|
+
Storage: ${storage.path} (${storage.source})`,
|
|
29780
|
+
level: "info",
|
|
29781
|
+
rpcDisplay: "dialog"
|
|
28909
29782
|
}, details);
|
|
28910
29783
|
} catch (error) {
|
|
28911
|
-
|
|
29784
|
+
sendStatus({
|
|
28912
29785
|
title: "/ctx-status",
|
|
28913
29786
|
text: `## Magic Status — Failed
|
|
28914
29787
|
|
|
@@ -28996,9 +29869,10 @@ function registerCtxWrapupCommand(pi, deps) {
|
|
|
28996
29869
|
pi.registerCommand("ctx-wrapup", {
|
|
28997
29870
|
description: "Compact older Magic Context history while keeping the newest messages raw",
|
|
28998
29871
|
handler: async (args, ctx) => {
|
|
29872
|
+
const sendStatus = createCtxStatusSender(pi, ctx);
|
|
28999
29873
|
const sessionId = resolveSessionId(ctx);
|
|
29000
29874
|
if (!sessionId) {
|
|
29001
|
-
|
|
29875
|
+
sendStatus({
|
|
29002
29876
|
title: "/ctx-wrapup",
|
|
29003
29877
|
text: `## Magic Wrapup
|
|
29004
29878
|
|
|
@@ -29009,7 +29883,7 @@ No active Pi session is available.`,
|
|
|
29009
29883
|
}
|
|
29010
29884
|
const currentDeps = deps.resolveRuntimeDeps?.(ctx) ?? deps;
|
|
29011
29885
|
if (currentDeps.compactionOff) {
|
|
29012
|
-
|
|
29886
|
+
sendStatus({
|
|
29013
29887
|
title: "/ctx-wrapup",
|
|
29014
29888
|
text: COMPACTION_OFF_COMMAND_UNAVAILABLE,
|
|
29015
29889
|
level: "warning"
|
|
@@ -29018,7 +29892,7 @@ No active Pi session is available.`,
|
|
|
29018
29892
|
}
|
|
29019
29893
|
const sessionMeta = getOrCreateSessionMeta(currentDeps.db, sessionId);
|
|
29020
29894
|
if (sessionMeta.isSubagent) {
|
|
29021
|
-
|
|
29895
|
+
sendStatus({
|
|
29022
29896
|
title: "/ctx-wrapup",
|
|
29023
29897
|
text: `## Magic Wrapup — Skipped
|
|
29024
29898
|
|
|
@@ -29028,7 +29902,7 @@ No active Pi session is available.`,
|
|
|
29028
29902
|
return;
|
|
29029
29903
|
}
|
|
29030
29904
|
if (!currentDeps.historianModel) {
|
|
29031
|
-
|
|
29905
|
+
sendStatus({
|
|
29032
29906
|
title: "/ctx-wrapup",
|
|
29033
29907
|
text: "## Magic Wrapup\n\n/ctx-wrapup is unavailable because `historian.model` is not configured.",
|
|
29034
29908
|
level: "error"
|
|
@@ -29037,7 +29911,7 @@ No active Pi session is available.`,
|
|
|
29037
29911
|
}
|
|
29038
29912
|
const parsed = parseWrapupArgs(args);
|
|
29039
29913
|
if (!parsed.ok) {
|
|
29040
|
-
|
|
29914
|
+
sendStatus({
|
|
29041
29915
|
title: "/ctx-wrapup",
|
|
29042
29916
|
text: `## Magic Wrapup — Invalid Arguments
|
|
29043
29917
|
|
|
@@ -29047,7 +29921,7 @@ ${parsed.message}`,
|
|
|
29047
29921
|
return;
|
|
29048
29922
|
}
|
|
29049
29923
|
const result = await runPiWrapup(pi, currentDeps, ctx, sessionId, parsed.messagesToKeep);
|
|
29050
|
-
|
|
29924
|
+
sendStatus({
|
|
29051
29925
|
title: "/ctx-wrapup",
|
|
29052
29926
|
text: result,
|
|
29053
29927
|
level: result.includes("Failed") || result.includes("Partial") ? "error" : "success"
|
|
@@ -29056,6 +29930,7 @@ ${parsed.message}`,
|
|
|
29056
29930
|
});
|
|
29057
29931
|
}
|
|
29058
29932
|
async function runPiWrapup(pi, deps, ctx, sessionId, messagesToKeep) {
|
|
29933
|
+
const sendStatus = createCtxStatusSender(pi, ctx);
|
|
29059
29934
|
if (getOrCreateSessionMeta(deps.db, sessionId).isSubagent) {
|
|
29060
29935
|
return `## Magic Wrapup — Skipped
|
|
29061
29936
|
|
|
@@ -29135,7 +30010,7 @@ No runnable wrapup boundary is available yet; wrapped up 0 messages into 0 compa
|
|
|
29135
30010
|
}
|
|
29136
30011
|
}, 60000);
|
|
29137
30012
|
try {
|
|
29138
|
-
|
|
30013
|
+
sendStatus({
|
|
29139
30014
|
title: "/ctx-wrapup",
|
|
29140
30015
|
text: `## Magic Wrapup
|
|
29141
30016
|
|
|
@@ -29191,7 +30066,7 @@ Eligible history is about ${initialPlan.snapshot.trueRawEligibleTokens.toLocaleS
|
|
|
29191
30066
|
failure = `${ownershipLostReason}; wrapped up through message ${lastEnd}. Run /ctx-wrapup again to continue.`;
|
|
29192
30067
|
break;
|
|
29193
30068
|
}
|
|
29194
|
-
|
|
30069
|
+
sendStatus({
|
|
29195
30070
|
title: "/ctx-wrapup",
|
|
29196
30071
|
text: `## Magic Wrapup
|
|
29197
30072
|
|
|
@@ -29246,7 +30121,7 @@ Chunk ${chunkIndex}: wrapping messages ${plan.snapshot.offset}-${plan.snapshot.e
|
|
|
29246
30121
|
language: deps.language,
|
|
29247
30122
|
compartmentLeaseHolderId: leaseHolder,
|
|
29248
30123
|
readBranchEntries: () => readBranchEntries(ctx),
|
|
29249
|
-
notifyIssue: (text) =>
|
|
30124
|
+
notifyIssue: (text) => sendStatus({
|
|
29250
30125
|
title: "/ctx-wrapup",
|
|
29251
30126
|
text,
|
|
29252
30127
|
level: "warning"
|
|
@@ -29323,7 +30198,7 @@ async function acquireCompartmentLeaseEventually(db, sessionId, renewWrapupMarke
|
|
|
29323
30198
|
return { ok: true, holderId };
|
|
29324
30199
|
if (!renewWrapupMarker({}))
|
|
29325
30200
|
return { ok: false, reason: "ownership_lost" };
|
|
29326
|
-
await new Promise((
|
|
30201
|
+
await new Promise((resolve3) => setTimeout(resolve3, Math.min(LEASE_WAIT_MS, remainingMs())));
|
|
29327
30202
|
}
|
|
29328
30203
|
}
|
|
29329
30204
|
function estimateChunks(tokens, chunkTokens) {
|
|
@@ -29400,42 +30275,6 @@ function registerPiFailClosedSurface(pi, args) {
|
|
|
29400
30275
|
log(`${PREFIX} fail-closed blocking surface registered (${args.reason.kind}); primary turns will error until storage recovers or the build is upgraded`);
|
|
29401
30276
|
}
|
|
29402
30277
|
|
|
29403
|
-
// src/pi-pressure.ts
|
|
29404
|
-
function extractAssistantUsage(message) {
|
|
29405
|
-
if (!message || typeof message !== "object")
|
|
29406
|
-
return null;
|
|
29407
|
-
const m = message;
|
|
29408
|
-
if (m.role !== "assistant")
|
|
29409
|
-
return null;
|
|
29410
|
-
if (!m.usage || typeof m.usage !== "object")
|
|
29411
|
-
return null;
|
|
29412
|
-
const u = m.usage;
|
|
29413
|
-
const result = {};
|
|
29414
|
-
if (typeof u.input === "number")
|
|
29415
|
-
result.input = u.input;
|
|
29416
|
-
if (typeof u.output === "number")
|
|
29417
|
-
result.output = u.output;
|
|
29418
|
-
if (typeof u.cacheRead === "number")
|
|
29419
|
-
result.cacheRead = u.cacheRead;
|
|
29420
|
-
if (typeof u.cacheWrite === "number")
|
|
29421
|
-
result.cacheWrite = u.cacheWrite;
|
|
29422
|
-
if (typeof u.totalTokens === "number")
|
|
29423
|
-
result.totalTokens = u.totalTokens;
|
|
29424
|
-
return result;
|
|
29425
|
-
}
|
|
29426
|
-
function computePiPressure(usage, contextLimit) {
|
|
29427
|
-
if (!usage)
|
|
29428
|
-
return null;
|
|
29429
|
-
const input = usage.input ?? 0;
|
|
29430
|
-
const cacheRead = usage.cacheRead ?? 0;
|
|
29431
|
-
const cacheWrite = usage.cacheWrite ?? 0;
|
|
29432
|
-
const inputTokens = input + cacheRead + cacheWrite;
|
|
29433
|
-
if (inputTokens === 0)
|
|
29434
|
-
return null;
|
|
29435
|
-
const percentage = contextLimit > 0 ? inputTokens / contextLimit * 100 : 0;
|
|
29436
|
-
return { inputTokens, percentage };
|
|
29437
|
-
}
|
|
29438
|
-
|
|
29439
30278
|
// src/strip-tag-prefix.ts
|
|
29440
30279
|
function stripTagPrefixFromAssistantMessage(message) {
|
|
29441
30280
|
if (message.role !== "assistant")
|
|
@@ -29461,19 +30300,43 @@ function stripTagPrefixFromAssistantMessage(message) {
|
|
|
29461
30300
|
|
|
29462
30301
|
// src/index.ts
|
|
29463
30302
|
var PREFIX2 = "[magic-context][pi]";
|
|
29464
|
-
var
|
|
29465
|
-
|
|
29466
|
-
|
|
30303
|
+
var PI_CHILD_INIT_CONTEXT = Symbol.for("magic-context.pi.child-init-context");
|
|
30304
|
+
var SUBAGENT_CHILD_SESSION_CREATED = "subagents:child:session-created";
|
|
30305
|
+
var SUBAGENT_CHILD_DISPOSED = "subagents:child:disposed";
|
|
30306
|
+
var PI_STARTUP_MAINTENANCE_SCHEDULED = Symbol.for("magic-context.pi.startup-maintenance-scheduled");
|
|
30307
|
+
function getPiChildInitContext() {
|
|
30308
|
+
const globals = globalThis;
|
|
30309
|
+
const existing = globals[PI_CHILD_INIT_CONTEXT];
|
|
30310
|
+
if (existing instanceof AsyncLocalStorage)
|
|
30311
|
+
return existing;
|
|
30312
|
+
const context = new AsyncLocalStorage;
|
|
30313
|
+
globals[PI_CHILD_INIT_CONTEXT] = context;
|
|
30314
|
+
return context;
|
|
29467
30315
|
}
|
|
29468
|
-
function
|
|
29469
|
-
|
|
30316
|
+
function isPiInProcessSubagentInit() {
|
|
30317
|
+
return getPiChildInitContext().getStore() === true;
|
|
29470
30318
|
}
|
|
29471
|
-
function
|
|
29472
|
-
|
|
29473
|
-
|
|
29474
|
-
|
|
29475
|
-
|
|
29476
|
-
|
|
30319
|
+
function clearPiInProcessSubagentInitContext() {
|
|
30320
|
+
getPiChildInitContext().enterWith(false);
|
|
30321
|
+
}
|
|
30322
|
+
function registerPiSubagentInitContext(pi) {
|
|
30323
|
+
const context = getPiChildInitContext();
|
|
30324
|
+
const unsubscribeCreated = pi.events.on(SUBAGENT_CHILD_SESSION_CREATED, () => context.enterWith(true));
|
|
30325
|
+
const unsubscribeDisposed = pi.events.on(SUBAGENT_CHILD_DISPOSED, () => context.enterWith(false));
|
|
30326
|
+
return () => {
|
|
30327
|
+
unsubscribeCreated();
|
|
30328
|
+
unsubscribeDisposed();
|
|
30329
|
+
};
|
|
30330
|
+
}
|
|
30331
|
+
function claimPiStartupMaintenance() {
|
|
30332
|
+
const globals = globalThis;
|
|
30333
|
+
if (globals[PI_STARTUP_MAINTENANCE_SCHEDULED] === true)
|
|
30334
|
+
return false;
|
|
30335
|
+
globals[PI_STARTUP_MAINTENANCE_SCHEDULED] = true;
|
|
30336
|
+
return true;
|
|
30337
|
+
}
|
|
30338
|
+
function clearPiStartupMaintenanceClaim() {
|
|
30339
|
+
delete globalThis[PI_STARTUP_MAINTENANCE_SCHEDULED];
|
|
29477
30340
|
}
|
|
29478
30341
|
function resolveCurrentProject(ctx, allowHomeProject = false) {
|
|
29479
30342
|
const projectDir = ctx.cwd;
|
|
@@ -29587,7 +30450,7 @@ function ensureConfigLocationsMigrated(dir) {
|
|
|
29587
30450
|
});
|
|
29588
30451
|
}
|
|
29589
30452
|
function logPiConfigLoad(args) {
|
|
29590
|
-
const key =
|
|
30453
|
+
const key = resolve3(args.dir);
|
|
29591
30454
|
if (args.dedupe && loggedPiConfigDirs.has(key))
|
|
29592
30455
|
return;
|
|
29593
30456
|
if (args.dedupe) {
|
|
@@ -29607,9 +30470,9 @@ var __test = {
|
|
|
29607
30470
|
resetLoggedPiConfigDirs() {
|
|
29608
30471
|
loggedPiConfigDirs.clear();
|
|
29609
30472
|
},
|
|
29610
|
-
|
|
29611
|
-
|
|
29612
|
-
|
|
30473
|
+
clearPiInProcessSubagentInitContext,
|
|
30474
|
+
claimPiStartupMaintenance,
|
|
30475
|
+
clearPiStartupMaintenanceClaim
|
|
29613
30476
|
};
|
|
29614
30477
|
function formatTokens(value) {
|
|
29615
30478
|
return value.toLocaleString();
|
|
@@ -29681,7 +30544,7 @@ async function persistPiPressureFromMessageEnd(args) {
|
|
|
29681
30544
|
}
|
|
29682
30545
|
var PLUGIN_VERSION = (() => {
|
|
29683
30546
|
try {
|
|
29684
|
-
const req =
|
|
30547
|
+
const req = createRequire2(import.meta.url);
|
|
29685
30548
|
return req("../package.json").version;
|
|
29686
30549
|
} catch {
|
|
29687
30550
|
return "0.0.0";
|
|
@@ -29722,6 +30585,8 @@ function resolveHistorianFromConfig(config) {
|
|
|
29722
30585
|
fallbackModels,
|
|
29723
30586
|
historianChunkTokens,
|
|
29724
30587
|
timeoutMs: config.historian_timeout_ms,
|
|
30588
|
+
temperature: historian?.temperature,
|
|
30589
|
+
maxOutputTokens: historian?.maxTokens ?? 32000,
|
|
29725
30590
|
twoPass: historian?.two_pass === true,
|
|
29726
30591
|
thinkingLevel: resolved.primary?.qualifier,
|
|
29727
30592
|
executeThresholdPercentage: config.execute_threshold_percentage,
|
|
@@ -29754,11 +30619,12 @@ async function src_default(pi) {
|
|
|
29754
30619
|
log(`${PREFIX2} subagent child detected (${MAGIC_CONTEXT_PI_SUBAGENT_ENV}=1); skipping full extension registration`);
|
|
29755
30620
|
return;
|
|
29756
30621
|
}
|
|
29757
|
-
if (
|
|
29758
|
-
log(`${PREFIX2} in-process
|
|
30622
|
+
if (isPiInProcessSubagentInit()) {
|
|
30623
|
+
log(`${PREFIX2} in-process subagent child detected; skipping full extension registration`);
|
|
29759
30624
|
return;
|
|
29760
30625
|
}
|
|
29761
|
-
|
|
30626
|
+
const unregisterPiSubagentInitContext = registerPiSubagentInitContext(pi);
|
|
30627
|
+
registerPiSubagentInitContextCleanup(pi, unregisterPiSubagentInitContext);
|
|
29762
30628
|
beginBootQuietPeriod();
|
|
29763
30629
|
const bootProjectDir = process.cwd();
|
|
29764
30630
|
ensureConfigLocationsMigrated(bootProjectDir);
|
|
@@ -29769,7 +30635,7 @@ async function src_default(pi) {
|
|
|
29769
30635
|
mmapSizeMb: bootConfig.config.sqlite.mmap_size_mb
|
|
29770
30636
|
});
|
|
29771
30637
|
const storageDir = getMagicContextStorageDir();
|
|
29772
|
-
const dbPath =
|
|
30638
|
+
const dbPath = join6(storageDir, "context.db");
|
|
29773
30639
|
let db;
|
|
29774
30640
|
let openFailureCause = null;
|
|
29775
30641
|
try {
|
|
@@ -29830,27 +30696,44 @@ async function src_default(pi) {
|
|
|
29830
30696
|
}
|
|
29831
30697
|
async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
29832
30698
|
const db = database;
|
|
29833
|
-
|
|
29834
|
-
|
|
29835
|
-
|
|
30699
|
+
if (claimPiStartupMaintenance()) {
|
|
30700
|
+
scheduleAfterBootQuiet(() => {
|
|
30701
|
+
runDeferredV22Backfill(db).catch((err) => {
|
|
30702
|
+
warn(`[v22-backfill] background runner failed: ${err}`);
|
|
30703
|
+
});
|
|
29836
30704
|
});
|
|
29837
|
-
|
|
29838
|
-
|
|
29839
|
-
|
|
29840
|
-
|
|
29841
|
-
|
|
29842
|
-
|
|
29843
|
-
|
|
29844
|
-
|
|
29845
|
-
|
|
29846
|
-
|
|
29847
|
-
|
|
29848
|
-
|
|
29849
|
-
|
|
29850
|
-
|
|
29851
|
-
|
|
30705
|
+
scheduleAfterBootQuiet(() => {
|
|
30706
|
+
(async () => {
|
|
30707
|
+
try {
|
|
30708
|
+
let sessions;
|
|
30709
|
+
await runSessionProjectBackfill(database, async (afterSessionId, limit) => {
|
|
30710
|
+
if (!sessions) {
|
|
30711
|
+
const api = await loadDefaultPiSessionApi();
|
|
30712
|
+
const sessionsById2 = new Map;
|
|
30713
|
+
for (const session of await api.listSessions()) {
|
|
30714
|
+
const sessionId = typeof session?.id === "string" ? session.id : "";
|
|
30715
|
+
const directory = typeof session?.cwd === "string" ? session.cwd : "";
|
|
30716
|
+
if (sessionId && (!sessionsById2.has(sessionId) || directory)) {
|
|
30717
|
+
sessionsById2.set(sessionId, { sessionId, directory });
|
|
30718
|
+
}
|
|
30719
|
+
}
|
|
30720
|
+
sessions = [...sessionsById2.values()];
|
|
30721
|
+
}
|
|
30722
|
+
const offset = afterSessionId === null ? 0 : sessions.findIndex((session) => session.sessionId === afterSessionId) + 1;
|
|
30723
|
+
return sessions.slice(offset, offset + limit);
|
|
30724
|
+
});
|
|
30725
|
+
} catch (err) {
|
|
30726
|
+
warn(`[session-projects] background runner failed: ${err}`);
|
|
30727
|
+
}
|
|
30728
|
+
})();
|
|
30729
|
+
}, 0);
|
|
30730
|
+
}
|
|
29852
30731
|
const projectDir = process.cwd();
|
|
29853
30732
|
const seenDreamerProjectIdentities = new Set;
|
|
30733
|
+
const dreamerRegistrationOwner = {};
|
|
30734
|
+
const commandLifecycleController = new AbortController;
|
|
30735
|
+
registerCtxStatusLifecycleSignal(pi, commandLifecycleController.signal);
|
|
30736
|
+
let sessionShuttingDown = false;
|
|
29854
30737
|
ensureConfigLocationsMigrated(projectDir);
|
|
29855
30738
|
const { config, warnings, loadedFromPaths, registrationPromptSurface } = loadPiConfig({
|
|
29856
30739
|
cwd: projectDir
|
|
@@ -29993,6 +30876,32 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
29993
30876
|
}
|
|
29994
30877
|
const bootProjectDeps = buildProjectDeps(projectDir, projectIdentity, config);
|
|
29995
30878
|
projectDepsByDir.set(projectDir, bootProjectDeps);
|
|
30879
|
+
function syncDreamerProjectRegistration(current) {
|
|
30880
|
+
if (sessionShuttingDown)
|
|
30881
|
+
return;
|
|
30882
|
+
seenDreamerProjectIdentities.add(current.projectIdentity);
|
|
30883
|
+
if (!current.dreamerConfig) {
|
|
30884
|
+
unregisterPiDreamerProject({
|
|
30885
|
+
projectIdentity: current.projectIdentity,
|
|
30886
|
+
registrationOwner: dreamerRegistrationOwner
|
|
30887
|
+
});
|
|
30888
|
+
return;
|
|
30889
|
+
}
|
|
30890
|
+
registerPiDreamerProject({
|
|
30891
|
+
db,
|
|
30892
|
+
projectDir: current.projectDir,
|
|
30893
|
+
projectIdentity: current.projectIdentity,
|
|
30894
|
+
registrationOwner: dreamerRegistrationOwner,
|
|
30895
|
+
config: current.dreamerConfig,
|
|
30896
|
+
embeddingConfig: current.config.embedding,
|
|
30897
|
+
memoryEnabled: current.config.memory.enabled,
|
|
30898
|
+
retinaHandoff: current.config.smart_notes.retina_handoff,
|
|
30899
|
+
mural: current.config.mural,
|
|
30900
|
+
language: current.config.language,
|
|
30901
|
+
gitCommitIndexing: current.config.memory.git_commit_indexing,
|
|
30902
|
+
onAdjunctsRefreshNeeded: signalPiSystemPromptRefreshForProject
|
|
30903
|
+
});
|
|
30904
|
+
}
|
|
29996
30905
|
const todowriteEnabled = bootProjectDeps.config.todowrite.enabled !== false;
|
|
29997
30906
|
const todowriteOverlayEnabled = todowriteEnabled && bootProjectDeps.config.todowrite.overlay !== false;
|
|
29998
30907
|
registerMagicContextTools(pi, {
|
|
@@ -30187,7 +31096,9 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
30187
31096
|
},
|
|
30188
31097
|
dreamerEnabled: bootProjectDeps.dreamerEnabled,
|
|
30189
31098
|
resolveDreamerEnabled: (ctx) => resolveCurrentProjectDeps(ctx).dreamerEnabled,
|
|
30190
|
-
onProjectSeen: (identity) => seenDreamerProjectIdentities.add(identity)
|
|
31099
|
+
onProjectSeen: (identity) => seenDreamerProjectIdentities.add(identity),
|
|
31100
|
+
ensureRegistered: (ctx) => syncDreamerProjectRegistration(resolveCurrentProjectDeps(ctx)),
|
|
31101
|
+
registrationOwner: dreamerRegistrationOwner
|
|
30191
31102
|
});
|
|
30192
31103
|
info("registered /ctx-dream");
|
|
30193
31104
|
registerCtxEmbedCommand(pi, {
|
|
@@ -30207,19 +31118,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
30207
31118
|
info("registered /ctx-embed");
|
|
30208
31119
|
const dreamerConfig = bootProjectDeps.dreamerConfig;
|
|
30209
31120
|
if (dreamerConfig) {
|
|
30210
|
-
|
|
30211
|
-
db,
|
|
30212
|
-
projectDir,
|
|
30213
|
-
projectIdentity,
|
|
30214
|
-
config: dreamerConfig,
|
|
30215
|
-
embeddingConfig: bootProjectDeps.config.embedding,
|
|
30216
|
-
memoryEnabled: bootProjectDeps.config.memory.enabled,
|
|
30217
|
-
retinaHandoff: bootProjectDeps.config.smart_notes.retina_handoff,
|
|
30218
|
-
mural: bootProjectDeps.config.mural,
|
|
30219
|
-
language: bootProjectDeps.config.language,
|
|
30220
|
-
gitCommitIndexing: bootProjectDeps.config.memory.git_commit_indexing,
|
|
30221
|
-
onAdjunctsRefreshNeeded: signalPiSystemPromptRefreshForProject
|
|
30222
|
-
});
|
|
31121
|
+
syncDreamerProjectRegistration(bootProjectDeps);
|
|
30223
31122
|
info(`registered dreamer (${summarizeDreamSchedule(dreamerConfig)})`);
|
|
30224
31123
|
} else {
|
|
30225
31124
|
info(bootProjectDeps.dreamerEnabled ? "registered dreamer: DISABLED (no dreamer config)" : "registered dreamer: DISABLED (dreamer.disable=true or no dreamer config)");
|
|
@@ -30250,33 +31149,10 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
30250
31149
|
projectIdentity: effectiveProjectDeps.projectIdentity
|
|
30251
31150
|
};
|
|
30252
31151
|
const effectiveConfig = effectiveProjectDeps.config;
|
|
30253
|
-
|
|
30254
|
-
|
|
30255
|
-
|
|
30256
|
-
|
|
30257
|
-
registerPiDreamerProject({
|
|
30258
|
-
db,
|
|
30259
|
-
projectDir: currentProject.projectDir,
|
|
30260
|
-
projectIdentity: currentProject.projectIdentity,
|
|
30261
|
-
config: effectiveDreamerConfig,
|
|
30262
|
-
embeddingConfig: effectiveConfig.embedding,
|
|
30263
|
-
memoryEnabled: effectiveConfig.memory.enabled,
|
|
30264
|
-
retinaHandoff: effectiveConfig.smart_notes.retina_handoff,
|
|
30265
|
-
language: effectiveConfig.language,
|
|
30266
|
-
gitCommitIndexing: effectiveConfig.memory.git_commit_indexing,
|
|
30267
|
-
onAdjunctsRefreshNeeded: signalPiSystemPromptRefreshForProject
|
|
30268
|
-
});
|
|
30269
|
-
} catch (err) {
|
|
30270
|
-
warn("before_agent_start: registerPiDreamerProject threw:", err);
|
|
30271
|
-
}
|
|
30272
|
-
} else {
|
|
30273
|
-
try {
|
|
30274
|
-
unregisterPiDreamerProject({
|
|
30275
|
-
projectIdentity: currentProject.projectIdentity
|
|
30276
|
-
});
|
|
30277
|
-
} catch (err) {
|
|
30278
|
-
warn("before_agent_start: unregisterPiDreamerProject threw:", err);
|
|
30279
|
-
}
|
|
31152
|
+
try {
|
|
31153
|
+
syncDreamerProjectRegistration(effectiveProjectDeps);
|
|
31154
|
+
} catch (err) {
|
|
31155
|
+
warn("before_agent_start: dreamer registration sync threw:", err);
|
|
30280
31156
|
}
|
|
30281
31157
|
const sm = ctx.sessionManager;
|
|
30282
31158
|
let sessionId;
|
|
@@ -30538,39 +31414,47 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
30538
31414
|
}
|
|
30539
31415
|
});
|
|
30540
31416
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
31417
|
+
sessionShuttingDown = true;
|
|
31418
|
+
commandLifecycleController.abort();
|
|
30541
31419
|
const SHUTDOWN_DRAIN_MS = 5000;
|
|
31420
|
+
const sessionId = resolveSessionId(ctx);
|
|
30542
31421
|
try {
|
|
30543
|
-
|
|
31422
|
+
for (const identity of seenDreamerProjectIdentities) {
|
|
31423
|
+
unregisterPiDreamerProject({
|
|
31424
|
+
projectIdentity: identity,
|
|
31425
|
+
registrationOwner: dreamerRegistrationOwner
|
|
31426
|
+
});
|
|
31427
|
+
}
|
|
30544
31428
|
} catch (err) {
|
|
30545
|
-
warn("shutdown:
|
|
31429
|
+
warn("shutdown: unregisterPiDreamerProject threw:", err);
|
|
30546
31430
|
}
|
|
30547
|
-
|
|
30548
|
-
|
|
30549
|
-
|
|
30550
|
-
|
|
31431
|
+
if (sessionId) {
|
|
31432
|
+
try {
|
|
31433
|
+
await withTimeout(awaitInFlightHistorians(sessionId), SHUTDOWN_DRAIN_MS);
|
|
31434
|
+
} catch (err) {
|
|
31435
|
+
warn("shutdown: historian drain threw:", err);
|
|
31436
|
+
}
|
|
31437
|
+
try {
|
|
31438
|
+
await withTimeout(awaitInFlightRecomps(sessionId), SHUTDOWN_DRAIN_MS);
|
|
31439
|
+
} catch (err) {
|
|
31440
|
+
warn("shutdown: recomp drain threw:", err);
|
|
31441
|
+
}
|
|
31442
|
+
abortInFlightRecomps(sessionId);
|
|
30551
31443
|
}
|
|
30552
31444
|
try {
|
|
30553
|
-
await withTimeout(awaitInFlightDreamers(), SHUTDOWN_DRAIN_MS);
|
|
31445
|
+
await withTimeout(awaitInFlightDreamers(dreamerRegistrationOwner), SHUTDOWN_DRAIN_MS);
|
|
30554
31446
|
} catch (err) {
|
|
30555
31447
|
warn("shutdown: dreamer drain threw:", err);
|
|
30556
31448
|
}
|
|
30557
|
-
try {
|
|
30558
|
-
for (const identity of seenDreamerProjectIdentities) {
|
|
30559
|
-
unregisterPiDreamerProject({ projectIdentity: identity });
|
|
30560
|
-
}
|
|
30561
|
-
} catch (err) {
|
|
30562
|
-
warn("shutdown: unregisterPiDreamerProject threw:", err);
|
|
30563
|
-
}
|
|
30564
31449
|
try {
|
|
30565
31450
|
const sm = ctx.sessionManager;
|
|
30566
|
-
const
|
|
30567
|
-
if (typeof
|
|
30568
|
-
clearPiSystemPromptSession(
|
|
30569
|
-
promptSurfaceGuidanceEpochs.clear(
|
|
30570
|
-
clearContextHandlerSession(
|
|
31451
|
+
const sessionId2 = typeof sm?.getSessionId === "function" ? sm.getSessionId() : undefined;
|
|
31452
|
+
if (typeof sessionId2 === "string" && sessionId2.length > 0) {
|
|
31453
|
+
clearPiSystemPromptSession(sessionId2);
|
|
31454
|
+
promptSurfaceGuidanceEpochs.clear(sessionId2);
|
|
31455
|
+
clearContextHandlerSession(sessionId2);
|
|
30571
31456
|
}
|
|
30572
31457
|
} catch {}
|
|
30573
|
-
clearPiMagicContextActive();
|
|
30574
31458
|
});
|
|
30575
31459
|
pi.on("session_before_switch", (_event, ctx) => {
|
|
30576
31460
|
try {
|
|
@@ -30584,6 +31468,9 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
30584
31468
|
} catch {}
|
|
30585
31469
|
});
|
|
30586
31470
|
}
|
|
31471
|
+
function registerPiSubagentInitContextCleanup(pi, unsubscribe) {
|
|
31472
|
+
pi.on("session_shutdown", unsubscribe);
|
|
31473
|
+
}
|
|
30587
31474
|
function formatExecuteThresholdForLog(value) {
|
|
30588
31475
|
if (value === undefined)
|
|
30589
31476
|
return "65%";
|