@cortexkit/magic-context 0.47.0 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2088 -484
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2212,8 +2212,12 @@ function flush() {
|
|
|
2212
2212
|
let currentSize = getCurrentLogSize(logFile);
|
|
2213
2213
|
const dataSize = Buffer.byteLength(data);
|
|
2214
2214
|
if (currentSize > 0 && currentSize + dataSize > MAX_LOG_FILE_BYTES) {
|
|
2215
|
-
|
|
2216
|
-
currentSize =
|
|
2215
|
+
flushesSinceSizeCheck = SIZE_CHECK_INTERVAL_FLUSHES;
|
|
2216
|
+
currentSize = getCurrentLogSize(logFile);
|
|
2217
|
+
if (currentSize > 0 && currentSize + dataSize > MAX_LOG_FILE_BYTES) {
|
|
2218
|
+
rotateLogFile(logFile, currentSize);
|
|
2219
|
+
currentSize = 0;
|
|
2220
|
+
}
|
|
2217
2221
|
}
|
|
2218
2222
|
fs.appendFileSync(logFile, data, { encoding: "utf8", mode: 384 });
|
|
2219
2223
|
buffer = [];
|
|
@@ -3476,6 +3480,15 @@ function migrateLegacyExperimental(rawConfig, warnings) {
|
|
|
3476
3480
|
return patched;
|
|
3477
3481
|
}
|
|
3478
3482
|
|
|
3483
|
+
// ../plugin/src/config/mural-model-deprecation.ts
|
|
3484
|
+
function warnDeprecatedMuralModel(config, warnings) {
|
|
3485
|
+
const mural = config.mural;
|
|
3486
|
+
if (typeof mural === "object" && mural !== null && Object.hasOwn(mural, "model")) {
|
|
3487
|
+
warnings.push(MURAL_MODEL_DEPRECATION_WARNING);
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
var MURAL_MODEL_DEPRECATION_WARNING = "mural.model is deprecated and ignored; compress-cues now uses the dreamer model for each harness, like every other dreamer task. To override it, set dreamer.opencode.tasks.compress-cues.model (or the pi/omp equivalent). This key no longer does anything; remove it.";
|
|
3491
|
+
|
|
3479
3492
|
// ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/core/core.js
|
|
3480
3493
|
function $constructor(name, initializer, params) {
|
|
3481
3494
|
function init(inst, def) {
|
|
@@ -9315,7 +9328,7 @@ var init_magic_context = __esm(() => {
|
|
|
9315
9328
|
allow_home_project: boolean2().default(false).describe("Allow Magic Context sessions launched from the exact canonical home directory. A non-git home uses its deterministic dir: identity; a home repository uses its git: identity. USER-LEVEL ONLY: project config is ignored. The home identity is excluded from registry seed exports, never resolves descendants by containment, and cannot join a workspace."),
|
|
9316
9329
|
mural: object({
|
|
9317
9330
|
enabled: boolean2().default(false),
|
|
9318
|
-
model:
|
|
9331
|
+
model: unknown().optional().describe("Deprecated: ignored. compress-cues now uses the dreamer model for each harness, like every other dreamer task; override it with dreamer.opencode.tasks.compress-cues.model (or the pi/omp equivalent). Remove this key; it no longer does anything.").meta({ deprecated: true })
|
|
9319
9332
|
}).default({ enabled: false }).describe("Experimental mural: a single deterministically-rendered image of project memories that did not fit the context budget. Cues are compressed per-memory by the compress-cues dreamer task."),
|
|
9320
9333
|
transform_mode: _enum(["ts", "rust"]).default("ts").describe('Experimental: routes the entire Magic Context runtime for the project through the ck-mc Rust module over subc (requires user-level `subc` config); "ts" is the current TypeScript pipeline.'),
|
|
9321
9334
|
auto_update: boolean2().optional().describe("Enable automatic npm self-update checks for the OpenCode plugin. Security: USER-only in config loader, so hostile project configs cannot suppress updates."),
|
|
@@ -9325,8 +9338,9 @@ var init_magic_context = __esm(() => {
|
|
|
9325
9338
|
historian: HistorianConfigSchema.describe("Historian metadata plus independent strict OpenCode, Pi, and OMP execution blocks. Retained metadata stays at historian; model, fallback_models, variant, and thinking_level belong only in historian.opencode, historian.pi, or historian.omp."),
|
|
9326
9339
|
dreamer: DreamerConfigSchema.optional().describe("Dreamer metadata and scheduling plus independent strict OpenCode, Pi, and OMP execution blocks. schedule and promotion_threshold stay at dreamer.tasks; model, fallback_models, variant, thinking_level, and timeout_minutes belong only in the matching harness block."),
|
|
9327
9340
|
smart_notes: object({
|
|
9341
|
+
enabled: boolean2().default(true).describe("Enable smart-note authoring and condition evaluation. User-level only: tool definitions are process-wide. Changes require a host restart and rebuild each session's cached prompt once. Pending notes remain stored and unchecked; already-ready notes still surface."),
|
|
9328
9342
|
retina_handoff: boolean2().default(false).describe("When true, dreamer skips smart notes whose surface conditions compiled to retina provider configs at authoring time. Default false keeps both paths active until the retina consumer is deployed.")
|
|
9329
|
-
}).default({ retina_handoff: false }).describe("Smart-note ownership transition controls."),
|
|
9343
|
+
}).default({ enabled: true, retina_handoff: false }).describe("Smart-note ownership transition controls."),
|
|
9330
9344
|
cache_ttl: union([string2(), object({ default: string2() }).catchall(string2())]).default("5m").describe(`How long Magic Context assumes the provider's cached prefix stays valid. This is MC's own deferral gate — it does not change the provider's actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard, then default). User and project settings, including an explicit "5m" or object default, apply on the next pass. Only built-in defaults are frozen per session, including across restarts: when unset, GPT-5.6 and later (including gpt-6*, through any provider prefix) use 30m, other models use 5m. /ctx-status shows the effective TTL and whether it comes from your config or a frozen built-in default. Editing the TTL does not itself rewrite prompt bytes; a lowered TTL rebuilds only after normal idle expiry. OpenAI documents at least 30 minutes since the latest write or reuse: https://developers.openai.com/api/docs/guides/prompt-caching (Cache lifetime and Summary of model differences). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).`),
|
|
9331
9345
|
prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe("Prompt-surface presets: default is full; models use bare model IDs, provider/model, or provider/* routing keys. Guidance and tool-description overrides are user-level only. OpenCode 1.x, Pi, and OMP register tool descriptions once per process (they follow the default preset). OpenCode 2 rewrites the five ctx_* descriptions per request from the draft model."),
|
|
9332
9346
|
output_reserve: union([
|
|
@@ -9431,7 +9445,6 @@ var init_magic_context = __esm(() => {
|
|
|
9431
9445
|
});
|
|
9432
9446
|
LIVE_RELOAD_CONFIG_PATHS = [
|
|
9433
9447
|
"cache_ttl",
|
|
9434
|
-
"mural.model",
|
|
9435
9448
|
"toast_duration_ms",
|
|
9436
9449
|
"historian.opencode.model",
|
|
9437
9450
|
"historian.opencode.fallback_models",
|
|
@@ -9612,16 +9625,6 @@ function stripEscalationAtExecutableSite(block, path, removed) {
|
|
|
9612
9625
|
}
|
|
9613
9626
|
}
|
|
9614
9627
|
}
|
|
9615
|
-
function stripNestedMuralModels(node, path, removed) {
|
|
9616
|
-
for (const [key, value] of Object.entries(node)) {
|
|
9617
|
-
if (key === "mural" && isPlainObject2(value) && "model" in value) {
|
|
9618
|
-
delete value.model;
|
|
9619
|
-
removed.push(`${path}.${key}.model`);
|
|
9620
|
-
} else if (isPlainObject2(value)) {
|
|
9621
|
-
stripNestedMuralModels(value, `${path}.${key}`, removed);
|
|
9622
|
-
}
|
|
9623
|
-
}
|
|
9624
|
-
}
|
|
9625
9628
|
function isValidPercentageThreshold(value) {
|
|
9626
9629
|
return typeof value === "number" && Number.isFinite(value) && value >= 20 && value <= 90;
|
|
9627
9630
|
}
|
|
@@ -9762,6 +9765,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
9762
9765
|
delete storage.enforce_private_permissions;
|
|
9763
9766
|
warnings.push("Ignoring storage.enforce_private_permissions from project config (security: only user-level config may opt into externally managed shared storage permissions).");
|
|
9764
9767
|
}
|
|
9768
|
+
const smartNotes = projectRaw.smart_notes;
|
|
9769
|
+
if (isPlainObject2(smartNotes) && "enabled" in smartNotes) {
|
|
9770
|
+
delete smartNotes.enabled;
|
|
9771
|
+
warnings.push("Ignoring smart_notes.enabled from project config (only user-level config may change process-wide tool definitions; restart required).");
|
|
9772
|
+
}
|
|
9765
9773
|
const promptSurface = projectRaw.prompt_surface;
|
|
9766
9774
|
if (isPlainObject2(promptSurface)) {
|
|
9767
9775
|
const removed = [];
|
|
@@ -9860,27 +9868,6 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
9860
9868
|
delete dreamer.runner;
|
|
9861
9869
|
warnings.push("Ignoring dreamer.runner from project config (security: which process and provider account run dreamer completions is a user-level setting).");
|
|
9862
9870
|
}
|
|
9863
|
-
const mural = projectRaw.mural;
|
|
9864
|
-
if (isPlainObject2(mural) && "model" in mural) {
|
|
9865
|
-
delete mural.model;
|
|
9866
|
-
warnings.push("Ignoring mural.model from project config (security: the mural cue-compressor model is a user-level setting; a repository cannot choose where project memory is sent).");
|
|
9867
|
-
}
|
|
9868
|
-
const experimental = projectRaw.experimental;
|
|
9869
|
-
const legacyMural = isPlainObject2(experimental) ? experimental.mural : undefined;
|
|
9870
|
-
if (isPlainObject2(legacyMural) && "model" in legacyMural) {
|
|
9871
|
-
delete legacyMural.model;
|
|
9872
|
-
warnings.push("Ignoring experimental.mural.model from project config (security: the mural cue-compressor model is a user-level setting; use user-level mural.model).");
|
|
9873
|
-
}
|
|
9874
|
-
const nestedMuralRemoved = [];
|
|
9875
|
-
for (const agentKey of HIDDEN_AGENT_KEYS) {
|
|
9876
|
-
const block = projectRaw[agentKey];
|
|
9877
|
-
if (!isPlainObject2(block))
|
|
9878
|
-
continue;
|
|
9879
|
-
stripNestedMuralModels(block, agentKey, nestedMuralRemoved);
|
|
9880
|
-
}
|
|
9881
|
-
if (nestedMuralRemoved.length > 0) {
|
|
9882
|
-
warnings.push(`Ignoring ${nestedMuralRemoved.join(", ")} from project config (security: the mural cue-compressor model is a user-level setting; a repository cannot choose where project memory is sent).`);
|
|
9883
|
-
}
|
|
9884
9871
|
return warnings;
|
|
9885
9872
|
}
|
|
9886
9873
|
function constrainProjectThresholdOverrides(args) {
|
|
@@ -10929,6 +10916,7 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
10929
10916
|
}
|
|
10930
10917
|
preMigrationWarnings.push(...misplacedAgentModelWarnings(rawConfig));
|
|
10931
10918
|
const migratedExperimental = migrateLegacyExperimental(configWithoutRemovedAgent, preMigrationWarnings);
|
|
10919
|
+
warnDeprecatedMuralModel(migratedExperimental, preMigrationWarnings);
|
|
10932
10920
|
const migratedDreamer = migrateDreamerV2(migratedExperimental, preMigrationWarnings);
|
|
10933
10921
|
const migrated = migrateLegacyAgentEnabledInMemory(migratedDreamer, preMigrationWarnings);
|
|
10934
10922
|
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
@@ -12856,17 +12844,23 @@ __export(exports_sqlite, {
|
|
|
12856
12844
|
detectSqliteRuntime: () => detectSqliteRuntime,
|
|
12857
12845
|
getSqliteDatabasePath: () => getSqliteDatabasePath,
|
|
12858
12846
|
getSqliteMemoryStats: () => getSqliteMemoryStats,
|
|
12847
|
+
getTagIdentityWriteGeneration: () => getTagIdentityWriteGeneration,
|
|
12859
12848
|
guardSqliteTransformPass: () => guardSqliteTransformPass,
|
|
12849
|
+
indexCoordinationInput: () => indexCoordinationInput,
|
|
12860
12850
|
isTransientSqliteError: () => isTransientSqliteError,
|
|
12861
12851
|
loadSqliteModule: () => loadSqliteModule,
|
|
12852
|
+
mayChangeTagIdentity: () => mayChangeTagIdentity,
|
|
12862
12853
|
prepareCachedStatement: () => prepareCachedStatement,
|
|
12863
12854
|
registerSlowWriteReporter: () => registerSlowWriteReporter,
|
|
12864
12855
|
registerSqliteDiagnosticSink: () => registerSqliteDiagnosticSink,
|
|
12856
|
+
releaseIndexOwner: () => releaseIndexOwner,
|
|
12865
12857
|
withAsyncPrivilegedWriter: () => withAsyncPrivilegedWriter,
|
|
12858
|
+
withIndexChunk: () => withIndexChunk,
|
|
12866
12859
|
withPrivilegedWriter: () => withPrivilegedWriter,
|
|
12867
12860
|
withSqliteBackgroundWriter: () => withSqliteBackgroundWriter,
|
|
12868
12861
|
withSqliteTransformPass: () => withSqliteTransformPass,
|
|
12869
|
-
withoutSqliteTransformPass: () => withoutSqliteTransformPass
|
|
12862
|
+
withoutSqliteTransformPass: () => withoutSqliteTransformPass,
|
|
12863
|
+
yieldIndexChunk: () => yieldIndexChunk
|
|
12870
12864
|
});
|
|
12871
12865
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
12872
12866
|
import { statSync as statSync4 } from "node:fs";
|
|
@@ -12900,10 +12894,31 @@ function isModuleNotFoundError(error, specifier) {
|
|
|
12900
12894
|
return false;
|
|
12901
12895
|
return code === "ERR_MODULE_NOT_FOUND" || code === "ERR_UNKNOWN_BUILTIN_MODULE" || code === "MODULE_NOT_FOUND" || name === "ResolveMessage" || details.includes("module not found") || details.includes("cannot find module") || details.includes("cannot find package") || details.includes("no such built-in module");
|
|
12902
12896
|
}
|
|
12897
|
+
function isNodeSqliteExperimentalWarning(args) {
|
|
12898
|
+
const [warning, options] = args;
|
|
12899
|
+
const message = warning instanceof Error ? warning.message : warning;
|
|
12900
|
+
const type = typeof options === "string" ? options : options && typeof options === "object" ? options.type : undefined;
|
|
12901
|
+
return type === "ExperimentalWarning" && typeof message === "string" && message.startsWith("SQLite is an experimental feature");
|
|
12902
|
+
}
|
|
12903
|
+
async function importSqliteModuleForRuntime(runtime, specifier, importer) {
|
|
12904
|
+
if (runtime !== "Node.js")
|
|
12905
|
+
return importer(specifier);
|
|
12906
|
+
const originalEmitWarning = process.emitWarning;
|
|
12907
|
+
process.emitWarning = function(...args) {
|
|
12908
|
+
if (isNodeSqliteExperimentalWarning(args))
|
|
12909
|
+
return;
|
|
12910
|
+
Reflect.apply(originalEmitWarning, this, args);
|
|
12911
|
+
};
|
|
12912
|
+
try {
|
|
12913
|
+
return await importer(specifier);
|
|
12914
|
+
} finally {
|
|
12915
|
+
process.emitWarning = originalEmitWarning;
|
|
12916
|
+
}
|
|
12917
|
+
}
|
|
12903
12918
|
async function loadSqliteModule(runtime = detectSqliteRuntime(), importer = importSqliteModule) {
|
|
12904
12919
|
const specifier = runtime === "Bun" ? bunSpec : nodeSpec;
|
|
12905
12920
|
try {
|
|
12906
|
-
return await
|
|
12921
|
+
return await importSqliteModuleForRuntime(runtime, specifier, importer);
|
|
12907
12922
|
} catch (error) {
|
|
12908
12923
|
if (isModuleNotFoundError(error, specifier)) {
|
|
12909
12924
|
throw new SqliteRuntimeUnavailableError(runtime, specifier, error);
|
|
@@ -12911,6 +12926,67 @@ async function loadSqliteModule(runtime = detectSqliteRuntime(), importer = impo
|
|
|
12911
12926
|
throw error;
|
|
12912
12927
|
}
|
|
12913
12928
|
}
|
|
12929
|
+
function mayChangeTagIdentity(sql) {
|
|
12930
|
+
if (!/\btags\b/i.test(sql) || /^\s*(?:SELECT|EXPLAIN|PRAGMA)\b/i.test(sql))
|
|
12931
|
+
return false;
|
|
12932
|
+
if (/^\s*WITH\b/i.test(sql) && !/\b(?:INSERT|UPDATE|DELETE|REPLACE)\b/i.test(sql))
|
|
12933
|
+
return false;
|
|
12934
|
+
if (/;\s*\S/.test(sql) || /\bREPLACE\b/i.test(sql) || /\bON\s+CONFLICT\b/i.test(sql))
|
|
12935
|
+
return true;
|
|
12936
|
+
const insert = /^\s*INSERT\s+INTO\s+(?:main\.)?["`]?tags["`]?\s*\(([^)]*)\)/i.exec(sql);
|
|
12937
|
+
if (insert) {
|
|
12938
|
+
const columns = (insert[1] ?? "").split(",").map((column) => column.trim().replace(/["`[\]]/g, "").toLowerCase());
|
|
12939
|
+
return columns.includes("id") || columns.includes("rowid");
|
|
12940
|
+
}
|
|
12941
|
+
const update = /^\s*UPDATE\s+(?:main\.)?["`]?tags["`]?\s+SET\s+([\s\S]*?)\bWHERE\b/i.exec(sql);
|
|
12942
|
+
if (update && !/\bSELECT\b/i.test(sql)) {
|
|
12943
|
+
const assignments = topLevelCommaSegments(update[1] ?? "");
|
|
12944
|
+
if (!assignments)
|
|
12945
|
+
return true;
|
|
12946
|
+
return !assignments.every((assignment) => {
|
|
12947
|
+
const column = /^\s*["`]?(\w+)["`]?\s*=(?!=)/.exec(assignment)?.[1];
|
|
12948
|
+
return column !== undefined && TAG_COLUMNS_OUTSIDE_IDENTITY.has(column.toLowerCase());
|
|
12949
|
+
});
|
|
12950
|
+
}
|
|
12951
|
+
return true;
|
|
12952
|
+
}
|
|
12953
|
+
function topLevelCommaSegments(text) {
|
|
12954
|
+
const segments = [];
|
|
12955
|
+
let depth = 0;
|
|
12956
|
+
let quote = null;
|
|
12957
|
+
let start = 0;
|
|
12958
|
+
for (let index = 0;index < text.length; index += 1) {
|
|
12959
|
+
const char = text[index];
|
|
12960
|
+
if (quote) {
|
|
12961
|
+
if (char === quote) {
|
|
12962
|
+
if (text[index + 1] === quote)
|
|
12963
|
+
index += 1;
|
|
12964
|
+
else
|
|
12965
|
+
quote = null;
|
|
12966
|
+
}
|
|
12967
|
+
continue;
|
|
12968
|
+
}
|
|
12969
|
+
if (char === "'" || char === '"' || char === "`")
|
|
12970
|
+
quote = char;
|
|
12971
|
+
else if (char === "(")
|
|
12972
|
+
depth += 1;
|
|
12973
|
+
else if (char === ")") {
|
|
12974
|
+
depth -= 1;
|
|
12975
|
+
if (depth < 0)
|
|
12976
|
+
return null;
|
|
12977
|
+
} else if (char === "," && depth === 0) {
|
|
12978
|
+
segments.push(text.slice(start, index));
|
|
12979
|
+
start = index + 1;
|
|
12980
|
+
}
|
|
12981
|
+
}
|
|
12982
|
+
if (quote || depth !== 0)
|
|
12983
|
+
return null;
|
|
12984
|
+
segments.push(text.slice(start));
|
|
12985
|
+
return segments;
|
|
12986
|
+
}
|
|
12987
|
+
function getTagIdentityWriteGeneration() {
|
|
12988
|
+
return tagIdentityWriteGeneration;
|
|
12989
|
+
}
|
|
12914
12990
|
function installTransactionRouting(db, readonly) {
|
|
12915
12991
|
const nativeExec = db.exec.bind(db);
|
|
12916
12992
|
Object.defineProperty(db, "exec", {
|
|
@@ -12929,8 +13005,14 @@ function installTransactionRouting(db, readonly) {
|
|
|
12929
13005
|
}
|
|
12930
13006
|
if (WRITER_TRANSACTION_END.test(sql) && openWriterTransactions.has(db))
|
|
12931
13007
|
return endWriterTransaction(db, () => nativeExec(sql), sql);
|
|
12932
|
-
if (!/^\s*(?:SELECT|EXPLAIN|PRAGMA|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i.test(sql))
|
|
12933
|
-
|
|
13008
|
+
if (!/^\s*(?:SELECT|EXPLAIN|PRAGMA|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i.test(sql)) {
|
|
13009
|
+
try {
|
|
13010
|
+
return withAutocommitTimeout(db, () => nativeExec(sql));
|
|
13011
|
+
} finally {
|
|
13012
|
+
if (mayChangeTagIdentity(sql))
|
|
13013
|
+
tagIdentityWriteGeneration += 1;
|
|
13014
|
+
}
|
|
13015
|
+
}
|
|
12934
13016
|
return nativeExec(sql);
|
|
12935
13017
|
}
|
|
12936
13018
|
});
|
|
@@ -12941,13 +13023,23 @@ function installTransactionRouting(db, readonly) {
|
|
|
12941
13023
|
value: (sql) => {
|
|
12942
13024
|
const statement = nativePrepare(sql);
|
|
12943
13025
|
if (!readonly && !/^\s*(?:SELECT|EXPLAIN|PRAGMA)\b/i.test(sql)) {
|
|
13026
|
+
const changesTagIdentity = mayChangeTagIdentity(sql);
|
|
12944
13027
|
for (const method of ["run", "get", "all"]) {
|
|
12945
13028
|
const execute = statement[method].bind(statement);
|
|
12946
13029
|
Object.defineProperty(statement, method, {
|
|
12947
13030
|
configurable: true,
|
|
12948
|
-
value: (...args) =>
|
|
13031
|
+
value: (...args) => {
|
|
13032
|
+
try {
|
|
13033
|
+
return withAutocommitTimeout(db, () => execute(...args));
|
|
13034
|
+
} finally {
|
|
13035
|
+
if (changesTagIdentity)
|
|
13036
|
+
tagIdentityWriteGeneration += 1;
|
|
13037
|
+
}
|
|
13038
|
+
}
|
|
12949
13039
|
});
|
|
12950
13040
|
}
|
|
13041
|
+
if (changesTagIdentity)
|
|
13042
|
+
wrapRemainingTagWriteForms(statement);
|
|
12951
13043
|
}
|
|
12952
13044
|
return statement;
|
|
12953
13045
|
}
|
|
@@ -12995,6 +13087,35 @@ function installTransactionRouting(db, readonly) {
|
|
|
12995
13087
|
}
|
|
12996
13088
|
});
|
|
12997
13089
|
}
|
|
13090
|
+
function wrapRemainingTagWriteForms(statement) {
|
|
13091
|
+
if (typeof statement.iterate === "function") {
|
|
13092
|
+
const iterate = statement.iterate.bind(statement);
|
|
13093
|
+
Object.defineProperty(statement, "iterate", {
|
|
13094
|
+
configurable: true,
|
|
13095
|
+
value: function* (...args) {
|
|
13096
|
+
tagIdentityWriteGeneration += 1;
|
|
13097
|
+
try {
|
|
13098
|
+
yield* iterate(...args);
|
|
13099
|
+
} finally {
|
|
13100
|
+
tagIdentityWriteGeneration += 1;
|
|
13101
|
+
}
|
|
13102
|
+
}
|
|
13103
|
+
});
|
|
13104
|
+
}
|
|
13105
|
+
if (typeof statement.values === "function") {
|
|
13106
|
+
const values = statement.values.bind(statement);
|
|
13107
|
+
Object.defineProperty(statement, "values", {
|
|
13108
|
+
configurable: true,
|
|
13109
|
+
value: (...args) => {
|
|
13110
|
+
try {
|
|
13111
|
+
return values(...args);
|
|
13112
|
+
} finally {
|
|
13113
|
+
tagIdentityWriteGeneration += 1;
|
|
13114
|
+
}
|
|
13115
|
+
}
|
|
13116
|
+
});
|
|
13117
|
+
}
|
|
13118
|
+
}
|
|
12998
13119
|
function trackSqliteConnection(db, filename, options) {
|
|
12999
13120
|
const originalClose = db.close.bind(db);
|
|
13000
13121
|
const sequence = nextSqliteConnectionSequence++;
|
|
@@ -13054,6 +13175,10 @@ function getSqliteDatabasePath(db) {
|
|
|
13054
13175
|
return connection.filename === ":memory:" || connection.filename === "<buffer>" ? null : connection.filename;
|
|
13055
13176
|
}
|
|
13056
13177
|
}
|
|
13178
|
+
const native = db;
|
|
13179
|
+
const path = native.filename ?? native.name;
|
|
13180
|
+
if (typeof path === "string" && path !== ":memory:" && path !== "")
|
|
13181
|
+
return path;
|
|
13057
13182
|
return null;
|
|
13058
13183
|
}
|
|
13059
13184
|
function pragmaValue(db, name) {
|
|
@@ -13135,6 +13260,15 @@ function getSqliteMemoryStats() {
|
|
|
13135
13260
|
connections
|
|
13136
13261
|
};
|
|
13137
13262
|
}
|
|
13263
|
+
function closeReleasingStatements(close, args) {
|
|
13264
|
+
if (args[0] === true)
|
|
13265
|
+
return close(true);
|
|
13266
|
+
try {
|
|
13267
|
+
return close(true);
|
|
13268
|
+
} catch {
|
|
13269
|
+
return close(...args);
|
|
13270
|
+
}
|
|
13271
|
+
}
|
|
13138
13272
|
function ownPreparedStatement(db, statement) {
|
|
13139
13273
|
const finalizable = statement;
|
|
13140
13274
|
if (typeof finalizable.finalize !== "function")
|
|
@@ -13158,7 +13292,7 @@ function ownPreparedStatement(db, statement) {
|
|
|
13158
13292
|
}
|
|
13159
13293
|
}
|
|
13160
13294
|
references.clear();
|
|
13161
|
-
const result = close
|
|
13295
|
+
const result = closeReleasingStatements(close, args);
|
|
13162
13296
|
if (failure)
|
|
13163
13297
|
throw failure;
|
|
13164
13298
|
return result;
|
|
@@ -13188,22 +13322,29 @@ function withSqliteTransformPass(operation) {
|
|
|
13188
13322
|
const existing = transformPassScope.getStore();
|
|
13189
13323
|
if (existing?.active)
|
|
13190
13324
|
return operation();
|
|
13191
|
-
const
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
|
|
13198
|
-
|
|
13325
|
+
const reservation = reserveForegroundSqliteTurn();
|
|
13326
|
+
const run = (release) => {
|
|
13327
|
+
const lease = { active: true, remainingWaitMs: FOREGROUND_IN_PASS_BUSY_TIMEOUT_MS };
|
|
13328
|
+
return transformPassScope.run(lease, () => {
|
|
13329
|
+
try {
|
|
13330
|
+
const result = operation();
|
|
13331
|
+
if (result && typeof result.then === "function") {
|
|
13332
|
+
return Promise.resolve(result).finally(() => {
|
|
13333
|
+
lease.active = false;
|
|
13334
|
+
release();
|
|
13335
|
+
});
|
|
13336
|
+
}
|
|
13337
|
+
lease.active = false;
|
|
13338
|
+
release();
|
|
13339
|
+
return result;
|
|
13340
|
+
} catch (error) {
|
|
13341
|
+
lease.active = false;
|
|
13342
|
+
release();
|
|
13343
|
+
throw error;
|
|
13199
13344
|
}
|
|
13200
|
-
|
|
13201
|
-
|
|
13202
|
-
|
|
13203
|
-
lease.active = false;
|
|
13204
|
-
throw error;
|
|
13205
|
-
}
|
|
13206
|
-
});
|
|
13345
|
+
});
|
|
13346
|
+
};
|
|
13347
|
+
return typeof reservation === "function" ? run(reservation) : reservation.then(run);
|
|
13207
13348
|
}
|
|
13208
13349
|
function withoutSqliteTransformPass(operation) {
|
|
13209
13350
|
return transformPassScope.run(undefined, operation);
|
|
@@ -13291,18 +13432,20 @@ function acquireShort(db, acquire, site) {
|
|
|
13291
13432
|
}
|
|
13292
13433
|
function endWriterTransaction(db, end, sql) {
|
|
13293
13434
|
let ended = false;
|
|
13435
|
+
const endStarted = performance.now();
|
|
13294
13436
|
try {
|
|
13295
13437
|
const result = end();
|
|
13296
13438
|
ended = true;
|
|
13297
13439
|
return result;
|
|
13298
13440
|
} finally {
|
|
13299
13441
|
const open = openWriterTransactions.get(db);
|
|
13442
|
+
const endMs = performance.now() - endStarted;
|
|
13300
13443
|
if (open && !isInTransaction(db)) {
|
|
13301
13444
|
openWriterTransactions.delete(db);
|
|
13302
13445
|
const holdMs = performance.now() - open.acquiredAt;
|
|
13303
13446
|
if (open.acquireMs >= SLOW_WRITER_LOG_MS || holdMs >= SLOW_WRITER_LOG_MS) {
|
|
13304
13447
|
const outcome = /^\s*ROLLBACK/i.test(sql) ? "rolled_back" : ended ? "committed" : "failed";
|
|
13305
|
-
reportSqliteDiagnostic(`sqlite writer site=${open.site} lane=${open.lane} acquire_ms=${Math.round(open.acquireMs)} hold_ms=${Math.round(holdMs)} attempts=${open.attempts} outcome=${outcome}`);
|
|
13448
|
+
reportSqliteDiagnostic(`sqlite writer site=${open.site} lane=${open.lane} acquire_ms=${Math.round(open.acquireMs)} hold_ms=${Math.round(holdMs)} end_ms=${Math.round(endMs)} attempts=${open.attempts} outcome=${outcome}`);
|
|
13306
13449
|
}
|
|
13307
13450
|
}
|
|
13308
13451
|
}
|
|
@@ -13442,7 +13585,55 @@ function withPrivilegedWriter(db, operation) {
|
|
|
13442
13585
|
throw error;
|
|
13443
13586
|
}
|
|
13444
13587
|
}
|
|
13445
|
-
|
|
13588
|
+
function indexCoordinationInput() {
|
|
13589
|
+
return {
|
|
13590
|
+
indexCoordination: indexCoordinationBuffer,
|
|
13591
|
+
indexOwner: Atomics.add(indexCoordinationState, 2, 1) + 1
|
|
13592
|
+
};
|
|
13593
|
+
}
|
|
13594
|
+
function reserveForegroundSqliteTurn() {
|
|
13595
|
+
Atomics.add(indexCoordinationState, 0, 1);
|
|
13596
|
+
const release = () => {
|
|
13597
|
+
Atomics.sub(indexCoordinationState, 0, 1);
|
|
13598
|
+
Atomics.notify(indexCoordinationState, 0);
|
|
13599
|
+
};
|
|
13600
|
+
if (Atomics.load(indexCoordinationState, 1) === 0)
|
|
13601
|
+
return release;
|
|
13602
|
+
return (async () => {
|
|
13603
|
+
while (Atomics.load(indexCoordinationState, 1) !== 0)
|
|
13604
|
+
await yieldIndexTurn();
|
|
13605
|
+
return release;
|
|
13606
|
+
})();
|
|
13607
|
+
}
|
|
13608
|
+
function releaseIndexOwner(input) {
|
|
13609
|
+
if (!input.indexCoordination || !input.indexOwner)
|
|
13610
|
+
return;
|
|
13611
|
+
const shared = new Int32Array(input.indexCoordination);
|
|
13612
|
+
Atomics.compareExchange(shared, 1, input.indexOwner, 0);
|
|
13613
|
+
Atomics.notify(shared, 1);
|
|
13614
|
+
}
|
|
13615
|
+
async function withIndexChunk(input, operation) {
|
|
13616
|
+
if (!input.indexCoordination || !input.indexOwner)
|
|
13617
|
+
return operation();
|
|
13618
|
+
const shared = new Int32Array(input.indexCoordination);
|
|
13619
|
+
for (;; ) {
|
|
13620
|
+
if (Atomics.load(shared, 0) === 0 && Atomics.compareExchange(shared, 1, 0, input.indexOwner) === 0) {
|
|
13621
|
+
if (Atomics.load(shared, 0) === 0)
|
|
13622
|
+
break;
|
|
13623
|
+
releaseIndexOwner(input);
|
|
13624
|
+
}
|
|
13625
|
+
await yieldIndexTurn();
|
|
13626
|
+
}
|
|
13627
|
+
try {
|
|
13628
|
+
return await operation();
|
|
13629
|
+
} finally {
|
|
13630
|
+
releaseIndexOwner(input);
|
|
13631
|
+
}
|
|
13632
|
+
}
|
|
13633
|
+
async function yieldIndexChunk() {
|
|
13634
|
+
await yieldIndexTurn();
|
|
13635
|
+
}
|
|
13636
|
+
var reportSlowPrivilegedWrite, sqliteDiagnosticSink, bunSpec, nodeSpec, SqliteRuntimeUnavailableError, detectedRuntime, isBun, sqliteModule, DatabaseImpl, trackedSqliteConnections, nextSqliteConnectionSequence = 1, TAG_COLUMNS_OUTSIDE_IDENTITY, tagIdentityWriteGeneration = 0, TrackedDatabase, Database, statementOwners, FIRST_PRUNE_AT = 256, privilegeDepth, transformPassScope, admissionScope, backgroundWriterScope, SqliteAcquisitionBusyError, SHORT_BUSY_TIMEOUT_MS = 25, FOREGROUND_IN_PASS_BUSY_TIMEOUT_MS = 250, FOREGROUND_ACQUISITION_BUDGET_MS = 16500, SLOW_WRITER_LOG_MS = 250, WRITER_TRANSACTION_END, writerAcquisitionScope, openWriterTransactions, indexCoordinationKey, indexCoordinationHeap, indexCoordinationBuffer, indexCoordinationState, yieldIndexTurn = () => new Promise((resolve) => setTimeout(resolve, 1));
|
|
13446
13637
|
var init_sqlite = __esm(async () => {
|
|
13447
13638
|
bunSpec = "bun:" + "sqlite";
|
|
13448
13639
|
nodeSpec = "node:" + "sqlite";
|
|
@@ -13462,6 +13653,19 @@ var init_sqlite = __esm(async () => {
|
|
|
13462
13653
|
sqliteModule = await loadSqliteModule(detectedRuntime);
|
|
13463
13654
|
DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
|
|
13464
13655
|
trackedSqliteConnections = new Map;
|
|
13656
|
+
TAG_COLUMNS_OUTSIDE_IDENTITY = new Set([
|
|
13657
|
+
"status",
|
|
13658
|
+
"drop_mode",
|
|
13659
|
+
"byte_size",
|
|
13660
|
+
"input_byte_size",
|
|
13661
|
+
"reasoning_byte_size",
|
|
13662
|
+
"token_count",
|
|
13663
|
+
"input_token_count",
|
|
13664
|
+
"caveman_depth",
|
|
13665
|
+
"entry_fingerprint",
|
|
13666
|
+
"tool_name",
|
|
13667
|
+
"harness"
|
|
13668
|
+
]);
|
|
13465
13669
|
TrackedDatabase = new Proxy(DatabaseImpl, {
|
|
13466
13670
|
construct(target, args) {
|
|
13467
13671
|
const db = Reflect.construct(target, args, target);
|
|
@@ -13486,6 +13690,11 @@ var init_sqlite = __esm(async () => {
|
|
|
13486
13690
|
WRITER_TRANSACTION_END = /^\s*(?:COMMIT|END|ROLLBACK)(?:\s+TRANSACTION)?\s*;?\s*$/i;
|
|
13487
13691
|
writerAcquisitionScope = new AsyncLocalStorage;
|
|
13488
13692
|
openWriterTransactions = new WeakMap;
|
|
13693
|
+
indexCoordinationKey = Symbol.for("magic-context.index-foreground-coordination.v1");
|
|
13694
|
+
indexCoordinationHeap = globalThis;
|
|
13695
|
+
indexCoordinationBuffer = indexCoordinationHeap[indexCoordinationKey] ?? new SharedArrayBuffer(3 * Int32Array.BYTES_PER_ELEMENT);
|
|
13696
|
+
indexCoordinationHeap[indexCoordinationKey] = indexCoordinationBuffer;
|
|
13697
|
+
indexCoordinationState = new Int32Array(indexCoordinationBuffer);
|
|
13489
13698
|
});
|
|
13490
13699
|
|
|
13491
13700
|
// src/lib/docs-proposal-gitignore.ts
|
|
@@ -22933,6 +23142,22 @@ function readConfiguredOpenCodePluginSpec(config) {
|
|
|
22933
23142
|
}
|
|
22934
23143
|
return "latest";
|
|
22935
23144
|
}
|
|
23145
|
+
function readReferencedOpenCodePluginSpecs(config, host) {
|
|
23146
|
+
const specs = new Set;
|
|
23147
|
+
for (const { key, entry } of readPluginEntries(config)) {
|
|
23148
|
+
if (host === "opencode1" && key !== "plugin")
|
|
23149
|
+
continue;
|
|
23150
|
+
const specifier = pluginEntrySpecifier(entry);
|
|
23151
|
+
const spec = specifier === undefined ? undefined : openCodeV2PluginSpecOf(specifier);
|
|
23152
|
+
if (spec !== undefined)
|
|
23153
|
+
specs.add(spec);
|
|
23154
|
+
}
|
|
23155
|
+
return specs;
|
|
23156
|
+
}
|
|
23157
|
+
function describeUnusedOpenCodePluginCache(input) {
|
|
23158
|
+
const why = input.loadedFrom ? `the config loads Magic Context from ${input.loadedFrom}` : `no ${input.host} plugin entry in the config references it`;
|
|
23159
|
+
return `${input.host} plugin cache: unused cached copy of ${OPENCODE_PLUGIN_NAME}@${input.spec} (cached: ${input.cached ?? "unreadable"}); ${input.host} never loads it because ${why}. Informational, nothing breaks; safe to delete: ${input.paths.join(", ")}`;
|
|
23160
|
+
}
|
|
22936
23161
|
function pluginEntrySpecifier(entry) {
|
|
22937
23162
|
if (typeof entry === "string")
|
|
22938
23163
|
return entry;
|
|
@@ -23158,6 +23383,9 @@ function checkOpenCodeV2PluginCache(options, deps = {}) {
|
|
|
23158
23383
|
const distTag = options.distTag && options.distTag !== "latest" ? options.distTag : undefined;
|
|
23159
23384
|
const slot = deps.slot ?? getOpenCodeV2PluginCacheSlot(undefined, distTag ?? "latest");
|
|
23160
23385
|
const tagged = distTag ? { distTag } : {};
|
|
23386
|
+
if (options.referencedSpecs !== undefined && !options.referencedSpecs.has(distTag ?? "latest")) {
|
|
23387
|
+
return existsSync13(slot) ? { action: "unused", slot, cached: readOpenCodeV2CachedPluginVersion(slot), ...tagged } : { action: "not_found", slot, unused: true, ...tagged };
|
|
23388
|
+
}
|
|
23161
23389
|
if (!existsSync13(slot))
|
|
23162
23390
|
return { action: "not_found", slot, ...tagged };
|
|
23163
23391
|
const cached = readOpenCodeV2CachedPluginVersion(slot);
|
|
@@ -23197,7 +23425,7 @@ function reportOpenCodeV2PluginCache(result, report, options) {
|
|
|
23197
23425
|
const slotName = result.distTag ? ` @${result.distTag}` : "";
|
|
23198
23426
|
switch (result.action) {
|
|
23199
23427
|
case "not_found":
|
|
23200
|
-
if (options.reportMissing) {
|
|
23428
|
+
if (options.reportMissing && !result.unused) {
|
|
23201
23429
|
report.pass(`OpenCode 2 plugin cache has no Magic Context${slotName} install yet (OpenCode installs it on next start)`);
|
|
23202
23430
|
}
|
|
23203
23431
|
return { fixed: false, issue: false };
|
|
@@ -23225,6 +23453,15 @@ function reportOpenCodeV2PluginCache(result, report, options) {
|
|
|
23225
23453
|
report.pass(`Cleared ${result.forced ? "" : "outdated "}Magic Context${slotName} from the OpenCode 2 plugin cache (${versions}${result.forced ? ", --force" : ""}) — OpenCode installs the ${result.distTag ? `current ${tag} release` : "latest"} on next start`);
|
|
23226
23454
|
report.info(` ${result.slot}`);
|
|
23227
23455
|
return { fixed: true, issue: false };
|
|
23456
|
+
case "unused":
|
|
23457
|
+
report.info(describeUnusedOpenCodePluginCache({
|
|
23458
|
+
host: "OpenCode 2",
|
|
23459
|
+
spec: tag,
|
|
23460
|
+
cached: result.cached,
|
|
23461
|
+
paths: [result.slot],
|
|
23462
|
+
loadedFrom: options.loadedFrom
|
|
23463
|
+
}));
|
|
23464
|
+
return { fixed: false, issue: false };
|
|
23228
23465
|
case "error":
|
|
23229
23466
|
report.warn(`Could not clear the OpenCode 2 plugin cache: ${result.error}`);
|
|
23230
23467
|
report.info(` Manually delete: ${result.slot}`);
|
|
@@ -28760,6 +28997,90 @@ var init_migrations = __esm(async () => {
|
|
|
28760
28997
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
28761
28998
|
});
|
|
28762
28999
|
|
|
29000
|
+
// ../plugin/src/features/magic-context/storage-tag-identity-revision.ts
|
|
29001
|
+
function installTagIdentityRevisionTrigger(db) {
|
|
29002
|
+
db.exec(`DROP TRIGGER IF EXISTS temp.mc_tag_identity_revision_au;
|
|
29003
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_bi;
|
|
29004
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_ai;
|
|
29005
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_au;
|
|
29006
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_ad;
|
|
29007
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_seed_ai;`);
|
|
29008
|
+
db.exec(`CREATE TEMP TRIGGER mc_tag_revision_seed_ai AFTER INSERT ON main.schema_migrations_meta
|
|
29009
|
+
WHEN INSTR(NEW.value, ':') = 0 AND (
|
|
29010
|
+
SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
|
|
29011
|
+
OR SUBSTR(NEW.key, 1, ${TAG_IDENTITY_REVISION_PREFIX.length}) = '${TAG_IDENTITY_REVISION_PREFIX}')
|
|
29012
|
+
BEGIN
|
|
29013
|
+
INSERT INTO schema_migrations_meta (key, value) VALUES ('${TAG_REVISION_INCARNATION_KEY}', '1')
|
|
29014
|
+
ON CONFLICT(key) DO UPDATE SET value = CAST(CASE
|
|
29015
|
+
WHEN CAST(value AS INTEGER) < 9223372036854775807 THEN CAST(value AS INTEGER) + 1
|
|
29016
|
+
ELSE NULL END AS TEXT);
|
|
29017
|
+
UPDATE schema_migrations_meta SET value =
|
|
29018
|
+
(SELECT value FROM schema_migrations_meta WHERE key = '${TAG_REVISION_INCARNATION_KEY}')
|
|
29019
|
+
|| ':' || CAST(NEW.value AS TEXT) WHERE key = NEW.key;
|
|
29020
|
+
INSERT INTO schema_migrations_meta (key, value)
|
|
29021
|
+
SELECT '${TAG_REVISION_INCARNATION_KEY}', '1'
|
|
29022
|
+
WHERE SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
|
|
29023
|
+
AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta
|
|
29024
|
+
WHERE key = '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}))
|
|
29025
|
+
ON CONFLICT(key) DO UPDATE SET value = CAST(CASE
|
|
29026
|
+
WHEN CAST(value AS INTEGER) < 9223372036854775807 THEN CAST(value AS INTEGER) + 1
|
|
29027
|
+
ELSE NULL END AS TEXT);
|
|
29028
|
+
INSERT INTO schema_migrations_meta (key, value)
|
|
29029
|
+
SELECT '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}),
|
|
29030
|
+
(SELECT value FROM schema_migrations_meta WHERE key = '${TAG_REVISION_INCARNATION_KEY}') || ':0'
|
|
29031
|
+
WHERE SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
|
|
29032
|
+
AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta
|
|
29033
|
+
WHERE key = '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}));
|
|
29034
|
+
END;`);
|
|
29035
|
+
db.exec(TRIGGER_SQL);
|
|
29036
|
+
db.exec(`CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_bi BEFORE INSERT ON main.tags BEGIN
|
|
29037
|
+
${BUMP_INSERT_CONFLICTS(TAG_REVISION_PREFIX)};
|
|
29038
|
+
${BUMP_INSERT_CONFLICTS(TAG_IDENTITY_REVISION_PREFIX)};
|
|
29039
|
+
UPDATE session_meta SET tags_version = tags_version + 1
|
|
29040
|
+
WHERE session_id IN (SELECT session_id FROM (${TAG_INSERT_CONFLICT_ROWS}));
|
|
29041
|
+
END;`);
|
|
29042
|
+
db.exec(`CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_ai AFTER INSERT ON main.tags BEGIN
|
|
29043
|
+
${BUMP("NEW.session_id", TAG_REVISION_PREFIX)};
|
|
29044
|
+
END;
|
|
29045
|
+
CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_au AFTER UPDATE ON main.tags BEGIN
|
|
29046
|
+
${BUMP("OLD.session_id", TAG_REVISION_PREFIX)};
|
|
29047
|
+
INSERT INTO schema_migrations_meta (key, value)
|
|
29048
|
+
SELECT '${TAG_REVISION_PREFIX}' || NEW.session_id, '1'
|
|
29049
|
+
WHERE NEW.session_id IS NOT OLD.session_id
|
|
29050
|
+
ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()};
|
|
29051
|
+
END;
|
|
29052
|
+
CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_ad AFTER DELETE ON main.tags BEGIN
|
|
29053
|
+
${BUMP("OLD.session_id", TAG_REVISION_PREFIX)};
|
|
29054
|
+
END;`);
|
|
29055
|
+
}
|
|
29056
|
+
var TAG_IDENTITY_REVISION_PREFIX = "tag_identity_revision:", TAG_REVISION_PREFIX = "tag_revision:", TAG_REVISION_INCARNATION_KEY = "tag_revision_incarnation", tagRevisionIncarnationSql = (value) => `CASE WHEN INSTR(${value}, ':') > 0 THEN SUBSTR(${value}, 1, INSTR(${value}, ':') - 1) ELSE '0' END`, tagRevisionCountSql = (value) => `CAST(CASE WHEN INSTR(${value}, ':') > 0 THEN SUBSTR(${value}, INSTR(${value}, ':') + 1) ELSE ${value} END AS INTEGER)`, ADVANCE = (delta = "1") => `CASE
|
|
29057
|
+
WHEN ${tagRevisionCountSql("value")} <= 9223372036854775807 - ${delta}
|
|
29058
|
+
THEN (${tagRevisionIncarnationSql("value")}) || ':' || CAST(${tagRevisionCountSql("value")} + ${delta} AS TEXT)
|
|
29059
|
+
ELSE NULL END`, BUMP = (session, prefix = TAG_IDENTITY_REVISION_PREFIX) => `INSERT INTO schema_migrations_meta (key, value)
|
|
29060
|
+
VALUES ('${prefix}' || ${session}, '1')
|
|
29061
|
+
ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()}`, TAG_INSERT_CONFLICT_ROWS = `SELECT id, session_id, tag_number FROM tags WHERE id = NEW.id
|
|
29062
|
+
UNION SELECT id, session_id, tag_number FROM tags WHERE session_id = NEW.session_id AND tag_number = NEW.tag_number
|
|
29063
|
+
UNION SELECT id, session_id, tag_number FROM tags
|
|
29064
|
+
WHERE NEW.type = 'tool' AND NEW.tool_owner_message_id IS NOT NULL
|
|
29065
|
+
AND type = 'tool' AND tool_owner_message_id IS NOT NULL
|
|
29066
|
+
AND session_id = NEW.session_id AND message_id = NEW.message_id
|
|
29067
|
+
AND tool_owner_message_id = NEW.tool_owner_message_id`, BUMP_INSERT_CONFLICTS = (prefix) => `INSERT INTO schema_migrations_meta (key, value)
|
|
29068
|
+
SELECT '${prefix}' || session_id, CAST(COUNT(*) AS TEXT)
|
|
29069
|
+
FROM (${TAG_INSERT_CONFLICT_ROWS}) GROUP BY session_id
|
|
29070
|
+
ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE("CAST(excluded.value AS INTEGER)")}`, TRIGGER_SQL;
|
|
29071
|
+
var init_storage_tag_identity_revision = __esm(() => {
|
|
29072
|
+
TRIGGER_SQL = `CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_identity_revision_au
|
|
29073
|
+
AFTER UPDATE OF id, session_id, message_id, tag_number, type, tool_owner_message_id, reasoning_token_count
|
|
29074
|
+
ON main.tags
|
|
29075
|
+
BEGIN
|
|
29076
|
+
${BUMP("OLD.session_id")};
|
|
29077
|
+
INSERT INTO schema_migrations_meta (key, value)
|
|
29078
|
+
SELECT '${TAG_IDENTITY_REVISION_PREFIX}' || NEW.session_id, '1'
|
|
29079
|
+
WHERE NEW.session_id IS NOT OLD.session_id
|
|
29080
|
+
ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()};
|
|
29081
|
+
END`;
|
|
29082
|
+
});
|
|
29083
|
+
|
|
28763
29084
|
// ../plugin/src/shared/commit-detection.ts
|
|
28764
29085
|
function createCommitHashExtractPattern() {
|
|
28765
29086
|
return new RegExp(`\`?\\b(${HASH_HEX})\\b\`?`, "gi");
|
|
@@ -28782,6 +29103,271 @@ function removeSystemReminders(text) {
|
|
|
28782
29103
|
}
|
|
28783
29104
|
var SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: MAGIC-CONTEXT";
|
|
28784
29105
|
|
|
29106
|
+
// ../plugin/src/hooks/magic-context/token-count-exact.ts
|
|
29107
|
+
function hasInternals(tokenizer) {
|
|
29108
|
+
const value = tokenizer;
|
|
29109
|
+
return !!value && value.patternRegex instanceof RegExp && value.patternRegex.global && typeof value.stringRankEncoder === "object" && value.stringRankEncoder !== null && Array.isArray(value.binaryFirstByteIndex);
|
|
29110
|
+
}
|
|
29111
|
+
function isValidUtf8(bytes) {
|
|
29112
|
+
let index = 0;
|
|
29113
|
+
while (index < bytes.length) {
|
|
29114
|
+
const first = bytes[index];
|
|
29115
|
+
let size = 0;
|
|
29116
|
+
let codePoint = 0;
|
|
29117
|
+
if (first <= 127) {
|
|
29118
|
+
size = 1;
|
|
29119
|
+
codePoint = first;
|
|
29120
|
+
} else if ((first & 224) === 192) {
|
|
29121
|
+
size = 2;
|
|
29122
|
+
codePoint = first & 31;
|
|
29123
|
+
if (first <= 193)
|
|
29124
|
+
return false;
|
|
29125
|
+
} else if ((first & 240) === 224) {
|
|
29126
|
+
size = 3;
|
|
29127
|
+
codePoint = first & 15;
|
|
29128
|
+
} else if ((first & 248) === 240) {
|
|
29129
|
+
size = 4;
|
|
29130
|
+
codePoint = first & 7;
|
|
29131
|
+
if (first > 244)
|
|
29132
|
+
return false;
|
|
29133
|
+
} else
|
|
29134
|
+
return false;
|
|
29135
|
+
if (index + size > bytes.length)
|
|
29136
|
+
return false;
|
|
29137
|
+
for (let offset = 1;offset < size; offset += 1) {
|
|
29138
|
+
const byte = bytes[index + offset];
|
|
29139
|
+
if ((byte & 192) !== 128)
|
|
29140
|
+
return false;
|
|
29141
|
+
codePoint = codePoint << 6 | byte & 63;
|
|
29142
|
+
}
|
|
29143
|
+
if (size === 2 && codePoint < 128)
|
|
29144
|
+
return false;
|
|
29145
|
+
if (size === 3 && codePoint < 2048)
|
|
29146
|
+
return false;
|
|
29147
|
+
if (size === 4 && codePoint < 65536)
|
|
29148
|
+
return false;
|
|
29149
|
+
if (codePoint >= 55296 && codePoint <= 57343)
|
|
29150
|
+
return false;
|
|
29151
|
+
if (codePoint > 1114111)
|
|
29152
|
+
return false;
|
|
29153
|
+
index += size;
|
|
29154
|
+
}
|
|
29155
|
+
return true;
|
|
29156
|
+
}
|
|
29157
|
+
function binarySearchBytes(sorted, key) {
|
|
29158
|
+
let low = 0;
|
|
29159
|
+
let high = sorted.length - 1;
|
|
29160
|
+
while (low <= high) {
|
|
29161
|
+
const mid = low + high >>> 1;
|
|
29162
|
+
const midKey = sorted[mid][0];
|
|
29163
|
+
let compare = 0;
|
|
29164
|
+
const shared = Math.min(midKey.length, key.length);
|
|
29165
|
+
for (let index = 0;index < shared; index += 1) {
|
|
29166
|
+
compare = midKey[index] - key[index];
|
|
29167
|
+
if (compare !== 0)
|
|
29168
|
+
break;
|
|
29169
|
+
}
|
|
29170
|
+
if (compare === 0)
|
|
29171
|
+
compare = midKey.length - key.length;
|
|
29172
|
+
if (compare === 0)
|
|
29173
|
+
return sorted[mid][1];
|
|
29174
|
+
if (compare < 0)
|
|
29175
|
+
low = mid + 1;
|
|
29176
|
+
else
|
|
29177
|
+
high = mid - 1;
|
|
29178
|
+
}
|
|
29179
|
+
return -1;
|
|
29180
|
+
}
|
|
29181
|
+
function rankOf(tokenizer, slice) {
|
|
29182
|
+
if (isValidUtf8(slice)) {
|
|
29183
|
+
const rank = tokenizer.stringRankEncoder[textDecoder.decode(slice)];
|
|
29184
|
+
if (rank !== undefined)
|
|
29185
|
+
return rank;
|
|
29186
|
+
}
|
|
29187
|
+
const bucket = tokenizer.binaryFirstByteIndex[slice[0]];
|
|
29188
|
+
if (bucket !== null && bucket !== undefined) {
|
|
29189
|
+
const rank = binarySearchBytes(bucket, slice);
|
|
29190
|
+
if (rank !== -1)
|
|
29191
|
+
return rank;
|
|
29192
|
+
}
|
|
29193
|
+
return NO_RANK;
|
|
29194
|
+
}
|
|
29195
|
+
function mergeByScanning(tokenizer, bytes) {
|
|
29196
|
+
const starts = [];
|
|
29197
|
+
const ranks = [];
|
|
29198
|
+
const pairRank = (index) => {
|
|
29199
|
+
const end = starts[index + 2];
|
|
29200
|
+
return end === undefined ? NO_RANK : rankOf(tokenizer, bytes.subarray(starts[index], end));
|
|
29201
|
+
};
|
|
29202
|
+
for (let index = 0;index <= bytes.length; index += 1)
|
|
29203
|
+
starts.push(index);
|
|
29204
|
+
for (let index = 0;index < starts.length; index += 1)
|
|
29205
|
+
ranks.push(pairRank(index));
|
|
29206
|
+
while (starts.length > 1) {
|
|
29207
|
+
let minRank = NO_RANK;
|
|
29208
|
+
let minIndex = -1;
|
|
29209
|
+
for (let index = 0;index < ranks.length - 1; index += 1) {
|
|
29210
|
+
if (ranks[index] < minRank) {
|
|
29211
|
+
minRank = ranks[index];
|
|
29212
|
+
minIndex = index;
|
|
29213
|
+
}
|
|
29214
|
+
}
|
|
29215
|
+
if (minIndex === -1)
|
|
29216
|
+
break;
|
|
29217
|
+
starts.splice(minIndex + 1, 1);
|
|
29218
|
+
ranks.splice(minIndex, 1);
|
|
29219
|
+
ranks[minIndex] = pairRank(minIndex);
|
|
29220
|
+
if (minIndex > 0)
|
|
29221
|
+
ranks[minIndex - 1] = pairRank(minIndex - 1);
|
|
29222
|
+
}
|
|
29223
|
+
const tokens = [];
|
|
29224
|
+
for (let index = 0;index < starts.length - 1; index += 1) {
|
|
29225
|
+
const rank = rankOf(tokenizer, bytes.subarray(starts[index], starts[index + 1]));
|
|
29226
|
+
if (rank !== NO_RANK)
|
|
29227
|
+
tokens.push(rank);
|
|
29228
|
+
}
|
|
29229
|
+
return tokens;
|
|
29230
|
+
}
|
|
29231
|
+
function mergeWithHeap(tokenizer, bytes) {
|
|
29232
|
+
const length = bytes.length;
|
|
29233
|
+
const next = new Int32Array(length + 1);
|
|
29234
|
+
const prev = new Int32Array(length + 1);
|
|
29235
|
+
const alive = new Uint8Array(length + 1).fill(1);
|
|
29236
|
+
const rank = new Float64Array(length + 1).fill(NO_RANK);
|
|
29237
|
+
for (let index = 0;index <= length; index += 1) {
|
|
29238
|
+
next[index] = index + 1;
|
|
29239
|
+
prev[index] = index - 1;
|
|
29240
|
+
}
|
|
29241
|
+
const heapRank = [];
|
|
29242
|
+
const heapAt = [];
|
|
29243
|
+
const less = (a, b) => heapRank[a] < heapRank[b] || heapRank[a] === heapRank[b] && heapAt[a] < heapAt[b];
|
|
29244
|
+
const swap = (a, b) => {
|
|
29245
|
+
[heapRank[a], heapRank[b]] = [heapRank[b], heapRank[a]];
|
|
29246
|
+
[heapAt[a], heapAt[b]] = [heapAt[b], heapAt[a]];
|
|
29247
|
+
};
|
|
29248
|
+
const push = (value, at) => {
|
|
29249
|
+
heapRank.push(value);
|
|
29250
|
+
heapAt.push(at);
|
|
29251
|
+
let child = heapRank.length - 1;
|
|
29252
|
+
while (child > 0) {
|
|
29253
|
+
const parent = child - 1 >> 1;
|
|
29254
|
+
if (!less(child, parent))
|
|
29255
|
+
break;
|
|
29256
|
+
swap(child, parent);
|
|
29257
|
+
child = parent;
|
|
29258
|
+
}
|
|
29259
|
+
};
|
|
29260
|
+
const pop = () => {
|
|
29261
|
+
const last = heapRank.length - 1;
|
|
29262
|
+
swap(0, last);
|
|
29263
|
+
heapRank.pop();
|
|
29264
|
+
heapAt.pop();
|
|
29265
|
+
let parent = 0;
|
|
29266
|
+
for (;; ) {
|
|
29267
|
+
const left = parent * 2 + 1;
|
|
29268
|
+
const right = left + 1;
|
|
29269
|
+
let smallest = parent;
|
|
29270
|
+
if (left < heapRank.length && less(left, smallest))
|
|
29271
|
+
smallest = left;
|
|
29272
|
+
if (right < heapRank.length && less(right, smallest))
|
|
29273
|
+
smallest = right;
|
|
29274
|
+
if (smallest === parent)
|
|
29275
|
+
break;
|
|
29276
|
+
swap(parent, smallest);
|
|
29277
|
+
parent = smallest;
|
|
29278
|
+
}
|
|
29279
|
+
};
|
|
29280
|
+
const pairRank = (at) => {
|
|
29281
|
+
const middle = next[at];
|
|
29282
|
+
if (middle >= length)
|
|
29283
|
+
return NO_RANK;
|
|
29284
|
+
return rankOf(tokenizer, bytes.subarray(at, next[middle]));
|
|
29285
|
+
};
|
|
29286
|
+
const update = (at) => {
|
|
29287
|
+
rank[at] = pairRank(at);
|
|
29288
|
+
if (rank[at] !== NO_RANK)
|
|
29289
|
+
push(rank[at], at);
|
|
29290
|
+
};
|
|
29291
|
+
for (let at = 0;at < length; at += 1)
|
|
29292
|
+
update(at);
|
|
29293
|
+
while (heapRank.length > 0) {
|
|
29294
|
+
const value = heapRank[0];
|
|
29295
|
+
const at = heapAt[0];
|
|
29296
|
+
pop();
|
|
29297
|
+
if (!alive[at] || rank[at] !== value)
|
|
29298
|
+
continue;
|
|
29299
|
+
const removed = next[at];
|
|
29300
|
+
alive[removed] = 0;
|
|
29301
|
+
next[at] = next[removed];
|
|
29302
|
+
prev[next[removed]] = at;
|
|
29303
|
+
update(at);
|
|
29304
|
+
if (at > 0)
|
|
29305
|
+
update(prev[at]);
|
|
29306
|
+
}
|
|
29307
|
+
const tokens = [];
|
|
29308
|
+
for (let at = 0;at < length; at = next[at]) {
|
|
29309
|
+
const value = rankOf(tokenizer, bytes.subarray(at, next[at]));
|
|
29310
|
+
if (value !== NO_RANK)
|
|
29311
|
+
tokens.push(value);
|
|
29312
|
+
}
|
|
29313
|
+
return tokens;
|
|
29314
|
+
}
|
|
29315
|
+
function mergePiece(tokenizer, piece) {
|
|
29316
|
+
let cache = mergeCaches.get(tokenizer);
|
|
29317
|
+
if (!cache) {
|
|
29318
|
+
cache = { current: new Map, previous: new Map };
|
|
29319
|
+
mergeCaches.set(tokenizer, cache);
|
|
29320
|
+
}
|
|
29321
|
+
let tokens = cache.current.get(piece);
|
|
29322
|
+
if (tokens)
|
|
29323
|
+
return tokens;
|
|
29324
|
+
tokens = cache.previous.get(piece);
|
|
29325
|
+
if (!tokens) {
|
|
29326
|
+
const bytes = textEncoder.encode(piece);
|
|
29327
|
+
mergedPieces += 1;
|
|
29328
|
+
tokens = bytes.length > LONG_PIECE_BYTES ? mergeWithHeap(tokenizer, bytes) : mergeByScanning(tokenizer, bytes);
|
|
29329
|
+
}
|
|
29330
|
+
if (cache.current.size >= MERGE_CACHE_GENERATION) {
|
|
29331
|
+
cache.previous = cache.current;
|
|
29332
|
+
cache.current = new Map;
|
|
29333
|
+
}
|
|
29334
|
+
cache.current.set(piece, tokens);
|
|
29335
|
+
return tokens;
|
|
29336
|
+
}
|
|
29337
|
+
function encodeTokensExactly(tokenizer, text) {
|
|
29338
|
+
if (!hasInternals(tokenizer)) {
|
|
29339
|
+
return tokenizer.encode(text, "all");
|
|
29340
|
+
}
|
|
29341
|
+
if (text.length < 10) {
|
|
29342
|
+
const direct = tokenizer.stringRankEncoder[text];
|
|
29343
|
+
if (direct !== undefined)
|
|
29344
|
+
return [direct];
|
|
29345
|
+
}
|
|
29346
|
+
const tokens = [];
|
|
29347
|
+
const regex = tokenizer.patternRegex;
|
|
29348
|
+
regex.lastIndex = 0;
|
|
29349
|
+
for (let match = regex.exec(text);match !== null; match = regex.exec(text)) {
|
|
29350
|
+
const piece = match[0];
|
|
29351
|
+
const direct = tokenizer.stringRankEncoder[piece];
|
|
29352
|
+
if (direct !== undefined) {
|
|
29353
|
+
tokens.push(direct);
|
|
29354
|
+
continue;
|
|
29355
|
+
}
|
|
29356
|
+
for (const token of mergePiece(tokenizer, piece))
|
|
29357
|
+
tokens.push(token);
|
|
29358
|
+
}
|
|
29359
|
+
return tokens;
|
|
29360
|
+
}
|
|
29361
|
+
function countTokensExactly(tokenizer, text) {
|
|
29362
|
+
return encodeTokensExactly(tokenizer, text).length;
|
|
29363
|
+
}
|
|
29364
|
+
var NO_RANK = 4294967295, LONG_PIECE_BYTES = 256, MERGE_CACHE_GENERATION = 50000, textEncoder, textDecoder, mergeCaches, mergedPieces = 0;
|
|
29365
|
+
var init_token_count_exact = __esm(() => {
|
|
29366
|
+
textEncoder = new TextEncoder;
|
|
29367
|
+
textDecoder = new TextDecoder("utf-8");
|
|
29368
|
+
mergeCaches = new WeakMap;
|
|
29369
|
+
});
|
|
29370
|
+
|
|
28785
29371
|
// ../plugin/src/hooks/magic-context/read-session-formatting.ts
|
|
28786
29372
|
import { createRequire as createRequire2 } from "node:module";
|
|
28787
29373
|
function hasMeaningfulUserText(parts) {
|
|
@@ -28924,7 +29510,7 @@ function estimateTokens(text) {
|
|
|
28924
29510
|
if (!activeTokenizer)
|
|
28925
29511
|
return estimateTokensHeuristically(text);
|
|
28926
29512
|
try {
|
|
28927
|
-
return activeTokenizer
|
|
29513
|
+
return countTokensExactly(activeTokenizer, text);
|
|
28928
29514
|
} catch (error) {
|
|
28929
29515
|
tokenizer = undefined;
|
|
28930
29516
|
tokenizerLoadAttempted = true;
|
|
@@ -29015,21 +29601,41 @@ var MAX_COMMITS_PER_BLOCK = 5, tokenizer, tokenizerLoadAttempted = false, tokeni
|
|
|
29015
29601
|
var init_read_session_formatting = __esm(() => {
|
|
29016
29602
|
init_commit_detection();
|
|
29017
29603
|
init_logger();
|
|
29604
|
+
init_token_count_exact();
|
|
29018
29605
|
promptTokenCounts = new Map;
|
|
29019
29606
|
PROMPT_TOKEN_COUNT_BYTES = 8 * 1024 * 1024;
|
|
29020
29607
|
});
|
|
29021
29608
|
|
|
29022
29609
|
// ../plugin/src/shared/stable-json.ts
|
|
29023
29610
|
function stableStringify(value, seen = new WeakSet) {
|
|
29024
|
-
|
|
29025
|
-
|
|
29026
|
-
|
|
29027
|
-
|
|
29028
|
-
|
|
29029
|
-
|
|
29611
|
+
const pieces = [];
|
|
29612
|
+
writeStable(value, seen, pieces);
|
|
29613
|
+
return pieces.join("");
|
|
29614
|
+
}
|
|
29615
|
+
function writeStable(value, seen, pieces) {
|
|
29616
|
+
if (value === undefined) {
|
|
29617
|
+
pieces.push("undefined");
|
|
29618
|
+
return;
|
|
29619
|
+
}
|
|
29620
|
+
if (value === null || typeof value !== "object") {
|
|
29621
|
+
pieces.push(JSON.stringify(value) ?? String(value));
|
|
29622
|
+
return;
|
|
29623
|
+
}
|
|
29624
|
+
if (seen.has(value)) {
|
|
29625
|
+
pieces.push('"[Circular]"');
|
|
29626
|
+
return;
|
|
29627
|
+
}
|
|
29030
29628
|
seen.add(value);
|
|
29031
29629
|
if (Array.isArray(value)) {
|
|
29032
|
-
|
|
29630
|
+
pieces.push("[");
|
|
29631
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
29632
|
+
if (index > 0)
|
|
29633
|
+
pieces.push(",");
|
|
29634
|
+
if (index in value)
|
|
29635
|
+
writeStable(value[index], seen, pieces);
|
|
29636
|
+
}
|
|
29637
|
+
pieces.push("]");
|
|
29638
|
+
return;
|
|
29033
29639
|
}
|
|
29034
29640
|
const entries = Object.entries(value).sort(([a], [b]) => {
|
|
29035
29641
|
if (a < b)
|
|
@@ -29038,7 +29644,14 @@ function stableStringify(value, seen = new WeakSet) {
|
|
|
29038
29644
|
return 1;
|
|
29039
29645
|
return 0;
|
|
29040
29646
|
});
|
|
29041
|
-
|
|
29647
|
+
pieces.push("{");
|
|
29648
|
+
entries.forEach(([key, child], index) => {
|
|
29649
|
+
if (index > 0)
|
|
29650
|
+
pieces.push(",");
|
|
29651
|
+
pieces.push(JSON.stringify(key), ":");
|
|
29652
|
+
writeStable(child, seen, pieces);
|
|
29653
|
+
});
|
|
29654
|
+
pieces.push("}");
|
|
29042
29655
|
}
|
|
29043
29656
|
|
|
29044
29657
|
// ../plugin/src/features/magic-context/tool-definition-tokens.ts
|
|
@@ -29724,6 +30337,19 @@ var init_image_token_estimate = __esm(() => {
|
|
|
29724
30337
|
JPEG_SCAN_LIMIT_BYTES = 256 * 1024;
|
|
29725
30338
|
});
|
|
29726
30339
|
|
|
30340
|
+
// ../plugin/src/hooks/magic-context/provider-visible-parts.ts
|
|
30341
|
+
var KEPT_TOOL_STATE_FIELDS;
|
|
30342
|
+
var init_provider_visible_parts = __esm(() => {
|
|
30343
|
+
KEPT_TOOL_STATE_FIELDS = new Set([
|
|
30344
|
+
"status",
|
|
30345
|
+
"input",
|
|
30346
|
+
"output",
|
|
30347
|
+
"error",
|
|
30348
|
+
"attachments",
|
|
30349
|
+
"content"
|
|
30350
|
+
]);
|
|
30351
|
+
});
|
|
30352
|
+
|
|
29727
30353
|
// ../plugin/src/hooks/magic-context/todo-view.ts
|
|
29728
30354
|
var TODO_STATUS_PENDING = "pending", TODO_STATUS_IN_PROGRESS = "in_progress", TODO_STATUS_COMPLETED = "completed", TODO_STATUS_CANCELLED = "cancelled", TODO_PRIORITY_HIGH = "high", TODO_PRIORITY_MEDIUM = "medium", TODO_PRIORITY_LOW = "low", TODO_STATUSES, TODO_PRIORITIES, TODO_STATUS_SET, TODO_PRIORITY_SET, TERMINAL_STATUSES, TITLE_DONE_STATUSES;
|
|
29729
30355
|
var init_todo_view = __esm(() => {
|
|
@@ -29753,10 +30379,11 @@ var init_tail_hygiene_walk = __esm(() => {
|
|
|
29753
30379
|
init_reclaim_protection();
|
|
29754
30380
|
init_tag_owner_id();
|
|
29755
30381
|
init_image_token_estimate();
|
|
30382
|
+
init_provider_visible_parts();
|
|
29756
30383
|
init_read_session_formatting();
|
|
29757
30384
|
init_todo_view();
|
|
29758
30385
|
init_reclaim_protection();
|
|
29759
|
-
MAX_CONTENT_MEMO_BYTES =
|
|
30386
|
+
MAX_CONTENT_MEMO_BYTES = 256 * 1024 * 1024;
|
|
29760
30387
|
contentMemo = new Map;
|
|
29761
30388
|
contentMemoOrder = new Set;
|
|
29762
30389
|
baselineMeasurementMemo = new Map;
|
|
@@ -29822,12 +30449,14 @@ function pickNearestPriorOwner(candidates, currentMessageId, times) {
|
|
|
29822
30449
|
}
|
|
29823
30450
|
return best?.id ?? null;
|
|
29824
30451
|
}
|
|
29825
|
-
var insertTagStatements, updateTagStatusStatements, updateTagDropModeStatements, updateTagMessageIdStatements, getTagNumbersByMessageIdStatements, deleteTagsByMessageIdStatements, getMaxTagNumberBySessionStatements, getTagNumberByMessageIdStatements, getAssignableTagNumberByMessageIdStatements, hasPiFallbackMessageTagStatements, updateTagByteSizeStatements, updateTagInputByteSizeStatements, recentTagOwnerStatements, RECLAIM_HINT_EXCLUDED_TOOLS, getActiveToolTagsForAgeReclaimStatements, scopedActiveTokenTotalStatements, updateTagTokenCountStatements, updateTagInputTokenCountStatements, inertWhitespaceStatements, foldStatements, getOwnerScopedToolTagNumbersStatements, getMinMessageTagNumberForRawIdStatements, getActiveTagsBySessionStatements, getNullOwnerToolTagsBySessionStatements, getDroppedTagsBySessionStatements, getMaxDroppedTagNumberStatements, newestToolTagNumberStatements, droppedNumberStatements, tagByIdStatements, getToolTagNumberByOwnerStatements, getNullOwnerToolTagStatements, adoptNullOwnerToolTagStatements, getToolOwnerByTagIdStatements, deleteToolTagsByOwnerStatements;
|
|
29826
|
-
var init_storage_tags = __esm(() => {
|
|
30452
|
+
var insertTagStatements, updateTagStatusStatements, updateTagDropModeStatements, updateTagMessageIdStatements, getTagNumbersByMessageIdStatements, deleteTagsByMessageIdStatements, getMaxTagNumberBySessionStatements, getTagNumberByMessageIdStatements, getAssignableTagNumberByMessageIdStatements, hasPiFallbackMessageTagStatements, updateTagByteSizeStatements, updateTagInputByteSizeStatements, recentTagOwnerStatements, RECLAIM_HINT_EXCLUDED_TOOLS, getActiveToolTagsForAgeReclaimStatements, scopedActiveTokenTotalStatements, updateTagTokenCountStatements, updateTagInputTokenCountStatements, tagOwnerSummaries, TAG_OWNER_COLUMNS = "id, type, message_id, tool_owner_message_id, tag_number, reasoning_token_count", TAG_OWNER_APPENDED_WITH_SHAPE_SQL, inertWhitespaceStatements, inertWhitespaceByNumberStatements, foldStatements, getOwnerScopedToolTagNumbersStatements, getMinMessageTagNumberForRawIdStatements, getActiveTagsBySessionStatements, getNullOwnerToolTagsBySessionStatements, getDroppedTagsBySessionStatements, getMaxDroppedTagNumberStatements, newestToolTagNumberStatements, droppedNumberStatements, tagByIdStatements, getToolTagNumberByOwnerStatements, getNullOwnerToolTagStatements, adoptNullOwnerToolTagStatements, getToolOwnerByTagIdStatements, deleteToolTagsByOwnerStatements;
|
|
30453
|
+
var init_storage_tags = __esm(async () => {
|
|
29827
30454
|
init_emergency_drop();
|
|
29828
30455
|
init_tag_owner_id();
|
|
29829
30456
|
init_migration_v95_perf_indexes();
|
|
29830
30457
|
init_storage_ops();
|
|
30458
|
+
init_storage_tag_identity_revision();
|
|
30459
|
+
await init_sqlite();
|
|
29831
30460
|
insertTagStatements = new WeakMap;
|
|
29832
30461
|
updateTagStatusStatements = new WeakMap;
|
|
29833
30462
|
updateTagDropModeStatements = new WeakMap;
|
|
@@ -29855,7 +30484,14 @@ var init_storage_tags = __esm(() => {
|
|
|
29855
30484
|
scopedActiveTokenTotalStatements = new WeakMap;
|
|
29856
30485
|
updateTagTokenCountStatements = new WeakMap;
|
|
29857
30486
|
updateTagInputTokenCountStatements = new WeakMap;
|
|
30487
|
+
tagOwnerSummaries = new WeakMap;
|
|
30488
|
+
TAG_OWNER_APPENDED_WITH_SHAPE_SQL = `SELECT ${TAG_OWNER_COLUMNS}, 0 AS shape, NULL AS tag_count, NULL AS max_id, NULL AS revision
|
|
30489
|
+
FROM tags WHERE id > ? AND +session_id = ?
|
|
30490
|
+
UNION ALL
|
|
30491
|
+
SELECT NULL, NULL, NULL, NULL, NULL, NULL, 1, COUNT(*), MAX(id), (SELECT value FROM schema_migrations_meta WHERE key = ?)
|
|
30492
|
+
FROM tags WHERE session_id = ?`;
|
|
29858
30493
|
inertWhitespaceStatements = new WeakMap;
|
|
30494
|
+
inertWhitespaceByNumberStatements = new WeakMap;
|
|
29859
30495
|
foldStatements = new WeakMap;
|
|
29860
30496
|
getOwnerScopedToolTagNumbersStatements = new WeakMap;
|
|
29861
30497
|
getMinMessageTagNumberForRawIdStatements = new WeakMap;
|
|
@@ -29973,92 +30609,28 @@ function isHostUnservedRow(value) {
|
|
|
29973
30609
|
}
|
|
29974
30610
|
var HOST_UNSERVED_ROW = "hostUnservedRow";
|
|
29975
30611
|
|
|
29976
|
-
// ../plugin/src/
|
|
29977
|
-
function
|
|
29978
|
-
|
|
29979
|
-
|
|
29980
|
-
|
|
29981
|
-
|
|
29982
|
-
return;
|
|
29983
|
-
}
|
|
29984
|
-
try {
|
|
29985
|
-
closeQuietly(cachedReadOnlyDb.db);
|
|
29986
|
-
} catch (error) {
|
|
29987
|
-
log("[magic-context] failed to close cached OpenCode read-only DB:", error);
|
|
29988
|
-
} finally {
|
|
29989
|
-
cachedReadOnlyDb = null;
|
|
29990
|
-
}
|
|
29991
|
-
}
|
|
29992
|
-
function getReadOnlySessionDb() {
|
|
29993
|
-
if (!harnessOwnsOpenCodeStore()) {
|
|
29994
|
-
throw new Error("OpenCode session database is not readable from a Pi-compatible process; its history lives in Pi sessions");
|
|
29995
|
-
}
|
|
29996
|
-
const resolution = resolveOpenCodeDbPath();
|
|
29997
|
-
const dbPath = resolution.path;
|
|
29998
|
-
if (!openCodeDbPathExists(resolution)) {
|
|
29999
|
-
throw new Error(`OpenCode session database is unavailable at ${dbPath} (source=${resolution.source})`);
|
|
30000
|
-
}
|
|
30001
|
-
if (cachedReadOnlyDb?.path === dbPath) {
|
|
30002
|
-
return cachedReadOnlyDb.db;
|
|
30003
|
-
}
|
|
30004
|
-
closeCachedReadOnlyDb();
|
|
30005
|
-
const db = new Database(dbPath, { readonly: true });
|
|
30006
|
-
try {
|
|
30007
|
-
assertOpenCodeStoreGeneration(db, "v1", dbPath);
|
|
30008
|
-
} catch (error) {
|
|
30009
|
-
closeQuietly(db);
|
|
30010
|
-
throw error;
|
|
30612
|
+
// ../plugin/src/shared/exit-abort-registry.ts
|
|
30613
|
+
function abortAll() {
|
|
30614
|
+
for (const controller of controllers) {
|
|
30615
|
+
try {
|
|
30616
|
+
controller.abort();
|
|
30617
|
+
} catch {}
|
|
30011
30618
|
}
|
|
30012
|
-
cachedReadOnlyDb = { path: dbPath, db };
|
|
30013
|
-
clearOpenCodeDbReadFailure();
|
|
30014
|
-
return db;
|
|
30015
|
-
}
|
|
30016
|
-
function withReadOnlySessionDb(fn) {
|
|
30017
|
-
return fn(getReadOnlySessionDb());
|
|
30018
30619
|
}
|
|
30019
|
-
function
|
|
30020
|
-
|
|
30021
|
-
|
|
30022
|
-
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
|
|
30023
|
-
return typeof row?.count === "number" ? row.count : 0;
|
|
30024
|
-
}
|
|
30025
|
-
function logProbeFailureOnce(resolution, error) {
|
|
30026
|
-
const failure = recordOpenCodeDbReadFailure(resolution, error);
|
|
30027
|
-
if (!claimOpenCodeDbDiagnosticOnce("session-state-probe", resolution))
|
|
30620
|
+
function registerExitAbort(controller) {
|
|
30621
|
+
controllers.add(controller);
|
|
30622
|
+
if (listenerRegistered)
|
|
30028
30623
|
return;
|
|
30029
|
-
|
|
30030
|
-
|
|
30031
|
-
log(message);
|
|
30624
|
+
listenerRegistered = true;
|
|
30625
|
+
process.once("exit", abortAll);
|
|
30032
30626
|
}
|
|
30033
|
-
|
|
30034
|
-
|
|
30035
|
-
|
|
30036
|
-
return result;
|
|
30037
|
-
try {
|
|
30038
|
-
withReadOnlySessionDb((db) => {
|
|
30039
|
-
const placeholders = messageIds.map(() => "?").join(",");
|
|
30040
|
-
const rows = db.prepare(`SELECT id, time_created FROM message WHERE session_id = ? AND id IN (${placeholders})`).all(sessionId, ...messageIds);
|
|
30041
|
-
for (const row of rows) {
|
|
30042
|
-
if (typeof row.id === "string" && typeof row.time_created === "number") {
|
|
30043
|
-
result.set(row.id, row.time_created);
|
|
30044
|
-
}
|
|
30045
|
-
}
|
|
30046
|
-
});
|
|
30047
|
-
} catch (error) {
|
|
30048
|
-
logProbeFailureOnce(resolveOpenCodeDbPath(), error);
|
|
30049
|
-
}
|
|
30050
|
-
return result;
|
|
30051
|
-
}
|
|
30052
|
-
var cachedReadOnlyDb = null, trackedSessions, pendingParts, probeLogObserverForTests;
|
|
30053
|
-
var init_read_session_db = __esm(async () => {
|
|
30054
|
-
init_logger();
|
|
30055
|
-
init_opencode_db_path();
|
|
30056
|
-
await init_sqlite();
|
|
30057
|
-
trackedSessions = new Map;
|
|
30058
|
-
pendingParts = new Map;
|
|
30627
|
+
var controllers, listenerRegistered = false;
|
|
30628
|
+
var init_exit_abort_registry = __esm(() => {
|
|
30629
|
+
controllers = new Set;
|
|
30059
30630
|
});
|
|
30060
30631
|
|
|
30061
30632
|
// ../plugin/src/hooks/magic-context/read-session-raw.ts
|
|
30633
|
+
import { isMainThread as isMainThread2 } from "node:worker_threads";
|
|
30062
30634
|
function isRawMessageRow(row) {
|
|
30063
30635
|
if (row === null || typeof row !== "object")
|
|
30064
30636
|
return false;
|
|
@@ -30118,7 +30690,7 @@ function readRawSessionMessagesFromDb(db, sessionId) {
|
|
|
30118
30690
|
if (messageIds.length === 0)
|
|
30119
30691
|
continue;
|
|
30120
30692
|
const placeholders = messageIds.map(() => "?").join(", ");
|
|
30121
|
-
const partRows = db.prepare(`SELECT message_id, data, time_updated
|
|
30693
|
+
const partRows = db.prepare(`SELECT message_id, ${RAW_PART_DATA_SQL} AS data, time_updated
|
|
30122
30694
|
FROM part
|
|
30123
30695
|
WHERE +session_id = ?
|
|
30124
30696
|
AND likelihood(message_id IN (${placeholders}), 0.000001)
|
|
@@ -30150,7 +30722,7 @@ function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, fin
|
|
|
30150
30722
|
if (messageRows.length === 0)
|
|
30151
30723
|
return [];
|
|
30152
30724
|
const placeholders = messageRows.map(() => "?").join(", ");
|
|
30153
|
-
const partRows = db.prepare(`SELECT message_id, data, time_updated
|
|
30725
|
+
const partRows = db.prepare(`SELECT message_id, ${RAW_PART_DATA_SQL} AS data, time_updated
|
|
30154
30726
|
FROM part
|
|
30155
30727
|
WHERE +session_id = ?
|
|
30156
30728
|
AND likelihood(message_id IN (${placeholders}), 0.000001)
|
|
@@ -30162,29 +30734,44 @@ function readRawMessagePageRows(db, sessionId, afterOrdinal, limit, finalWaterma
|
|
|
30162
30734
|
const pageSize = Math.min(Math.max(1, Math.floor(limit)), remaining);
|
|
30163
30735
|
if (pageSize === 0)
|
|
30164
30736
|
return [];
|
|
30165
|
-
|
|
30166
|
-
|
|
30167
|
-
|
|
30168
|
-
|
|
30169
|
-
|
|
30170
|
-
|
|
30171
|
-
|
|
30172
|
-
|
|
30173
|
-
|
|
30174
|
-
|
|
30175
|
-
|
|
30176
|
-
|
|
30177
|
-
|
|
30178
|
-
|
|
30179
|
-
|
|
30180
|
-
|
|
30181
|
-
|
|
30182
|
-
|
|
30183
|
-
|
|
30184
|
-
|
|
30185
|
-
|
|
30186
|
-
|
|
30187
|
-
|
|
30737
|
+
return withReadSnapshot(db, () => {
|
|
30738
|
+
const ordinal = Math.max(0, Math.floor(afterOrdinal));
|
|
30739
|
+
const points = currentOrdinalCheckpoints(db, sessionId)?.scan.checkpoints ?? [];
|
|
30740
|
+
let low = 0;
|
|
30741
|
+
let high = points.length;
|
|
30742
|
+
while (low < high) {
|
|
30743
|
+
const middle = Math.floor((low + high) / 2);
|
|
30744
|
+
if (points[middle].ordinal <= ordinal)
|
|
30745
|
+
low = middle + 1;
|
|
30746
|
+
else
|
|
30747
|
+
high = middle;
|
|
30748
|
+
}
|
|
30749
|
+
const floor = points[low - 1];
|
|
30750
|
+
const useFloor = floor && (!after || compareOrdinalKeys(floor, after) > 0);
|
|
30751
|
+
const anchor = useFloor ? floor : after;
|
|
30752
|
+
const skip = anchor === after && after ? 0 : ordinal - (floor?.ordinal ?? 0);
|
|
30753
|
+
if (skip > ORDINAL_LOOKUP_LIMIT) {
|
|
30754
|
+
prewarmRawSessionOrdinalsForDb(db, sessionId);
|
|
30755
|
+
throw new RawOrdinalsNotReady;
|
|
30756
|
+
}
|
|
30757
|
+
const rawLimit = skip + pageSize + ORDINAL_LOOKUP_LIMIT;
|
|
30758
|
+
const rows = db.prepare(`SELECT id, data, time_created, time_updated, ${EXCLUDED_ROW_SQL} AS excluded
|
|
30759
|
+
FROM message WHERE id IN (
|
|
30760
|
+
SELECT id FROM message WHERE session_id = ?
|
|
30761
|
+
${anchor ? "AND (time_created, id) > (?, ?)" : ""}
|
|
30762
|
+
ORDER BY time_created, id LIMIT ?)
|
|
30763
|
+
ORDER BY time_created, id`).all(sessionId, ...anchor ? [anchor.timeCreated, anchor.id] : [], rawLimit);
|
|
30764
|
+
rawMessagePageRowsVisited += rows.length;
|
|
30765
|
+
const eligible = rows.filter((row) => row.excluded !== 1);
|
|
30766
|
+
if (eligible.length <= skip && rows.length === rawLimit) {
|
|
30767
|
+
prewarmRawSessionOrdinalsForDb(db, sessionId);
|
|
30768
|
+
throw new RawOrdinalsNotReady;
|
|
30769
|
+
}
|
|
30770
|
+
return eligible.slice(skip, skip + pageSize).filter(isRawMessageRow).map((row, index) => ({
|
|
30771
|
+
...row,
|
|
30772
|
+
ordinal: ordinal + index + 1
|
|
30773
|
+
}));
|
|
30774
|
+
});
|
|
30188
30775
|
}
|
|
30189
30776
|
function assembleRawMessagePage(messageRows, partRows) {
|
|
30190
30777
|
const partsByMessageId = new Map;
|
|
@@ -30223,6 +30810,9 @@ function readRawSessionMessageSummaryPageFromDb(db, sessionId, afterOrdinal, lim
|
|
|
30223
30810
|
return assembleRawMessagePage(messageRows, partRows);
|
|
30224
30811
|
}
|
|
30225
30812
|
function countRawSessionMessageOrdinalsFromDb(db, sessionId) {
|
|
30813
|
+
const indexed = countCanonicalOrdinalsIndexed(db, sessionId, null, null);
|
|
30814
|
+
if (indexed !== null)
|
|
30815
|
+
return indexed;
|
|
30226
30816
|
const row = db.prepare(`SELECT COUNT(*) AS count
|
|
30227
30817
|
FROM message
|
|
30228
30818
|
WHERE session_id = ?
|
|
@@ -30309,7 +30899,7 @@ function readRawSessionTailFromDb(db, sessionId, baseOrdinal, anchorMessageId) {
|
|
|
30309
30899
|
for (let i = 0;i < ids.length; i += CHUNK) {
|
|
30310
30900
|
const slice = ids.slice(i, i + CHUNK);
|
|
30311
30901
|
const placeholders = slice.map(() => "?").join(",");
|
|
30312
|
-
const partRows = db.prepare(`SELECT message_id, data, time_updated FROM part WHERE +session_id = ? AND likelihood(message_id IN (${placeholders}), 0.000001) ORDER BY time_created ASC, id ASC`).all(sessionId, ...slice).filter(isRawPartRow);
|
|
30902
|
+
const partRows = db.prepare(`SELECT message_id, ${RAW_PART_DATA_SQL} AS data, time_updated FROM part WHERE +session_id = ? AND likelihood(message_id IN (${placeholders}), 0.000001) ORDER BY time_created ASC, id ASC`).all(sessionId, ...slice).filter(isRawPartRow);
|
|
30313
30903
|
for (const part of partRows) {
|
|
30314
30904
|
const list = partsByMessageId.get(part.message_id) ?? [];
|
|
30315
30905
|
list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
|
|
@@ -30355,49 +30945,431 @@ function readRawSessionMessagePartsByIdFromDb(db, sessionId, messageId, onQuery)
|
|
|
30355
30945
|
version: row.time_updated ?? null
|
|
30356
30946
|
};
|
|
30357
30947
|
}
|
|
30358
|
-
function
|
|
30359
|
-
|
|
30360
|
-
|
|
30361
|
-
|
|
30362
|
-
|
|
30363
|
-
|
|
30364
|
-
|
|
30365
|
-
|
|
30366
|
-
ELSE 0 END = 1
|
|
30367
|
-
AND CASE WHEN json_valid(candidate.data) = 1
|
|
30368
|
-
THEN COALESCE(json_extract(candidate.data, '$.finish'), '')
|
|
30369
|
-
ELSE '' END = 'stop'
|
|
30370
|
-
)
|
|
30371
|
-
AND (candidate.time_created < target.time_created
|
|
30372
|
-
OR (candidate.time_created = target.time_created AND candidate.id <= target.id))
|
|
30373
|
-
WHERE target.session_id = ?
|
|
30374
|
-
AND target.id = ?
|
|
30375
|
-
AND NOT (
|
|
30376
|
-
CASE WHEN json_valid(target.data) = 1
|
|
30377
|
-
THEN COALESCE(json_extract(target.data, '$.summary'), 0)
|
|
30378
|
-
ELSE 0 END = 1
|
|
30379
|
-
AND CASE WHEN json_valid(target.data) = 1
|
|
30380
|
-
THEN COALESCE(json_extract(target.data, '$.finish'), '')
|
|
30381
|
-
ELSE '' END = 'stop'
|
|
30382
|
-
)`).get(sessionId, messageId);
|
|
30383
|
-
const ordinal = row?.ordinal;
|
|
30384
|
-
return typeof ordinal === "number" && ordinal > 0 ? ordinal : null;
|
|
30948
|
+
function ordinalRangeSql(lowerBound) {
|
|
30949
|
+
return `SELECT COUNT(*) AS visited,
|
|
30950
|
+
COALESCE(SUM(CASE WHEN ${ORDINAL_SUMMARY_FLAG_SQL} AND ${ORDINAL_STOP_FLAG_SQL}
|
|
30951
|
+
THEN 0 ELSE 1 END), 0) AS eligible
|
|
30952
|
+
FROM message
|
|
30953
|
+
WHERE session_id = ?
|
|
30954
|
+
${lowerBound ? "AND (time_created, id) > (?, ?)" : ""}
|
|
30955
|
+
AND (time_created, id) <= (?, ?)`;
|
|
30385
30956
|
}
|
|
30386
|
-
function
|
|
30387
|
-
|
|
30388
|
-
|
|
30957
|
+
function readStoreStamp(db) {
|
|
30958
|
+
try {
|
|
30959
|
+
const row = db.prepare(`SELECT data_version AS dataVersion, total_changes() AS totalChanges,
|
|
30960
|
+
(SELECT schema_version FROM pragma_schema_version) AS schemaVersion
|
|
30961
|
+
FROM pragma_data_version`).get();
|
|
30962
|
+
if (typeof row?.dataVersion !== "number" || typeof row.totalChanges !== "number" || typeof row.schemaVersion !== "number")
|
|
30963
|
+
return null;
|
|
30964
|
+
return {
|
|
30965
|
+
dataVersion: row.dataVersion,
|
|
30966
|
+
totalChanges: row.totalChanges,
|
|
30967
|
+
schemaVersion: row.schemaVersion
|
|
30968
|
+
};
|
|
30969
|
+
} catch {
|
|
30389
30970
|
return null;
|
|
30390
30971
|
}
|
|
30391
|
-
|
|
30392
|
-
|
|
30972
|
+
}
|
|
30973
|
+
function sameStoreStamp(left, right) {
|
|
30974
|
+
return left !== null && right !== null && left.dataVersion === right.dataVersion && left.totalChanges === right.totalChanges && left.schemaVersion === right.schemaVersion;
|
|
30975
|
+
}
|
|
30976
|
+
function compareOrdinalKeys(left, right) {
|
|
30977
|
+
if (left.timeCreated !== right.timeCreated)
|
|
30978
|
+
return left.timeCreated < right.timeCreated ? -1 : 1;
|
|
30979
|
+
if (left.id === right.id)
|
|
30980
|
+
return 0;
|
|
30981
|
+
return Buffer.compare(Buffer.from(left.id, "utf8"), Buffer.from(right.id, "utf8"));
|
|
30982
|
+
}
|
|
30983
|
+
function countEligibleOrdinals(db, sessionId, after, through) {
|
|
30984
|
+
const indexed = countCanonicalOrdinalsIndexed(db, sessionId, after, through);
|
|
30985
|
+
if (indexed !== null)
|
|
30986
|
+
return indexed;
|
|
30987
|
+
const row = after ? db.prepare(ORDINAL_RANGE_BETWEEN_SQL).get(sessionId, after.timeCreated, after.id, through.timeCreated, through.id) : db.prepare(ORDINAL_RANGE_FROM_START_SQL).get(sessionId, through.timeCreated, through.id);
|
|
30988
|
+
const visited = typeof row?.visited === "number" ? row.visited : 0;
|
|
30989
|
+
ordinalRowsVisited += visited;
|
|
30990
|
+
ordinalJsonRowsRead += visited;
|
|
30991
|
+
return typeof row?.eligible === "number" ? row.eligible : 0;
|
|
30992
|
+
}
|
|
30993
|
+
function survivingAnchor(db, set) {
|
|
30994
|
+
if (set.anchors.length === 0)
|
|
30393
30995
|
return null;
|
|
30996
|
+
const current = new Map(db.prepare(ANCHOR_CHECK_SQL).all(JSON.stringify(set.anchors.map((anchor) => anchor.rowid))).map((row) => [row.rid, row.id]));
|
|
30997
|
+
return set.anchors.find((anchor) => current.get(anchor.rowid) === anchor.id);
|
|
30998
|
+
}
|
|
30999
|
+
function currentOrdinalCheckpoints(db, sessionId) {
|
|
31000
|
+
const cached = ordinalCheckpoints.get(db)?.get(sessionId);
|
|
31001
|
+
if (!cached)
|
|
31002
|
+
return;
|
|
31003
|
+
return withReadSnapshot(db, () => {
|
|
31004
|
+
if (!extendOrdinalCheckpoints(db, sessionId, cached.scan, ORDINAL_LOOKUP_LIMIT))
|
|
31005
|
+
return;
|
|
31006
|
+
cached.epoch = getRawSessionSummaryEpoch(sessionId);
|
|
31007
|
+
return cached;
|
|
31008
|
+
});
|
|
31009
|
+
}
|
|
31010
|
+
function extendOrdinalCheckpoints(db, sessionId, scan, limit) {
|
|
31011
|
+
const points = scan.checkpoints ?? [];
|
|
31012
|
+
const exists = (point) => Boolean(db.prepare("SELECT 1 FROM message WHERE id=? AND session_id=? AND time_created=?").get(point.id, sessionId, point.timeCreated));
|
|
31013
|
+
if (points.length && !exists(points[points.length - 1])) {
|
|
31014
|
+
let low = 0;
|
|
31015
|
+
let high = points.length;
|
|
31016
|
+
while (low < high) {
|
|
31017
|
+
const middle = Math.floor((low + high) / 2);
|
|
31018
|
+
if (exists(points[middle]))
|
|
31019
|
+
low = middle + 1;
|
|
31020
|
+
else
|
|
31021
|
+
high = middle;
|
|
31022
|
+
}
|
|
31023
|
+
points.length = low;
|
|
31024
|
+
scan.total = points.at(-1)?.ordinal ?? 0;
|
|
31025
|
+
scan.sessionRows = points.at(-1)?.storedCount ?? 0;
|
|
31026
|
+
}
|
|
31027
|
+
const tail = points.at(-1);
|
|
31028
|
+
const rows = db.prepare(`SELECT id, time_created AS timeCreated, ${EXCLUDED_ROW_SQL} AS excluded FROM message
|
|
31029
|
+
WHERE session_id=?${tail ? " AND (time_created,id) > (?,?)" : ""}
|
|
31030
|
+
ORDER BY time_created,id${limit === undefined ? "" : ` LIMIT ${limit + 1}`}`).all(sessionId, ...tail ? [tail.timeCreated, tail.id] : []);
|
|
31031
|
+
ordinalJsonRowsRead += rows.length;
|
|
31032
|
+
if (limit !== undefined && rows.length > limit)
|
|
31033
|
+
return false;
|
|
31034
|
+
let total = scan.total ?? 0;
|
|
31035
|
+
if (rows.length && tail && (tail.storedCount ?? 0) % 256 !== 0)
|
|
31036
|
+
points.pop();
|
|
31037
|
+
for (let index = 0;index < rows.length; index++) {
|
|
31038
|
+
const row = rows[index];
|
|
31039
|
+
if (row.excluded !== 1)
|
|
31040
|
+
total++;
|
|
31041
|
+
const storedCount = scan.sessionRows + index + 1;
|
|
31042
|
+
if (storedCount % 256 === 0 || index === rows.length - 1)
|
|
31043
|
+
points.push({ id: row.id, timeCreated: row.timeCreated, ordinal: total, storedCount });
|
|
31044
|
+
}
|
|
31045
|
+
scan.checkpoints = points;
|
|
31046
|
+
scan.sessionRows += rows.length;
|
|
31047
|
+
scan.total = total;
|
|
31048
|
+
return true;
|
|
31049
|
+
}
|
|
31050
|
+
function rawOrdinalSummarySeed(db, sessionId) {
|
|
31051
|
+
const retained = ordinalCheckpoints.get(db)?.get(sessionId);
|
|
31052
|
+
if (retained)
|
|
31053
|
+
return retained.scan;
|
|
31054
|
+
const seed = ordinalSummarySeeds.get(db)?.get(sessionId);
|
|
31055
|
+
if (!seed || seed.epoch !== getRawSessionSummaryEpoch(sessionId))
|
|
31056
|
+
return;
|
|
31057
|
+
return {
|
|
31058
|
+
...seed.scan,
|
|
31059
|
+
ids: [...new Set([...seed.scan.ids, ...writtenSummaryIds.get(sessionId) ?? []])]
|
|
31060
|
+
};
|
|
31061
|
+
}
|
|
31062
|
+
function boundedOrdinalPrefix(db, sessionId, through) {
|
|
31063
|
+
const cached = currentOrdinalCheckpoints(db, sessionId);
|
|
31064
|
+
if (cached && through === null)
|
|
31065
|
+
return cached.scan.total ?? 0;
|
|
31066
|
+
let floor;
|
|
31067
|
+
if (cached && through) {
|
|
31068
|
+
const points = cached.scan.checkpoints ?? [];
|
|
31069
|
+
let low = 0;
|
|
31070
|
+
let high = points.length;
|
|
31071
|
+
while (low < high) {
|
|
31072
|
+
const middle = Math.floor((low + high) / 2);
|
|
31073
|
+
if (compareOrdinalKeys(points[middle], through) <= 0)
|
|
31074
|
+
low = middle + 1;
|
|
31075
|
+
else
|
|
31076
|
+
high = middle;
|
|
31077
|
+
}
|
|
31078
|
+
floor = points[low - 1];
|
|
31079
|
+
if (floor && compareOrdinalKeys(floor, through) === 0)
|
|
31080
|
+
return floor.ordinal;
|
|
31081
|
+
}
|
|
31082
|
+
const bindings = [sessionId];
|
|
31083
|
+
if (floor)
|
|
31084
|
+
bindings.push(floor.timeCreated, floor.id);
|
|
31085
|
+
if (through)
|
|
31086
|
+
bindings.push(through.timeCreated, through.id);
|
|
31087
|
+
const rows = db.prepare(`SELECT ${EXCLUDED_ROW_SQL} AS excluded FROM message WHERE id IN (
|
|
31088
|
+
SELECT id FROM message WHERE session_id = ?${floor ? " AND (time_created, id) > (?, ?)" : ""}${through ? " AND (time_created, id) <= (?, ?)" : ""}
|
|
31089
|
+
ORDER BY time_created, id LIMIT ${ORDINAL_LOOKUP_LIMIT + 1})`).all(...bindings);
|
|
31090
|
+
ordinalRowsVisited += rows.length;
|
|
31091
|
+
ordinalJsonRowsRead += rows.length;
|
|
31092
|
+
if (rows.length > ORDINAL_LOOKUP_LIMIT) {
|
|
31093
|
+
prewarmRawSessionOrdinalsForDb(db, sessionId);
|
|
31094
|
+
throw new RawOrdinalsNotReady;
|
|
31095
|
+
}
|
|
31096
|
+
return (floor?.ordinal ?? 0) + rows.reduce((sum, row) => sum + (row.excluded === 1 ? 0 : 1), 0);
|
|
31097
|
+
}
|
|
31098
|
+
function scanRawSessionSummaryRows(db, sessionId, previous) {
|
|
31099
|
+
return withReadSnapshot(db, () => {
|
|
31100
|
+
if (previous?.checkpoints) {
|
|
31101
|
+
extendOrdinalCheckpoints(db, sessionId, previous);
|
|
31102
|
+
return previous;
|
|
31103
|
+
}
|
|
31104
|
+
if (previous) {
|
|
31105
|
+
const sessions = summaryCandidateSets.get(db) ?? new Map;
|
|
31106
|
+
sessions.set(sessionId, {
|
|
31107
|
+
epoch: getRawSessionSummaryEpoch(sessionId),
|
|
31108
|
+
anchors: previous.anchors,
|
|
31109
|
+
ids: new Set(previous.ids)
|
|
31110
|
+
});
|
|
31111
|
+
summaryCandidateSets.set(db, sessions);
|
|
31112
|
+
}
|
|
31113
|
+
const incremental = previous && isRawSessionSummaryWarm(db, sessionId) ? summaryCandidatesOf(db, sessionId) : undefined;
|
|
31114
|
+
const rows = incremental ? [] : db.prepare(SUMMARY_FULL_SCAN_SQL).all(sessionId, sessionId);
|
|
31115
|
+
const anchors = [];
|
|
31116
|
+
const ids = [];
|
|
31117
|
+
let sessionRows = 0;
|
|
31118
|
+
for (const row of rows) {
|
|
31119
|
+
if (row.kind === 1 && typeof row.rid === "number" && typeof row.id === "string")
|
|
31120
|
+
anchors.push({ rowid: row.rid, id: row.id });
|
|
31121
|
+
else if (row.kind === 2 && typeof row.id === "string")
|
|
31122
|
+
ids.push(row.id);
|
|
31123
|
+
else if (row.kind === 4 && typeof row.rid === "number")
|
|
31124
|
+
sessionRows = row.rid;
|
|
31125
|
+
}
|
|
31126
|
+
if (incremental) {
|
|
31127
|
+
ids.push(...incremental.ids);
|
|
31128
|
+
anchors.push(...summaryCandidateSets.get(db)?.get(sessionId)?.anchors ?? []);
|
|
31129
|
+
sessionRows = countStoredRawSessionRowsIndexed(db, sessionId);
|
|
31130
|
+
}
|
|
31131
|
+
anchors.sort((left, right) => right.rowid - left.rowid);
|
|
31132
|
+
anchors.length = Math.min(anchors.length, SUMMARY_ANCHOR_LIMIT);
|
|
31133
|
+
const keys = db.prepare(`SELECT id, time_created AS timeCreated, ${EXCLUDED_ROW_SQL} AS excluded FROM message WHERE session_id = ?
|
|
31134
|
+
ORDER BY time_created, id`).all(sessionId);
|
|
31135
|
+
const checkpoints = [];
|
|
31136
|
+
let total = 0;
|
|
31137
|
+
for (let index = 0;index < keys.length; index++) {
|
|
31138
|
+
const key = keys[index];
|
|
31139
|
+
if (key.excluded !== 1)
|
|
31140
|
+
total++;
|
|
31141
|
+
if (index % 256 === 255 || index === keys.length - 1)
|
|
31142
|
+
checkpoints.push({
|
|
31143
|
+
id: key.id,
|
|
31144
|
+
timeCreated: key.timeCreated,
|
|
31145
|
+
ordinal: total,
|
|
31146
|
+
storedCount: index + 1
|
|
31147
|
+
});
|
|
31148
|
+
}
|
|
31149
|
+
return { anchors, ids, sessionRows, checkpoints, total };
|
|
31150
|
+
});
|
|
31151
|
+
}
|
|
31152
|
+
function getRawSessionSummaryEpoch(sessionId) {
|
|
31153
|
+
return summaryCandidateEpochs.get(sessionId) ?? 0;
|
|
31154
|
+
}
|
|
31155
|
+
function installRawSessionSummaryScan(db, sessionId, scan, epoch, workerPrepared = false) {
|
|
31156
|
+
if (epoch !== getRawSessionSummaryEpoch(sessionId))
|
|
31157
|
+
return false;
|
|
31158
|
+
const seeds = ordinalSummarySeeds.get(db) ?? new Map;
|
|
31159
|
+
seeds.set(sessionId, { epoch, scan });
|
|
31160
|
+
ordinalSummarySeeds.set(db, seeds);
|
|
31161
|
+
if (scan.checkpoints && workerPrepared) {
|
|
31162
|
+
const counts = ordinalCheckpoints.get(db) ?? new Map;
|
|
31163
|
+
counts.set(sessionId, { epoch, scan });
|
|
31164
|
+
ordinalCheckpoints.set(db, counts);
|
|
31165
|
+
} else if (getSqliteDatabasePath(db) && isMainThread2)
|
|
31166
|
+
return false;
|
|
31167
|
+
if (isRawSessionSummaryWarm(db, sessionId))
|
|
31168
|
+
return true;
|
|
31169
|
+
let sessions = summaryCandidateSets.get(db);
|
|
31170
|
+
if (!sessions) {
|
|
31171
|
+
sessions = new Map;
|
|
31172
|
+
summaryCandidateSets.set(db, sessions);
|
|
30394
31173
|
}
|
|
30395
|
-
|
|
30396
|
-
|
|
30397
|
-
|
|
30398
|
-
|
|
30399
|
-
|
|
30400
|
-
|
|
31174
|
+
sessions.set(sessionId, { epoch, anchors: [...scan.anchors], ids: new Set(scan.ids) });
|
|
31175
|
+
return isRawSessionSummaryWarm(db, sessionId);
|
|
31176
|
+
}
|
|
31177
|
+
function isRawSessionSummaryWarm(db, sessionId) {
|
|
31178
|
+
if (isMainThread2 && getSqliteDatabasePath(db)) {
|
|
31179
|
+
return Boolean(currentOrdinalCheckpoints(db, sessionId));
|
|
31180
|
+
}
|
|
31181
|
+
const set = summaryCandidateSets.get(db)?.get(sessionId);
|
|
31182
|
+
if (!set || set.epoch !== getRawSessionSummaryEpoch(sessionId))
|
|
31183
|
+
return false;
|
|
31184
|
+
try {
|
|
31185
|
+
return survivingAnchor(db, set) !== undefined;
|
|
31186
|
+
} catch {
|
|
31187
|
+
return false;
|
|
31188
|
+
}
|
|
31189
|
+
}
|
|
31190
|
+
function countStoredRawSessionRowsIndexed(db, sessionId) {
|
|
31191
|
+
const row = db.prepare("SELECT COUNT(*) AS count FROM message WHERE session_id = ?").get(sessionId);
|
|
31192
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
31193
|
+
}
|
|
31194
|
+
function summaryCandidatesOf(db, sessionId) {
|
|
31195
|
+
let sessions = summaryCandidateSets.get(db);
|
|
31196
|
+
if (!sessions) {
|
|
31197
|
+
sessions = new Map;
|
|
31198
|
+
summaryCandidateSets.set(db, sessions);
|
|
31199
|
+
}
|
|
31200
|
+
const epoch = getRawSessionSummaryEpoch(sessionId);
|
|
31201
|
+
const cached = sessions.get(sessionId);
|
|
31202
|
+
const floor = cached && cached.epoch === epoch ? survivingAnchor(db, cached) : undefined;
|
|
31203
|
+
let ids;
|
|
31204
|
+
let anchors;
|
|
31205
|
+
if (floor === undefined) {
|
|
31206
|
+
const scan = scanRawSessionSummaryRows(db, sessionId);
|
|
31207
|
+
summaryFullScans += 1;
|
|
31208
|
+
ordinalJsonRowsRead += scan.sessionRows;
|
|
31209
|
+
ids = new Set(scan.ids);
|
|
31210
|
+
anchors = scan.anchors;
|
|
31211
|
+
} else {
|
|
31212
|
+
const rows = db.prepare(SUMMARY_SCAN_AFTER_SQL).all(floor?.rowid ?? 0, sessionId);
|
|
31213
|
+
ids = cached?.ids ?? new Set;
|
|
31214
|
+
anchors = [];
|
|
31215
|
+
for (const row of rows) {
|
|
31216
|
+
if (row.kind === 1 && typeof row.rid === "number" && typeof row.id === "string")
|
|
31217
|
+
anchors.push({ rowid: row.rid, id: row.id });
|
|
31218
|
+
else if (row.kind === 2 && typeof row.id === "string")
|
|
31219
|
+
ids.add(row.id);
|
|
31220
|
+
if (row.kind === 2 || row.kind === 3)
|
|
31221
|
+
ordinalJsonRowsRead += 1;
|
|
31222
|
+
}
|
|
31223
|
+
anchors.sort((left, right) => right.rowid - left.rowid);
|
|
31224
|
+
anchors.length = Math.min(anchors.length, SUMMARY_ANCHOR_LIMIT);
|
|
31225
|
+
}
|
|
31226
|
+
for (const id of writtenSummaryIds.get(sessionId) ?? [])
|
|
31227
|
+
ids.add(id);
|
|
31228
|
+
sessions.set(sessionId, { epoch, anchors, ids });
|
|
31229
|
+
const top = anchors[0];
|
|
31230
|
+
return { ids: [...ids], floorRowid: top?.rowid ?? 0, floorId: top?.id ?? null };
|
|
31231
|
+
}
|
|
31232
|
+
function canonicalCountSql(lower, upper) {
|
|
31233
|
+
const range = `${lower ? " AND (time_created, id) > (?, ?)" : ""}${upper ? " AND (time_created, id) <= (?, ?)" : ""}`;
|
|
31234
|
+
return `SELECT
|
|
31235
|
+
(SELECT COUNT(*) FROM message WHERE session_id = ?${range}) AS stored,
|
|
31236
|
+
(SELECT COUNT(*) FROM message
|
|
31237
|
+
WHERE id IN (SELECT value FROM json_each(?)) AND +session_id = ?${range}
|
|
31238
|
+
AND ${EXCLUDED_ROW_SQL}) AS knownExcluded,
|
|
31239
|
+
(SELECT COUNT(*) FROM message
|
|
31240
|
+
WHERE rowid > ? AND +session_id = ? AND id NOT IN (SELECT value FROM json_each(?))${range}
|
|
31241
|
+
AND ${EXCLUDED_ROW_SQL}) AS newExcluded,
|
|
31242
|
+
(SELECT id FROM message WHERE rowid = ?) AS floorId`;
|
|
31243
|
+
}
|
|
31244
|
+
function canonicalCountStatementText(lower, upper) {
|
|
31245
|
+
const key = `${lower}:${upper}`;
|
|
31246
|
+
let sql = CANONICAL_COUNT_SQL.get(key);
|
|
31247
|
+
if (!sql) {
|
|
31248
|
+
sql = canonicalCountSql(lower, upper);
|
|
31249
|
+
CANONICAL_COUNT_SQL.set(key, sql);
|
|
31250
|
+
}
|
|
31251
|
+
return sql;
|
|
31252
|
+
}
|
|
31253
|
+
function countCanonicalOrdinalsIndexed(db, sessionId, after, through) {
|
|
31254
|
+
if (isMainThread2 && getSqliteDatabasePath(db)) {
|
|
31255
|
+
return withReadSnapshot(db, () => boundedOrdinalPrefix(db, sessionId, through) - (after ? boundedOrdinalPrefix(db, sessionId, after) : 0));
|
|
31256
|
+
}
|
|
31257
|
+
if (indexedCountUnsupported.has(db))
|
|
31258
|
+
return null;
|
|
31259
|
+
const range = [];
|
|
31260
|
+
if (after)
|
|
31261
|
+
range.push(after.timeCreated, after.id);
|
|
31262
|
+
if (through)
|
|
31263
|
+
range.push(through.timeCreated, through.id);
|
|
31264
|
+
try {
|
|
31265
|
+
return withReadSnapshot(db, () => {
|
|
31266
|
+
for (let attempt = 0;attempt < STABLE_STORE_ATTEMPTS; attempt += 1) {
|
|
31267
|
+
const view = summaryCandidatesOf(db, sessionId);
|
|
31268
|
+
const ids = JSON.stringify(view.ids);
|
|
31269
|
+
const row = db.prepare(canonicalCountStatementText(after !== null, through !== null)).get(sessionId, ...range, ids, sessionId, ...range, view.floorRowid, sessionId, ids, ...range, view.floorRowid);
|
|
31270
|
+
if (view.floorId !== null && row?.floorId !== view.floorId)
|
|
31271
|
+
continue;
|
|
31272
|
+
const stored = typeof row?.stored === "number" ? row.stored : 0;
|
|
31273
|
+
const excluded = (typeof row?.knownExcluded === "number" ? row.knownExcluded : 0) + (typeof row?.newExcluded === "number" ? row.newExcluded : 0);
|
|
31274
|
+
ordinalRowsVisited += stored;
|
|
31275
|
+
ordinalJsonRowsRead += view.ids.length;
|
|
31276
|
+
return stored - excluded;
|
|
31277
|
+
}
|
|
31278
|
+
return null;
|
|
31279
|
+
});
|
|
31280
|
+
} catch (error) {
|
|
31281
|
+
if (/no such (column|table|function)|json_each/i.test(String(error))) {
|
|
31282
|
+
indexedCountUnsupported.add(db);
|
|
31283
|
+
return null;
|
|
31284
|
+
}
|
|
31285
|
+
throw error;
|
|
31286
|
+
}
|
|
31287
|
+
}
|
|
31288
|
+
function connectionHasOpenTransaction(db) {
|
|
31289
|
+
const state = db;
|
|
31290
|
+
return state.inTransaction === true || state.isTransaction === true;
|
|
31291
|
+
}
|
|
31292
|
+
function withReadSnapshot(db, read) {
|
|
31293
|
+
if (connectionHasOpenTransaction(db))
|
|
31294
|
+
return read();
|
|
31295
|
+
db.exec("BEGIN");
|
|
31296
|
+
try {
|
|
31297
|
+
return read();
|
|
31298
|
+
} finally {
|
|
31299
|
+
if (connectionHasOpenTransaction(db))
|
|
31300
|
+
db.exec("ROLLBACK");
|
|
31301
|
+
}
|
|
31302
|
+
}
|
|
31303
|
+
function reusableWatermark(db, sessionId, stamp) {
|
|
31304
|
+
const watermark = ordinalWatermarks.get(db)?.get(sessionId);
|
|
31305
|
+
if (!watermark || watermark.epoch !== (ordinalWatermarkEpochs.get(sessionId) ?? 0) || !sameStoreStamp(watermark.stamp, stamp))
|
|
31306
|
+
return null;
|
|
31307
|
+
return watermark;
|
|
31308
|
+
}
|
|
31309
|
+
function rememberOrdinalWatermark(db, sessionId, key, ordinal, stamp) {
|
|
31310
|
+
let sessions = ordinalWatermarks.get(db);
|
|
31311
|
+
if (!sessions) {
|
|
31312
|
+
sessions = new Map;
|
|
31313
|
+
ordinalWatermarks.set(db, sessions);
|
|
31314
|
+
}
|
|
31315
|
+
const current = sessions.get(sessionId);
|
|
31316
|
+
if (current && sameStoreStamp(current.stamp, stamp) && compareOrdinalKeys(current, key) >= 0)
|
|
31317
|
+
return;
|
|
31318
|
+
sessions.set(sessionId, {
|
|
31319
|
+
timeCreated: key.timeCreated,
|
|
31320
|
+
id: key.id,
|
|
31321
|
+
ordinal,
|
|
31322
|
+
stamp,
|
|
31323
|
+
epoch: ordinalWatermarkEpochs.get(sessionId) ?? 0
|
|
31324
|
+
});
|
|
31325
|
+
}
|
|
31326
|
+
function canonicalOrdinalOf(db, sessionId, readTarget) {
|
|
31327
|
+
for (let attempt = 1;; attempt += 1) {
|
|
31328
|
+
const before = readStoreStamp(db);
|
|
31329
|
+
const target = readTarget();
|
|
31330
|
+
if (!target)
|
|
31331
|
+
return null;
|
|
31332
|
+
const watermark = attempt < STABLE_STORE_ATTEMPTS ? reusableWatermark(db, sessionId, before) : null;
|
|
31333
|
+
if (!watermark) {
|
|
31334
|
+
const ordinal = countEligibleOrdinals(db, sessionId, null, target);
|
|
31335
|
+
if (before && sameStoreStamp(before, readStoreStamp(db)))
|
|
31336
|
+
rememberOrdinalWatermark(db, sessionId, target, ordinal, before);
|
|
31337
|
+
return { target, ordinal };
|
|
31338
|
+
}
|
|
31339
|
+
const order = compareOrdinalKeys(target, watermark);
|
|
31340
|
+
const ordinal = order === 0 ? watermark.ordinal : order < 0 ? watermark.ordinal - countEligibleOrdinals(db, sessionId, target, watermark) : watermark.ordinal + countEligibleOrdinals(db, sessionId, watermark, target);
|
|
31341
|
+
if (sameStoreStamp(before, readStoreStamp(db))) {
|
|
31342
|
+
rememberOrdinalWatermark(db, sessionId, target, ordinal, before);
|
|
31343
|
+
return { target, ordinal };
|
|
31344
|
+
}
|
|
31345
|
+
}
|
|
31346
|
+
}
|
|
31347
|
+
function readRawSessionMessageOrdinalByIdFromDb(db, sessionId, messageId) {
|
|
31348
|
+
const counted = canonicalOrdinalOf(db, sessionId, () => {
|
|
31349
|
+
const row = db.prepare(`SELECT id, time_created, ${ORDINAL_SUMMARY_FLAG_SQL} AND ${ORDINAL_STOP_FLAG_SQL} AS excluded
|
|
31350
|
+
FROM message WHERE session_id = ? AND id = ?`).get(sessionId, messageId);
|
|
31351
|
+
if (typeof row?.id !== "string" || typeof row.time_created !== "number")
|
|
31352
|
+
return null;
|
|
31353
|
+
return { id: row.id, timeCreated: row.time_created, excluded: row.excluded === 1 };
|
|
31354
|
+
});
|
|
31355
|
+
if (!counted || counted.target.excluded)
|
|
31356
|
+
return null;
|
|
31357
|
+
return counted.ordinal > 0 ? counted.ordinal : null;
|
|
31358
|
+
}
|
|
31359
|
+
function readRawSessionMessageByIdFromDb(db, sessionId, messageId) {
|
|
31360
|
+
const counted = canonicalOrdinalOf(db, sessionId, () => {
|
|
31361
|
+
const row = db.prepare("SELECT id, data, time_created, time_updated FROM message WHERE session_id = ? AND id = ?").get(sessionId, messageId);
|
|
31362
|
+
if (!row || !isRawMessageRow(row) || typeof row.time_created !== "number")
|
|
31363
|
+
return null;
|
|
31364
|
+
const parsed = parseJsonRecord(row.data);
|
|
31365
|
+
if (!parsed || isRawCompactionSummaryInfo(parsed))
|
|
31366
|
+
return null;
|
|
31367
|
+
return { ...row, timeCreated: row.time_created, info: parsed };
|
|
31368
|
+
});
|
|
31369
|
+
if (!counted)
|
|
31370
|
+
return null;
|
|
31371
|
+
const { target: row, ordinal } = counted;
|
|
31372
|
+
const info = row.info;
|
|
30401
31373
|
if (ordinal <= 0) {
|
|
30402
31374
|
return null;
|
|
30403
31375
|
}
|
|
@@ -30461,8 +31433,147 @@ function readRawSeedTailFromDb(db, sessionId, boundaryId) {
|
|
|
30461
31433
|
throw new Error("state_sync materialized boundary is missing from raw storage");
|
|
30462
31434
|
return messages;
|
|
30463
31435
|
}
|
|
30464
|
-
|
|
30465
|
-
|
|
31436
|
+
function readBoundaryEndpointRows(db, sessionId, ids, blockIds, into) {
|
|
31437
|
+
if (ids.length > 0) {
|
|
31438
|
+
boundaryEndpointRowsRead += ids.length;
|
|
31439
|
+
const wanted = JSON.stringify(ids);
|
|
31440
|
+
const ordinals = new Map;
|
|
31441
|
+
for (const row of db.prepare(BOUNDARY_ORDINAL_SQL).all(sessionId, wanted)) {
|
|
31442
|
+
ordinals.set(row.id, row.ordinal);
|
|
31443
|
+
}
|
|
31444
|
+
const rows = db.prepare(BOUNDARY_MESSAGE_SQL).all(sessionId, wanted);
|
|
31445
|
+
for (const id of ids)
|
|
31446
|
+
into.set(id, null);
|
|
31447
|
+
for (const row of rows) {
|
|
31448
|
+
if (!isRawMessageRow(row) || typeof row.time_created !== "number")
|
|
31449
|
+
continue;
|
|
31450
|
+
const info = parseJsonRecord(row.data);
|
|
31451
|
+
if (!info || isRawCompactionSummaryInfo(info))
|
|
31452
|
+
continue;
|
|
31453
|
+
into.set(row.id, {
|
|
31454
|
+
ordinal: ordinals.get(row.id) ?? null,
|
|
31455
|
+
createdAt: row.time_created
|
|
31456
|
+
});
|
|
31457
|
+
}
|
|
31458
|
+
}
|
|
31459
|
+
const servable = blockIds.filter((id) => {
|
|
31460
|
+
const endpoint = into.get(id);
|
|
31461
|
+
return endpoint && endpoint.lastBlockIndex === undefined;
|
|
31462
|
+
});
|
|
31463
|
+
if (servable.length === 0)
|
|
31464
|
+
return;
|
|
31465
|
+
const counts = new Map;
|
|
31466
|
+
for (const row of db.prepare(BOUNDARY_BLOCK_COUNT_SQL).all(sessionId, JSON.stringify(servable))) {
|
|
31467
|
+
counts.set(row.id, row.blocks);
|
|
31468
|
+
}
|
|
31469
|
+
for (const id of servable) {
|
|
31470
|
+
const endpoint = into.get(id);
|
|
31471
|
+
if (!endpoint)
|
|
31472
|
+
continue;
|
|
31473
|
+
const blocks = counts.get(id) ?? 0;
|
|
31474
|
+
into.set(id, { ...endpoint, lastBlockIndex: blocks > 0 ? blocks - 1 : 0 });
|
|
31475
|
+
}
|
|
31476
|
+
}
|
|
31477
|
+
function readRawSessionBoundaryEndpointsFromDb(db, sessionId, ids, blockIds = []) {
|
|
31478
|
+
const wanted = [...new Set(ids)];
|
|
31479
|
+
const wantedBlocks = [...new Set(blockIds)];
|
|
31480
|
+
let sessions = boundaryEndpointCaches.get(db);
|
|
31481
|
+
if (!sessions) {
|
|
31482
|
+
sessions = new Map;
|
|
31483
|
+
boundaryEndpointCaches.set(db, sessions);
|
|
31484
|
+
}
|
|
31485
|
+
for (let attempt = 1;; attempt += 1) {
|
|
31486
|
+
const before = readStoreStamp(db);
|
|
31487
|
+
const cached = sessions.get(sessionId);
|
|
31488
|
+
const reuse = attempt === 1 && cached && sameStoreStamp(cached.stamp, before);
|
|
31489
|
+
const endpoints = new Map(reuse ? cached.endpoints : []);
|
|
31490
|
+
const missing = wanted.filter((id) => !endpoints.has(id));
|
|
31491
|
+
withReadSnapshot(db, () => readBoundaryEndpointRows(db, sessionId, missing, wantedBlocks, endpoints));
|
|
31492
|
+
const unchanged = before !== null && sameStoreStamp(before, readStoreStamp(db));
|
|
31493
|
+
if (unchanged) {
|
|
31494
|
+
sessions.delete(sessionId);
|
|
31495
|
+
sessions.set(sessionId, { stamp: before, endpoints });
|
|
31496
|
+
while (sessions.size > BOUNDARY_ENDPOINT_CACHE_SESSIONS) {
|
|
31497
|
+
const oldest = sessions.keys().next().value;
|
|
31498
|
+
if (oldest === undefined)
|
|
31499
|
+
break;
|
|
31500
|
+
sessions.delete(oldest);
|
|
31501
|
+
}
|
|
31502
|
+
} else if (reuse) {
|
|
31503
|
+
continue;
|
|
31504
|
+
}
|
|
31505
|
+
return new Map(wanted.map((id) => [id, endpoints.get(id) ?? null]));
|
|
31506
|
+
}
|
|
31507
|
+
}
|
|
31508
|
+
var RAW_MESSAGE_PARTS_BY_ID_SQL = "SELECT message_id, data, time_updated FROM part WHERE +session_id = ? AND likelihood(message_id = ?, 0.000001) ORDER BY time_created ASC, id ASC", RAW_METADATA_KEEP_CHARS = 16384, RAW_METADATA_KEPT_KEYS, RAW_PART_DATA_SQL, rawMessagePageRowsVisited = 0, RAW_SUMMARY_TEXT_MAX_CHARS = 8192, RAW_SUMMARY_ARG_MAX_CHARS = 512, RAW_SUMMARY_TOOL_INPUT_KEYS, RAW_SUMMARY_PART_DATA_SQL, ORDINAL_SUMMARY_FLAG_SQL = `(CASE WHEN json_valid(data) = 1
|
|
31509
|
+
THEN COALESCE(json_extract(data, '$.summary'), 0)
|
|
31510
|
+
ELSE 0 END = 1)`, ORDINAL_STOP_FLAG_SQL = `(CASE WHEN json_valid(data) = 1
|
|
31511
|
+
THEN COALESCE(json_extract(data, '$.finish'), '')
|
|
31512
|
+
ELSE '' END = 'stop')`, ORDINAL_RANGE_FROM_START_SQL, ORDINAL_RANGE_BETWEEN_SQL, ordinalWatermarks, ordinalWatermarkEpochs, ordinalRowsVisited = 0, STABLE_STORE_ATTEMPTS = 3, EXCLUDED_ROW_SQL, SUMMARY_ANCHOR_SPAN = 256, SUMMARY_ANCHOR_LIMIT = 64, summaryCandidateSets, summaryCandidateEpochs, writtenSummaryIds, indexedCountUnsupported, ordinalJsonRowsRead = 0, summaryFullScans = 0, ANCHOR_ROWS_SQL, SUMMARY_FULL_SCAN_SQL, SUMMARY_SCAN_AFTER_SQL, ANCHOR_CHECK_SQL = "SELECT rowid AS rid, id FROM message WHERE rowid IN (SELECT value FROM json_each(?))", ordinalCheckpoints, ordinalSummarySeeds, ORDINAL_LOOKUP_LIMIT = 512, RawOrdinalsNotReady, CANONICAL_COUNT_SQL, BOUNDARY_ORDINAL_SQL = `
|
|
31513
|
+
SELECT id, ordinal FROM (
|
|
31514
|
+
SELECT id, ROW_NUMBER() OVER (ORDER BY time_created, id) AS ordinal
|
|
31515
|
+
FROM message
|
|
31516
|
+
WHERE session_id = ?
|
|
31517
|
+
AND typeof(id) = 'text' AND typeof(data) = 'text'
|
|
31518
|
+
AND CASE WHEN json_valid(data) THEN NOT (
|
|
31519
|
+
COALESCE(json_type(data, '$.summary'), '') = 'true'
|
|
31520
|
+
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop'
|
|
31521
|
+
) ELSE 1 END
|
|
31522
|
+
)
|
|
31523
|
+
WHERE id IN (SELECT value FROM json_each(?))`, BOUNDARY_MESSAGE_SQL = `
|
|
31524
|
+
SELECT id, data, time_created FROM message
|
|
31525
|
+
WHERE +session_id = ? AND id IN (SELECT value FROM json_each(?))`, BOUNDARY_BLOCK_COUNT_SQL = `
|
|
31526
|
+
SELECT message_id AS id, SUM(
|
|
31527
|
+
CASE
|
|
31528
|
+
WHEN NOT json_valid(data) OR json_type(data) <> 'object' THEN 0
|
|
31529
|
+
ELSE CASE (CASE WHEN json_type(data, '$.type') = 'text'
|
|
31530
|
+
THEN json_extract(data, '$.type') ELSE 'unknown' END)
|
|
31531
|
+
WHEN 'text' THEN CASE WHEN json_type(data, '$.ignored') = 'true' THEN 0 ELSE 1 END
|
|
31532
|
+
WHEN 'reasoning' THEN 1
|
|
31533
|
+
WHEN 'thinking' THEN 1
|
|
31534
|
+
WHEN 'redacted_thinking' THEN 1
|
|
31535
|
+
WHEN 'tool' THEN 1 + CASE
|
|
31536
|
+
WHEN json_type(data, '$.state') = 'object'
|
|
31537
|
+
AND json_type(data, '$.state.status') = 'text'
|
|
31538
|
+
AND json_extract(data, '$.state.status') IN ('completed', 'error')
|
|
31539
|
+
THEN 1 ELSE 0 END
|
|
31540
|
+
WHEN 'compaction' THEN 0
|
|
31541
|
+
WHEN 'step-finish' THEN 0
|
|
31542
|
+
WHEN 'snapshot' THEN 0
|
|
31543
|
+
WHEN 'patch' THEN 0
|
|
31544
|
+
WHEN 'agent' THEN 0
|
|
31545
|
+
WHEN 'retry' THEN 0
|
|
31546
|
+
ELSE 1
|
|
31547
|
+
END
|
|
31548
|
+
END) AS blocks
|
|
31549
|
+
FROM part
|
|
31550
|
+
WHERE +session_id = ?
|
|
31551
|
+
AND message_id IN (SELECT value FROM json_each(?))
|
|
31552
|
+
AND typeof(message_id) = 'text' AND typeof(data) = 'text'
|
|
31553
|
+
GROUP BY message_id`, boundaryEndpointCaches, BOUNDARY_ENDPOINT_CACHE_SESSIONS = 16, boundaryEndpointRowsRead = 0;
|
|
31554
|
+
var init_read_session_raw = __esm(async () => {
|
|
31555
|
+
await __promiseAll([
|
|
31556
|
+
init_sqlite(),
|
|
31557
|
+
init_raw_ordinal_warmup()
|
|
31558
|
+
]);
|
|
31559
|
+
RAW_METADATA_KEPT_KEYS = [
|
|
31560
|
+
"description",
|
|
31561
|
+
"title",
|
|
31562
|
+
"userAnswer",
|
|
31563
|
+
"answers",
|
|
31564
|
+
"answer",
|
|
31565
|
+
"selectedOptions",
|
|
31566
|
+
"customInput",
|
|
31567
|
+
"results"
|
|
31568
|
+
];
|
|
31569
|
+
RAW_PART_DATA_SQL = `CASE
|
|
31570
|
+
WHEN json_valid(data) = 1
|
|
31571
|
+
AND json_type(data, '$.state.metadata') = 'object'
|
|
31572
|
+
AND COALESCE(json_extract(data, '$.state.status'), '') <> 'error'
|
|
31573
|
+
AND length(json_extract(data, '$.state.metadata')) > ${RAW_METADATA_KEEP_CHARS}
|
|
31574
|
+
THEN json_set(data, '$.state.metadata', json_patch('{}', json_object(${RAW_METADATA_KEPT_KEYS.map((key) => `'${key}', json_extract(data, '$.state.metadata.${key}')`).join(", ")})))
|
|
31575
|
+
ELSE data
|
|
31576
|
+
END`;
|
|
30466
31577
|
RAW_SUMMARY_TOOL_INPUT_KEYS = [
|
|
30467
31578
|
"description",
|
|
30468
31579
|
"filePath",
|
|
@@ -30487,6 +31598,269 @@ var init_read_session_raw = __esm(() => {
|
|
|
30487
31598
|
)
|
|
30488
31599
|
)
|
|
30489
31600
|
END`;
|
|
31601
|
+
ORDINAL_RANGE_FROM_START_SQL = ordinalRangeSql(false);
|
|
31602
|
+
ORDINAL_RANGE_BETWEEN_SQL = ordinalRangeSql(true);
|
|
31603
|
+
ordinalWatermarks = new WeakMap;
|
|
31604
|
+
ordinalWatermarkEpochs = new Map;
|
|
31605
|
+
EXCLUDED_ROW_SQL = `${ORDINAL_SUMMARY_FLAG_SQL} AND ${ORDINAL_STOP_FLAG_SQL}`;
|
|
31606
|
+
summaryCandidateSets = new WeakMap;
|
|
31607
|
+
summaryCandidateEpochs = new Map;
|
|
31608
|
+
writtenSummaryIds = new Map;
|
|
31609
|
+
indexedCountUnsupported = new WeakSet;
|
|
31610
|
+
ANCHOR_ROWS_SQL = `SELECT rowid AS rid, id, 1 AS kind FROM message
|
|
31611
|
+
WHERE rowid > (SELECT MAX(rowid) FROM message) - ${SUMMARY_ANCHOR_SPAN}`;
|
|
31612
|
+
SUMMARY_FULL_SCAN_SQL = `${ANCHOR_ROWS_SQL}
|
|
31613
|
+
UNION ALL
|
|
31614
|
+
SELECT rowid, id, 2 FROM message WHERE session_id = ? AND ${ORDINAL_SUMMARY_FLAG_SQL}
|
|
31615
|
+
UNION ALL
|
|
31616
|
+
SELECT COUNT(*), NULL, 4 FROM message WHERE session_id = ?`;
|
|
31617
|
+
SUMMARY_SCAN_AFTER_SQL = `${ANCHOR_ROWS_SQL}
|
|
31618
|
+
UNION ALL
|
|
31619
|
+
SELECT rowid, id, CASE WHEN ${ORDINAL_SUMMARY_FLAG_SQL} THEN 2 ELSE 3 END
|
|
31620
|
+
FROM message WHERE rowid > ? AND +session_id = ?`;
|
|
31621
|
+
ordinalCheckpoints = new WeakMap;
|
|
31622
|
+
ordinalSummarySeeds = new WeakMap;
|
|
31623
|
+
RawOrdinalsNotReady = class RawOrdinalsNotReady extends Error {
|
|
31624
|
+
constructor() {
|
|
31625
|
+
super("canonical ordinals are warming off-thread; retry after preparation");
|
|
31626
|
+
}
|
|
31627
|
+
};
|
|
31628
|
+
CANONICAL_COUNT_SQL = new Map;
|
|
31629
|
+
boundaryEndpointCaches = new WeakMap;
|
|
31630
|
+
});
|
|
31631
|
+
|
|
31632
|
+
// ../plugin/src/hooks/magic-context/raw-ordinal-warmup.ts
|
|
31633
|
+
import { Worker } from "node:worker_threads";
|
|
31634
|
+
function stopRawSessionOrdinalWarmups() {
|
|
31635
|
+
for (const stop of [...activeWorkers.values()])
|
|
31636
|
+
stop("stopped");
|
|
31637
|
+
}
|
|
31638
|
+
function defaultEntry() {
|
|
31639
|
+
return new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "./raw-ordinal-warmup-worker.ts" : "./raw-ordinal-warmup-worker.js", import.meta.url);
|
|
31640
|
+
}
|
|
31641
|
+
function ensureExitHook() {
|
|
31642
|
+
if (exitHookRegistered)
|
|
31643
|
+
return;
|
|
31644
|
+
exitHookRegistered = true;
|
|
31645
|
+
const controller = new AbortController;
|
|
31646
|
+
controller.signal.addEventListener("abort", stopRawSessionOrdinalWarmups, { once: true });
|
|
31647
|
+
registerExitAbort(controller);
|
|
31648
|
+
}
|
|
31649
|
+
function runSessionWarmupWorker(input, options) {
|
|
31650
|
+
ensureExitHook();
|
|
31651
|
+
return new Promise((resolve) => {
|
|
31652
|
+
let worker;
|
|
31653
|
+
let deadline;
|
|
31654
|
+
let settled = false;
|
|
31655
|
+
const finish = (result) => {
|
|
31656
|
+
if (settled)
|
|
31657
|
+
return;
|
|
31658
|
+
settled = true;
|
|
31659
|
+
clearTimeout(deadline);
|
|
31660
|
+
if (worker) {
|
|
31661
|
+
activeWorkers.delete(worker);
|
|
31662
|
+
const stopped = worker.terminate();
|
|
31663
|
+
worker.unref();
|
|
31664
|
+
stopped.finally(() => {
|
|
31665
|
+
releaseIndexOwner(input);
|
|
31666
|
+
resolve(result);
|
|
31667
|
+
});
|
|
31668
|
+
return;
|
|
31669
|
+
}
|
|
31670
|
+
releaseIndexOwner(input);
|
|
31671
|
+
resolve(result);
|
|
31672
|
+
};
|
|
31673
|
+
const arm = (failure, ms) => {
|
|
31674
|
+
clearTimeout(deadline);
|
|
31675
|
+
deadline = setTimeout(() => finish({ failure, detail: `no reply within ${ms} ms` }), ms);
|
|
31676
|
+
deadline.unref?.();
|
|
31677
|
+
};
|
|
31678
|
+
try {
|
|
31679
|
+
worker = new Worker(options.entry ?? defaultEntry(), { workerData: input });
|
|
31680
|
+
} catch (error) {
|
|
31681
|
+
finish({ failure: "start-failed", detail: String(error) });
|
|
31682
|
+
return;
|
|
31683
|
+
}
|
|
31684
|
+
worker.unref();
|
|
31685
|
+
activeWorkers.set(worker, (failure) => finish({ failure, detail: "stopped" }));
|
|
31686
|
+
arm("not-accepted", options.acceptMs ?? ACCEPT_TIMEOUT_MS);
|
|
31687
|
+
worker.on("message", (reply) => {
|
|
31688
|
+
if (reply.kind === "accepted")
|
|
31689
|
+
arm("no-result", options.resultMs ?? RESULT_TIMEOUT_MS);
|
|
31690
|
+
else if (reply.kind === "scan")
|
|
31691
|
+
finish({ scan: reply.scan });
|
|
31692
|
+
else if (reply.kind === "tag-summary")
|
|
31693
|
+
finish({ summary: reply.summary });
|
|
31694
|
+
else if (reply.kind === "tag-delta")
|
|
31695
|
+
finish({ delta: reply.delta });
|
|
31696
|
+
else if (reply.kind === "indexed")
|
|
31697
|
+
finish({ inserted: reply.inserted, measurements: reply.measurements });
|
|
31698
|
+
else
|
|
31699
|
+
finish({ failure: "worker-error", detail: reply.error });
|
|
31700
|
+
});
|
|
31701
|
+
worker.on("error", (error) => finish({ failure: "worker-error", detail: String(error) }));
|
|
31702
|
+
worker.on("exit", (code) => finish({ failure: "exited", detail: `exit code ${code}` }));
|
|
31703
|
+
});
|
|
31704
|
+
}
|
|
31705
|
+
function prewarmRawSessionOrdinalsForDb(db, sessionId, options = {}) {
|
|
31706
|
+
if (isRawSessionSummaryWarm(db, sessionId))
|
|
31707
|
+
return Promise.resolve("warm");
|
|
31708
|
+
if (!db.prepare("SELECT 1 FROM sqlite_master WHERE name = 'message' AND type IN ('table', 'view')").get())
|
|
31709
|
+
return Promise.resolve("warm");
|
|
31710
|
+
const path = getSqliteDatabasePath(db);
|
|
31711
|
+
if (!path) {
|
|
31712
|
+
countRawSessionMessageOrdinalsFromDb(db, sessionId);
|
|
31713
|
+
return Promise.resolve("warm");
|
|
31714
|
+
}
|
|
31715
|
+
let connectionId = connectionIds.get(db);
|
|
31716
|
+
if (connectionId === undefined) {
|
|
31717
|
+
connectionId = ++nextConnectionId;
|
|
31718
|
+
connectionIds.set(db, connectionId);
|
|
31719
|
+
}
|
|
31720
|
+
const key = `${path}\x00${sessionId}\x00${connectionId}`;
|
|
31721
|
+
let shared = inFlight.get(key);
|
|
31722
|
+
if (!shared) {
|
|
31723
|
+
const failed = failedAt.get(key);
|
|
31724
|
+
if (failed !== undefined && Date.now() - failed < FAILURE_BACKOFF_MS)
|
|
31725
|
+
return Promise.resolve("failed");
|
|
31726
|
+
const epoch = getRawSessionSummaryEpoch(sessionId);
|
|
31727
|
+
const started = performance.now();
|
|
31728
|
+
const result = runSessionWarmupWorker({ path, sessionId, previous: rawOrdinalSummarySeed(db, sessionId) }, options).then((outcome) => {
|
|
31729
|
+
if ("failure" in outcome)
|
|
31730
|
+
recordFailure(key, sessionId, outcome.failure, outcome.detail);
|
|
31731
|
+
return outcome;
|
|
31732
|
+
}).finally(() => {
|
|
31733
|
+
if (inFlight.get(key) === scan)
|
|
31734
|
+
inFlight.delete(key);
|
|
31735
|
+
});
|
|
31736
|
+
const scan = { epoch, started, result };
|
|
31737
|
+
inFlight.set(key, scan);
|
|
31738
|
+
shared = scan;
|
|
31739
|
+
}
|
|
31740
|
+
const awaited = shared;
|
|
31741
|
+
return awaited.result.then((result) => {
|
|
31742
|
+
if (!("scan" in result))
|
|
31743
|
+
return "failed";
|
|
31744
|
+
try {
|
|
31745
|
+
if (installRawSessionSummaryScan(db, sessionId, result.scan, awaited.epoch, true)) {
|
|
31746
|
+
failedAt.delete(key);
|
|
31747
|
+
log(`[magic-context] canonical ordinals of ${sessionId} warmed off-thread (${result.scan.sessionRows} messages, ${Math.round(performance.now() - awaited.started)} ms)`);
|
|
31748
|
+
return "warm";
|
|
31749
|
+
}
|
|
31750
|
+
} catch {}
|
|
31751
|
+
recordFailure(key, sessionId, "superseded", `session removed during scan: epoch=${awaited.epoch}/${getRawSessionSummaryEpoch(sessionId)}`);
|
|
31752
|
+
return "failed";
|
|
31753
|
+
});
|
|
31754
|
+
}
|
|
31755
|
+
function recordFailure(key, sessionId, failure, detail) {
|
|
31756
|
+
failures.set(failure, (failures.get(failure) ?? 0) + 1);
|
|
31757
|
+
if (failure !== "superseded")
|
|
31758
|
+
failedAt.set(key, Date.now());
|
|
31759
|
+
log(`[magic-context] WARN canonical ordinal warm-up failed for ${sessionId} (${failure}: ${detail}); counts remain bounded and callers must defer or retry`);
|
|
31760
|
+
}
|
|
31761
|
+
var ACCEPT_TIMEOUT_MS = 2000, RESULT_TIMEOUT_MS, FAILURE_BACKOFF_MS, inFlight, connectionIds, nextConnectionId = 0, failedAt, activeWorkers, failures, exitHookRegistered = false;
|
|
31762
|
+
var init_raw_ordinal_warmup = __esm(async () => {
|
|
31763
|
+
init_exit_abort_registry();
|
|
31764
|
+
init_logger();
|
|
31765
|
+
await __promiseAll([
|
|
31766
|
+
init_sqlite(),
|
|
31767
|
+
init_read_session_raw()
|
|
31768
|
+
]);
|
|
31769
|
+
RESULT_TIMEOUT_MS = 10 * 60000;
|
|
31770
|
+
FAILURE_BACKOFF_MS = 5 * 60000;
|
|
31771
|
+
inFlight = new Map;
|
|
31772
|
+
connectionIds = new WeakMap;
|
|
31773
|
+
failedAt = new Map;
|
|
31774
|
+
activeWorkers = new Map;
|
|
31775
|
+
failures = new Map;
|
|
31776
|
+
});
|
|
31777
|
+
|
|
31778
|
+
// ../plugin/src/hooks/magic-context/read-session-db.ts
|
|
31779
|
+
function openCodeDbExists() {
|
|
31780
|
+
return harnessOwnsOpenCodeStore() && openCodeDbPathExists(resolveOpenCodeDbPath());
|
|
31781
|
+
}
|
|
31782
|
+
function closeCachedReadOnlyDb() {
|
|
31783
|
+
if (!cachedReadOnlyDb) {
|
|
31784
|
+
return;
|
|
31785
|
+
}
|
|
31786
|
+
try {
|
|
31787
|
+
closeQuietly(cachedReadOnlyDb.db);
|
|
31788
|
+
} catch (error) {
|
|
31789
|
+
log("[magic-context] failed to close cached OpenCode read-only DB:", error);
|
|
31790
|
+
} finally {
|
|
31791
|
+
cachedReadOnlyDb = null;
|
|
31792
|
+
}
|
|
31793
|
+
}
|
|
31794
|
+
function getReadOnlySessionDb() {
|
|
31795
|
+
if (!harnessOwnsOpenCodeStore()) {
|
|
31796
|
+
throw new Error("OpenCode session database is not readable from a Pi-compatible process; its history lives in Pi sessions");
|
|
31797
|
+
}
|
|
31798
|
+
const resolution = resolveOpenCodeDbPath();
|
|
31799
|
+
const dbPath = resolution.path;
|
|
31800
|
+
if (!openCodeDbPathExists(resolution)) {
|
|
31801
|
+
throw new Error(`OpenCode session database is unavailable at ${dbPath} (source=${resolution.source})`);
|
|
31802
|
+
}
|
|
31803
|
+
if (cachedReadOnlyDb?.path === dbPath) {
|
|
31804
|
+
return cachedReadOnlyDb.db;
|
|
31805
|
+
}
|
|
31806
|
+
closeCachedReadOnlyDb();
|
|
31807
|
+
const db = new Database(dbPath, { readonly: true });
|
|
31808
|
+
try {
|
|
31809
|
+
assertOpenCodeStoreGeneration(db, "v1", dbPath);
|
|
31810
|
+
} catch (error) {
|
|
31811
|
+
closeQuietly(db);
|
|
31812
|
+
throw error;
|
|
31813
|
+
}
|
|
31814
|
+
cachedReadOnlyDb = { path: dbPath, db };
|
|
31815
|
+
clearOpenCodeDbReadFailure();
|
|
31816
|
+
return db;
|
|
31817
|
+
}
|
|
31818
|
+
function withReadOnlySessionDb(fn) {
|
|
31819
|
+
return fn(getReadOnlySessionDb());
|
|
31820
|
+
}
|
|
31821
|
+
function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
31822
|
+
const row = db.prepare(`SELECT COUNT(*) as count FROM message WHERE session_id = ?
|
|
31823
|
+
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
31824
|
+
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
|
|
31825
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
31826
|
+
}
|
|
31827
|
+
function logProbeFailureOnce(resolution, error) {
|
|
31828
|
+
const failure = recordOpenCodeDbReadFailure(resolution, error);
|
|
31829
|
+
if (!claimOpenCodeDbDiagnosticOnce("session-state-probe", resolution))
|
|
31830
|
+
return;
|
|
31831
|
+
const message = `[magic-context] OpenCode DB probe failed: path=${resolution.path} source=${resolution.source} cause=${failure.message}`;
|
|
31832
|
+
probeLogObserverForTests?.(message);
|
|
31833
|
+
log(message);
|
|
31834
|
+
}
|
|
31835
|
+
function getMessageTimesFromOpenCodeDb(sessionId, messageIds) {
|
|
31836
|
+
const result = new Map;
|
|
31837
|
+
if (messageIds.length === 0 || !harnessOwnsOpenCodeStore())
|
|
31838
|
+
return result;
|
|
31839
|
+
try {
|
|
31840
|
+
withReadOnlySessionDb((db) => {
|
|
31841
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
31842
|
+
const rows = db.prepare(`SELECT id, time_created FROM message WHERE +session_id = ? AND id IN (${placeholders})`).all(sessionId, ...messageIds);
|
|
31843
|
+
for (const row of rows) {
|
|
31844
|
+
if (typeof row.id === "string" && typeof row.time_created === "number") {
|
|
31845
|
+
result.set(row.id, row.time_created);
|
|
31846
|
+
}
|
|
31847
|
+
}
|
|
31848
|
+
});
|
|
31849
|
+
} catch (error) {
|
|
31850
|
+
logProbeFailureOnce(resolveOpenCodeDbPath(), error);
|
|
31851
|
+
}
|
|
31852
|
+
return result;
|
|
31853
|
+
}
|
|
31854
|
+
var cachedReadOnlyDb = null, trackedSessions, pendingParts, probeLogObserverForTests;
|
|
31855
|
+
var init_read_session_db = __esm(async () => {
|
|
31856
|
+
init_logger();
|
|
31857
|
+
init_opencode_db_path();
|
|
31858
|
+
await __promiseAll([
|
|
31859
|
+
init_sqlite(),
|
|
31860
|
+
init_read_session_raw()
|
|
31861
|
+
]);
|
|
31862
|
+
trackedSessions = new Map;
|
|
31863
|
+
pendingParts = new Map;
|
|
30490
31864
|
});
|
|
30491
31865
|
|
|
30492
31866
|
// ../plugin/src/hooks/magic-context/read-session-true-raw-tokens.ts
|
|
@@ -30538,7 +31912,7 @@ function callIdFromPart(part) {
|
|
|
30538
31912
|
const state = isRecord2(part.state) ? part.state : null;
|
|
30539
31913
|
return state ? firstStringField(state, ["callID", "callId", "toolCallId", "tool_call_id", "id"]) ?? "" : "";
|
|
30540
31914
|
}
|
|
30541
|
-
function toolSignalFromPart(part) {
|
|
31915
|
+
function toolSignalFromPart(part, withText = true) {
|
|
30542
31916
|
if (!isRecord2(part))
|
|
30543
31917
|
return null;
|
|
30544
31918
|
const type = partType(part);
|
|
@@ -30557,8 +31931,8 @@ function toolSignalFromPart(part) {
|
|
|
30557
31931
|
callId,
|
|
30558
31932
|
hasInput: hasInput || openInvocation,
|
|
30559
31933
|
hasOutput,
|
|
30560
|
-
inputText: hasInput && state ? stringValue(state.input) : "",
|
|
30561
|
-
outputText: hasOutput ? stringValue(outputValue) : ""
|
|
31934
|
+
inputText: withText && hasInput && state ? stringValue(state.input) : "",
|
|
31935
|
+
outputText: withText && hasOutput ? stringValue(outputValue) : ""
|
|
30562
31936
|
};
|
|
30563
31937
|
}
|
|
30564
31938
|
if (type === "tool-invocation") {
|
|
@@ -30567,7 +31941,7 @@ function toolSignalFromPart(part) {
|
|
|
30567
31941
|
callId,
|
|
30568
31942
|
hasInput: args !== undefined,
|
|
30569
31943
|
hasOutput: false,
|
|
30570
|
-
inputText: args !== undefined ? stringValue(args) : "",
|
|
31944
|
+
inputText: withText && args !== undefined ? stringValue(args) : "",
|
|
30571
31945
|
outputText: ""
|
|
30572
31946
|
};
|
|
30573
31947
|
}
|
|
@@ -30577,7 +31951,7 @@ function toolSignalFromPart(part) {
|
|
|
30577
31951
|
callId,
|
|
30578
31952
|
hasInput: input !== undefined,
|
|
30579
31953
|
hasOutput: false,
|
|
30580
|
-
inputText: input !== undefined ? stringValue(input) : "",
|
|
31954
|
+
inputText: withText && input !== undefined ? stringValue(input) : "",
|
|
30581
31955
|
outputText: ""
|
|
30582
31956
|
};
|
|
30583
31957
|
}
|
|
@@ -30588,7 +31962,7 @@ function toolSignalFromPart(part) {
|
|
|
30588
31962
|
hasInput: false,
|
|
30589
31963
|
hasOutput: content !== undefined,
|
|
30590
31964
|
inputText: "",
|
|
30591
|
-
outputText: content !== undefined ? textFromToolResultContent(content) : ""
|
|
31965
|
+
outputText: withText && content !== undefined ? textFromToolResultContent(content) : ""
|
|
30592
31966
|
};
|
|
30593
31967
|
}
|
|
30594
31968
|
return null;
|
|
@@ -30598,7 +31972,7 @@ function buildToolArcs(messages) {
|
|
|
30598
31972
|
const arcs = [];
|
|
30599
31973
|
for (const message of messages) {
|
|
30600
31974
|
for (const part of message.parts) {
|
|
30601
|
-
const signal = toolSignalFromPart(part);
|
|
31975
|
+
const signal = toolSignalFromPart(part, false);
|
|
30602
31976
|
if (!signal || signal.callId.length === 0)
|
|
30603
31977
|
continue;
|
|
30604
31978
|
if (signal.hasInput && signal.hasOutput) {
|
|
@@ -30637,6 +32011,7 @@ function buildToolArcs(messages) {
|
|
|
30637
32011
|
}
|
|
30638
32012
|
var MAX_MESSAGE_CACHE_KEY_BYTES, messageEstimateCache, messageEstimateKeysByField;
|
|
30639
32013
|
var init_read_session_true_raw_tokens = __esm(() => {
|
|
32014
|
+
init_provider_visible_parts();
|
|
30640
32015
|
init_read_session_formatting();
|
|
30641
32016
|
MAX_MESSAGE_CACHE_KEY_BYTES = 64 * 1024 * 1024;
|
|
30642
32017
|
messageEstimateCache = new Map;
|
|
@@ -30798,8 +32173,10 @@ __export(exports_read_session_chunk, {
|
|
|
30798
32173
|
hasMeaningfulUserText: () => hasMeaningfulUserText,
|
|
30799
32174
|
hasRawMessageProvider: () => hasRawMessageProvider,
|
|
30800
32175
|
hasRawSessionMessageById: () => hasRawSessionMessageById,
|
|
32176
|
+
prepareRawSessionOrdinals: () => prepareRawSessionOrdinals,
|
|
30801
32177
|
primeInMemoryTailRawMessageCache: () => primeInMemoryTailRawMessageCache,
|
|
30802
32178
|
primeTailRawMessageCache: () => primeTailRawMessageCache,
|
|
32179
|
+
readRawSessionBoundaryEndpoints: () => readRawSessionBoundaryEndpoints,
|
|
30803
32180
|
readRawSessionMessageById: () => readRawSessionMessageById,
|
|
30804
32181
|
readRawSessionMessageIdOrdinals: () => readRawSessionMessageIdOrdinals,
|
|
30805
32182
|
readRawSessionMessageIdOrdinalsForRange: () => readRawSessionMessageIdOrdinalsForRange,
|
|
@@ -31068,6 +32445,36 @@ function readRawSessionMessageRange(sessionId, fromOrdinal, toOrdinal) {
|
|
|
31068
32445
|
}
|
|
31069
32446
|
return messages;
|
|
31070
32447
|
}
|
|
32448
|
+
async function prepareRawSessionOrdinals(sessionId) {
|
|
32449
|
+
if (sessionProviders.get(sessionId)?.provider)
|
|
32450
|
+
return true;
|
|
32451
|
+
if (!openCodeDbExists())
|
|
32452
|
+
return true;
|
|
32453
|
+
const db = withReadOnlySessionDb((connection) => connection);
|
|
32454
|
+
let timer;
|
|
32455
|
+
const deadline = Date.now() + 250;
|
|
32456
|
+
const prepare = async () => {
|
|
32457
|
+
for (let attempt = 0;attempt < 3 && Date.now() < deadline; attempt++) {
|
|
32458
|
+
if (await prewarmRawSessionOrdinalsForDb(db, sessionId) === "warm")
|
|
32459
|
+
return true;
|
|
32460
|
+
}
|
|
32461
|
+
return false;
|
|
32462
|
+
};
|
|
32463
|
+
try {
|
|
32464
|
+
const ready = await Promise.race([
|
|
32465
|
+
prepare(),
|
|
32466
|
+
new Promise((resolve) => {
|
|
32467
|
+
timer = setTimeout(() => resolve(false), 250);
|
|
32468
|
+
})
|
|
32469
|
+
]);
|
|
32470
|
+
if (!ready) {
|
|
32471
|
+
sessionLog(sessionId, "WARN canonical ordinal preparation unavailable within 250ms; exact reads must defer or retry");
|
|
32472
|
+
}
|
|
32473
|
+
return ready;
|
|
32474
|
+
} finally {
|
|
32475
|
+
clearTimeout(timer);
|
|
32476
|
+
}
|
|
32477
|
+
}
|
|
31071
32478
|
function primeTailRawMessageCache(args) {
|
|
31072
32479
|
const { sessionId, lastCompartmentEnd, anchorMessageId } = args;
|
|
31073
32480
|
if (!activeRawMessageCache)
|
|
@@ -31182,6 +32589,13 @@ function readRawSessionMessagePartsById(sessionId, messageId, onQuery) {
|
|
|
31182
32589
|
return null;
|
|
31183
32590
|
return withReadOnlySessionDb((db) => readRawSessionMessagePartsByIdFromDb(db, sessionId, messageId, onQuery));
|
|
31184
32591
|
}
|
|
32592
|
+
function readRawSessionBoundaryEndpoints(sessionId, ids, blockIds) {
|
|
32593
|
+
if (sessionProviders.get(sessionId)?.provider)
|
|
32594
|
+
return null;
|
|
32595
|
+
if (!openCodeDbExists())
|
|
32596
|
+
return new Map(ids.map((id) => [id, null]));
|
|
32597
|
+
return withReadOnlySessionDb((db) => readRawSessionBoundaryEndpointsFromDb(db, sessionId, ids, blockIds));
|
|
32598
|
+
}
|
|
31185
32599
|
function hasRawSessionMessageById(sessionId, messageId) {
|
|
31186
32600
|
const provider = sessionProviders.get(sessionId)?.provider;
|
|
31187
32601
|
if (provider?.hasMessageById)
|
|
@@ -31702,22 +33116,28 @@ function readRawSessionSeedTail(sessionId, boundaryId, onQuery) {
|
|
|
31702
33116
|
}
|
|
31703
33117
|
var BLOCK_TOKEN_MEMO_MAX = 2048, blockTokenMemo, activeRawMessageCache = null, activeAbsoluteCountCache = null, sessionProviders, boundedProviderWrappers, SYSTEM_REMINDER_BLOCK_REGEX, RAW_MESSAGE_RANGE_PAGE_SIZE = 100, RAW_MESSAGE_VISIT_PAGE_SIZE = 50, RAW_SESSION_TAG_KEY_PAGE_SIZE = 32, PROTECTED_TAIL_USER_TURNS = 5;
|
|
31704
33118
|
var init_read_session_chunk = __esm(async () => {
|
|
31705
|
-
init_storage_tags();
|
|
31706
33119
|
init_historian_tool_expansions();
|
|
33120
|
+
init_logger();
|
|
31707
33121
|
init_read_session_formatting();
|
|
31708
|
-
init_read_session_raw();
|
|
31709
33122
|
init_read_session_true_raw_tokens();
|
|
31710
33123
|
init_system_injection_stripper();
|
|
31711
33124
|
init_tag_part_guards();
|
|
31712
33125
|
init_tool_drop_target();
|
|
31713
33126
|
init_read_session_formatting();
|
|
31714
|
-
await
|
|
33127
|
+
await __promiseAll([
|
|
33128
|
+
init_storage_tags(),
|
|
33129
|
+
init_raw_ordinal_warmup(),
|
|
33130
|
+
init_read_session_db(),
|
|
33131
|
+
init_read_session_raw()
|
|
33132
|
+
]);
|
|
31715
33133
|
blockTokenMemo = new Map;
|
|
31716
33134
|
sessionProviders = new Map;
|
|
31717
33135
|
boundedProviderWrappers = new WeakMap;
|
|
31718
33136
|
SYSTEM_REMINDER_BLOCK_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
31719
33137
|
readRawSessionMessages.readPage = readRawSessionMessagePage;
|
|
31720
33138
|
readRawSessionMessages.getCount = getRawSessionMessageOrdinalCount;
|
|
33139
|
+
readRawSessionMessages.prepare = prepareRawSessionOrdinals;
|
|
33140
|
+
readRawSessionMessageById.prepare = prepareRawSessionOrdinals;
|
|
31721
33141
|
});
|
|
31722
33142
|
|
|
31723
33143
|
// ../plugin/src/features/magic-context/message-time-backfill.ts
|
|
@@ -33578,6 +34998,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
33578
34998
|
const version = getPersistedSchemaVersion(db);
|
|
33579
34999
|
if (version === 0 || version >= 95)
|
|
33580
35000
|
installV95PerfSchema(db, false, version === 0);
|
|
35001
|
+
installTagIdentityRevisionTrigger(db);
|
|
33581
35002
|
}
|
|
33582
35003
|
function healWedgedChannel2Claims(db) {
|
|
33583
35004
|
try {
|
|
@@ -33657,6 +35078,7 @@ function openDatabase(dbPathOrOptions) {
|
|
|
33657
35078
|
} else
|
|
33658
35079
|
runMigrations(db);
|
|
33659
35080
|
ensureContextStoreUuid(db);
|
|
35081
|
+
installTagIdentityRevisionTrigger(db);
|
|
33660
35082
|
return finishDatabaseOpen(db, dbPath, explicitDbPath, latestSupportedVersion);
|
|
33661
35083
|
} catch (error) {
|
|
33662
35084
|
if (db)
|
|
@@ -33691,6 +35113,7 @@ var init_storage_db = __esm(async () => {
|
|
|
33691
35113
|
init_migration_v95_perf_indexes();
|
|
33692
35114
|
init_migration_worker_client();
|
|
33693
35115
|
init_storage_schema_helpers();
|
|
35116
|
+
init_storage_tag_identity_revision();
|
|
33694
35117
|
init_tool_definition_tokens();
|
|
33695
35118
|
init_tool_owner_backfill();
|
|
33696
35119
|
await __promiseAll([
|
|
@@ -33896,6 +35319,9 @@ var init_config_location_migration = __esm(() => {
|
|
|
33896
35319
|
});
|
|
33897
35320
|
|
|
33898
35321
|
// ../plugin/src/features/magic-context/dreamer/task-registry.ts
|
|
35322
|
+
function availableDreamTasks(smartNotesEnabled = true) {
|
|
35323
|
+
return CANONICAL_DREAM_TASKS.filter((task) => smartNotesEnabled || task !== "evaluate-smart-notes");
|
|
35324
|
+
}
|
|
33899
35325
|
var CANONICAL_DREAM_TASKS, DREAM_TOOL_LOOP_TOKEN_BUDGETS, MEMORY_DOMAIN_TASKS, MEMORY_DOMAIN_SET;
|
|
33900
35326
|
var init_task_registry = __esm(() => {
|
|
33901
35327
|
CANONICAL_DREAM_TASKS = [
|
|
@@ -34646,8 +36072,10 @@ function openCodeConfigFileChain(directory, hostGeneration) {
|
|
|
34646
36072
|
const globalSupplementary = getOpenCodeConfigDirs().filter((dir) => dir !== globalDir).flatMap((dir) => [join17(dir, "opencode.json"), join17(dir, "opencode.jsonc")]);
|
|
34647
36073
|
const explicitConfig = process.env.OPENCODE_CONFIG?.trim();
|
|
34648
36074
|
const explicit = explicitConfig ? [explicitConfig] : [];
|
|
34649
|
-
const
|
|
34650
|
-
const
|
|
36075
|
+
const disableProjectConfig = process.env.OPENCODE_DISABLE_PROJECT_CONFIG?.toLowerCase();
|
|
36076
|
+
const skipProject = hostGeneration === "v1" && (disableProjectConfig === "true" || disableProjectConfig === "1");
|
|
36077
|
+
const direct = skipProject ? [] : [join17(directory, "opencode.json"), join17(directory, "opencode.jsonc")];
|
|
36078
|
+
const projectSupplementary = skipProject ? [] : [
|
|
34651
36079
|
join17(directory, ".opencode", "opencode.json"),
|
|
34652
36080
|
join17(directory, ".opencode", "opencode.jsonc")
|
|
34653
36081
|
];
|
|
@@ -35877,6 +37305,24 @@ function readCachedPluginVersion(pluginCacheDir) {
|
|
|
35877
37305
|
return;
|
|
35878
37306
|
}
|
|
35879
37307
|
}
|
|
37308
|
+
function readOpenCodePluginConfigUse(config, configDir) {
|
|
37309
|
+
const use = {
|
|
37310
|
+
referencedSpecs: {
|
|
37311
|
+
opencode1: readReferencedOpenCodePluginSpecs(config, "opencode1"),
|
|
37312
|
+
opencode2: readReferencedOpenCodePluginSpecs(config, "opencode2")
|
|
37313
|
+
},
|
|
37314
|
+
loadedFrom: {}
|
|
37315
|
+
};
|
|
37316
|
+
for (const { key, entry } of readPluginEntries(config)) {
|
|
37317
|
+
if (!isDevPathPluginEntry(entry, configDir))
|
|
37318
|
+
continue;
|
|
37319
|
+
const specifier = pluginEntryPackage(entry) ?? undefined;
|
|
37320
|
+
if (key === "plugin")
|
|
37321
|
+
use.loadedFrom.opencode1 ??= specifier;
|
|
37322
|
+
use.loadedFrom.opencode2 ??= specifier;
|
|
37323
|
+
}
|
|
37324
|
+
return use;
|
|
37325
|
+
}
|
|
35880
37326
|
async function clearPluginCache(options = {}, deps = {}) {
|
|
35881
37327
|
const remove = deps.remove ?? ((path) => rmSync6(path, { recursive: true, force: true }));
|
|
35882
37328
|
const pluginCacheRoots = getOpenCodePluginCacheRoots();
|
|
@@ -35889,6 +37335,15 @@ async function clearPluginCache(options = {}, deps = {}) {
|
|
|
35889
37335
|
path,
|
|
35890
37336
|
cached: readCachedPluginVersion(path)
|
|
35891
37337
|
}));
|
|
37338
|
+
if (options.referencedSpecs !== undefined && !options.referencedSpecs.has("latest")) {
|
|
37339
|
+
const firstEntry = cacheEntries[0];
|
|
37340
|
+
return {
|
|
37341
|
+
action: "unused",
|
|
37342
|
+
path: firstEntry?.path ?? pluginCacheRoots[0] ?? "",
|
|
37343
|
+
paths: cacheEntries.map((entry) => entry.path),
|
|
37344
|
+
cached: firstEntry?.cached
|
|
37345
|
+
};
|
|
37346
|
+
}
|
|
35892
37347
|
if (options.force !== true && latestVersion === undefined) {
|
|
35893
37348
|
const firstEntry = cacheEntries[0];
|
|
35894
37349
|
return {
|
|
@@ -35960,15 +37415,24 @@ async function clearPluginCache(options = {}, deps = {}) {
|
|
|
35960
37415
|
}
|
|
35961
37416
|
var init_doctor_opencode_cache = __esm(async () => {
|
|
35962
37417
|
init_opencode_plugin_cache();
|
|
35963
|
-
|
|
37418
|
+
init_opencode_plugin_registration();
|
|
37419
|
+
await __promiseAll([
|
|
37420
|
+
init_opencode(),
|
|
37421
|
+
init_doctor_opencode2_cache()
|
|
37422
|
+
]);
|
|
35964
37423
|
});
|
|
35965
37424
|
|
|
35966
37425
|
// src/commands/doctor-cached-plugin-fence.ts
|
|
35967
37426
|
import { existsSync as existsSync29 } from "node:fs";
|
|
35968
37427
|
import { dirname as dirname15 } from "node:path";
|
|
37428
|
+
function isReferenced(sources, host, spec) {
|
|
37429
|
+
const specs = sources.referencedSpecs?.[host];
|
|
37430
|
+
return specs === undefined || specs.has(spec);
|
|
37431
|
+
}
|
|
35969
37432
|
function listCachedOpenCodePluginFences(sources = {}) {
|
|
35970
37433
|
const fences = [];
|
|
35971
|
-
|
|
37434
|
+
const v1Referenced = isReferenced(sources, "opencode1", "latest");
|
|
37435
|
+
for (const root of v1Referenced ? sources.openCodeV1Roots ?? getOpenCodePluginCacheRoots() : []) {
|
|
35972
37436
|
const packageJson = getOpenCodePluginPackageJsonPath(root);
|
|
35973
37437
|
if (!existsSync29(packageJson))
|
|
35974
37438
|
continue;
|
|
@@ -35982,6 +37446,8 @@ function listCachedOpenCodePluginFences(sources = {}) {
|
|
|
35982
37446
|
for (const slot of listOpenCodeV2PluginCacheSlots(sources.openCodeV2NpmCacheDir)) {
|
|
35983
37447
|
if (!isOpenCodePluginDistTag(slot.spec))
|
|
35984
37448
|
continue;
|
|
37449
|
+
if (!isReferenced(sources, "opencode2", slot.spec))
|
|
37450
|
+
continue;
|
|
35985
37451
|
const generation = getOpenCodeV2ActiveGeneration(slot.slot);
|
|
35986
37452
|
if (!generation)
|
|
35987
37453
|
continue;
|
|
@@ -41170,11 +42636,6 @@ var init_user_facing_codes = __esm(() => {
|
|
|
41170
42636
|
sentence: "Magic Context has no context.db.",
|
|
41171
42637
|
action: "Run `npx @cortexkit/magic-context doctor store init`, then restart ck-mc."
|
|
41172
42638
|
},
|
|
41173
|
-
checkout_claim_held_elsewhere: {
|
|
41174
|
-
code: "MC-C16",
|
|
41175
|
-
sentence: "This request was not sent: this agent is checked out on another machine, so Magic Context will not work on its sessions here.",
|
|
41176
|
-
action: "Move the agent back to this machine, then send your message again."
|
|
41177
|
-
},
|
|
41178
42639
|
single_store_migration_required: {
|
|
41179
42640
|
code: "MC-C14",
|
|
41180
42641
|
sentence: "Magic Context's Rust mode needs a one-time migration of its store.",
|
|
@@ -42765,7 +44226,9 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
42765
44226
|
delete configToMigrate.protected_tags;
|
|
42766
44227
|
}
|
|
42767
44228
|
const agentMigrated = migrateLegacyAgentEnabledInMemory(configToMigrate, preMigrationWarnings);
|
|
42768
|
-
const
|
|
44229
|
+
const migratedExperimental = migrateLegacyExperimental(agentMigrated, preMigrationWarnings);
|
|
44230
|
+
warnDeprecatedMuralModel(migratedExperimental, preMigrationWarnings);
|
|
44231
|
+
const migrated = migrateDreamerV2(migratedExperimental, preMigrationWarnings);
|
|
42769
44232
|
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
42770
44233
|
if (parsed.success) {
|
|
42771
44234
|
return { config: parsed.data, warnings: preMigrationWarnings };
|
|
@@ -43607,64 +45070,66 @@ async function runHealthChecks(options) {
|
|
|
43607
45070
|
add(results, "fail", "OMP binary not found on PATH or in standard user bin directories");
|
|
43608
45071
|
} else {
|
|
43609
45072
|
const version = options.deps.getOmpVersion(omp.path);
|
|
43610
|
-
if (!version)
|
|
43611
|
-
add(results, "fail", `OMP at ${omp.path} could not report its version`);
|
|
43612
|
-
else if (isOlderThan(version, MIN_OMP_VERSION)) {
|
|
43613
|
-
add(results, "fail", `OMP ${version} is older than tested minimum ${MIN_OMP_VERSION}`);
|
|
43614
|
-
} else
|
|
43615
|
-
add(results, "pass", `OMP ${version} detected at ${omp.path}`);
|
|
43616
45073
|
const plugins = options.deps.listOmpPlugins(omp.path);
|
|
43617
45074
|
if (!plugins) {
|
|
43618
45075
|
add(results, "fail", "`omp plugin list --json` failed or returned invalid JSON");
|
|
43619
45076
|
} else {
|
|
43620
45077
|
const plugin = plugins.find((entry) => entry.name === OMP_PLUGIN_PACKAGE);
|
|
43621
45078
|
if (!plugin) {
|
|
43622
|
-
add(results, "
|
|
43623
|
-
repairPlan.installPlugin = true;
|
|
43624
|
-
} else if (!plugin.enabled) {
|
|
43625
|
-
add(results, "fail", `${OMP_PLUGIN_PACKAGE} is installed but disabled in OMP`);
|
|
45079
|
+
add(results, "info", `${version ? `Oh My Pi ${version}` : "Oh My Pi"} found; Magic Context is not installed there (run setup to add it)`);
|
|
43626
45080
|
repairPlan.installPlugin = true;
|
|
43627
45081
|
} else {
|
|
43628
|
-
|
|
43629
|
-
|
|
43630
|
-
if (
|
|
43631
|
-
add(results, "
|
|
43632
|
-
else
|
|
43633
|
-
add(results, "
|
|
43634
|
-
|
|
43635
|
-
add(results, "
|
|
43636
|
-
|
|
43637
|
-
|
|
43638
|
-
|
|
43639
|
-
|
|
43640
|
-
|
|
43641
|
-
|
|
43642
|
-
|
|
43643
|
-
|
|
43644
|
-
|
|
43645
|
-
|
|
43646
|
-
|
|
43647
|
-
|
|
43648
|
-
|
|
43649
|
-
|
|
43650
|
-
|
|
43651
|
-
|
|
43652
|
-
|
|
43653
|
-
|
|
43654
|
-
|
|
43655
|
-
|
|
43656
|
-
|
|
43657
|
-
|
|
43658
|
-
|
|
43659
|
-
|
|
43660
|
-
|
|
43661
|
-
|
|
43662
|
-
|
|
43663
|
-
|
|
43664
|
-
|
|
43665
|
-
|
|
43666
|
-
|
|
43667
|
-
|
|
45082
|
+
if (!version) {
|
|
45083
|
+
add(results, "fail", `OMP at ${omp.path} could not report its version`);
|
|
45084
|
+
} else if (isOlderThan(version, MIN_OMP_VERSION)) {
|
|
45085
|
+
add(results, "fail", `OMP ${version} is older than tested minimum ${MIN_OMP_VERSION}`);
|
|
45086
|
+
} else
|
|
45087
|
+
add(results, "pass", `OMP ${version} detected at ${omp.path}`);
|
|
45088
|
+
if (!plugin.enabled) {
|
|
45089
|
+
add(results, "fail", `${OMP_PLUGIN_PACKAGE} is installed but disabled in OMP`);
|
|
45090
|
+
repairPlan.installPlugin = true;
|
|
45091
|
+
} else {
|
|
45092
|
+
add(results, "pass", `${OMP_PLUGIN_PACKAGE} ${plugin.version} is enabled`);
|
|
45093
|
+
const manifest = pluginDeclaresOmp(plugin.path);
|
|
45094
|
+
if (manifest === true)
|
|
45095
|
+
add(results, "pass", "Plugin exposes an OMP/Pi extension manifest");
|
|
45096
|
+
else if (manifest === false)
|
|
45097
|
+
add(results, "fail", "Installed plugin has no OMP/Pi extension manifest");
|
|
45098
|
+
else
|
|
45099
|
+
add(results, "warn", "Could not inspect the installed plugin manifest");
|
|
45100
|
+
}
|
|
45101
|
+
const compaction = options.deps.getOmpSetting(omp.path, "compaction.enabled");
|
|
45102
|
+
if (compaction === false)
|
|
45103
|
+
add(results, "pass", "OMP native compaction is disabled");
|
|
45104
|
+
else if (compaction === true) {
|
|
45105
|
+
add(results, "fail", "OMP native compaction is enabled and conflicts with Magic Context");
|
|
45106
|
+
repairPlan.disableCompaction = true;
|
|
45107
|
+
} else
|
|
45108
|
+
add(results, "fail", "Could not read OMP compaction.enabled");
|
|
45109
|
+
const memory = options.deps.getOmpSetting(omp.path, "memory.backend");
|
|
45110
|
+
if (memory === "off")
|
|
45111
|
+
add(results, "pass", "OMP automatic memory backend is disabled");
|
|
45112
|
+
else if (typeof memory === "string") {
|
|
45113
|
+
add(results, "fail", `OMP memory.backend=${memory} duplicates Magic Context memory injection`);
|
|
45114
|
+
repairPlan.disableMemory = true;
|
|
45115
|
+
} else
|
|
45116
|
+
add(results, "fail", "Could not read OMP memory.backend");
|
|
45117
|
+
const nonGlobalSources = getOmpNonGlobalConfigSources(options.cwd);
|
|
45118
|
+
if (nonGlobalSources.length > 0 && (repairPlan.disableCompaction || repairPlan.disableMemory)) {
|
|
45119
|
+
add(results, "warn", "OMP project/overlay config owns effective conflicting settings; automatic global repair is disabled: " + nonGlobalSources.join(", "));
|
|
45120
|
+
}
|
|
45121
|
+
const reportedAgentDir = options.deps.runOmpCommand(omp.path, ["config", "path"], 1e4);
|
|
45122
|
+
if (!reportedAgentDir.ok) {
|
|
45123
|
+
add(results, "warn", "Could not verify OMP active agent directory");
|
|
45124
|
+
} else {
|
|
45125
|
+
const reportedPath = resolve15(reportedAgentDir.stdout);
|
|
45126
|
+
const expectedPath = resolve15(getOmpAgentDir());
|
|
45127
|
+
if (reportedPath === expectedPath) {
|
|
45128
|
+
add(results, "pass", `OMP agent directory resolved to ${getOmpAgentDir()}`);
|
|
45129
|
+
} else {
|
|
45130
|
+
add(results, "fail", `OMP reports agent directory ${reportedAgentDir.stdout}, but Magic Context resolved ${getOmpAgentDir()}`);
|
|
45131
|
+
}
|
|
45132
|
+
}
|
|
43668
45133
|
}
|
|
43669
45134
|
}
|
|
43670
45135
|
}
|
|
@@ -46665,6 +48130,16 @@ function listDanglingCompartmentBoundaries(contextDb, openCodeDb, hostGeneration
|
|
|
46665
48130
|
ORDER BY c.session_id ASC, c.sequence ASC`).all();
|
|
46666
48131
|
const statement = openCodeDb.prepare(`SELECT 1 AS found FROM ${selection.table} WHERE session_id = ? AND id = ? LIMIT 1`);
|
|
46667
48132
|
const exists = (sessionId, messageId) => statement.get(sessionId, messageId) != null;
|
|
48133
|
+
const sessionStatement = openCodeDb.prepare(`SELECT 1 AS found FROM ${selection.table} WHERE session_id = ? LIMIT 1`);
|
|
48134
|
+
const sessionPresence = new Map;
|
|
48135
|
+
const sessionInStore = (sessionId) => {
|
|
48136
|
+
let present = sessionPresence.get(sessionId);
|
|
48137
|
+
if (present === undefined) {
|
|
48138
|
+
present = sessionStatement.get(sessionId) != null;
|
|
48139
|
+
sessionPresence.set(sessionId, present);
|
|
48140
|
+
}
|
|
48141
|
+
return present;
|
|
48142
|
+
};
|
|
46668
48143
|
return rows.flatMap((row) => {
|
|
46669
48144
|
const missingStart = !exists(row.session_id, row.start_message_id);
|
|
46670
48145
|
const missingEnd = !exists(row.session_id, row.end_message_id);
|
|
@@ -46675,7 +48150,8 @@ function listDanglingCompartmentBoundaries(contextDb, openCodeDb, hostGeneration
|
|
|
46675
48150
|
sessionId: row.session_id,
|
|
46676
48151
|
sequence: row.sequence,
|
|
46677
48152
|
missingStartMessageId: missingStart ? row.start_message_id : null,
|
|
46678
|
-
missingEndMessageId: missingEnd ? row.end_message_id : null
|
|
48153
|
+
missingEndMessageId: missingEnd ? row.end_message_id : null,
|
|
48154
|
+
sessionInStore: sessionInStore(row.session_id)
|
|
46679
48155
|
}
|
|
46680
48156
|
];
|
|
46681
48157
|
});
|
|
@@ -46687,6 +48163,52 @@ function formatDanglingCompartmentBoundary(boundary) {
|
|
|
46687
48163
|
].filter((value) => value !== null);
|
|
46688
48164
|
return `session=${boundary.sessionId} sequence=${boundary.sequence} missing ${missing.join(" ")}`;
|
|
46689
48165
|
}
|
|
48166
|
+
function countDanglingCompartmentBoundariesBySession(boundaries) {
|
|
48167
|
+
const bySession = new Map;
|
|
48168
|
+
for (const boundary of boundaries) {
|
|
48169
|
+
const entry = bySession.get(boundary.sessionId);
|
|
48170
|
+
if (entry)
|
|
48171
|
+
entry.count++;
|
|
48172
|
+
else
|
|
48173
|
+
bySession.set(boundary.sessionId, {
|
|
48174
|
+
sessionId: boundary.sessionId,
|
|
48175
|
+
count: 1,
|
|
48176
|
+
sessionInStore: boundary.sessionInStore
|
|
48177
|
+
});
|
|
48178
|
+
}
|
|
48179
|
+
return [...bySession.values()].sort((a, b) => b.count - a.count || a.sessionId.localeCompare(b.sessionId));
|
|
48180
|
+
}
|
|
48181
|
+
function formatDanglingCompartmentBoundaryHeadline(boundaries, store) {
|
|
48182
|
+
const sessions = countDanglingCompartmentBoundariesBySession(boundaries);
|
|
48183
|
+
const absent = sessions.filter((session) => !session.sessionInStore).length;
|
|
48184
|
+
const scope = `${boundaries.length} compartment(s) in ${sessions.length} session(s)`;
|
|
48185
|
+
const absentNote = absent > 0 ? ` ${absent} of those session(s) have no messages in this store at all, so OpenCode cannot open them from it and their compartments are not used.` : "";
|
|
48186
|
+
if (store === "opencode2") {
|
|
48187
|
+
return `Informational, no action needed: ${scope} point at OpenCode message ids that are not in the OpenCode 2 store.${absentNote} Magic Context places these from the neighbouring compartments; any it cannot place are listed as excluded from range recovery below.`;
|
|
48188
|
+
}
|
|
48189
|
+
return `${scope} have dangling OpenCode boundary ids.${absentNote}`;
|
|
48190
|
+
}
|
|
48191
|
+
function formatDanglingCompartmentBoundaryDetails(boundaries, options = {}) {
|
|
48192
|
+
const limit = options.verbose ? Number.POSITIVE_INFINITY : options.limit ?? DANGLING_BOUNDARY_EXAMPLE_LIMIT;
|
|
48193
|
+
const sessions = countDanglingCompartmentBoundariesBySession(boundaries);
|
|
48194
|
+
const lines = [];
|
|
48195
|
+
lines.push(options.verbose || sessions.length <= limit ? "By session:" : `By session (largest ${limit} of ${sessions.length}):`);
|
|
48196
|
+
for (const session of sessions.slice(0, limit)) {
|
|
48197
|
+
lines.push(` session=${session.sessionId}: ${session.count} compartment(s)${session.sessionInStore ? "" : " (session has no messages in this store)"}`);
|
|
48198
|
+
}
|
|
48199
|
+
if (sessions.length > limit) {
|
|
48200
|
+
lines.push(` … and ${sessions.length - limit} more session(s)`);
|
|
48201
|
+
}
|
|
48202
|
+
lines.push(options.verbose || boundaries.length <= limit ? "Compartments:" : `Examples (${limit} of ${boundaries.length}):`);
|
|
48203
|
+
for (const boundary of boundaries.slice(0, limit)) {
|
|
48204
|
+
lines.push(` ${formatDanglingCompartmentBoundary(boundary)}`);
|
|
48205
|
+
}
|
|
48206
|
+
if (sessions.length > limit || boundaries.length > limit) {
|
|
48207
|
+
lines.push(`Run \`magic-context doctor --verbose\` for the full list of ${boundaries.length} compartment(s).`);
|
|
48208
|
+
}
|
|
48209
|
+
return lines;
|
|
48210
|
+
}
|
|
48211
|
+
var DANGLING_BOUNDARY_EXAMPLE_LIMIT = 10;
|
|
46690
48212
|
|
|
46691
48213
|
// src/commands/doctor-harness-relabel.ts
|
|
46692
48214
|
function reportUnresolvedHarnessRelabel(args) {
|
|
@@ -46840,6 +48362,9 @@ function withPluginEntrySpecifier(entry, specifier) {
|
|
|
46840
48362
|
}
|
|
46841
48363
|
return specifier;
|
|
46842
48364
|
}
|
|
48365
|
+
function isOpenCodePluginRegistered(config, configDir) {
|
|
48366
|
+
return readPluginEntries(config).some(({ entry }) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry, configDir));
|
|
48367
|
+
}
|
|
46843
48368
|
function checkOpenCodePluginEntry(config, configName, options, report) {
|
|
46844
48369
|
const allEntries = readPluginEntries(config);
|
|
46845
48370
|
const found = allEntries.find(({ entry }) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry, options.configDir));
|
|
@@ -47497,6 +49022,21 @@ function logOpenCodeInstallationTable(installations) {
|
|
|
47497
49022
|
function describeOpenCode2SessionAPIRequirement(hostVersion) {
|
|
47498
49023
|
return `OpenCode host ${hostVersion}; Magic Context requires OpenCode 2.0.22 or newer with session.remove and session.compact.`;
|
|
47499
49024
|
}
|
|
49025
|
+
function getOpenCodePluginHostStatus(hostLabel, hostVersion, installed) {
|
|
49026
|
+
if (!installed) {
|
|
49027
|
+
return {
|
|
49028
|
+
status: "info",
|
|
49029
|
+
message: `${hostLabel} found; Magic Context is not installed there (run setup to add it)`
|
|
49030
|
+
};
|
|
49031
|
+
}
|
|
49032
|
+
if (openCodeHostGenerationFromVersion(hostVersion) === "v2" && compareVersions(hostVersion, "2.0.22") === -1) {
|
|
49033
|
+
return {
|
|
49034
|
+
status: "fail",
|
|
49035
|
+
message: describeOpenCode2SessionAPIRequirement(hostVersion)
|
|
49036
|
+
};
|
|
49037
|
+
}
|
|
49038
|
+
return null;
|
|
49039
|
+
}
|
|
47500
49040
|
async function runDoctor2(options = {}) {
|
|
47501
49041
|
migrateConfigLocationsForCli(process.cwd(), log3);
|
|
47502
49042
|
if (options.issue) {
|
|
@@ -47572,8 +49112,15 @@ async function runDoctor2(options = {}) {
|
|
|
47572
49112
|
pass(installationReports.length > 1 ? `OpenCode ${activeInstallation.version} installed (active install marked above)` : `OpenCode ${activeInstallation.version} installed`);
|
|
47573
49113
|
}
|
|
47574
49114
|
const hostGeneration = openCodeHostGenerationFromVersion(activeInstallation.version);
|
|
47575
|
-
|
|
47576
|
-
|
|
49115
|
+
const paths = detectConfigPaths();
|
|
49116
|
+
let magicContextInstalled = false;
|
|
49117
|
+
let magicContextStatusKnown = paths.opencodeConfigFormat === "none";
|
|
49118
|
+
if (!magicContextStatusKnown) {
|
|
49119
|
+
try {
|
|
49120
|
+
const config = import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8"));
|
|
49121
|
+
magicContextInstalled = isOpenCodePluginRegistered(config, dirname25(paths.opencodeConfig));
|
|
49122
|
+
magicContextStatusKnown = true;
|
|
49123
|
+
} catch {}
|
|
47577
49124
|
}
|
|
47578
49125
|
const storeHostSelection = selectOpenCodeStoreHost(installationReports, openCodeHostGenerationFromVersion);
|
|
47579
49126
|
const storeHost = storeHostSelection?.host ?? activeInstallation;
|
|
@@ -47591,7 +49138,9 @@ async function runDoctor2(options = {}) {
|
|
|
47591
49138
|
const openCodeDbCheck = describeOpenCodeDatabaseDoctorCheck(openCodeDbResolution);
|
|
47592
49139
|
if (openCodeDbCheck.ok)
|
|
47593
49140
|
pass(openCodeDbCheck.message);
|
|
47594
|
-
else
|
|
49141
|
+
else if (magicContextStatusKnown && !magicContextInstalled) {
|
|
49142
|
+
log3.info("OpenCode session database not yet created (will be created on first OpenCode session)");
|
|
49143
|
+
} else
|
|
47595
49144
|
fail(openCodeDbCheck.message);
|
|
47596
49145
|
if (openCodeDbCheck.ok) {
|
|
47597
49146
|
let markerDb = null;
|
|
@@ -47612,7 +49161,7 @@ async function runDoctor2(options = {}) {
|
|
|
47612
49161
|
} else if (options.fix) {
|
|
47613
49162
|
warn(`${summary}; repaired=${report.repaired}, but some rows remain unconvertible`);
|
|
47614
49163
|
} else if (report.migrationCompleted) {
|
|
47615
|
-
log3.info(`${summary}; OpenCode 2 already converted this store`);
|
|
49164
|
+
log3.info(`${summary}; OpenCode 2 already converted this store, so these markers no longer matter (informational, no action needed)`);
|
|
47616
49165
|
} else {
|
|
47617
49166
|
warn(`${summary}; run \`magic-context doctor --fix\` before upgrading OpenCode`);
|
|
47618
49167
|
}
|
|
@@ -47640,14 +49189,18 @@ async function runDoctor2(options = {}) {
|
|
|
47640
49189
|
if (dangling.length === 0) {
|
|
47641
49190
|
pass("Compartment boundary ids resolve in the OpenCode session store");
|
|
47642
49191
|
} else if (storeGeneration === "v2" && /\d/.test(storeHost.version)) {
|
|
47643
|
-
log3.info(
|
|
47644
|
-
for (const
|
|
47645
|
-
|
|
49192
|
+
log3.info(formatDanglingCompartmentBoundaryHeadline(dangling, "opencode2"));
|
|
49193
|
+
for (const line of formatDanglingCompartmentBoundaryDetails(dangling, {
|
|
49194
|
+
verbose: options.verbose
|
|
49195
|
+
})) {
|
|
49196
|
+
log3.info(` ${line}`);
|
|
47646
49197
|
}
|
|
47647
49198
|
} else {
|
|
47648
|
-
warn(
|
|
47649
|
-
for (const
|
|
47650
|
-
|
|
49199
|
+
warn(formatDanglingCompartmentBoundaryHeadline(dangling, "other"));
|
|
49200
|
+
for (const line of formatDanglingCompartmentBoundaryDetails(dangling, {
|
|
49201
|
+
verbose: options.verbose
|
|
49202
|
+
})) {
|
|
49203
|
+
log3.warn(` ${line}`);
|
|
47651
49204
|
}
|
|
47652
49205
|
}
|
|
47653
49206
|
if (!supportsCoordinateGenerationReporting(contextDb)) {
|
|
@@ -47683,10 +49236,7 @@ async function runDoctor2(options = {}) {
|
|
|
47683
49236
|
}
|
|
47684
49237
|
}
|
|
47685
49238
|
const selfVersion = getSelfVersion2();
|
|
47686
|
-
const
|
|
47687
|
-
fetchNpmLatest(CLI_PACKAGE_NAME),
|
|
47688
|
-
fetchNpmLatest(OPENCODE_PLUGIN_NAME)
|
|
47689
|
-
]);
|
|
49239
|
+
const npmLatest = await fetchNpmLatest(CLI_PACKAGE_NAME);
|
|
47690
49240
|
const cliComparison = npmLatest ? compareVersions(selfVersion, npmLatest) : null;
|
|
47691
49241
|
if (!npmLatest) {
|
|
47692
49242
|
log3.info(`Magic Context CLI v${selfVersion}; npm latest check unavailable`);
|
|
@@ -47697,9 +49247,8 @@ async function runDoctor2(options = {}) {
|
|
|
47697
49247
|
} else {
|
|
47698
49248
|
pass(`Magic Context CLI v${selfVersion} is current (npm latest v${npmLatest})`);
|
|
47699
49249
|
}
|
|
47700
|
-
const paths = detectConfigPaths();
|
|
47701
49250
|
if (paths.opencodeConfigFormat === "none") {
|
|
47702
|
-
|
|
49251
|
+
magicContextStatusKnown = true;
|
|
47703
49252
|
} else {
|
|
47704
49253
|
pass(`OpenCode config: ${paths.opencodeConfig}`);
|
|
47705
49254
|
}
|
|
@@ -47869,6 +49418,7 @@ async function runDoctor2(options = {}) {
|
|
|
47869
49418
|
log3.warn("Could not migrate deprecated config keys in magic-context.jsonc");
|
|
47870
49419
|
}
|
|
47871
49420
|
}
|
|
49421
|
+
const openCodeHostLabel = activeInstallation.kind === "desktop" ? "OpenCode Desktop" : activeInstallation.version === "unknown" ? "OpenCode" : `OpenCode ${activeInstallation.version}`;
|
|
47872
49422
|
const reportedAutoUpdateStalls = new Set;
|
|
47873
49423
|
const reportAutoUpdateStall = (specifier) => {
|
|
47874
49424
|
const message = describeAutoUpdateStall(specifier, autoUpdateEnabled);
|
|
@@ -47883,71 +49433,90 @@ async function runDoctor2(options = {}) {
|
|
|
47883
49433
|
const config = import_comment_json11.parse(raw);
|
|
47884
49434
|
const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
|
|
47885
49435
|
const configDir = dirname25(paths.opencodeConfig);
|
|
47886
|
-
|
|
47887
|
-
|
|
47888
|
-
|
|
47889
|
-
|
|
47890
|
-
|
|
47891
|
-
|
|
47892
|
-
|
|
47893
|
-
|
|
47894
|
-
|
|
49436
|
+
magicContextInstalled = isOpenCodePluginRegistered(config, configDir);
|
|
49437
|
+
magicContextStatusKnown = true;
|
|
49438
|
+
if (magicContextInstalled) {
|
|
49439
|
+
if (checkPluginDuplicates(config, configName, { fix: options.fix, configDir }, {
|
|
49440
|
+
warn,
|
|
49441
|
+
pass: (message) => {
|
|
49442
|
+
pass(message);
|
|
49443
|
+
fixed++;
|
|
49444
|
+
},
|
|
49445
|
+
info: (message) => log3.info(message)
|
|
49446
|
+
})) {
|
|
49447
|
+
writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config, null, 2)}
|
|
47895
49448
|
`);
|
|
47896
|
-
|
|
47897
|
-
|
|
47898
|
-
|
|
47899
|
-
|
|
47900
|
-
|
|
47901
|
-
|
|
47902
|
-
|
|
47903
|
-
|
|
47904
|
-
|
|
47905
|
-
|
|
47906
|
-
|
|
47907
|
-
|
|
47908
|
-
|
|
47909
|
-
|
|
47910
|
-
|
|
47911
|
-
|
|
47912
|
-
|
|
47913
|
-
|
|
47914
|
-
|
|
49449
|
+
}
|
|
49450
|
+
const allEntries = readPluginEntries(config);
|
|
49451
|
+
if (allEntries.some(({ entry }) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry, configDir))) {
|
|
49452
|
+
warn("An unverifiable local OpenCode plugin path was ignored because its package name is not Magic Context");
|
|
49453
|
+
}
|
|
49454
|
+
if (checkOpenCodePluginEntry(config, configName, {
|
|
49455
|
+
force: options.force,
|
|
49456
|
+
registrationKey: pluginConfigKeyFor(hostGeneration),
|
|
49457
|
+
configDir
|
|
49458
|
+
}, {
|
|
49459
|
+
pass,
|
|
49460
|
+
warn,
|
|
49461
|
+
fixed: (message) => {
|
|
49462
|
+
pass(message);
|
|
49463
|
+
fixed++;
|
|
49464
|
+
},
|
|
49465
|
+
autoUpdateStall: reportAutoUpdateStall
|
|
49466
|
+
})) {
|
|
49467
|
+
writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config, null, 2)}
|
|
47915
49468
|
`);
|
|
49469
|
+
}
|
|
47916
49470
|
}
|
|
47917
49471
|
} catch {
|
|
47918
49472
|
warn("Could not parse opencode config to verify plugin entry");
|
|
47919
49473
|
}
|
|
47920
|
-
}
|
|
47921
|
-
const cwd = process.cwd();
|
|
47922
|
-
const compactionEnabled = resolveCompactionEnabledForDoctor();
|
|
47923
|
-
const conflictResult = detectConflicts(cwd, { compactionEnabled });
|
|
47924
|
-
log3.info("Compaction check: file-based; the running server's resolved config may differ — `opencode debug config` is authoritative");
|
|
47925
|
-
if (conflictResult.hasConflict) {
|
|
47926
|
-
for (const reason of conflictResult.reasons) {
|
|
47927
|
-
fail(`Conflict: ${reason}`);
|
|
47928
|
-
}
|
|
47929
|
-
const actions = fixConflicts(cwd, conflictResult.conflicts, { compactionEnabled });
|
|
47930
|
-
for (const action of actions) {
|
|
47931
|
-
pass(`Fixed: ${action}`);
|
|
47932
|
-
fixed++;
|
|
47933
|
-
}
|
|
47934
|
-
if (actions.length > 0) {
|
|
47935
|
-
warn("Restart OpenCode for conflict fixes to take effect");
|
|
47936
|
-
}
|
|
47937
49474
|
} else {
|
|
47938
|
-
|
|
47939
|
-
|
|
47940
|
-
|
|
47941
|
-
|
|
47942
|
-
|
|
49475
|
+
magicContextStatusKnown = true;
|
|
49476
|
+
}
|
|
49477
|
+
if (!magicContextStatusKnown)
|
|
49478
|
+
magicContextInstalled = true;
|
|
49479
|
+
const hostPluginStatus = magicContextStatusKnown ? getOpenCodePluginHostStatus(openCodeHostLabel, activeInstallation.version, magicContextInstalled) : null;
|
|
49480
|
+
if (hostPluginStatus?.status === "info")
|
|
49481
|
+
log3.info(hostPluginStatus.message);
|
|
49482
|
+
else if (hostPluginStatus?.status === "fail")
|
|
49483
|
+
fail(hostPluginStatus.message);
|
|
49484
|
+
else if (magicContextInstalled && hostGeneration === "v2") {
|
|
49485
|
+
log3.info(describeOpenCode2SessionAPIRequirement(activeInstallation.version));
|
|
49486
|
+
}
|
|
49487
|
+
const pluginNpmLatest = magicContextInstalled ? await fetchNpmLatest(OPENCODE_PLUGIN_NAME) : null;
|
|
49488
|
+
if (magicContextInstalled) {
|
|
49489
|
+
const cwd = process.cwd();
|
|
49490
|
+
const compactionEnabled = resolveCompactionEnabledForDoctor();
|
|
49491
|
+
const conflictResult = detectConflicts(cwd, { compactionEnabled });
|
|
49492
|
+
log3.info("Compaction check: file-based; the running server's resolved config may differ — `opencode debug config` is authoritative");
|
|
49493
|
+
if (conflictResult.hasConflict) {
|
|
49494
|
+
for (const reason of conflictResult.reasons) {
|
|
49495
|
+
fail(`Conflict: ${reason}`);
|
|
49496
|
+
}
|
|
49497
|
+
const actions = fixConflicts(cwd, conflictResult.conflicts, { compactionEnabled });
|
|
49498
|
+
for (const action of actions) {
|
|
49499
|
+
pass(`Fixed: ${action}`);
|
|
49500
|
+
fixed++;
|
|
49501
|
+
}
|
|
49502
|
+
if (actions.length > 0) {
|
|
49503
|
+
warn("Restart OpenCode for conflict fixes to take effect");
|
|
47943
49504
|
}
|
|
47944
49505
|
} else {
|
|
47945
|
-
|
|
49506
|
+
if (!compactionEnabled) {
|
|
49507
|
+
if (conflictResult.nativeCompaction.auto || conflictResult.nativeCompaction.prune) {
|
|
49508
|
+
pass("No conflicts detected (compaction, DCP, OMO hooks) — native compaction active (compaction-off mode)");
|
|
49509
|
+
} else {
|
|
49510
|
+
warn("No compaction manager is active: Magic Context compaction is off and OpenCode auto-compaction is disabled");
|
|
49511
|
+
}
|
|
49512
|
+
} else {
|
|
49513
|
+
pass("No conflicts detected (compaction, DCP, OMO hooks)");
|
|
49514
|
+
}
|
|
47946
49515
|
}
|
|
47947
49516
|
}
|
|
47948
|
-
if (hostGeneration === "v2") {
|
|
49517
|
+
if (magicContextInstalled && hostGeneration === "v2") {
|
|
47949
49518
|
pass("TUI sidebar loads from the plugin entry on OpenCode 2 (tui.json not used)");
|
|
47950
|
-
} else {
|
|
49519
|
+
} else if (magicContextInstalled) {
|
|
47951
49520
|
const tuiAdded = ensureTuiPluginEntry();
|
|
47952
49521
|
if (tuiAdded) {
|
|
47953
49522
|
pass("Added TUI sidebar plugin to tui.json");
|
|
@@ -48097,65 +49666,88 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
48097
49666
|
warn(`RPC discovery check unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
48098
49667
|
issues++;
|
|
48099
49668
|
}
|
|
48100
|
-
|
|
48101
|
-
|
|
48102
|
-
|
|
48103
|
-
|
|
48104
|
-
|
|
48105
|
-
|
|
48106
|
-
const versionInfo = cacheResult.cached ? ` (cached: ${cacheResult.cached}${cacheResult.latest ? `, latest: ${cacheResult.latest}` : ""})` : "";
|
|
48107
|
-
const reason = cacheResult.latest ? "outdated plugin cache" : "plugin cache (latest version check unavailable)";
|
|
48108
|
-
pass(`Cleared ${reason}${versionInfo} — latest will download on restart`);
|
|
48109
|
-
log3.info(` ${cacheResult.path}`);
|
|
48110
|
-
fixed++;
|
|
48111
|
-
} else if (cacheResult.action === "up_to_date") {
|
|
48112
|
-
pass(`Plugin cache up to date (v${cacheResult.cached})`);
|
|
48113
|
-
} else if (cacheResult.action === "check_unavailable") {
|
|
48114
|
-
warn(`Plugin cache version check unavailable; preserving cached plugin${cacheResult.cached ? ` (cached: ${cacheResult.cached})` : ""}. Use doctor --force to reinstall it.`);
|
|
48115
|
-
} else if (cacheResult.action === "in_use" || cacheResult.action === "in_use_unknown") {
|
|
48116
|
-
const versionInfo = cacheResult.cached ? ` (cached: ${cacheResult.cached}${cacheResult.latest ? `, latest: ${cacheResult.latest}` : ""})` : "";
|
|
48117
|
-
const why = cacheResult.action === "in_use" ? `OpenCode is running (pid ${cacheResult.pids?.join(", ")})` : cacheResult.reason ?? "could not tell whether OpenCode is running";
|
|
48118
|
-
warn(`Plugin cache${versionInfo} was not cleared: ${why}`);
|
|
48119
|
-
log3.info(" Quit OpenCode and rerun doctor to clear it.");
|
|
48120
|
-
for (const path of cacheResult.paths ?? [cacheResult.path])
|
|
48121
|
-
log3.info(` ${path}`);
|
|
48122
|
-
issues++;
|
|
48123
|
-
} else if (cacheResult.action === "error") {
|
|
48124
|
-
warn(`Could not clear plugin cache: ${cacheResult.error}`);
|
|
48125
|
-
if (cacheResult.clearedPaths && cacheResult.clearedPaths.length > 0) {
|
|
48126
|
-
log3.info(` Cleared roots: ${cacheResult.clearedPaths.join(", ")}`);
|
|
49669
|
+
if (magicContextInstalled) {
|
|
49670
|
+
let pluginConfigUse;
|
|
49671
|
+
if (paths.opencodeConfigFormat !== "none") {
|
|
49672
|
+
try {
|
|
49673
|
+
pluginConfigUse = readOpenCodePluginConfigUse(import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8")), dirname25(paths.opencodeConfig));
|
|
49674
|
+
} catch {}
|
|
48127
49675
|
}
|
|
48128
|
-
|
|
48129
|
-
|
|
48130
|
-
|
|
48131
|
-
|
|
49676
|
+
const cacheResult = await clearPluginCache({
|
|
49677
|
+
force: options.force,
|
|
49678
|
+
latestVersion: pluginNpmLatest,
|
|
49679
|
+
hostFiles: openCodeHostDatabaseFiles([openCodeDbResolution.path]),
|
|
49680
|
+
referencedSpecs: pluginConfigUse?.referencedSpecs.opencode1
|
|
49681
|
+
});
|
|
49682
|
+
if (cacheResult.action === "unused") {
|
|
49683
|
+
log3.info(describeUnusedOpenCodePluginCache({
|
|
49684
|
+
host: "OpenCode 1",
|
|
49685
|
+
spec: "latest",
|
|
49686
|
+
cached: cacheResult.cached,
|
|
49687
|
+
paths: cacheResult.paths ?? [cacheResult.path],
|
|
49688
|
+
loadedFrom: pluginConfigUse?.loadedFrom.opencode1
|
|
49689
|
+
}));
|
|
49690
|
+
} else if (cacheResult.action === "cleared") {
|
|
49691
|
+
const versionInfo = cacheResult.cached ? ` (cached: ${cacheResult.cached}${cacheResult.latest ? `, latest: ${cacheResult.latest}` : ""})` : "";
|
|
49692
|
+
const reason = cacheResult.latest ? "outdated plugin cache" : "plugin cache (latest version check unavailable)";
|
|
49693
|
+
pass(`Cleared ${reason}${versionInfo} — latest will download on restart`);
|
|
49694
|
+
log3.info(` ${cacheResult.path}`);
|
|
49695
|
+
fixed++;
|
|
49696
|
+
} else if (cacheResult.action === "up_to_date") {
|
|
49697
|
+
pass(`Plugin cache up to date (v${cacheResult.cached})`);
|
|
49698
|
+
} else if (cacheResult.action === "check_unavailable") {
|
|
49699
|
+
warn(`Plugin cache version check unavailable; preserving cached plugin${cacheResult.cached ? ` (cached: ${cacheResult.cached})` : ""}. Use doctor --force to reinstall it.`);
|
|
49700
|
+
} else if (cacheResult.action === "in_use" || cacheResult.action === "in_use_unknown") {
|
|
49701
|
+
const versionInfo = cacheResult.cached ? ` (cached: ${cacheResult.cached}${cacheResult.latest ? `, latest: ${cacheResult.latest}` : ""})` : "";
|
|
49702
|
+
const why = cacheResult.action === "in_use" ? `OpenCode is running (pid ${cacheResult.pids?.join(", ")})` : cacheResult.reason ?? "could not tell whether OpenCode is running";
|
|
49703
|
+
warn(`Plugin cache${versionInfo} was not cleared: ${why}`);
|
|
49704
|
+
log3.info(" Quit OpenCode and rerun doctor to clear it.");
|
|
49705
|
+
for (const path of cacheResult.paths ?? [cacheResult.path])
|
|
49706
|
+
log3.info(` ${path}`);
|
|
49707
|
+
issues++;
|
|
49708
|
+
} else if (cacheResult.action === "error") {
|
|
49709
|
+
warn(`Could not clear plugin cache: ${cacheResult.error}`);
|
|
49710
|
+
if (cacheResult.clearedPaths && cacheResult.clearedPaths.length > 0) {
|
|
49711
|
+
log3.info(` Cleared roots: ${cacheResult.clearedPaths.join(", ")}`);
|
|
49712
|
+
}
|
|
49713
|
+
if (cacheResult.failedPaths && cacheResult.failedPaths.length > 0) {
|
|
49714
|
+
log3.info(` Failed roots: ${cacheResult.failedPaths.join(", ")}`);
|
|
49715
|
+
} else {
|
|
49716
|
+
log3.info(` Manually delete: ${cacheResult.path}`);
|
|
49717
|
+
}
|
|
49718
|
+
issues++;
|
|
49719
|
+
} else if (hostGeneration !== "v2") {
|
|
49720
|
+
pass("Plugin cache clean (no cached version found)");
|
|
49721
|
+
}
|
|
49722
|
+
let v2DistTag;
|
|
49723
|
+
if (paths.opencodeConfigFormat !== "none") {
|
|
49724
|
+
try {
|
|
49725
|
+
v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8")));
|
|
49726
|
+
} catch {}
|
|
49727
|
+
}
|
|
49728
|
+
const v2Cache = reportOpenCodeV2PluginCache(checkOpenCodeV2PluginCache({
|
|
49729
|
+
fix: options.fix,
|
|
49730
|
+
force: options.force,
|
|
49731
|
+
latestVersion: v2DistTag ? await fetchNpmLatest(OPENCODE_PLUGIN_NAME, v2DistTag) : pluginNpmLatest,
|
|
49732
|
+
distTag: v2DistTag,
|
|
49733
|
+
hostFiles: openCodeHostDatabaseFiles([openCodeDbResolution.path]),
|
|
49734
|
+
referencedSpecs: pluginConfigUse?.referencedSpecs.opencode2
|
|
49735
|
+
}), { pass, warn, info: (message) => log3.info(message) }, {
|
|
49736
|
+
reportMissing: hostGeneration === "v2",
|
|
49737
|
+
loadedFrom: pluginConfigUse?.loadedFrom.opencode2
|
|
49738
|
+
});
|
|
49739
|
+
if (v2Cache.fixed)
|
|
49740
|
+
fixed++;
|
|
49741
|
+
if (v2Cache.issue)
|
|
49742
|
+
issues++;
|
|
49743
|
+
const sharedDbVersion = readContextDbSchemaVersion(dbPath);
|
|
49744
|
+
if (sharedDbVersion !== null) {
|
|
49745
|
+
reportCachedPluginFences(compareCachedPluginFences(listCachedOpenCodePluginFences({
|
|
49746
|
+
referencedSpecs: pluginConfigUse?.referencedSpecs
|
|
49747
|
+
}), sharedDbVersion), { pass, fail, info: (message) => log3.info(message) });
|
|
48132
49748
|
}
|
|
48133
|
-
issues++;
|
|
48134
|
-
} else if (hostGeneration !== "v2") {
|
|
48135
|
-
pass("Plugin cache clean (no cached version found)");
|
|
48136
|
-
}
|
|
48137
|
-
let v2DistTag;
|
|
48138
|
-
if (paths.opencodeConfigFormat !== "none") {
|
|
48139
|
-
try {
|
|
48140
|
-
v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8")));
|
|
48141
|
-
} catch {}
|
|
48142
|
-
}
|
|
48143
|
-
const v2Cache = reportOpenCodeV2PluginCache(checkOpenCodeV2PluginCache({
|
|
48144
|
-
fix: options.fix,
|
|
48145
|
-
force: options.force,
|
|
48146
|
-
latestVersion: v2DistTag ? await fetchNpmLatest(OPENCODE_PLUGIN_NAME, v2DistTag) : pluginNpmLatest,
|
|
48147
|
-
distTag: v2DistTag,
|
|
48148
|
-
hostFiles: openCodeHostDatabaseFiles([openCodeDbResolution.path])
|
|
48149
|
-
}), { pass, warn, info: (message) => log3.info(message) }, { reportMissing: hostGeneration === "v2" });
|
|
48150
|
-
if (v2Cache.fixed)
|
|
48151
|
-
fixed++;
|
|
48152
|
-
if (v2Cache.issue)
|
|
48153
|
-
issues++;
|
|
48154
|
-
const sharedDbVersion = readContextDbSchemaVersion(dbPath);
|
|
48155
|
-
if (sharedDbVersion !== null) {
|
|
48156
|
-
reportCachedPluginFences(compareCachedPluginFences(listCachedOpenCodePluginFences(), sharedDbVersion), { pass, fail, info: (message) => log3.info(message) });
|
|
48157
49749
|
}
|
|
48158
|
-
{
|
|
49750
|
+
if (magicContextInstalled) {
|
|
48159
49751
|
const ageWarnings = collectNpmReleaseAgeWarnings();
|
|
48160
49752
|
if (ageWarnings.length > 0) {
|
|
48161
49753
|
log3.warn("npm min-release-age restriction detected — this can prevent OpenCode from installing the latest plugin version");
|
|
@@ -48167,17 +49759,19 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
48167
49759
|
issues++;
|
|
48168
49760
|
}
|
|
48169
49761
|
}
|
|
48170
|
-
|
|
48171
|
-
|
|
48172
|
-
|
|
48173
|
-
|
|
48174
|
-
|
|
48175
|
-
|
|
48176
|
-
|
|
48177
|
-
|
|
48178
|
-
|
|
48179
|
-
|
|
48180
|
-
|
|
49762
|
+
if (magicContextInstalled) {
|
|
49763
|
+
const logHarnesses = [
|
|
49764
|
+
...hostGeneration === "v1" ? ["opencode"] : [],
|
|
49765
|
+
...hostGeneration === "v2" || storeGeneration === "v2" ? ["opencode2"] : []
|
|
49766
|
+
];
|
|
49767
|
+
const logFiles = logHarnesses.flatMap((harness) => inspectMagicContextLogs(harness)).filter((file, index, all) => all.findIndex((other) => other.path === file.path) === index);
|
|
49768
|
+
const existingLogFiles = logFiles.filter((file) => file.exists);
|
|
49769
|
+
if (existingLogFiles.length === 0) {
|
|
49770
|
+
log3.info(`No plugin log file yet; checked: ${logFiles.map((file) => file.path).join(", ")}`);
|
|
49771
|
+
} else {
|
|
49772
|
+
for (const file of existingLogFiles) {
|
|
49773
|
+
log3.info(`Log file read: ${formatLogFileInspection(file)}`);
|
|
49774
|
+
}
|
|
48181
49775
|
}
|
|
48182
49776
|
}
|
|
48183
49777
|
const diagnostics = await collectDiagnostics();
|
|
@@ -48358,13 +49952,12 @@ function resolveDreamerTaskModel(args) {
|
|
|
48358
49952
|
const taskQualifier = taskBlock?.[args.harness === "opencode" ? "variant" : "thinking_level"];
|
|
48359
49953
|
const harnessQualifier = harnessBlock[args.harness === "opencode" ? "variant" : "thinking_level"] ?? normalizeModelEntry(harnessBlock.model, args.harness)?.qualifier;
|
|
48360
49954
|
const taskHasModel = taskBlock !== undefined && hasOwn2(taskBlock, "model");
|
|
48361
|
-
const
|
|
48362
|
-
const primarySource = taskHasModel ? taskBlock?.model : usesMuralModel ? args.muralModel : harnessBlock.model;
|
|
49955
|
+
const primarySource = taskHasModel ? taskBlock?.model : harnessBlock.model;
|
|
48363
49956
|
const fallbackSource = taskBlock !== undefined && hasOwn2(taskBlock, "fallback_models") ? taskBlock.fallback_models : harnessBlock.fallback_models;
|
|
48364
49957
|
return {
|
|
48365
49958
|
primary: resolvePrimaryEntry({
|
|
48366
49959
|
entry: primarySource,
|
|
48367
|
-
defaultQualifier:
|
|
49960
|
+
defaultQualifier: taskQualifier ?? harnessQualifier,
|
|
48368
49961
|
harness: args.harness
|
|
48369
49962
|
}),
|
|
48370
49963
|
fallbacks: resolveFallbackEntries(fallbackSource, args.harness),
|
|
@@ -48375,13 +49968,12 @@ function resolveDreamerTaskModel(args) {
|
|
|
48375
49968
|
}
|
|
48376
49969
|
|
|
48377
49970
|
// ../plugin/src/features/magic-context/dreamer/task-config.ts
|
|
48378
|
-
function buildDreamTaskRuntimeConfigs(dreamer, harness, language,
|
|
48379
|
-
return
|
|
49971
|
+
function buildDreamTaskRuntimeConfigs(dreamer, harness, language, smartNotesEnabled = true) {
|
|
49972
|
+
return availableDreamTasks(smartNotesEnabled).map((task) => {
|
|
48380
49973
|
const resolved = resolveDreamerTaskModel({
|
|
48381
49974
|
config: { dreamer },
|
|
48382
49975
|
harness,
|
|
48383
|
-
task
|
|
48384
|
-
muralModel
|
|
49976
|
+
task
|
|
48385
49977
|
});
|
|
48386
49978
|
return {
|
|
48387
49979
|
task,
|
|
@@ -48489,7 +50081,7 @@ function runnablePiModelChains(config, harness) {
|
|
|
48489
50081
|
});
|
|
48490
50082
|
}
|
|
48491
50083
|
if (isDreamerRunnable(config)) {
|
|
48492
|
-
for (const task of buildDreamTaskRuntimeConfigs(config.dreamer, harness, config.language, config.
|
|
50084
|
+
for (const task of buildDreamTaskRuntimeConfigs(config.dreamer, harness, config.language, config.smart_notes?.enabled)) {
|
|
48493
50085
|
if (task.schedule.trim() === "")
|
|
48494
50086
|
continue;
|
|
48495
50087
|
const chain = [task.model, ...task.fallbackModels ?? []].filter((entry) => entry !== undefined);
|
|
@@ -49283,22 +50875,9 @@ async function runHealthChecks2(options) {
|
|
|
49283
50875
|
};
|
|
49284
50876
|
const self = options.deps.selfVersion();
|
|
49285
50877
|
const pi = options.deps.detectPiBinary();
|
|
49286
|
-
|
|
50878
|
+
const piVersion = pi ? options.deps.getPiVersion(pi.path) : null;
|
|
50879
|
+
if (!pi)
|
|
49287
50880
|
add2(results, "fail", "Pi binary not found on PATH or at ~/.pi/bin/pi");
|
|
49288
|
-
} else {
|
|
49289
|
-
const version = options.deps.getPiVersion(pi.path);
|
|
49290
|
-
if (version === null) {
|
|
49291
|
-
add2(results, "fail", `Pi CLI was found at ${pi.path} but could not be executed`);
|
|
49292
|
-
} else {
|
|
49293
|
-
add2(results, "pass", `Pi ${version} detected at ${pi.path}`);
|
|
49294
|
-
}
|
|
49295
|
-
const compare = compareSemver(version, MIN_PI_VERSION);
|
|
49296
|
-
if (compare !== null && compare < 0) {
|
|
49297
|
-
add2(results, "fail", `Pi ${version} is older than required ${MIN_PI_VERSION}. Subagents (historian/dreamer) use the long-form \`--extension\` flag introduced in Pi 0.71.0; older versions hard-fail with "Unknown option". Run \`pi update\` (or \`npm install -g @earendil-works/pi-coding-agent@latest\`).`);
|
|
49298
|
-
} else if (version) {
|
|
49299
|
-
add2(results, "pass", `Pi version meets minimum ${MIN_PI_VERSION} requirement`);
|
|
49300
|
-
}
|
|
49301
|
-
}
|
|
49302
50881
|
const latest = options.deps.getLatestNpmVersion();
|
|
49303
50882
|
const latestCompare = latest ? compareSemver(self, latest) : null;
|
|
49304
50883
|
if (latest && latestCompare === -1) {
|
|
@@ -49312,8 +50891,11 @@ async function runHealthChecks2(options) {
|
|
|
49312
50891
|
}
|
|
49313
50892
|
const settingsPath = getPiUserExtensionsPath();
|
|
49314
50893
|
let packages = [];
|
|
50894
|
+
let piPluginInstalled = false;
|
|
49315
50895
|
if (!existsSync47(settingsPath)) {
|
|
49316
|
-
|
|
50896
|
+
if (pi) {
|
|
50897
|
+
add2(results, "info", `${piVersion ? `Pi ${piVersion}` : "Pi"} found; Magic Context is not installed there (run setup to add it)`);
|
|
50898
|
+
}
|
|
49317
50899
|
repairPlan.addPackageEntry = true;
|
|
49318
50900
|
} else {
|
|
49319
50901
|
const parsed = readJsonc2(settingsPath);
|
|
@@ -49321,15 +50903,31 @@ async function runHealthChecks2(options) {
|
|
|
49321
50903
|
add2(results, "fail", `Could not parse Pi settings ${settingsPath}: ${parsed.error}`);
|
|
49322
50904
|
} else {
|
|
49323
50905
|
packages = packagesFrom(parsed.value);
|
|
49324
|
-
add2(results, "pass", `Pi settings found at ${settingsPath}`);
|
|
49325
50906
|
if (hasPiMagicContextPackage(packages)) {
|
|
50907
|
+
piPluginInstalled = true;
|
|
50908
|
+
add2(results, "pass", `Pi settings found at ${settingsPath}`);
|
|
49326
50909
|
add2(results, "pass", `${PI_PACKAGE_SOURCE} is registered in packages[]`);
|
|
49327
50910
|
} else {
|
|
49328
|
-
|
|
50911
|
+
if (pi) {
|
|
50912
|
+
add2(results, "info", `${piVersion ? `Pi ${piVersion}` : "Pi"} found; Magic Context is not installed there (run setup to add it)`);
|
|
50913
|
+
}
|
|
49329
50914
|
repairPlan.addPackageEntry = true;
|
|
49330
50915
|
}
|
|
49331
50916
|
}
|
|
49332
50917
|
}
|
|
50918
|
+
if (pi && piPluginInstalled) {
|
|
50919
|
+
if (piVersion === null) {
|
|
50920
|
+
add2(results, "fail", `Pi CLI was found at ${pi.path} but could not be executed`);
|
|
50921
|
+
} else {
|
|
50922
|
+
add2(results, "pass", `Pi ${piVersion} detected at ${pi.path}`);
|
|
50923
|
+
}
|
|
50924
|
+
const compare = compareSemver(piVersion, MIN_PI_VERSION);
|
|
50925
|
+
if (compare !== null && compare < 0) {
|
|
50926
|
+
add2(results, "fail", `Pi ${piVersion} is older than required ${MIN_PI_VERSION}. Subagents (historian/dreamer) use the long-form \`--extension\` flag introduced in Pi 0.71.0; older versions hard-fail with "Unknown option". Run \`pi update\` (or \`npm install -g @earendil-works/pi-coding-agent@latest\`).`);
|
|
50927
|
+
} else if (piVersion) {
|
|
50928
|
+
add2(results, "pass", `Pi version meets minimum ${MIN_PI_VERSION} requirement`);
|
|
50929
|
+
}
|
|
50930
|
+
}
|
|
49333
50931
|
const userConfigPath = getPiUserConfigPath();
|
|
49334
50932
|
const projectPath = projectConfigPath(options.cwd);
|
|
49335
50933
|
for (const [label, path, required] of [
|
|
@@ -49378,7 +50976,8 @@ async function runHealthChecks2(options) {
|
|
|
49378
50976
|
} else if (historianModel.startsWith("github-copilot/") && historianThinkingLevel) {
|
|
49379
50977
|
add2(results, "pass", `historian.model "${historianModel}" has thinking_level "${historianThinkingLevel}" configured`);
|
|
49380
50978
|
}
|
|
49381
|
-
|
|
50979
|
+
if (piPluginInstalled)
|
|
50980
|
+
checkPiModelChains(results, pi, loadedConfig.config, options.deps);
|
|
49382
50981
|
const storage = getMagicContextStorageResolution();
|
|
49383
50982
|
const storageDir = storage.path;
|
|
49384
50983
|
const dbPath = join41(storageDir, "context.db");
|
|
@@ -49501,7 +51100,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
49501
51100
|
}
|
|
49502
51101
|
} else if (loadedConfig.config.embedding.provider === "off") {
|
|
49503
51102
|
add2(results, "info", "Embedding provider disabled");
|
|
49504
|
-
} else {
|
|
51103
|
+
} else if (piPluginInstalled) {
|
|
49505
51104
|
let runtimeReported = false;
|
|
49506
51105
|
let firstFallback = null;
|
|
49507
51106
|
const brokenWarnings = [];
|
|
@@ -49540,38 +51139,40 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
49540
51139
|
}
|
|
49541
51140
|
}
|
|
49542
51141
|
}
|
|
49543
|
-
|
|
49544
|
-
|
|
49545
|
-
|
|
49546
|
-
|
|
49547
|
-
|
|
49548
|
-
|
|
49549
|
-
|
|
49550
|
-
|
|
49551
|
-
|
|
49552
|
-
|
|
49553
|
-
|
|
49554
|
-
|
|
49555
|
-
|
|
49556
|
-
|
|
49557
|
-
|
|
49558
|
-
|
|
49559
|
-
|
|
49560
|
-
|
|
49561
|
-
|
|
49562
|
-
|
|
49563
|
-
|
|
49564
|
-
|
|
49565
|
-
|
|
49566
|
-
|
|
49567
|
-
|
|
49568
|
-
|
|
49569
|
-
|
|
49570
|
-
|
|
49571
|
-
|
|
51142
|
+
if (piPluginInstalled) {
|
|
51143
|
+
const piEntries = packages.filter(isConfiguredPiMagicContextEntry2).map(describePiPackageEntry);
|
|
51144
|
+
if (piEntries.length > 1) {
|
|
51145
|
+
add2(results, "fail", `Multiple magic-context entries in Pi packages[] — this loads the plugin twice: ${piEntries.join(", ")}`);
|
|
51146
|
+
} else {
|
|
51147
|
+
add2(results, "pass", "No conflicting magic-context entries in Pi packages[]");
|
|
51148
|
+
}
|
|
51149
|
+
const otherExtensions = packages.filter((entry) => !isConfiguredPiMagicContextEntry2(entry)).map(describePiPackageEntry);
|
|
51150
|
+
if (otherExtensions.length > 0) {
|
|
51151
|
+
add2(results, "info", `Other Pi extensions registered: ${otherExtensions.join(", ")}`);
|
|
51152
|
+
} else {
|
|
51153
|
+
add2(results, "info", "No other Pi extensions listed in settings.json");
|
|
51154
|
+
}
|
|
51155
|
+
const configuredEntry = packages.find(isPiMagicContextPackageEntry);
|
|
51156
|
+
const configuredSpecifier = getPiMagicContextPackageSpecifier(configuredEntry);
|
|
51157
|
+
const expectedPluginVersion = pinnedVersionFromPackageSpecifier(configuredSpecifier) ?? latest ?? null;
|
|
51158
|
+
const staleCaches = findPiMagicContextCacheDirs(options.cwd, expectedPluginVersion, options.force === true);
|
|
51159
|
+
if (staleCaches.length > 0) {
|
|
51160
|
+
repairPlan.clearCachePaths = staleCaches.map((entry) => entry.path);
|
|
51161
|
+
add2(results, "warn", `Stale Pi extension cache found: ${staleCaches.map((entry) => `${entry.path}${entry.version ? ` (v${entry.version})` : ""}`).join(", ")}`);
|
|
51162
|
+
} else {
|
|
51163
|
+
add2(results, "pass", "Pi extension cache clean (no stale cached package found)");
|
|
51164
|
+
}
|
|
51165
|
+
const logFiles = inspectMagicContextLogs("pi");
|
|
51166
|
+
const existingLogFiles = logFiles.filter((file) => file.exists);
|
|
51167
|
+
if (existingLogFiles.length === 0) {
|
|
51168
|
+
add2(results, "info", `No plugin log file yet; checked: ${logFiles.map((file) => file.path).join(", ")}`);
|
|
51169
|
+
} else {
|
|
51170
|
+
for (const file of existingLogFiles) {
|
|
51171
|
+
add2(results, "info", `Log file read: ${formatLogFileInspection(file)}`);
|
|
51172
|
+
}
|
|
51173
|
+
const lastLine = readLogLines(existingLogFiles).at(-1);
|
|
51174
|
+
add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
|
|
49572
51175
|
}
|
|
49573
|
-
const lastLine = readLogLines(existingLogFiles).at(-1);
|
|
49574
|
-
add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
|
|
49575
51176
|
}
|
|
49576
51177
|
const diagnosticsForDumps = await collectDiagnostics2(options.cwd);
|
|
49577
51178
|
const dumpBuckets = diagnosticsForDumps.historianDumps.byProject;
|
|
@@ -49967,7 +51568,8 @@ async function dispatchDoctor(adapter, options) {
|
|
|
49967
51568
|
force: options.force,
|
|
49968
51569
|
fix: options.fix,
|
|
49969
51570
|
issue: options.issue,
|
|
49970
|
-
report: options.report
|
|
51571
|
+
report: options.report,
|
|
51572
|
+
verbose: options.verbose
|
|
49971
51573
|
});
|
|
49972
51574
|
}
|
|
49973
51575
|
case "pi": {
|
|
@@ -50131,6 +51733,7 @@ var DOCTOR_HELP = [
|
|
|
50131
51733
|
" --fix Repair safe, Magic Context-owned store rows and clear an outdated OpenCode 2 plugin cache",
|
|
50132
51734
|
" --force Force-clear the plugin cache",
|
|
50133
51735
|
" --clear Interactive cache cleanup picker",
|
|
51736
|
+
" --verbose Print long listings in full instead of a capped summary",
|
|
50134
51737
|
" --prune-discovery [--yes] List RPC discovery records that block offline maintenance, then remove them after confirmation",
|
|
50135
51738
|
" --issue Collect diagnostics and open a GitHub issue",
|
|
50136
51739
|
" --report <path> Write the issue diagnostics to <path> without prompting",
|
|
@@ -50389,6 +51992,7 @@ async function runCommand(command, rest) {
|
|
|
50389
51992
|
issue: rest.includes("--issue") || report !== null,
|
|
50390
51993
|
...report !== null ? { report } : {},
|
|
50391
51994
|
clear: rest.includes("--clear"),
|
|
51995
|
+
verbose: rest.includes("--verbose"),
|
|
50392
51996
|
checkV22Backfill: rest.includes("--check-v22-backfill"),
|
|
50393
51997
|
retryV22Backfill: rest.includes("--retry-v22-backfill"),
|
|
50394
51998
|
...rekeyV22DirIdentity !== null ? { rekeyV22DirIdentity } : {},
|