@cortexkit/magic-context 0.47.0 → 0.48.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 +1857 -459
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3476,6 +3476,15 @@ function migrateLegacyExperimental(rawConfig, warnings) {
|
|
|
3476
3476
|
return patched;
|
|
3477
3477
|
}
|
|
3478
3478
|
|
|
3479
|
+
// ../plugin/src/config/mural-model-deprecation.ts
|
|
3480
|
+
function warnDeprecatedMuralModel(config, warnings) {
|
|
3481
|
+
const mural = config.mural;
|
|
3482
|
+
if (typeof mural === "object" && mural !== null && Object.hasOwn(mural, "model")) {
|
|
3483
|
+
warnings.push(MURAL_MODEL_DEPRECATION_WARNING);
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
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.";
|
|
3487
|
+
|
|
3479
3488
|
// ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/core/core.js
|
|
3480
3489
|
function $constructor(name, initializer, params) {
|
|
3481
3490
|
function init(inst, def) {
|
|
@@ -9315,7 +9324,7 @@ var init_magic_context = __esm(() => {
|
|
|
9315
9324
|
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
9325
|
mural: object({
|
|
9317
9326
|
enabled: boolean2().default(false),
|
|
9318
|
-
model:
|
|
9327
|
+
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
9328
|
}).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
9329
|
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
9330
|
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 +9334,9 @@ var init_magic_context = __esm(() => {
|
|
|
9325
9334
|
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
9335
|
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
9336
|
smart_notes: object({
|
|
9337
|
+
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
9338
|
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."),
|
|
9339
|
+
}).default({ enabled: true, retina_handoff: false }).describe("Smart-note ownership transition controls."),
|
|
9330
9340
|
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
9341
|
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
9342
|
output_reserve: union([
|
|
@@ -9431,7 +9441,6 @@ var init_magic_context = __esm(() => {
|
|
|
9431
9441
|
});
|
|
9432
9442
|
LIVE_RELOAD_CONFIG_PATHS = [
|
|
9433
9443
|
"cache_ttl",
|
|
9434
|
-
"mural.model",
|
|
9435
9444
|
"toast_duration_ms",
|
|
9436
9445
|
"historian.opencode.model",
|
|
9437
9446
|
"historian.opencode.fallback_models",
|
|
@@ -9612,16 +9621,6 @@ function stripEscalationAtExecutableSite(block, path, removed) {
|
|
|
9612
9621
|
}
|
|
9613
9622
|
}
|
|
9614
9623
|
}
|
|
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
9624
|
function isValidPercentageThreshold(value) {
|
|
9626
9625
|
return typeof value === "number" && Number.isFinite(value) && value >= 20 && value <= 90;
|
|
9627
9626
|
}
|
|
@@ -9762,6 +9761,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
9762
9761
|
delete storage.enforce_private_permissions;
|
|
9763
9762
|
warnings.push("Ignoring storage.enforce_private_permissions from project config (security: only user-level config may opt into externally managed shared storage permissions).");
|
|
9764
9763
|
}
|
|
9764
|
+
const smartNotes = projectRaw.smart_notes;
|
|
9765
|
+
if (isPlainObject2(smartNotes) && "enabled" in smartNotes) {
|
|
9766
|
+
delete smartNotes.enabled;
|
|
9767
|
+
warnings.push("Ignoring smart_notes.enabled from project config (only user-level config may change process-wide tool definitions; restart required).");
|
|
9768
|
+
}
|
|
9765
9769
|
const promptSurface = projectRaw.prompt_surface;
|
|
9766
9770
|
if (isPlainObject2(promptSurface)) {
|
|
9767
9771
|
const removed = [];
|
|
@@ -9860,27 +9864,6 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
9860
9864
|
delete dreamer.runner;
|
|
9861
9865
|
warnings.push("Ignoring dreamer.runner from project config (security: which process and provider account run dreamer completions is a user-level setting).");
|
|
9862
9866
|
}
|
|
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
9867
|
return warnings;
|
|
9885
9868
|
}
|
|
9886
9869
|
function constrainProjectThresholdOverrides(args) {
|
|
@@ -10929,6 +10912,7 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
10929
10912
|
}
|
|
10930
10913
|
preMigrationWarnings.push(...misplacedAgentModelWarnings(rawConfig));
|
|
10931
10914
|
const migratedExperimental = migrateLegacyExperimental(configWithoutRemovedAgent, preMigrationWarnings);
|
|
10915
|
+
warnDeprecatedMuralModel(migratedExperimental, preMigrationWarnings);
|
|
10932
10916
|
const migratedDreamer = migrateDreamerV2(migratedExperimental, preMigrationWarnings);
|
|
10933
10917
|
const migrated = migrateLegacyAgentEnabledInMemory(migratedDreamer, preMigrationWarnings);
|
|
10934
10918
|
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
@@ -12856,17 +12840,23 @@ __export(exports_sqlite, {
|
|
|
12856
12840
|
detectSqliteRuntime: () => detectSqliteRuntime,
|
|
12857
12841
|
getSqliteDatabasePath: () => getSqliteDatabasePath,
|
|
12858
12842
|
getSqliteMemoryStats: () => getSqliteMemoryStats,
|
|
12843
|
+
getTagIdentityWriteGeneration: () => getTagIdentityWriteGeneration,
|
|
12859
12844
|
guardSqliteTransformPass: () => guardSqliteTransformPass,
|
|
12845
|
+
indexCoordinationInput: () => indexCoordinationInput,
|
|
12860
12846
|
isTransientSqliteError: () => isTransientSqliteError,
|
|
12861
12847
|
loadSqliteModule: () => loadSqliteModule,
|
|
12848
|
+
mayChangeTagIdentity: () => mayChangeTagIdentity,
|
|
12862
12849
|
prepareCachedStatement: () => prepareCachedStatement,
|
|
12863
12850
|
registerSlowWriteReporter: () => registerSlowWriteReporter,
|
|
12864
12851
|
registerSqliteDiagnosticSink: () => registerSqliteDiagnosticSink,
|
|
12852
|
+
releaseIndexOwner: () => releaseIndexOwner,
|
|
12865
12853
|
withAsyncPrivilegedWriter: () => withAsyncPrivilegedWriter,
|
|
12854
|
+
withIndexChunk: () => withIndexChunk,
|
|
12866
12855
|
withPrivilegedWriter: () => withPrivilegedWriter,
|
|
12867
12856
|
withSqliteBackgroundWriter: () => withSqliteBackgroundWriter,
|
|
12868
12857
|
withSqliteTransformPass: () => withSqliteTransformPass,
|
|
12869
|
-
withoutSqliteTransformPass: () => withoutSqliteTransformPass
|
|
12858
|
+
withoutSqliteTransformPass: () => withoutSqliteTransformPass,
|
|
12859
|
+
yieldIndexChunk: () => yieldIndexChunk
|
|
12870
12860
|
});
|
|
12871
12861
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
12872
12862
|
import { statSync as statSync4 } from "node:fs";
|
|
@@ -12900,10 +12890,31 @@ function isModuleNotFoundError(error, specifier) {
|
|
|
12900
12890
|
return false;
|
|
12901
12891
|
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
12892
|
}
|
|
12893
|
+
function isNodeSqliteExperimentalWarning(args) {
|
|
12894
|
+
const [warning, options] = args;
|
|
12895
|
+
const message = warning instanceof Error ? warning.message : warning;
|
|
12896
|
+
const type = typeof options === "string" ? options : options && typeof options === "object" ? options.type : undefined;
|
|
12897
|
+
return type === "ExperimentalWarning" && typeof message === "string" && message.startsWith("SQLite is an experimental feature");
|
|
12898
|
+
}
|
|
12899
|
+
async function importSqliteModuleForRuntime(runtime, specifier, importer) {
|
|
12900
|
+
if (runtime !== "Node.js")
|
|
12901
|
+
return importer(specifier);
|
|
12902
|
+
const originalEmitWarning = process.emitWarning;
|
|
12903
|
+
process.emitWarning = function(...args) {
|
|
12904
|
+
if (isNodeSqliteExperimentalWarning(args))
|
|
12905
|
+
return;
|
|
12906
|
+
Reflect.apply(originalEmitWarning, this, args);
|
|
12907
|
+
};
|
|
12908
|
+
try {
|
|
12909
|
+
return await importer(specifier);
|
|
12910
|
+
} finally {
|
|
12911
|
+
process.emitWarning = originalEmitWarning;
|
|
12912
|
+
}
|
|
12913
|
+
}
|
|
12903
12914
|
async function loadSqliteModule(runtime = detectSqliteRuntime(), importer = importSqliteModule) {
|
|
12904
12915
|
const specifier = runtime === "Bun" ? bunSpec : nodeSpec;
|
|
12905
12916
|
try {
|
|
12906
|
-
return await
|
|
12917
|
+
return await importSqliteModuleForRuntime(runtime, specifier, importer);
|
|
12907
12918
|
} catch (error) {
|
|
12908
12919
|
if (isModuleNotFoundError(error, specifier)) {
|
|
12909
12920
|
throw new SqliteRuntimeUnavailableError(runtime, specifier, error);
|
|
@@ -12911,6 +12922,67 @@ async function loadSqliteModule(runtime = detectSqliteRuntime(), importer = impo
|
|
|
12911
12922
|
throw error;
|
|
12912
12923
|
}
|
|
12913
12924
|
}
|
|
12925
|
+
function mayChangeTagIdentity(sql) {
|
|
12926
|
+
if (!/\btags\b/i.test(sql) || /^\s*(?:SELECT|EXPLAIN|PRAGMA)\b/i.test(sql))
|
|
12927
|
+
return false;
|
|
12928
|
+
if (/^\s*WITH\b/i.test(sql) && !/\b(?:INSERT|UPDATE|DELETE|REPLACE)\b/i.test(sql))
|
|
12929
|
+
return false;
|
|
12930
|
+
if (/;\s*\S/.test(sql) || /\bREPLACE\b/i.test(sql) || /\bON\s+CONFLICT\b/i.test(sql))
|
|
12931
|
+
return true;
|
|
12932
|
+
const insert = /^\s*INSERT\s+INTO\s+(?:main\.)?["`]?tags["`]?\s*\(([^)]*)\)/i.exec(sql);
|
|
12933
|
+
if (insert) {
|
|
12934
|
+
const columns = (insert[1] ?? "").split(",").map((column) => column.trim().replace(/["`[\]]/g, "").toLowerCase());
|
|
12935
|
+
return columns.includes("id") || columns.includes("rowid");
|
|
12936
|
+
}
|
|
12937
|
+
const update = /^\s*UPDATE\s+(?:main\.)?["`]?tags["`]?\s+SET\s+([\s\S]*?)\bWHERE\b/i.exec(sql);
|
|
12938
|
+
if (update && !/\bSELECT\b/i.test(sql)) {
|
|
12939
|
+
const assignments = topLevelCommaSegments(update[1] ?? "");
|
|
12940
|
+
if (!assignments)
|
|
12941
|
+
return true;
|
|
12942
|
+
return !assignments.every((assignment) => {
|
|
12943
|
+
const column = /^\s*["`]?(\w+)["`]?\s*=(?!=)/.exec(assignment)?.[1];
|
|
12944
|
+
return column !== undefined && TAG_COLUMNS_OUTSIDE_IDENTITY.has(column.toLowerCase());
|
|
12945
|
+
});
|
|
12946
|
+
}
|
|
12947
|
+
return true;
|
|
12948
|
+
}
|
|
12949
|
+
function topLevelCommaSegments(text) {
|
|
12950
|
+
const segments = [];
|
|
12951
|
+
let depth = 0;
|
|
12952
|
+
let quote = null;
|
|
12953
|
+
let start = 0;
|
|
12954
|
+
for (let index = 0;index < text.length; index += 1) {
|
|
12955
|
+
const char = text[index];
|
|
12956
|
+
if (quote) {
|
|
12957
|
+
if (char === quote) {
|
|
12958
|
+
if (text[index + 1] === quote)
|
|
12959
|
+
index += 1;
|
|
12960
|
+
else
|
|
12961
|
+
quote = null;
|
|
12962
|
+
}
|
|
12963
|
+
continue;
|
|
12964
|
+
}
|
|
12965
|
+
if (char === "'" || char === '"' || char === "`")
|
|
12966
|
+
quote = char;
|
|
12967
|
+
else if (char === "(")
|
|
12968
|
+
depth += 1;
|
|
12969
|
+
else if (char === ")") {
|
|
12970
|
+
depth -= 1;
|
|
12971
|
+
if (depth < 0)
|
|
12972
|
+
return null;
|
|
12973
|
+
} else if (char === "," && depth === 0) {
|
|
12974
|
+
segments.push(text.slice(start, index));
|
|
12975
|
+
start = index + 1;
|
|
12976
|
+
}
|
|
12977
|
+
}
|
|
12978
|
+
if (quote || depth !== 0)
|
|
12979
|
+
return null;
|
|
12980
|
+
segments.push(text.slice(start));
|
|
12981
|
+
return segments;
|
|
12982
|
+
}
|
|
12983
|
+
function getTagIdentityWriteGeneration() {
|
|
12984
|
+
return tagIdentityWriteGeneration;
|
|
12985
|
+
}
|
|
12914
12986
|
function installTransactionRouting(db, readonly) {
|
|
12915
12987
|
const nativeExec = db.exec.bind(db);
|
|
12916
12988
|
Object.defineProperty(db, "exec", {
|
|
@@ -12929,8 +13001,14 @@ function installTransactionRouting(db, readonly) {
|
|
|
12929
13001
|
}
|
|
12930
13002
|
if (WRITER_TRANSACTION_END.test(sql) && openWriterTransactions.has(db))
|
|
12931
13003
|
return endWriterTransaction(db, () => nativeExec(sql), sql);
|
|
12932
|
-
if (!/^\s*(?:SELECT|EXPLAIN|PRAGMA|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i.test(sql))
|
|
12933
|
-
|
|
13004
|
+
if (!/^\s*(?:SELECT|EXPLAIN|PRAGMA|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i.test(sql)) {
|
|
13005
|
+
try {
|
|
13006
|
+
return withAutocommitTimeout(db, () => nativeExec(sql));
|
|
13007
|
+
} finally {
|
|
13008
|
+
if (mayChangeTagIdentity(sql))
|
|
13009
|
+
tagIdentityWriteGeneration += 1;
|
|
13010
|
+
}
|
|
13011
|
+
}
|
|
12934
13012
|
return nativeExec(sql);
|
|
12935
13013
|
}
|
|
12936
13014
|
});
|
|
@@ -12941,13 +13019,23 @@ function installTransactionRouting(db, readonly) {
|
|
|
12941
13019
|
value: (sql) => {
|
|
12942
13020
|
const statement = nativePrepare(sql);
|
|
12943
13021
|
if (!readonly && !/^\s*(?:SELECT|EXPLAIN|PRAGMA)\b/i.test(sql)) {
|
|
13022
|
+
const changesTagIdentity = mayChangeTagIdentity(sql);
|
|
12944
13023
|
for (const method of ["run", "get", "all"]) {
|
|
12945
13024
|
const execute = statement[method].bind(statement);
|
|
12946
13025
|
Object.defineProperty(statement, method, {
|
|
12947
13026
|
configurable: true,
|
|
12948
|
-
value: (...args) =>
|
|
13027
|
+
value: (...args) => {
|
|
13028
|
+
try {
|
|
13029
|
+
return withAutocommitTimeout(db, () => execute(...args));
|
|
13030
|
+
} finally {
|
|
13031
|
+
if (changesTagIdentity)
|
|
13032
|
+
tagIdentityWriteGeneration += 1;
|
|
13033
|
+
}
|
|
13034
|
+
}
|
|
12949
13035
|
});
|
|
12950
13036
|
}
|
|
13037
|
+
if (changesTagIdentity)
|
|
13038
|
+
wrapRemainingTagWriteForms(statement);
|
|
12951
13039
|
}
|
|
12952
13040
|
return statement;
|
|
12953
13041
|
}
|
|
@@ -12995,6 +13083,35 @@ function installTransactionRouting(db, readonly) {
|
|
|
12995
13083
|
}
|
|
12996
13084
|
});
|
|
12997
13085
|
}
|
|
13086
|
+
function wrapRemainingTagWriteForms(statement) {
|
|
13087
|
+
if (typeof statement.iterate === "function") {
|
|
13088
|
+
const iterate = statement.iterate.bind(statement);
|
|
13089
|
+
Object.defineProperty(statement, "iterate", {
|
|
13090
|
+
configurable: true,
|
|
13091
|
+
value: function* (...args) {
|
|
13092
|
+
tagIdentityWriteGeneration += 1;
|
|
13093
|
+
try {
|
|
13094
|
+
yield* iterate(...args);
|
|
13095
|
+
} finally {
|
|
13096
|
+
tagIdentityWriteGeneration += 1;
|
|
13097
|
+
}
|
|
13098
|
+
}
|
|
13099
|
+
});
|
|
13100
|
+
}
|
|
13101
|
+
if (typeof statement.values === "function") {
|
|
13102
|
+
const values = statement.values.bind(statement);
|
|
13103
|
+
Object.defineProperty(statement, "values", {
|
|
13104
|
+
configurable: true,
|
|
13105
|
+
value: (...args) => {
|
|
13106
|
+
try {
|
|
13107
|
+
return values(...args);
|
|
13108
|
+
} finally {
|
|
13109
|
+
tagIdentityWriteGeneration += 1;
|
|
13110
|
+
}
|
|
13111
|
+
}
|
|
13112
|
+
});
|
|
13113
|
+
}
|
|
13114
|
+
}
|
|
12998
13115
|
function trackSqliteConnection(db, filename, options) {
|
|
12999
13116
|
const originalClose = db.close.bind(db);
|
|
13000
13117
|
const sequence = nextSqliteConnectionSequence++;
|
|
@@ -13054,6 +13171,10 @@ function getSqliteDatabasePath(db) {
|
|
|
13054
13171
|
return connection.filename === ":memory:" || connection.filename === "<buffer>" ? null : connection.filename;
|
|
13055
13172
|
}
|
|
13056
13173
|
}
|
|
13174
|
+
const native = db;
|
|
13175
|
+
const path = native.filename ?? native.name;
|
|
13176
|
+
if (typeof path === "string" && path !== ":memory:" && path !== "")
|
|
13177
|
+
return path;
|
|
13057
13178
|
return null;
|
|
13058
13179
|
}
|
|
13059
13180
|
function pragmaValue(db, name) {
|
|
@@ -13135,6 +13256,15 @@ function getSqliteMemoryStats() {
|
|
|
13135
13256
|
connections
|
|
13136
13257
|
};
|
|
13137
13258
|
}
|
|
13259
|
+
function closeReleasingStatements(close, args) {
|
|
13260
|
+
if (args[0] === true)
|
|
13261
|
+
return close(true);
|
|
13262
|
+
try {
|
|
13263
|
+
return close(true);
|
|
13264
|
+
} catch {
|
|
13265
|
+
return close(...args);
|
|
13266
|
+
}
|
|
13267
|
+
}
|
|
13138
13268
|
function ownPreparedStatement(db, statement) {
|
|
13139
13269
|
const finalizable = statement;
|
|
13140
13270
|
if (typeof finalizable.finalize !== "function")
|
|
@@ -13158,7 +13288,7 @@ function ownPreparedStatement(db, statement) {
|
|
|
13158
13288
|
}
|
|
13159
13289
|
}
|
|
13160
13290
|
references.clear();
|
|
13161
|
-
const result = close
|
|
13291
|
+
const result = closeReleasingStatements(close, args);
|
|
13162
13292
|
if (failure)
|
|
13163
13293
|
throw failure;
|
|
13164
13294
|
return result;
|
|
@@ -13188,22 +13318,29 @@ function withSqliteTransformPass(operation) {
|
|
|
13188
13318
|
const existing = transformPassScope.getStore();
|
|
13189
13319
|
if (existing?.active)
|
|
13190
13320
|
return operation();
|
|
13191
|
-
const
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
|
|
13198
|
-
|
|
13321
|
+
const reservation = reserveForegroundSqliteTurn();
|
|
13322
|
+
const run = (release) => {
|
|
13323
|
+
const lease = { active: true, remainingWaitMs: FOREGROUND_IN_PASS_BUSY_TIMEOUT_MS };
|
|
13324
|
+
return transformPassScope.run(lease, () => {
|
|
13325
|
+
try {
|
|
13326
|
+
const result = operation();
|
|
13327
|
+
if (result && typeof result.then === "function") {
|
|
13328
|
+
return Promise.resolve(result).finally(() => {
|
|
13329
|
+
lease.active = false;
|
|
13330
|
+
release();
|
|
13331
|
+
});
|
|
13332
|
+
}
|
|
13333
|
+
lease.active = false;
|
|
13334
|
+
release();
|
|
13335
|
+
return result;
|
|
13336
|
+
} catch (error) {
|
|
13337
|
+
lease.active = false;
|
|
13338
|
+
release();
|
|
13339
|
+
throw error;
|
|
13199
13340
|
}
|
|
13200
|
-
|
|
13201
|
-
|
|
13202
|
-
|
|
13203
|
-
lease.active = false;
|
|
13204
|
-
throw error;
|
|
13205
|
-
}
|
|
13206
|
-
});
|
|
13341
|
+
});
|
|
13342
|
+
};
|
|
13343
|
+
return typeof reservation === "function" ? run(reservation) : reservation.then(run);
|
|
13207
13344
|
}
|
|
13208
13345
|
function withoutSqliteTransformPass(operation) {
|
|
13209
13346
|
return transformPassScope.run(undefined, operation);
|
|
@@ -13291,18 +13428,20 @@ function acquireShort(db, acquire, site) {
|
|
|
13291
13428
|
}
|
|
13292
13429
|
function endWriterTransaction(db, end, sql) {
|
|
13293
13430
|
let ended = false;
|
|
13431
|
+
const endStarted = performance.now();
|
|
13294
13432
|
try {
|
|
13295
13433
|
const result = end();
|
|
13296
13434
|
ended = true;
|
|
13297
13435
|
return result;
|
|
13298
13436
|
} finally {
|
|
13299
13437
|
const open = openWriterTransactions.get(db);
|
|
13438
|
+
const endMs = performance.now() - endStarted;
|
|
13300
13439
|
if (open && !isInTransaction(db)) {
|
|
13301
13440
|
openWriterTransactions.delete(db);
|
|
13302
13441
|
const holdMs = performance.now() - open.acquiredAt;
|
|
13303
13442
|
if (open.acquireMs >= SLOW_WRITER_LOG_MS || holdMs >= SLOW_WRITER_LOG_MS) {
|
|
13304
13443
|
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}`);
|
|
13444
|
+
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
13445
|
}
|
|
13307
13446
|
}
|
|
13308
13447
|
}
|
|
@@ -13442,7 +13581,55 @@ function withPrivilegedWriter(db, operation) {
|
|
|
13442
13581
|
throw error;
|
|
13443
13582
|
}
|
|
13444
13583
|
}
|
|
13445
|
-
|
|
13584
|
+
function indexCoordinationInput() {
|
|
13585
|
+
return {
|
|
13586
|
+
indexCoordination: indexCoordinationBuffer,
|
|
13587
|
+
indexOwner: Atomics.add(indexCoordinationState, 2, 1) + 1
|
|
13588
|
+
};
|
|
13589
|
+
}
|
|
13590
|
+
function reserveForegroundSqliteTurn() {
|
|
13591
|
+
Atomics.add(indexCoordinationState, 0, 1);
|
|
13592
|
+
const release = () => {
|
|
13593
|
+
Atomics.sub(indexCoordinationState, 0, 1);
|
|
13594
|
+
Atomics.notify(indexCoordinationState, 0);
|
|
13595
|
+
};
|
|
13596
|
+
if (Atomics.load(indexCoordinationState, 1) === 0)
|
|
13597
|
+
return release;
|
|
13598
|
+
return (async () => {
|
|
13599
|
+
while (Atomics.load(indexCoordinationState, 1) !== 0)
|
|
13600
|
+
await yieldIndexTurn();
|
|
13601
|
+
return release;
|
|
13602
|
+
})();
|
|
13603
|
+
}
|
|
13604
|
+
function releaseIndexOwner(input) {
|
|
13605
|
+
if (!input.indexCoordination || !input.indexOwner)
|
|
13606
|
+
return;
|
|
13607
|
+
const shared = new Int32Array(input.indexCoordination);
|
|
13608
|
+
Atomics.compareExchange(shared, 1, input.indexOwner, 0);
|
|
13609
|
+
Atomics.notify(shared, 1);
|
|
13610
|
+
}
|
|
13611
|
+
async function withIndexChunk(input, operation) {
|
|
13612
|
+
if (!input.indexCoordination || !input.indexOwner)
|
|
13613
|
+
return operation();
|
|
13614
|
+
const shared = new Int32Array(input.indexCoordination);
|
|
13615
|
+
for (;; ) {
|
|
13616
|
+
if (Atomics.load(shared, 0) === 0 && Atomics.compareExchange(shared, 1, 0, input.indexOwner) === 0) {
|
|
13617
|
+
if (Atomics.load(shared, 0) === 0)
|
|
13618
|
+
break;
|
|
13619
|
+
releaseIndexOwner(input);
|
|
13620
|
+
}
|
|
13621
|
+
await yieldIndexTurn();
|
|
13622
|
+
}
|
|
13623
|
+
try {
|
|
13624
|
+
return await operation();
|
|
13625
|
+
} finally {
|
|
13626
|
+
releaseIndexOwner(input);
|
|
13627
|
+
}
|
|
13628
|
+
}
|
|
13629
|
+
async function yieldIndexChunk() {
|
|
13630
|
+
await yieldIndexTurn();
|
|
13631
|
+
}
|
|
13632
|
+
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
13633
|
var init_sqlite = __esm(async () => {
|
|
13447
13634
|
bunSpec = "bun:" + "sqlite";
|
|
13448
13635
|
nodeSpec = "node:" + "sqlite";
|
|
@@ -13462,6 +13649,19 @@ var init_sqlite = __esm(async () => {
|
|
|
13462
13649
|
sqliteModule = await loadSqliteModule(detectedRuntime);
|
|
13463
13650
|
DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
|
|
13464
13651
|
trackedSqliteConnections = new Map;
|
|
13652
|
+
TAG_COLUMNS_OUTSIDE_IDENTITY = new Set([
|
|
13653
|
+
"status",
|
|
13654
|
+
"drop_mode",
|
|
13655
|
+
"byte_size",
|
|
13656
|
+
"input_byte_size",
|
|
13657
|
+
"reasoning_byte_size",
|
|
13658
|
+
"token_count",
|
|
13659
|
+
"input_token_count",
|
|
13660
|
+
"caveman_depth",
|
|
13661
|
+
"entry_fingerprint",
|
|
13662
|
+
"tool_name",
|
|
13663
|
+
"harness"
|
|
13664
|
+
]);
|
|
13465
13665
|
TrackedDatabase = new Proxy(DatabaseImpl, {
|
|
13466
13666
|
construct(target, args) {
|
|
13467
13667
|
const db = Reflect.construct(target, args, target);
|
|
@@ -13486,6 +13686,11 @@ var init_sqlite = __esm(async () => {
|
|
|
13486
13686
|
WRITER_TRANSACTION_END = /^\s*(?:COMMIT|END|ROLLBACK)(?:\s+TRANSACTION)?\s*;?\s*$/i;
|
|
13487
13687
|
writerAcquisitionScope = new AsyncLocalStorage;
|
|
13488
13688
|
openWriterTransactions = new WeakMap;
|
|
13689
|
+
indexCoordinationKey = Symbol.for("magic-context.index-foreground-coordination.v1");
|
|
13690
|
+
indexCoordinationHeap = globalThis;
|
|
13691
|
+
indexCoordinationBuffer = indexCoordinationHeap[indexCoordinationKey] ?? new SharedArrayBuffer(3 * Int32Array.BYTES_PER_ELEMENT);
|
|
13692
|
+
indexCoordinationHeap[indexCoordinationKey] = indexCoordinationBuffer;
|
|
13693
|
+
indexCoordinationState = new Int32Array(indexCoordinationBuffer);
|
|
13489
13694
|
});
|
|
13490
13695
|
|
|
13491
13696
|
// src/lib/docs-proposal-gitignore.ts
|
|
@@ -22933,6 +23138,22 @@ function readConfiguredOpenCodePluginSpec(config) {
|
|
|
22933
23138
|
}
|
|
22934
23139
|
return "latest";
|
|
22935
23140
|
}
|
|
23141
|
+
function readReferencedOpenCodePluginSpecs(config, host) {
|
|
23142
|
+
const specs = new Set;
|
|
23143
|
+
for (const { key, entry } of readPluginEntries(config)) {
|
|
23144
|
+
if (host === "opencode1" && key !== "plugin")
|
|
23145
|
+
continue;
|
|
23146
|
+
const specifier = pluginEntrySpecifier(entry);
|
|
23147
|
+
const spec = specifier === undefined ? undefined : openCodeV2PluginSpecOf(specifier);
|
|
23148
|
+
if (spec !== undefined)
|
|
23149
|
+
specs.add(spec);
|
|
23150
|
+
}
|
|
23151
|
+
return specs;
|
|
23152
|
+
}
|
|
23153
|
+
function describeUnusedOpenCodePluginCache(input) {
|
|
23154
|
+
const why = input.loadedFrom ? `the config loads Magic Context from ${input.loadedFrom}` : `no ${input.host} plugin entry in the config references it`;
|
|
23155
|
+
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(", ")}`;
|
|
23156
|
+
}
|
|
22936
23157
|
function pluginEntrySpecifier(entry) {
|
|
22937
23158
|
if (typeof entry === "string")
|
|
22938
23159
|
return entry;
|
|
@@ -23158,6 +23379,9 @@ function checkOpenCodeV2PluginCache(options, deps = {}) {
|
|
|
23158
23379
|
const distTag = options.distTag && options.distTag !== "latest" ? options.distTag : undefined;
|
|
23159
23380
|
const slot = deps.slot ?? getOpenCodeV2PluginCacheSlot(undefined, distTag ?? "latest");
|
|
23160
23381
|
const tagged = distTag ? { distTag } : {};
|
|
23382
|
+
if (options.referencedSpecs !== undefined && !options.referencedSpecs.has(distTag ?? "latest")) {
|
|
23383
|
+
return existsSync13(slot) ? { action: "unused", slot, cached: readOpenCodeV2CachedPluginVersion(slot), ...tagged } : { action: "not_found", slot, unused: true, ...tagged };
|
|
23384
|
+
}
|
|
23161
23385
|
if (!existsSync13(slot))
|
|
23162
23386
|
return { action: "not_found", slot, ...tagged };
|
|
23163
23387
|
const cached = readOpenCodeV2CachedPluginVersion(slot);
|
|
@@ -23197,7 +23421,7 @@ function reportOpenCodeV2PluginCache(result, report, options) {
|
|
|
23197
23421
|
const slotName = result.distTag ? ` @${result.distTag}` : "";
|
|
23198
23422
|
switch (result.action) {
|
|
23199
23423
|
case "not_found":
|
|
23200
|
-
if (options.reportMissing) {
|
|
23424
|
+
if (options.reportMissing && !result.unused) {
|
|
23201
23425
|
report.pass(`OpenCode 2 plugin cache has no Magic Context${slotName} install yet (OpenCode installs it on next start)`);
|
|
23202
23426
|
}
|
|
23203
23427
|
return { fixed: false, issue: false };
|
|
@@ -23225,6 +23449,15 @@ function reportOpenCodeV2PluginCache(result, report, options) {
|
|
|
23225
23449
|
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
23450
|
report.info(` ${result.slot}`);
|
|
23227
23451
|
return { fixed: true, issue: false };
|
|
23452
|
+
case "unused":
|
|
23453
|
+
report.info(describeUnusedOpenCodePluginCache({
|
|
23454
|
+
host: "OpenCode 2",
|
|
23455
|
+
spec: tag,
|
|
23456
|
+
cached: result.cached,
|
|
23457
|
+
paths: [result.slot],
|
|
23458
|
+
loadedFrom: options.loadedFrom
|
|
23459
|
+
}));
|
|
23460
|
+
return { fixed: false, issue: false };
|
|
23228
23461
|
case "error":
|
|
23229
23462
|
report.warn(`Could not clear the OpenCode 2 plugin cache: ${result.error}`);
|
|
23230
23463
|
report.info(` Manually delete: ${result.slot}`);
|
|
@@ -28760,6 +28993,26 @@ var init_migrations = __esm(async () => {
|
|
|
28760
28993
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
28761
28994
|
});
|
|
28762
28995
|
|
|
28996
|
+
// ../plugin/src/features/magic-context/storage-tag-identity-revision.ts
|
|
28997
|
+
function installTagIdentityRevisionTrigger(db) {
|
|
28998
|
+
db.exec(TRIGGER_SQL);
|
|
28999
|
+
}
|
|
29000
|
+
var TAG_IDENTITY_REVISION_PREFIX = "tag_identity_revision:", BUMP = (session) => `INSERT INTO schema_migrations_meta (key, value)
|
|
29001
|
+
VALUES ('${TAG_IDENTITY_REVISION_PREFIX}' || ${session}, '1')
|
|
29002
|
+
ON CONFLICT(key) DO UPDATE SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT)`, TRIGGER_SQL;
|
|
29003
|
+
var init_storage_tag_identity_revision = __esm(() => {
|
|
29004
|
+
TRIGGER_SQL = `CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_identity_revision_au
|
|
29005
|
+
AFTER UPDATE OF id, session_id, message_id, tag_number, type, tool_owner_message_id, reasoning_token_count
|
|
29006
|
+
ON main.tags
|
|
29007
|
+
BEGIN
|
|
29008
|
+
${BUMP("OLD.session_id")};
|
|
29009
|
+
INSERT INTO schema_migrations_meta (key, value)
|
|
29010
|
+
SELECT '${TAG_IDENTITY_REVISION_PREFIX}' || NEW.session_id, '1'
|
|
29011
|
+
WHERE NEW.session_id IS NOT OLD.session_id
|
|
29012
|
+
ON CONFLICT(key) DO UPDATE SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT);
|
|
29013
|
+
END`;
|
|
29014
|
+
});
|
|
29015
|
+
|
|
28763
29016
|
// ../plugin/src/shared/commit-detection.ts
|
|
28764
29017
|
function createCommitHashExtractPattern() {
|
|
28765
29018
|
return new RegExp(`\`?\\b(${HASH_HEX})\\b\`?`, "gi");
|
|
@@ -28782,6 +29035,271 @@ function removeSystemReminders(text) {
|
|
|
28782
29035
|
}
|
|
28783
29036
|
var SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: MAGIC-CONTEXT";
|
|
28784
29037
|
|
|
29038
|
+
// ../plugin/src/hooks/magic-context/token-count-exact.ts
|
|
29039
|
+
function hasInternals(tokenizer) {
|
|
29040
|
+
const value = tokenizer;
|
|
29041
|
+
return !!value && value.patternRegex instanceof RegExp && value.patternRegex.global && typeof value.stringRankEncoder === "object" && value.stringRankEncoder !== null && Array.isArray(value.binaryFirstByteIndex);
|
|
29042
|
+
}
|
|
29043
|
+
function isValidUtf8(bytes) {
|
|
29044
|
+
let index = 0;
|
|
29045
|
+
while (index < bytes.length) {
|
|
29046
|
+
const first = bytes[index];
|
|
29047
|
+
let size = 0;
|
|
29048
|
+
let codePoint = 0;
|
|
29049
|
+
if (first <= 127) {
|
|
29050
|
+
size = 1;
|
|
29051
|
+
codePoint = first;
|
|
29052
|
+
} else if ((first & 224) === 192) {
|
|
29053
|
+
size = 2;
|
|
29054
|
+
codePoint = first & 31;
|
|
29055
|
+
if (first <= 193)
|
|
29056
|
+
return false;
|
|
29057
|
+
} else if ((first & 240) === 224) {
|
|
29058
|
+
size = 3;
|
|
29059
|
+
codePoint = first & 15;
|
|
29060
|
+
} else if ((first & 248) === 240) {
|
|
29061
|
+
size = 4;
|
|
29062
|
+
codePoint = first & 7;
|
|
29063
|
+
if (first > 244)
|
|
29064
|
+
return false;
|
|
29065
|
+
} else
|
|
29066
|
+
return false;
|
|
29067
|
+
if (index + size > bytes.length)
|
|
29068
|
+
return false;
|
|
29069
|
+
for (let offset = 1;offset < size; offset += 1) {
|
|
29070
|
+
const byte = bytes[index + offset];
|
|
29071
|
+
if ((byte & 192) !== 128)
|
|
29072
|
+
return false;
|
|
29073
|
+
codePoint = codePoint << 6 | byte & 63;
|
|
29074
|
+
}
|
|
29075
|
+
if (size === 2 && codePoint < 128)
|
|
29076
|
+
return false;
|
|
29077
|
+
if (size === 3 && codePoint < 2048)
|
|
29078
|
+
return false;
|
|
29079
|
+
if (size === 4 && codePoint < 65536)
|
|
29080
|
+
return false;
|
|
29081
|
+
if (codePoint >= 55296 && codePoint <= 57343)
|
|
29082
|
+
return false;
|
|
29083
|
+
if (codePoint > 1114111)
|
|
29084
|
+
return false;
|
|
29085
|
+
index += size;
|
|
29086
|
+
}
|
|
29087
|
+
return true;
|
|
29088
|
+
}
|
|
29089
|
+
function binarySearchBytes(sorted, key) {
|
|
29090
|
+
let low = 0;
|
|
29091
|
+
let high = sorted.length - 1;
|
|
29092
|
+
while (low <= high) {
|
|
29093
|
+
const mid = low + high >>> 1;
|
|
29094
|
+
const midKey = sorted[mid][0];
|
|
29095
|
+
let compare = 0;
|
|
29096
|
+
const shared = Math.min(midKey.length, key.length);
|
|
29097
|
+
for (let index = 0;index < shared; index += 1) {
|
|
29098
|
+
compare = midKey[index] - key[index];
|
|
29099
|
+
if (compare !== 0)
|
|
29100
|
+
break;
|
|
29101
|
+
}
|
|
29102
|
+
if (compare === 0)
|
|
29103
|
+
compare = midKey.length - key.length;
|
|
29104
|
+
if (compare === 0)
|
|
29105
|
+
return sorted[mid][1];
|
|
29106
|
+
if (compare < 0)
|
|
29107
|
+
low = mid + 1;
|
|
29108
|
+
else
|
|
29109
|
+
high = mid - 1;
|
|
29110
|
+
}
|
|
29111
|
+
return -1;
|
|
29112
|
+
}
|
|
29113
|
+
function rankOf(tokenizer, slice) {
|
|
29114
|
+
if (isValidUtf8(slice)) {
|
|
29115
|
+
const rank = tokenizer.stringRankEncoder[textDecoder.decode(slice)];
|
|
29116
|
+
if (rank !== undefined)
|
|
29117
|
+
return rank;
|
|
29118
|
+
}
|
|
29119
|
+
const bucket = tokenizer.binaryFirstByteIndex[slice[0]];
|
|
29120
|
+
if (bucket !== null && bucket !== undefined) {
|
|
29121
|
+
const rank = binarySearchBytes(bucket, slice);
|
|
29122
|
+
if (rank !== -1)
|
|
29123
|
+
return rank;
|
|
29124
|
+
}
|
|
29125
|
+
return NO_RANK;
|
|
29126
|
+
}
|
|
29127
|
+
function mergeByScanning(tokenizer, bytes) {
|
|
29128
|
+
const starts = [];
|
|
29129
|
+
const ranks = [];
|
|
29130
|
+
const pairRank = (index) => {
|
|
29131
|
+
const end = starts[index + 2];
|
|
29132
|
+
return end === undefined ? NO_RANK : rankOf(tokenizer, bytes.subarray(starts[index], end));
|
|
29133
|
+
};
|
|
29134
|
+
for (let index = 0;index <= bytes.length; index += 1)
|
|
29135
|
+
starts.push(index);
|
|
29136
|
+
for (let index = 0;index < starts.length; index += 1)
|
|
29137
|
+
ranks.push(pairRank(index));
|
|
29138
|
+
while (starts.length > 1) {
|
|
29139
|
+
let minRank = NO_RANK;
|
|
29140
|
+
let minIndex = -1;
|
|
29141
|
+
for (let index = 0;index < ranks.length - 1; index += 1) {
|
|
29142
|
+
if (ranks[index] < minRank) {
|
|
29143
|
+
minRank = ranks[index];
|
|
29144
|
+
minIndex = index;
|
|
29145
|
+
}
|
|
29146
|
+
}
|
|
29147
|
+
if (minIndex === -1)
|
|
29148
|
+
break;
|
|
29149
|
+
starts.splice(minIndex + 1, 1);
|
|
29150
|
+
ranks.splice(minIndex, 1);
|
|
29151
|
+
ranks[minIndex] = pairRank(minIndex);
|
|
29152
|
+
if (minIndex > 0)
|
|
29153
|
+
ranks[minIndex - 1] = pairRank(minIndex - 1);
|
|
29154
|
+
}
|
|
29155
|
+
const tokens = [];
|
|
29156
|
+
for (let index = 0;index < starts.length - 1; index += 1) {
|
|
29157
|
+
const rank = rankOf(tokenizer, bytes.subarray(starts[index], starts[index + 1]));
|
|
29158
|
+
if (rank !== NO_RANK)
|
|
29159
|
+
tokens.push(rank);
|
|
29160
|
+
}
|
|
29161
|
+
return tokens;
|
|
29162
|
+
}
|
|
29163
|
+
function mergeWithHeap(tokenizer, bytes) {
|
|
29164
|
+
const length = bytes.length;
|
|
29165
|
+
const next = new Int32Array(length + 1);
|
|
29166
|
+
const prev = new Int32Array(length + 1);
|
|
29167
|
+
const alive = new Uint8Array(length + 1).fill(1);
|
|
29168
|
+
const rank = new Float64Array(length + 1).fill(NO_RANK);
|
|
29169
|
+
for (let index = 0;index <= length; index += 1) {
|
|
29170
|
+
next[index] = index + 1;
|
|
29171
|
+
prev[index] = index - 1;
|
|
29172
|
+
}
|
|
29173
|
+
const heapRank = [];
|
|
29174
|
+
const heapAt = [];
|
|
29175
|
+
const less = (a, b) => heapRank[a] < heapRank[b] || heapRank[a] === heapRank[b] && heapAt[a] < heapAt[b];
|
|
29176
|
+
const swap = (a, b) => {
|
|
29177
|
+
[heapRank[a], heapRank[b]] = [heapRank[b], heapRank[a]];
|
|
29178
|
+
[heapAt[a], heapAt[b]] = [heapAt[b], heapAt[a]];
|
|
29179
|
+
};
|
|
29180
|
+
const push = (value, at) => {
|
|
29181
|
+
heapRank.push(value);
|
|
29182
|
+
heapAt.push(at);
|
|
29183
|
+
let child = heapRank.length - 1;
|
|
29184
|
+
while (child > 0) {
|
|
29185
|
+
const parent = child - 1 >> 1;
|
|
29186
|
+
if (!less(child, parent))
|
|
29187
|
+
break;
|
|
29188
|
+
swap(child, parent);
|
|
29189
|
+
child = parent;
|
|
29190
|
+
}
|
|
29191
|
+
};
|
|
29192
|
+
const pop = () => {
|
|
29193
|
+
const last = heapRank.length - 1;
|
|
29194
|
+
swap(0, last);
|
|
29195
|
+
heapRank.pop();
|
|
29196
|
+
heapAt.pop();
|
|
29197
|
+
let parent = 0;
|
|
29198
|
+
for (;; ) {
|
|
29199
|
+
const left = parent * 2 + 1;
|
|
29200
|
+
const right = left + 1;
|
|
29201
|
+
let smallest = parent;
|
|
29202
|
+
if (left < heapRank.length && less(left, smallest))
|
|
29203
|
+
smallest = left;
|
|
29204
|
+
if (right < heapRank.length && less(right, smallest))
|
|
29205
|
+
smallest = right;
|
|
29206
|
+
if (smallest === parent)
|
|
29207
|
+
break;
|
|
29208
|
+
swap(parent, smallest);
|
|
29209
|
+
parent = smallest;
|
|
29210
|
+
}
|
|
29211
|
+
};
|
|
29212
|
+
const pairRank = (at) => {
|
|
29213
|
+
const middle = next[at];
|
|
29214
|
+
if (middle >= length)
|
|
29215
|
+
return NO_RANK;
|
|
29216
|
+
return rankOf(tokenizer, bytes.subarray(at, next[middle]));
|
|
29217
|
+
};
|
|
29218
|
+
const update = (at) => {
|
|
29219
|
+
rank[at] = pairRank(at);
|
|
29220
|
+
if (rank[at] !== NO_RANK)
|
|
29221
|
+
push(rank[at], at);
|
|
29222
|
+
};
|
|
29223
|
+
for (let at = 0;at < length; at += 1)
|
|
29224
|
+
update(at);
|
|
29225
|
+
while (heapRank.length > 0) {
|
|
29226
|
+
const value = heapRank[0];
|
|
29227
|
+
const at = heapAt[0];
|
|
29228
|
+
pop();
|
|
29229
|
+
if (!alive[at] || rank[at] !== value)
|
|
29230
|
+
continue;
|
|
29231
|
+
const removed = next[at];
|
|
29232
|
+
alive[removed] = 0;
|
|
29233
|
+
next[at] = next[removed];
|
|
29234
|
+
prev[next[removed]] = at;
|
|
29235
|
+
update(at);
|
|
29236
|
+
if (at > 0)
|
|
29237
|
+
update(prev[at]);
|
|
29238
|
+
}
|
|
29239
|
+
const tokens = [];
|
|
29240
|
+
for (let at = 0;at < length; at = next[at]) {
|
|
29241
|
+
const value = rankOf(tokenizer, bytes.subarray(at, next[at]));
|
|
29242
|
+
if (value !== NO_RANK)
|
|
29243
|
+
tokens.push(value);
|
|
29244
|
+
}
|
|
29245
|
+
return tokens;
|
|
29246
|
+
}
|
|
29247
|
+
function mergePiece(tokenizer, piece) {
|
|
29248
|
+
let cache = mergeCaches.get(tokenizer);
|
|
29249
|
+
if (!cache) {
|
|
29250
|
+
cache = { current: new Map, previous: new Map };
|
|
29251
|
+
mergeCaches.set(tokenizer, cache);
|
|
29252
|
+
}
|
|
29253
|
+
let tokens = cache.current.get(piece);
|
|
29254
|
+
if (tokens)
|
|
29255
|
+
return tokens;
|
|
29256
|
+
tokens = cache.previous.get(piece);
|
|
29257
|
+
if (!tokens) {
|
|
29258
|
+
const bytes = textEncoder.encode(piece);
|
|
29259
|
+
mergedPieces += 1;
|
|
29260
|
+
tokens = bytes.length > LONG_PIECE_BYTES ? mergeWithHeap(tokenizer, bytes) : mergeByScanning(tokenizer, bytes);
|
|
29261
|
+
}
|
|
29262
|
+
if (cache.current.size >= MERGE_CACHE_GENERATION) {
|
|
29263
|
+
cache.previous = cache.current;
|
|
29264
|
+
cache.current = new Map;
|
|
29265
|
+
}
|
|
29266
|
+
cache.current.set(piece, tokens);
|
|
29267
|
+
return tokens;
|
|
29268
|
+
}
|
|
29269
|
+
function encodeTokensExactly(tokenizer, text) {
|
|
29270
|
+
if (!hasInternals(tokenizer)) {
|
|
29271
|
+
return tokenizer.encode(text, "all");
|
|
29272
|
+
}
|
|
29273
|
+
if (text.length < 10) {
|
|
29274
|
+
const direct = tokenizer.stringRankEncoder[text];
|
|
29275
|
+
if (direct !== undefined)
|
|
29276
|
+
return [direct];
|
|
29277
|
+
}
|
|
29278
|
+
const tokens = [];
|
|
29279
|
+
const regex = tokenizer.patternRegex;
|
|
29280
|
+
regex.lastIndex = 0;
|
|
29281
|
+
for (let match = regex.exec(text);match !== null; match = regex.exec(text)) {
|
|
29282
|
+
const piece = match[0];
|
|
29283
|
+
const direct = tokenizer.stringRankEncoder[piece];
|
|
29284
|
+
if (direct !== undefined) {
|
|
29285
|
+
tokens.push(direct);
|
|
29286
|
+
continue;
|
|
29287
|
+
}
|
|
29288
|
+
for (const token of mergePiece(tokenizer, piece))
|
|
29289
|
+
tokens.push(token);
|
|
29290
|
+
}
|
|
29291
|
+
return tokens;
|
|
29292
|
+
}
|
|
29293
|
+
function countTokensExactly(tokenizer, text) {
|
|
29294
|
+
return encodeTokensExactly(tokenizer, text).length;
|
|
29295
|
+
}
|
|
29296
|
+
var NO_RANK = 4294967295, LONG_PIECE_BYTES = 256, MERGE_CACHE_GENERATION = 50000, textEncoder, textDecoder, mergeCaches, mergedPieces = 0;
|
|
29297
|
+
var init_token_count_exact = __esm(() => {
|
|
29298
|
+
textEncoder = new TextEncoder;
|
|
29299
|
+
textDecoder = new TextDecoder("utf-8");
|
|
29300
|
+
mergeCaches = new WeakMap;
|
|
29301
|
+
});
|
|
29302
|
+
|
|
28785
29303
|
// ../plugin/src/hooks/magic-context/read-session-formatting.ts
|
|
28786
29304
|
import { createRequire as createRequire2 } from "node:module";
|
|
28787
29305
|
function hasMeaningfulUserText(parts) {
|
|
@@ -28924,7 +29442,7 @@ function estimateTokens(text) {
|
|
|
28924
29442
|
if (!activeTokenizer)
|
|
28925
29443
|
return estimateTokensHeuristically(text);
|
|
28926
29444
|
try {
|
|
28927
|
-
return activeTokenizer
|
|
29445
|
+
return countTokensExactly(activeTokenizer, text);
|
|
28928
29446
|
} catch (error) {
|
|
28929
29447
|
tokenizer = undefined;
|
|
28930
29448
|
tokenizerLoadAttempted = true;
|
|
@@ -29015,21 +29533,41 @@ var MAX_COMMITS_PER_BLOCK = 5, tokenizer, tokenizerLoadAttempted = false, tokeni
|
|
|
29015
29533
|
var init_read_session_formatting = __esm(() => {
|
|
29016
29534
|
init_commit_detection();
|
|
29017
29535
|
init_logger();
|
|
29536
|
+
init_token_count_exact();
|
|
29018
29537
|
promptTokenCounts = new Map;
|
|
29019
29538
|
PROMPT_TOKEN_COUNT_BYTES = 8 * 1024 * 1024;
|
|
29020
29539
|
});
|
|
29021
29540
|
|
|
29022
29541
|
// ../plugin/src/shared/stable-json.ts
|
|
29023
29542
|
function stableStringify(value, seen = new WeakSet) {
|
|
29024
|
-
|
|
29025
|
-
|
|
29026
|
-
|
|
29027
|
-
|
|
29028
|
-
|
|
29029
|
-
|
|
29543
|
+
const pieces = [];
|
|
29544
|
+
writeStable(value, seen, pieces);
|
|
29545
|
+
return pieces.join("");
|
|
29546
|
+
}
|
|
29547
|
+
function writeStable(value, seen, pieces) {
|
|
29548
|
+
if (value === undefined) {
|
|
29549
|
+
pieces.push("undefined");
|
|
29550
|
+
return;
|
|
29551
|
+
}
|
|
29552
|
+
if (value === null || typeof value !== "object") {
|
|
29553
|
+
pieces.push(JSON.stringify(value) ?? String(value));
|
|
29554
|
+
return;
|
|
29555
|
+
}
|
|
29556
|
+
if (seen.has(value)) {
|
|
29557
|
+
pieces.push('"[Circular]"');
|
|
29558
|
+
return;
|
|
29559
|
+
}
|
|
29030
29560
|
seen.add(value);
|
|
29031
29561
|
if (Array.isArray(value)) {
|
|
29032
|
-
|
|
29562
|
+
pieces.push("[");
|
|
29563
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
29564
|
+
if (index > 0)
|
|
29565
|
+
pieces.push(",");
|
|
29566
|
+
if (index in value)
|
|
29567
|
+
writeStable(value[index], seen, pieces);
|
|
29568
|
+
}
|
|
29569
|
+
pieces.push("]");
|
|
29570
|
+
return;
|
|
29033
29571
|
}
|
|
29034
29572
|
const entries = Object.entries(value).sort(([a], [b]) => {
|
|
29035
29573
|
if (a < b)
|
|
@@ -29038,7 +29576,14 @@ function stableStringify(value, seen = new WeakSet) {
|
|
|
29038
29576
|
return 1;
|
|
29039
29577
|
return 0;
|
|
29040
29578
|
});
|
|
29041
|
-
|
|
29579
|
+
pieces.push("{");
|
|
29580
|
+
entries.forEach(([key, child], index) => {
|
|
29581
|
+
if (index > 0)
|
|
29582
|
+
pieces.push(",");
|
|
29583
|
+
pieces.push(JSON.stringify(key), ":");
|
|
29584
|
+
writeStable(child, seen, pieces);
|
|
29585
|
+
});
|
|
29586
|
+
pieces.push("}");
|
|
29042
29587
|
}
|
|
29043
29588
|
|
|
29044
29589
|
// ../plugin/src/features/magic-context/tool-definition-tokens.ts
|
|
@@ -29724,6 +30269,19 @@ var init_image_token_estimate = __esm(() => {
|
|
|
29724
30269
|
JPEG_SCAN_LIMIT_BYTES = 256 * 1024;
|
|
29725
30270
|
});
|
|
29726
30271
|
|
|
30272
|
+
// ../plugin/src/hooks/magic-context/provider-visible-parts.ts
|
|
30273
|
+
var KEPT_TOOL_STATE_FIELDS;
|
|
30274
|
+
var init_provider_visible_parts = __esm(() => {
|
|
30275
|
+
KEPT_TOOL_STATE_FIELDS = new Set([
|
|
30276
|
+
"status",
|
|
30277
|
+
"input",
|
|
30278
|
+
"output",
|
|
30279
|
+
"error",
|
|
30280
|
+
"attachments",
|
|
30281
|
+
"content"
|
|
30282
|
+
]);
|
|
30283
|
+
});
|
|
30284
|
+
|
|
29727
30285
|
// ../plugin/src/hooks/magic-context/todo-view.ts
|
|
29728
30286
|
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
30287
|
var init_todo_view = __esm(() => {
|
|
@@ -29753,10 +30311,11 @@ var init_tail_hygiene_walk = __esm(() => {
|
|
|
29753
30311
|
init_reclaim_protection();
|
|
29754
30312
|
init_tag_owner_id();
|
|
29755
30313
|
init_image_token_estimate();
|
|
30314
|
+
init_provider_visible_parts();
|
|
29756
30315
|
init_read_session_formatting();
|
|
29757
30316
|
init_todo_view();
|
|
29758
30317
|
init_reclaim_protection();
|
|
29759
|
-
MAX_CONTENT_MEMO_BYTES =
|
|
30318
|
+
MAX_CONTENT_MEMO_BYTES = 256 * 1024 * 1024;
|
|
29760
30319
|
contentMemo = new Map;
|
|
29761
30320
|
contentMemoOrder = new Set;
|
|
29762
30321
|
baselineMeasurementMemo = new Map;
|
|
@@ -29822,12 +30381,14 @@ function pickNearestPriorOwner(candidates, currentMessageId, times) {
|
|
|
29822
30381
|
}
|
|
29823
30382
|
return best?.id ?? null;
|
|
29824
30383
|
}
|
|
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(() => {
|
|
30384
|
+
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, foldStatements, getOwnerScopedToolTagNumbersStatements, getMinMessageTagNumberForRawIdStatements, getActiveTagsBySessionStatements, getNullOwnerToolTagsBySessionStatements, getDroppedTagsBySessionStatements, getMaxDroppedTagNumberStatements, newestToolTagNumberStatements, droppedNumberStatements, tagByIdStatements, getToolTagNumberByOwnerStatements, getNullOwnerToolTagStatements, adoptNullOwnerToolTagStatements, getToolOwnerByTagIdStatements, deleteToolTagsByOwnerStatements;
|
|
30385
|
+
var init_storage_tags = __esm(async () => {
|
|
29827
30386
|
init_emergency_drop();
|
|
29828
30387
|
init_tag_owner_id();
|
|
29829
30388
|
init_migration_v95_perf_indexes();
|
|
29830
30389
|
init_storage_ops();
|
|
30390
|
+
init_storage_tag_identity_revision();
|
|
30391
|
+
await init_sqlite();
|
|
29831
30392
|
insertTagStatements = new WeakMap;
|
|
29832
30393
|
updateTagStatusStatements = new WeakMap;
|
|
29833
30394
|
updateTagDropModeStatements = new WeakMap;
|
|
@@ -29855,6 +30416,12 @@ var init_storage_tags = __esm(() => {
|
|
|
29855
30416
|
scopedActiveTokenTotalStatements = new WeakMap;
|
|
29856
30417
|
updateTagTokenCountStatements = new WeakMap;
|
|
29857
30418
|
updateTagInputTokenCountStatements = new WeakMap;
|
|
30419
|
+
tagOwnerSummaries = new WeakMap;
|
|
30420
|
+
TAG_OWNER_APPENDED_WITH_SHAPE_SQL = `SELECT ${TAG_OWNER_COLUMNS}, 0 AS shape, NULL AS tag_count, NULL AS max_id, NULL AS revision
|
|
30421
|
+
FROM tags WHERE id > ? AND +session_id = ?
|
|
30422
|
+
UNION ALL
|
|
30423
|
+
SELECT NULL, NULL, NULL, NULL, NULL, NULL, 1, COUNT(*), MAX(id), (SELECT value FROM schema_migrations_meta WHERE key = ?)
|
|
30424
|
+
FROM tags WHERE session_id = ?`;
|
|
29858
30425
|
inertWhitespaceStatements = new WeakMap;
|
|
29859
30426
|
foldStatements = new WeakMap;
|
|
29860
30427
|
getOwnerScopedToolTagNumbersStatements = new WeakMap;
|
|
@@ -29973,92 +30540,28 @@ function isHostUnservedRow(value) {
|
|
|
29973
30540
|
}
|
|
29974
30541
|
var HOST_UNSERVED_ROW = "hostUnservedRow";
|
|
29975
30542
|
|
|
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;
|
|
30543
|
+
// ../plugin/src/shared/exit-abort-registry.ts
|
|
30544
|
+
function abortAll() {
|
|
30545
|
+
for (const controller of controllers) {
|
|
30546
|
+
try {
|
|
30547
|
+
controller.abort();
|
|
30548
|
+
} catch {}
|
|
30011
30549
|
}
|
|
30012
|
-
cachedReadOnlyDb = { path: dbPath, db };
|
|
30013
|
-
clearOpenCodeDbReadFailure();
|
|
30014
|
-
return db;
|
|
30015
|
-
}
|
|
30016
|
-
function withReadOnlySessionDb(fn) {
|
|
30017
|
-
return fn(getReadOnlySessionDb());
|
|
30018
|
-
}
|
|
30019
|
-
function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
30020
|
-
const row = db.prepare(`SELECT COUNT(*) as count FROM message WHERE session_id = ?
|
|
30021
|
-
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
30022
|
-
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
|
|
30023
|
-
return typeof row?.count === "number" ? row.count : 0;
|
|
30024
30550
|
}
|
|
30025
|
-
function
|
|
30026
|
-
|
|
30027
|
-
if (
|
|
30551
|
+
function registerExitAbort(controller) {
|
|
30552
|
+
controllers.add(controller);
|
|
30553
|
+
if (listenerRegistered)
|
|
30028
30554
|
return;
|
|
30029
|
-
|
|
30030
|
-
|
|
30031
|
-
log(message);
|
|
30555
|
+
listenerRegistered = true;
|
|
30556
|
+
process.once("exit", abortAll);
|
|
30032
30557
|
}
|
|
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;
|
|
30558
|
+
var controllers, listenerRegistered = false;
|
|
30559
|
+
var init_exit_abort_registry = __esm(() => {
|
|
30560
|
+
controllers = new Set;
|
|
30059
30561
|
});
|
|
30060
30562
|
|
|
30061
30563
|
// ../plugin/src/hooks/magic-context/read-session-raw.ts
|
|
30564
|
+
import { isMainThread as isMainThread2 } from "node:worker_threads";
|
|
30062
30565
|
function isRawMessageRow(row) {
|
|
30063
30566
|
if (row === null || typeof row !== "object")
|
|
30064
30567
|
return false;
|
|
@@ -30118,7 +30621,7 @@ function readRawSessionMessagesFromDb(db, sessionId) {
|
|
|
30118
30621
|
if (messageIds.length === 0)
|
|
30119
30622
|
continue;
|
|
30120
30623
|
const placeholders = messageIds.map(() => "?").join(", ");
|
|
30121
|
-
const partRows = db.prepare(`SELECT message_id, data, time_updated
|
|
30624
|
+
const partRows = db.prepare(`SELECT message_id, ${RAW_PART_DATA_SQL} AS data, time_updated
|
|
30122
30625
|
FROM part
|
|
30123
30626
|
WHERE +session_id = ?
|
|
30124
30627
|
AND likelihood(message_id IN (${placeholders}), 0.000001)
|
|
@@ -30150,7 +30653,7 @@ function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, fin
|
|
|
30150
30653
|
if (messageRows.length === 0)
|
|
30151
30654
|
return [];
|
|
30152
30655
|
const placeholders = messageRows.map(() => "?").join(", ");
|
|
30153
|
-
const partRows = db.prepare(`SELECT message_id, data, time_updated
|
|
30656
|
+
const partRows = db.prepare(`SELECT message_id, ${RAW_PART_DATA_SQL} AS data, time_updated
|
|
30154
30657
|
FROM part
|
|
30155
30658
|
WHERE +session_id = ?
|
|
30156
30659
|
AND likelihood(message_id IN (${placeholders}), 0.000001)
|
|
@@ -30223,6 +30726,9 @@ function readRawSessionMessageSummaryPageFromDb(db, sessionId, afterOrdinal, lim
|
|
|
30223
30726
|
return assembleRawMessagePage(messageRows, partRows);
|
|
30224
30727
|
}
|
|
30225
30728
|
function countRawSessionMessageOrdinalsFromDb(db, sessionId) {
|
|
30729
|
+
const indexed = countCanonicalOrdinalsIndexed(db, sessionId, null, null);
|
|
30730
|
+
if (indexed !== null)
|
|
30731
|
+
return indexed;
|
|
30226
30732
|
const row = db.prepare(`SELECT COUNT(*) AS count
|
|
30227
30733
|
FROM message
|
|
30228
30734
|
WHERE session_id = ?
|
|
@@ -30309,7 +30815,7 @@ function readRawSessionTailFromDb(db, sessionId, baseOrdinal, anchorMessageId) {
|
|
|
30309
30815
|
for (let i = 0;i < ids.length; i += CHUNK) {
|
|
30310
30816
|
const slice = ids.slice(i, i + CHUNK);
|
|
30311
30817
|
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);
|
|
30818
|
+
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
30819
|
for (const part of partRows) {
|
|
30314
30820
|
const list = partsByMessageId.get(part.message_id) ?? [];
|
|
30315
30821
|
list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
|
|
@@ -30355,49 +30861,431 @@ function readRawSessionMessagePartsByIdFromDb(db, sessionId, messageId, onQuery)
|
|
|
30355
30861
|
version: row.time_updated ?? null
|
|
30356
30862
|
};
|
|
30357
30863
|
}
|
|
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;
|
|
30864
|
+
function ordinalRangeSql(lowerBound) {
|
|
30865
|
+
return `SELECT COUNT(*) AS visited,
|
|
30866
|
+
COALESCE(SUM(CASE WHEN ${ORDINAL_SUMMARY_FLAG_SQL} AND ${ORDINAL_STOP_FLAG_SQL}
|
|
30867
|
+
THEN 0 ELSE 1 END), 0) AS eligible
|
|
30868
|
+
FROM message
|
|
30869
|
+
WHERE session_id = ?
|
|
30870
|
+
${lowerBound ? "AND (time_created, id) > (?, ?)" : ""}
|
|
30871
|
+
AND (time_created, id) <= (?, ?)`;
|
|
30385
30872
|
}
|
|
30386
|
-
function
|
|
30387
|
-
|
|
30388
|
-
|
|
30873
|
+
function readStoreStamp(db) {
|
|
30874
|
+
try {
|
|
30875
|
+
const row = db.prepare(`SELECT data_version AS dataVersion, total_changes() AS totalChanges,
|
|
30876
|
+
(SELECT schema_version FROM pragma_schema_version) AS schemaVersion
|
|
30877
|
+
FROM pragma_data_version`).get();
|
|
30878
|
+
if (typeof row?.dataVersion !== "number" || typeof row.totalChanges !== "number" || typeof row.schemaVersion !== "number")
|
|
30879
|
+
return null;
|
|
30880
|
+
return {
|
|
30881
|
+
dataVersion: row.dataVersion,
|
|
30882
|
+
totalChanges: row.totalChanges,
|
|
30883
|
+
schemaVersion: row.schemaVersion
|
|
30884
|
+
};
|
|
30885
|
+
} catch {
|
|
30389
30886
|
return null;
|
|
30390
30887
|
}
|
|
30391
|
-
|
|
30392
|
-
|
|
30888
|
+
}
|
|
30889
|
+
function sameStoreStamp(left, right) {
|
|
30890
|
+
return left !== null && right !== null && left.dataVersion === right.dataVersion && left.totalChanges === right.totalChanges && left.schemaVersion === right.schemaVersion;
|
|
30891
|
+
}
|
|
30892
|
+
function compareOrdinalKeys(left, right) {
|
|
30893
|
+
if (left.timeCreated !== right.timeCreated)
|
|
30894
|
+
return left.timeCreated < right.timeCreated ? -1 : 1;
|
|
30895
|
+
if (left.id === right.id)
|
|
30896
|
+
return 0;
|
|
30897
|
+
return Buffer.compare(Buffer.from(left.id, "utf8"), Buffer.from(right.id, "utf8"));
|
|
30898
|
+
}
|
|
30899
|
+
function countEligibleOrdinals(db, sessionId, after, through) {
|
|
30900
|
+
const indexed = countCanonicalOrdinalsIndexed(db, sessionId, after, through);
|
|
30901
|
+
if (indexed !== null)
|
|
30902
|
+
return indexed;
|
|
30903
|
+
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);
|
|
30904
|
+
const visited = typeof row?.visited === "number" ? row.visited : 0;
|
|
30905
|
+
ordinalRowsVisited += visited;
|
|
30906
|
+
ordinalJsonRowsRead += visited;
|
|
30907
|
+
return typeof row?.eligible === "number" ? row.eligible : 0;
|
|
30908
|
+
}
|
|
30909
|
+
function survivingAnchor(db, set) {
|
|
30910
|
+
if (set.anchors.length === 0)
|
|
30393
30911
|
return null;
|
|
30912
|
+
const current = new Map(db.prepare(ANCHOR_CHECK_SQL).all(JSON.stringify(set.anchors.map((anchor) => anchor.rowid))).map((row) => [row.rid, row.id]));
|
|
30913
|
+
return set.anchors.find((anchor) => current.get(anchor.rowid) === anchor.id);
|
|
30914
|
+
}
|
|
30915
|
+
function currentOrdinalCheckpoints(db, sessionId) {
|
|
30916
|
+
const cached = ordinalCheckpoints.get(db)?.get(sessionId);
|
|
30917
|
+
if (!cached)
|
|
30918
|
+
return;
|
|
30919
|
+
return withReadSnapshot(db, () => {
|
|
30920
|
+
if (!extendOrdinalCheckpoints(db, sessionId, cached.scan, ORDINAL_LOOKUP_LIMIT))
|
|
30921
|
+
return;
|
|
30922
|
+
cached.epoch = getRawSessionSummaryEpoch(sessionId);
|
|
30923
|
+
return cached;
|
|
30924
|
+
});
|
|
30925
|
+
}
|
|
30926
|
+
function extendOrdinalCheckpoints(db, sessionId, scan, limit) {
|
|
30927
|
+
const points = scan.checkpoints ?? [];
|
|
30928
|
+
const exists = (point) => Boolean(db.prepare("SELECT 1 FROM message WHERE id=? AND session_id=? AND time_created=?").get(point.id, sessionId, point.timeCreated));
|
|
30929
|
+
if (points.length && !exists(points[points.length - 1])) {
|
|
30930
|
+
let low = 0;
|
|
30931
|
+
let high = points.length;
|
|
30932
|
+
while (low < high) {
|
|
30933
|
+
const middle = Math.floor((low + high) / 2);
|
|
30934
|
+
if (exists(points[middle]))
|
|
30935
|
+
low = middle + 1;
|
|
30936
|
+
else
|
|
30937
|
+
high = middle;
|
|
30938
|
+
}
|
|
30939
|
+
points.length = low;
|
|
30940
|
+
scan.total = points.at(-1)?.ordinal ?? 0;
|
|
30941
|
+
scan.sessionRows = points.at(-1)?.storedCount ?? 0;
|
|
30942
|
+
}
|
|
30943
|
+
const tail = points.at(-1);
|
|
30944
|
+
const rows = db.prepare(`SELECT id, time_created AS timeCreated, ${EXCLUDED_ROW_SQL} AS excluded FROM message
|
|
30945
|
+
WHERE session_id=?${tail ? " AND (time_created,id) > (?,?)" : ""}
|
|
30946
|
+
ORDER BY time_created,id${limit === undefined ? "" : ` LIMIT ${limit + 1}`}`).all(sessionId, ...tail ? [tail.timeCreated, tail.id] : []);
|
|
30947
|
+
ordinalJsonRowsRead += rows.length;
|
|
30948
|
+
if (limit !== undefined && rows.length > limit)
|
|
30949
|
+
return false;
|
|
30950
|
+
let total = scan.total ?? 0;
|
|
30951
|
+
if (rows.length && tail && (tail.storedCount ?? 0) % 256 !== 0)
|
|
30952
|
+
points.pop();
|
|
30953
|
+
for (let index = 0;index < rows.length; index++) {
|
|
30954
|
+
const row = rows[index];
|
|
30955
|
+
if (row.excluded !== 1)
|
|
30956
|
+
total++;
|
|
30957
|
+
const storedCount = scan.sessionRows + index + 1;
|
|
30958
|
+
if (storedCount % 256 === 0 || index === rows.length - 1)
|
|
30959
|
+
points.push({ id: row.id, timeCreated: row.timeCreated, ordinal: total, storedCount });
|
|
30960
|
+
}
|
|
30961
|
+
scan.checkpoints = points;
|
|
30962
|
+
scan.sessionRows += rows.length;
|
|
30963
|
+
scan.total = total;
|
|
30964
|
+
return true;
|
|
30965
|
+
}
|
|
30966
|
+
function rawOrdinalSummarySeed(db, sessionId) {
|
|
30967
|
+
const retained = ordinalCheckpoints.get(db)?.get(sessionId);
|
|
30968
|
+
if (retained)
|
|
30969
|
+
return retained.scan;
|
|
30970
|
+
const seed = ordinalSummarySeeds.get(db)?.get(sessionId);
|
|
30971
|
+
if (!seed || seed.epoch !== getRawSessionSummaryEpoch(sessionId))
|
|
30972
|
+
return;
|
|
30973
|
+
return {
|
|
30974
|
+
...seed.scan,
|
|
30975
|
+
ids: [...new Set([...seed.scan.ids, ...writtenSummaryIds.get(sessionId) ?? []])]
|
|
30976
|
+
};
|
|
30977
|
+
}
|
|
30978
|
+
function boundedOrdinalPrefix(db, sessionId, through) {
|
|
30979
|
+
const cached = currentOrdinalCheckpoints(db, sessionId);
|
|
30980
|
+
if (cached && through === null)
|
|
30981
|
+
return cached.scan.total ?? 0;
|
|
30982
|
+
let floor;
|
|
30983
|
+
if (cached && through) {
|
|
30984
|
+
const points = cached.scan.checkpoints ?? [];
|
|
30985
|
+
let low = 0;
|
|
30986
|
+
let high = points.length;
|
|
30987
|
+
while (low < high) {
|
|
30988
|
+
const middle = Math.floor((low + high) / 2);
|
|
30989
|
+
if (compareOrdinalKeys(points[middle], through) <= 0)
|
|
30990
|
+
low = middle + 1;
|
|
30991
|
+
else
|
|
30992
|
+
high = middle;
|
|
30993
|
+
}
|
|
30994
|
+
floor = points[low - 1];
|
|
30995
|
+
if (floor && compareOrdinalKeys(floor, through) === 0)
|
|
30996
|
+
return floor.ordinal;
|
|
30997
|
+
}
|
|
30998
|
+
const bindings = [sessionId];
|
|
30999
|
+
if (floor)
|
|
31000
|
+
bindings.push(floor.timeCreated, floor.id);
|
|
31001
|
+
if (through)
|
|
31002
|
+
bindings.push(through.timeCreated, through.id);
|
|
31003
|
+
const rows = db.prepare(`SELECT ${EXCLUDED_ROW_SQL} AS excluded FROM message WHERE id IN (
|
|
31004
|
+
SELECT id FROM message WHERE session_id = ?${floor ? " AND (time_created, id) > (?, ?)" : ""}${through ? " AND (time_created, id) <= (?, ?)" : ""}
|
|
31005
|
+
ORDER BY time_created, id LIMIT ${ORDINAL_LOOKUP_LIMIT + 1})`).all(...bindings);
|
|
31006
|
+
ordinalRowsVisited += rows.length;
|
|
31007
|
+
ordinalJsonRowsRead += rows.length;
|
|
31008
|
+
if (rows.length > ORDINAL_LOOKUP_LIMIT) {
|
|
31009
|
+
prewarmRawSessionOrdinalsForDb(db, sessionId);
|
|
31010
|
+
throw new RawOrdinalsNotReady;
|
|
31011
|
+
}
|
|
31012
|
+
return (floor?.ordinal ?? 0) + rows.reduce((sum, row) => sum + (row.excluded === 1 ? 0 : 1), 0);
|
|
31013
|
+
}
|
|
31014
|
+
function scanRawSessionSummaryRows(db, sessionId, previous) {
|
|
31015
|
+
return withReadSnapshot(db, () => {
|
|
31016
|
+
if (previous?.checkpoints) {
|
|
31017
|
+
extendOrdinalCheckpoints(db, sessionId, previous);
|
|
31018
|
+
return previous;
|
|
31019
|
+
}
|
|
31020
|
+
if (previous) {
|
|
31021
|
+
const sessions = summaryCandidateSets.get(db) ?? new Map;
|
|
31022
|
+
sessions.set(sessionId, {
|
|
31023
|
+
epoch: getRawSessionSummaryEpoch(sessionId),
|
|
31024
|
+
anchors: previous.anchors,
|
|
31025
|
+
ids: new Set(previous.ids)
|
|
31026
|
+
});
|
|
31027
|
+
summaryCandidateSets.set(db, sessions);
|
|
31028
|
+
}
|
|
31029
|
+
const incremental = previous && isRawSessionSummaryWarm(db, sessionId) ? summaryCandidatesOf(db, sessionId) : undefined;
|
|
31030
|
+
const rows = incremental ? [] : db.prepare(SUMMARY_FULL_SCAN_SQL).all(sessionId, sessionId);
|
|
31031
|
+
const anchors = [];
|
|
31032
|
+
const ids = [];
|
|
31033
|
+
let sessionRows = 0;
|
|
31034
|
+
for (const row of rows) {
|
|
31035
|
+
if (row.kind === 1 && typeof row.rid === "number" && typeof row.id === "string")
|
|
31036
|
+
anchors.push({ rowid: row.rid, id: row.id });
|
|
31037
|
+
else if (row.kind === 2 && typeof row.id === "string")
|
|
31038
|
+
ids.push(row.id);
|
|
31039
|
+
else if (row.kind === 4 && typeof row.rid === "number")
|
|
31040
|
+
sessionRows = row.rid;
|
|
31041
|
+
}
|
|
31042
|
+
if (incremental) {
|
|
31043
|
+
ids.push(...incremental.ids);
|
|
31044
|
+
anchors.push(...summaryCandidateSets.get(db)?.get(sessionId)?.anchors ?? []);
|
|
31045
|
+
sessionRows = countStoredRawSessionRowsIndexed(db, sessionId);
|
|
31046
|
+
}
|
|
31047
|
+
anchors.sort((left, right) => right.rowid - left.rowid);
|
|
31048
|
+
anchors.length = Math.min(anchors.length, SUMMARY_ANCHOR_LIMIT);
|
|
31049
|
+
const keys = db.prepare(`SELECT id, time_created AS timeCreated, ${EXCLUDED_ROW_SQL} AS excluded FROM message WHERE session_id = ?
|
|
31050
|
+
ORDER BY time_created, id`).all(sessionId);
|
|
31051
|
+
const checkpoints = [];
|
|
31052
|
+
let total = 0;
|
|
31053
|
+
for (let index = 0;index < keys.length; index++) {
|
|
31054
|
+
const key = keys[index];
|
|
31055
|
+
if (key.excluded !== 1)
|
|
31056
|
+
total++;
|
|
31057
|
+
if (index % 256 === 255 || index === keys.length - 1)
|
|
31058
|
+
checkpoints.push({
|
|
31059
|
+
id: key.id,
|
|
31060
|
+
timeCreated: key.timeCreated,
|
|
31061
|
+
ordinal: total,
|
|
31062
|
+
storedCount: index + 1
|
|
31063
|
+
});
|
|
31064
|
+
}
|
|
31065
|
+
return { anchors, ids, sessionRows, checkpoints, total };
|
|
31066
|
+
});
|
|
31067
|
+
}
|
|
31068
|
+
function getRawSessionSummaryEpoch(sessionId) {
|
|
31069
|
+
return summaryCandidateEpochs.get(sessionId) ?? 0;
|
|
31070
|
+
}
|
|
31071
|
+
function installRawSessionSummaryScan(db, sessionId, scan, epoch, workerPrepared = false) {
|
|
31072
|
+
if (epoch !== getRawSessionSummaryEpoch(sessionId))
|
|
31073
|
+
return false;
|
|
31074
|
+
const seeds = ordinalSummarySeeds.get(db) ?? new Map;
|
|
31075
|
+
seeds.set(sessionId, { epoch, scan });
|
|
31076
|
+
ordinalSummarySeeds.set(db, seeds);
|
|
31077
|
+
if (scan.checkpoints && workerPrepared) {
|
|
31078
|
+
const counts = ordinalCheckpoints.get(db) ?? new Map;
|
|
31079
|
+
counts.set(sessionId, { epoch, scan });
|
|
31080
|
+
ordinalCheckpoints.set(db, counts);
|
|
31081
|
+
} else if (getSqliteDatabasePath(db) && isMainThread2)
|
|
31082
|
+
return false;
|
|
31083
|
+
if (isRawSessionSummaryWarm(db, sessionId))
|
|
31084
|
+
return true;
|
|
31085
|
+
let sessions = summaryCandidateSets.get(db);
|
|
31086
|
+
if (!sessions) {
|
|
31087
|
+
sessions = new Map;
|
|
31088
|
+
summaryCandidateSets.set(db, sessions);
|
|
30394
31089
|
}
|
|
30395
|
-
|
|
30396
|
-
|
|
30397
|
-
|
|
30398
|
-
|
|
30399
|
-
|
|
30400
|
-
|
|
31090
|
+
sessions.set(sessionId, { epoch, anchors: [...scan.anchors], ids: new Set(scan.ids) });
|
|
31091
|
+
return isRawSessionSummaryWarm(db, sessionId);
|
|
31092
|
+
}
|
|
31093
|
+
function isRawSessionSummaryWarm(db, sessionId) {
|
|
31094
|
+
if (isMainThread2 && getSqliteDatabasePath(db)) {
|
|
31095
|
+
return Boolean(currentOrdinalCheckpoints(db, sessionId));
|
|
31096
|
+
}
|
|
31097
|
+
const set = summaryCandidateSets.get(db)?.get(sessionId);
|
|
31098
|
+
if (!set || set.epoch !== getRawSessionSummaryEpoch(sessionId))
|
|
31099
|
+
return false;
|
|
31100
|
+
try {
|
|
31101
|
+
return survivingAnchor(db, set) !== undefined;
|
|
31102
|
+
} catch {
|
|
31103
|
+
return false;
|
|
31104
|
+
}
|
|
31105
|
+
}
|
|
31106
|
+
function countStoredRawSessionRowsIndexed(db, sessionId) {
|
|
31107
|
+
const row = db.prepare("SELECT COUNT(*) AS count FROM message WHERE session_id = ?").get(sessionId);
|
|
31108
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
31109
|
+
}
|
|
31110
|
+
function summaryCandidatesOf(db, sessionId) {
|
|
31111
|
+
let sessions = summaryCandidateSets.get(db);
|
|
31112
|
+
if (!sessions) {
|
|
31113
|
+
sessions = new Map;
|
|
31114
|
+
summaryCandidateSets.set(db, sessions);
|
|
31115
|
+
}
|
|
31116
|
+
const epoch = getRawSessionSummaryEpoch(sessionId);
|
|
31117
|
+
const cached = sessions.get(sessionId);
|
|
31118
|
+
const floor = cached && cached.epoch === epoch ? survivingAnchor(db, cached) : undefined;
|
|
31119
|
+
let ids;
|
|
31120
|
+
let anchors;
|
|
31121
|
+
if (floor === undefined) {
|
|
31122
|
+
const scan = scanRawSessionSummaryRows(db, sessionId);
|
|
31123
|
+
summaryFullScans += 1;
|
|
31124
|
+
ordinalJsonRowsRead += scan.sessionRows;
|
|
31125
|
+
ids = new Set(scan.ids);
|
|
31126
|
+
anchors = scan.anchors;
|
|
31127
|
+
} else {
|
|
31128
|
+
const rows = db.prepare(SUMMARY_SCAN_AFTER_SQL).all(floor?.rowid ?? 0, sessionId);
|
|
31129
|
+
ids = cached?.ids ?? new Set;
|
|
31130
|
+
anchors = [];
|
|
31131
|
+
for (const row of rows) {
|
|
31132
|
+
if (row.kind === 1 && typeof row.rid === "number" && typeof row.id === "string")
|
|
31133
|
+
anchors.push({ rowid: row.rid, id: row.id });
|
|
31134
|
+
else if (row.kind === 2 && typeof row.id === "string")
|
|
31135
|
+
ids.add(row.id);
|
|
31136
|
+
if (row.kind === 2 || row.kind === 3)
|
|
31137
|
+
ordinalJsonRowsRead += 1;
|
|
31138
|
+
}
|
|
31139
|
+
anchors.sort((left, right) => right.rowid - left.rowid);
|
|
31140
|
+
anchors.length = Math.min(anchors.length, SUMMARY_ANCHOR_LIMIT);
|
|
31141
|
+
}
|
|
31142
|
+
for (const id of writtenSummaryIds.get(sessionId) ?? [])
|
|
31143
|
+
ids.add(id);
|
|
31144
|
+
sessions.set(sessionId, { epoch, anchors, ids });
|
|
31145
|
+
const top = anchors[0];
|
|
31146
|
+
return { ids: [...ids], floorRowid: top?.rowid ?? 0, floorId: top?.id ?? null };
|
|
31147
|
+
}
|
|
31148
|
+
function canonicalCountSql(lower, upper) {
|
|
31149
|
+
const range = `${lower ? " AND (time_created, id) > (?, ?)" : ""}${upper ? " AND (time_created, id) <= (?, ?)" : ""}`;
|
|
31150
|
+
return `SELECT
|
|
31151
|
+
(SELECT COUNT(*) FROM message WHERE session_id = ?${range}) AS stored,
|
|
31152
|
+
(SELECT COUNT(*) FROM message
|
|
31153
|
+
WHERE id IN (SELECT value FROM json_each(?)) AND +session_id = ?${range}
|
|
31154
|
+
AND ${EXCLUDED_ROW_SQL}) AS knownExcluded,
|
|
31155
|
+
(SELECT COUNT(*) FROM message
|
|
31156
|
+
WHERE rowid > ? AND +session_id = ? AND id NOT IN (SELECT value FROM json_each(?))${range}
|
|
31157
|
+
AND ${EXCLUDED_ROW_SQL}) AS newExcluded,
|
|
31158
|
+
(SELECT id FROM message WHERE rowid = ?) AS floorId`;
|
|
31159
|
+
}
|
|
31160
|
+
function canonicalCountStatementText(lower, upper) {
|
|
31161
|
+
const key = `${lower}:${upper}`;
|
|
31162
|
+
let sql = CANONICAL_COUNT_SQL.get(key);
|
|
31163
|
+
if (!sql) {
|
|
31164
|
+
sql = canonicalCountSql(lower, upper);
|
|
31165
|
+
CANONICAL_COUNT_SQL.set(key, sql);
|
|
31166
|
+
}
|
|
31167
|
+
return sql;
|
|
31168
|
+
}
|
|
31169
|
+
function countCanonicalOrdinalsIndexed(db, sessionId, after, through) {
|
|
31170
|
+
if (isMainThread2 && getSqliteDatabasePath(db)) {
|
|
31171
|
+
return withReadSnapshot(db, () => boundedOrdinalPrefix(db, sessionId, through) - (after ? boundedOrdinalPrefix(db, sessionId, after) : 0));
|
|
31172
|
+
}
|
|
31173
|
+
if (indexedCountUnsupported.has(db))
|
|
31174
|
+
return null;
|
|
31175
|
+
const range = [];
|
|
31176
|
+
if (after)
|
|
31177
|
+
range.push(after.timeCreated, after.id);
|
|
31178
|
+
if (through)
|
|
31179
|
+
range.push(through.timeCreated, through.id);
|
|
31180
|
+
try {
|
|
31181
|
+
return withReadSnapshot(db, () => {
|
|
31182
|
+
for (let attempt = 0;attempt < STABLE_STORE_ATTEMPTS; attempt += 1) {
|
|
31183
|
+
const view = summaryCandidatesOf(db, sessionId);
|
|
31184
|
+
const ids = JSON.stringify(view.ids);
|
|
31185
|
+
const row = db.prepare(canonicalCountStatementText(after !== null, through !== null)).get(sessionId, ...range, ids, sessionId, ...range, view.floorRowid, sessionId, ids, ...range, view.floorRowid);
|
|
31186
|
+
if (view.floorId !== null && row?.floorId !== view.floorId)
|
|
31187
|
+
continue;
|
|
31188
|
+
const stored = typeof row?.stored === "number" ? row.stored : 0;
|
|
31189
|
+
const excluded = (typeof row?.knownExcluded === "number" ? row.knownExcluded : 0) + (typeof row?.newExcluded === "number" ? row.newExcluded : 0);
|
|
31190
|
+
ordinalRowsVisited += stored;
|
|
31191
|
+
ordinalJsonRowsRead += view.ids.length;
|
|
31192
|
+
return stored - excluded;
|
|
31193
|
+
}
|
|
31194
|
+
return null;
|
|
31195
|
+
});
|
|
31196
|
+
} catch (error) {
|
|
31197
|
+
if (/no such (column|table|function)|json_each/i.test(String(error))) {
|
|
31198
|
+
indexedCountUnsupported.add(db);
|
|
31199
|
+
return null;
|
|
31200
|
+
}
|
|
31201
|
+
throw error;
|
|
31202
|
+
}
|
|
31203
|
+
}
|
|
31204
|
+
function connectionHasOpenTransaction(db) {
|
|
31205
|
+
const state = db;
|
|
31206
|
+
return state.inTransaction === true || state.isTransaction === true;
|
|
31207
|
+
}
|
|
31208
|
+
function withReadSnapshot(db, read) {
|
|
31209
|
+
if (connectionHasOpenTransaction(db))
|
|
31210
|
+
return read();
|
|
31211
|
+
db.exec("BEGIN");
|
|
31212
|
+
try {
|
|
31213
|
+
return read();
|
|
31214
|
+
} finally {
|
|
31215
|
+
if (connectionHasOpenTransaction(db))
|
|
31216
|
+
db.exec("ROLLBACK");
|
|
31217
|
+
}
|
|
31218
|
+
}
|
|
31219
|
+
function reusableWatermark(db, sessionId, stamp) {
|
|
31220
|
+
const watermark = ordinalWatermarks.get(db)?.get(sessionId);
|
|
31221
|
+
if (!watermark || watermark.epoch !== (ordinalWatermarkEpochs.get(sessionId) ?? 0) || !sameStoreStamp(watermark.stamp, stamp))
|
|
31222
|
+
return null;
|
|
31223
|
+
return watermark;
|
|
31224
|
+
}
|
|
31225
|
+
function rememberOrdinalWatermark(db, sessionId, key, ordinal, stamp) {
|
|
31226
|
+
let sessions = ordinalWatermarks.get(db);
|
|
31227
|
+
if (!sessions) {
|
|
31228
|
+
sessions = new Map;
|
|
31229
|
+
ordinalWatermarks.set(db, sessions);
|
|
31230
|
+
}
|
|
31231
|
+
const current = sessions.get(sessionId);
|
|
31232
|
+
if (current && sameStoreStamp(current.stamp, stamp) && compareOrdinalKeys(current, key) >= 0)
|
|
31233
|
+
return;
|
|
31234
|
+
sessions.set(sessionId, {
|
|
31235
|
+
timeCreated: key.timeCreated,
|
|
31236
|
+
id: key.id,
|
|
31237
|
+
ordinal,
|
|
31238
|
+
stamp,
|
|
31239
|
+
epoch: ordinalWatermarkEpochs.get(sessionId) ?? 0
|
|
31240
|
+
});
|
|
31241
|
+
}
|
|
31242
|
+
function canonicalOrdinalOf(db, sessionId, readTarget) {
|
|
31243
|
+
for (let attempt = 1;; attempt += 1) {
|
|
31244
|
+
const before = readStoreStamp(db);
|
|
31245
|
+
const target = readTarget();
|
|
31246
|
+
if (!target)
|
|
31247
|
+
return null;
|
|
31248
|
+
const watermark = attempt < STABLE_STORE_ATTEMPTS ? reusableWatermark(db, sessionId, before) : null;
|
|
31249
|
+
if (!watermark) {
|
|
31250
|
+
const ordinal = countEligibleOrdinals(db, sessionId, null, target);
|
|
31251
|
+
if (before && sameStoreStamp(before, readStoreStamp(db)))
|
|
31252
|
+
rememberOrdinalWatermark(db, sessionId, target, ordinal, before);
|
|
31253
|
+
return { target, ordinal };
|
|
31254
|
+
}
|
|
31255
|
+
const order = compareOrdinalKeys(target, watermark);
|
|
31256
|
+
const ordinal = order === 0 ? watermark.ordinal : order < 0 ? watermark.ordinal - countEligibleOrdinals(db, sessionId, target, watermark) : watermark.ordinal + countEligibleOrdinals(db, sessionId, watermark, target);
|
|
31257
|
+
if (sameStoreStamp(before, readStoreStamp(db))) {
|
|
31258
|
+
rememberOrdinalWatermark(db, sessionId, target, ordinal, before);
|
|
31259
|
+
return { target, ordinal };
|
|
31260
|
+
}
|
|
31261
|
+
}
|
|
31262
|
+
}
|
|
31263
|
+
function readRawSessionMessageOrdinalByIdFromDb(db, sessionId, messageId) {
|
|
31264
|
+
const counted = canonicalOrdinalOf(db, sessionId, () => {
|
|
31265
|
+
const row = db.prepare(`SELECT id, time_created, ${ORDINAL_SUMMARY_FLAG_SQL} AND ${ORDINAL_STOP_FLAG_SQL} AS excluded
|
|
31266
|
+
FROM message WHERE session_id = ? AND id = ?`).get(sessionId, messageId);
|
|
31267
|
+
if (typeof row?.id !== "string" || typeof row.time_created !== "number")
|
|
31268
|
+
return null;
|
|
31269
|
+
return { id: row.id, timeCreated: row.time_created, excluded: row.excluded === 1 };
|
|
31270
|
+
});
|
|
31271
|
+
if (!counted || counted.target.excluded)
|
|
31272
|
+
return null;
|
|
31273
|
+
return counted.ordinal > 0 ? counted.ordinal : null;
|
|
31274
|
+
}
|
|
31275
|
+
function readRawSessionMessageByIdFromDb(db, sessionId, messageId) {
|
|
31276
|
+
const counted = canonicalOrdinalOf(db, sessionId, () => {
|
|
31277
|
+
const row = db.prepare("SELECT id, data, time_created, time_updated FROM message WHERE session_id = ? AND id = ?").get(sessionId, messageId);
|
|
31278
|
+
if (!row || !isRawMessageRow(row) || typeof row.time_created !== "number")
|
|
31279
|
+
return null;
|
|
31280
|
+
const parsed = parseJsonRecord(row.data);
|
|
31281
|
+
if (!parsed || isRawCompactionSummaryInfo(parsed))
|
|
31282
|
+
return null;
|
|
31283
|
+
return { ...row, timeCreated: row.time_created, info: parsed };
|
|
31284
|
+
});
|
|
31285
|
+
if (!counted)
|
|
31286
|
+
return null;
|
|
31287
|
+
const { target: row, ordinal } = counted;
|
|
31288
|
+
const info = row.info;
|
|
30401
31289
|
if (ordinal <= 0) {
|
|
30402
31290
|
return null;
|
|
30403
31291
|
}
|
|
@@ -30461,8 +31349,34 @@ function readRawSeedTailFromDb(db, sessionId, boundaryId) {
|
|
|
30461
31349
|
throw new Error("state_sync materialized boundary is missing from raw storage");
|
|
30462
31350
|
return messages;
|
|
30463
31351
|
}
|
|
30464
|
-
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_SUMMARY_TEXT_MAX_CHARS = 8192, RAW_SUMMARY_ARG_MAX_CHARS = 512, RAW_SUMMARY_TOOL_INPUT_KEYS, RAW_SUMMARY_PART_DATA_SQL
|
|
30465
|
-
|
|
31352
|
+
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, 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
|
|
31353
|
+
THEN COALESCE(json_extract(data, '$.summary'), 0)
|
|
31354
|
+
ELSE 0 END = 1)`, ORDINAL_STOP_FLAG_SQL = `(CASE WHEN json_valid(data) = 1
|
|
31355
|
+
THEN COALESCE(json_extract(data, '$.finish'), '')
|
|
31356
|
+
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;
|
|
31357
|
+
var init_read_session_raw = __esm(async () => {
|
|
31358
|
+
await __promiseAll([
|
|
31359
|
+
init_sqlite(),
|
|
31360
|
+
init_raw_ordinal_warmup()
|
|
31361
|
+
]);
|
|
31362
|
+
RAW_METADATA_KEPT_KEYS = [
|
|
31363
|
+
"description",
|
|
31364
|
+
"title",
|
|
31365
|
+
"userAnswer",
|
|
31366
|
+
"answers",
|
|
31367
|
+
"answer",
|
|
31368
|
+
"selectedOptions",
|
|
31369
|
+
"customInput",
|
|
31370
|
+
"results"
|
|
31371
|
+
];
|
|
31372
|
+
RAW_PART_DATA_SQL = `CASE
|
|
31373
|
+
WHEN json_valid(data) = 1
|
|
31374
|
+
AND json_type(data, '$.state.metadata') = 'object'
|
|
31375
|
+
AND COALESCE(json_extract(data, '$.state.status'), '') <> 'error'
|
|
31376
|
+
AND length(json_extract(data, '$.state.metadata')) > ${RAW_METADATA_KEEP_CHARS}
|
|
31377
|
+
THEN json_set(data, '$.state.metadata', json_patch('{}', json_object(${RAW_METADATA_KEPT_KEYS.map((key) => `'${key}', json_extract(data, '$.state.metadata.${key}')`).join(", ")})))
|
|
31378
|
+
ELSE data
|
|
31379
|
+
END`;
|
|
30466
31380
|
RAW_SUMMARY_TOOL_INPUT_KEYS = [
|
|
30467
31381
|
"description",
|
|
30468
31382
|
"filePath",
|
|
@@ -30487,6 +31401,268 @@ var init_read_session_raw = __esm(() => {
|
|
|
30487
31401
|
)
|
|
30488
31402
|
)
|
|
30489
31403
|
END`;
|
|
31404
|
+
ORDINAL_RANGE_FROM_START_SQL = ordinalRangeSql(false);
|
|
31405
|
+
ORDINAL_RANGE_BETWEEN_SQL = ordinalRangeSql(true);
|
|
31406
|
+
ordinalWatermarks = new WeakMap;
|
|
31407
|
+
ordinalWatermarkEpochs = new Map;
|
|
31408
|
+
EXCLUDED_ROW_SQL = `${ORDINAL_SUMMARY_FLAG_SQL} AND ${ORDINAL_STOP_FLAG_SQL}`;
|
|
31409
|
+
summaryCandidateSets = new WeakMap;
|
|
31410
|
+
summaryCandidateEpochs = new Map;
|
|
31411
|
+
writtenSummaryIds = new Map;
|
|
31412
|
+
indexedCountUnsupported = new WeakSet;
|
|
31413
|
+
ANCHOR_ROWS_SQL = `SELECT rowid AS rid, id, 1 AS kind FROM message
|
|
31414
|
+
WHERE rowid > (SELECT MAX(rowid) FROM message) - ${SUMMARY_ANCHOR_SPAN}`;
|
|
31415
|
+
SUMMARY_FULL_SCAN_SQL = `${ANCHOR_ROWS_SQL}
|
|
31416
|
+
UNION ALL
|
|
31417
|
+
SELECT rowid, id, 2 FROM message WHERE session_id = ? AND ${ORDINAL_SUMMARY_FLAG_SQL}
|
|
31418
|
+
UNION ALL
|
|
31419
|
+
SELECT COUNT(*), NULL, 4 FROM message WHERE session_id = ?`;
|
|
31420
|
+
SUMMARY_SCAN_AFTER_SQL = `${ANCHOR_ROWS_SQL}
|
|
31421
|
+
UNION ALL
|
|
31422
|
+
SELECT rowid, id, CASE WHEN ${ORDINAL_SUMMARY_FLAG_SQL} THEN 2 ELSE 3 END
|
|
31423
|
+
FROM message WHERE rowid > ? AND +session_id = ?`;
|
|
31424
|
+
ordinalCheckpoints = new WeakMap;
|
|
31425
|
+
ordinalSummarySeeds = new WeakMap;
|
|
31426
|
+
RawOrdinalsNotReady = class RawOrdinalsNotReady extends Error {
|
|
31427
|
+
constructor() {
|
|
31428
|
+
super("canonical ordinals are warming off-thread; retry after preparation");
|
|
31429
|
+
}
|
|
31430
|
+
};
|
|
31431
|
+
CANONICAL_COUNT_SQL = new Map;
|
|
31432
|
+
});
|
|
31433
|
+
|
|
31434
|
+
// ../plugin/src/hooks/magic-context/raw-ordinal-warmup.ts
|
|
31435
|
+
import { Worker } from "node:worker_threads";
|
|
31436
|
+
function stopRawSessionOrdinalWarmups() {
|
|
31437
|
+
for (const stop of [...activeWorkers.values()])
|
|
31438
|
+
stop("stopped");
|
|
31439
|
+
}
|
|
31440
|
+
function defaultEntry() {
|
|
31441
|
+
return new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "./raw-ordinal-warmup-worker.ts" : "./raw-ordinal-warmup-worker.js", import.meta.url);
|
|
31442
|
+
}
|
|
31443
|
+
function ensureExitHook() {
|
|
31444
|
+
if (exitHookRegistered)
|
|
31445
|
+
return;
|
|
31446
|
+
exitHookRegistered = true;
|
|
31447
|
+
const controller = new AbortController;
|
|
31448
|
+
controller.signal.addEventListener("abort", stopRawSessionOrdinalWarmups, { once: true });
|
|
31449
|
+
registerExitAbort(controller);
|
|
31450
|
+
}
|
|
31451
|
+
function runSessionWarmupWorker(input, options) {
|
|
31452
|
+
ensureExitHook();
|
|
31453
|
+
return new Promise((resolve) => {
|
|
31454
|
+
let worker;
|
|
31455
|
+
let deadline;
|
|
31456
|
+
let settled = false;
|
|
31457
|
+
const finish = (result) => {
|
|
31458
|
+
if (settled)
|
|
31459
|
+
return;
|
|
31460
|
+
settled = true;
|
|
31461
|
+
clearTimeout(deadline);
|
|
31462
|
+
if (worker) {
|
|
31463
|
+
activeWorkers.delete(worker);
|
|
31464
|
+
const stopped = worker.terminate();
|
|
31465
|
+
worker.unref();
|
|
31466
|
+
stopped.finally(() => {
|
|
31467
|
+
releaseIndexOwner(input);
|
|
31468
|
+
resolve(result);
|
|
31469
|
+
});
|
|
31470
|
+
return;
|
|
31471
|
+
}
|
|
31472
|
+
releaseIndexOwner(input);
|
|
31473
|
+
resolve(result);
|
|
31474
|
+
};
|
|
31475
|
+
const arm = (failure, ms) => {
|
|
31476
|
+
clearTimeout(deadline);
|
|
31477
|
+
deadline = setTimeout(() => finish({ failure, detail: `no reply within ${ms} ms` }), ms);
|
|
31478
|
+
deadline.unref?.();
|
|
31479
|
+
};
|
|
31480
|
+
try {
|
|
31481
|
+
worker = new Worker(options.entry ?? defaultEntry(), { workerData: input });
|
|
31482
|
+
} catch (error) {
|
|
31483
|
+
finish({ failure: "start-failed", detail: String(error) });
|
|
31484
|
+
return;
|
|
31485
|
+
}
|
|
31486
|
+
worker.unref();
|
|
31487
|
+
activeWorkers.set(worker, (failure) => finish({ failure, detail: "stopped" }));
|
|
31488
|
+
arm("not-accepted", options.acceptMs ?? ACCEPT_TIMEOUT_MS);
|
|
31489
|
+
worker.on("message", (reply) => {
|
|
31490
|
+
if (reply.kind === "accepted")
|
|
31491
|
+
arm("no-result", options.resultMs ?? RESULT_TIMEOUT_MS);
|
|
31492
|
+
else if (reply.kind === "scan")
|
|
31493
|
+
finish({ scan: reply.scan });
|
|
31494
|
+
else if (reply.kind === "tag-summary")
|
|
31495
|
+
finish({ summary: reply.summary });
|
|
31496
|
+
else if (reply.kind === "tag-delta")
|
|
31497
|
+
finish({ delta: reply.delta });
|
|
31498
|
+
else if (reply.kind === "indexed")
|
|
31499
|
+
finish({ inserted: reply.inserted, measurements: reply.measurements });
|
|
31500
|
+
else
|
|
31501
|
+
finish({ failure: "worker-error", detail: reply.error });
|
|
31502
|
+
});
|
|
31503
|
+
worker.on("error", (error) => finish({ failure: "worker-error", detail: String(error) }));
|
|
31504
|
+
worker.on("exit", (code) => finish({ failure: "exited", detail: `exit code ${code}` }));
|
|
31505
|
+
});
|
|
31506
|
+
}
|
|
31507
|
+
function prewarmRawSessionOrdinalsForDb(db, sessionId, options = {}) {
|
|
31508
|
+
if (isRawSessionSummaryWarm(db, sessionId))
|
|
31509
|
+
return Promise.resolve("warm");
|
|
31510
|
+
if (!db.prepare("SELECT 1 FROM sqlite_master WHERE name = 'message' AND type IN ('table', 'view')").get())
|
|
31511
|
+
return Promise.resolve("warm");
|
|
31512
|
+
const path = getSqliteDatabasePath(db);
|
|
31513
|
+
if (!path) {
|
|
31514
|
+
countRawSessionMessageOrdinalsFromDb(db, sessionId);
|
|
31515
|
+
return Promise.resolve("warm");
|
|
31516
|
+
}
|
|
31517
|
+
let connectionId = connectionIds.get(db);
|
|
31518
|
+
if (connectionId === undefined) {
|
|
31519
|
+
connectionId = ++nextConnectionId;
|
|
31520
|
+
connectionIds.set(db, connectionId);
|
|
31521
|
+
}
|
|
31522
|
+
const key = `${path}\x00${sessionId}\x00${connectionId}`;
|
|
31523
|
+
let shared = inFlight.get(key);
|
|
31524
|
+
if (!shared) {
|
|
31525
|
+
const failed = failedAt.get(key);
|
|
31526
|
+
if (failed !== undefined && Date.now() - failed < FAILURE_BACKOFF_MS)
|
|
31527
|
+
return Promise.resolve("failed");
|
|
31528
|
+
const epoch = getRawSessionSummaryEpoch(sessionId);
|
|
31529
|
+
const started = performance.now();
|
|
31530
|
+
const result = runSessionWarmupWorker({ path, sessionId, previous: rawOrdinalSummarySeed(db, sessionId) }, options).then((outcome) => {
|
|
31531
|
+
if ("failure" in outcome)
|
|
31532
|
+
recordFailure(key, sessionId, outcome.failure, outcome.detail);
|
|
31533
|
+
return outcome;
|
|
31534
|
+
}).finally(() => {
|
|
31535
|
+
if (inFlight.get(key) === scan)
|
|
31536
|
+
inFlight.delete(key);
|
|
31537
|
+
});
|
|
31538
|
+
const scan = { epoch, started, result };
|
|
31539
|
+
inFlight.set(key, scan);
|
|
31540
|
+
shared = scan;
|
|
31541
|
+
}
|
|
31542
|
+
const awaited = shared;
|
|
31543
|
+
return awaited.result.then((result) => {
|
|
31544
|
+
if (!("scan" in result))
|
|
31545
|
+
return "failed";
|
|
31546
|
+
try {
|
|
31547
|
+
if (installRawSessionSummaryScan(db, sessionId, result.scan, awaited.epoch, true)) {
|
|
31548
|
+
failedAt.delete(key);
|
|
31549
|
+
log(`[magic-context] canonical ordinals of ${sessionId} warmed off-thread (${result.scan.sessionRows} messages, ${Math.round(performance.now() - awaited.started)} ms)`);
|
|
31550
|
+
return "warm";
|
|
31551
|
+
}
|
|
31552
|
+
} catch {}
|
|
31553
|
+
recordFailure(key, sessionId, "superseded", `session removed during scan: epoch=${awaited.epoch}/${getRawSessionSummaryEpoch(sessionId)}`);
|
|
31554
|
+
return "failed";
|
|
31555
|
+
});
|
|
31556
|
+
}
|
|
31557
|
+
function recordFailure(key, sessionId, failure, detail) {
|
|
31558
|
+
failures.set(failure, (failures.get(failure) ?? 0) + 1);
|
|
31559
|
+
if (failure !== "superseded")
|
|
31560
|
+
failedAt.set(key, Date.now());
|
|
31561
|
+
log(`[magic-context] WARN canonical ordinal warm-up failed for ${sessionId} (${failure}: ${detail}); counts remain bounded and callers must defer or retry`);
|
|
31562
|
+
}
|
|
31563
|
+
var ACCEPT_TIMEOUT_MS = 2000, RESULT_TIMEOUT_MS, FAILURE_BACKOFF_MS, inFlight, connectionIds, nextConnectionId = 0, failedAt, activeWorkers, failures, exitHookRegistered = false;
|
|
31564
|
+
var init_raw_ordinal_warmup = __esm(async () => {
|
|
31565
|
+
init_exit_abort_registry();
|
|
31566
|
+
init_logger();
|
|
31567
|
+
await __promiseAll([
|
|
31568
|
+
init_sqlite(),
|
|
31569
|
+
init_read_session_raw()
|
|
31570
|
+
]);
|
|
31571
|
+
RESULT_TIMEOUT_MS = 10 * 60000;
|
|
31572
|
+
FAILURE_BACKOFF_MS = 5 * 60000;
|
|
31573
|
+
inFlight = new Map;
|
|
31574
|
+
connectionIds = new WeakMap;
|
|
31575
|
+
failedAt = new Map;
|
|
31576
|
+
activeWorkers = new Map;
|
|
31577
|
+
failures = new Map;
|
|
31578
|
+
});
|
|
31579
|
+
|
|
31580
|
+
// ../plugin/src/hooks/magic-context/read-session-db.ts
|
|
31581
|
+
function openCodeDbExists() {
|
|
31582
|
+
return harnessOwnsOpenCodeStore() && openCodeDbPathExists(resolveOpenCodeDbPath());
|
|
31583
|
+
}
|
|
31584
|
+
function closeCachedReadOnlyDb() {
|
|
31585
|
+
if (!cachedReadOnlyDb) {
|
|
31586
|
+
return;
|
|
31587
|
+
}
|
|
31588
|
+
try {
|
|
31589
|
+
closeQuietly(cachedReadOnlyDb.db);
|
|
31590
|
+
} catch (error) {
|
|
31591
|
+
log("[magic-context] failed to close cached OpenCode read-only DB:", error);
|
|
31592
|
+
} finally {
|
|
31593
|
+
cachedReadOnlyDb = null;
|
|
31594
|
+
}
|
|
31595
|
+
}
|
|
31596
|
+
function getReadOnlySessionDb() {
|
|
31597
|
+
if (!harnessOwnsOpenCodeStore()) {
|
|
31598
|
+
throw new Error("OpenCode session database is not readable from a Pi-compatible process; its history lives in Pi sessions");
|
|
31599
|
+
}
|
|
31600
|
+
const resolution = resolveOpenCodeDbPath();
|
|
31601
|
+
const dbPath = resolution.path;
|
|
31602
|
+
if (!openCodeDbPathExists(resolution)) {
|
|
31603
|
+
throw new Error(`OpenCode session database is unavailable at ${dbPath} (source=${resolution.source})`);
|
|
31604
|
+
}
|
|
31605
|
+
if (cachedReadOnlyDb?.path === dbPath) {
|
|
31606
|
+
return cachedReadOnlyDb.db;
|
|
31607
|
+
}
|
|
31608
|
+
closeCachedReadOnlyDb();
|
|
31609
|
+
const db = new Database(dbPath, { readonly: true });
|
|
31610
|
+
try {
|
|
31611
|
+
assertOpenCodeStoreGeneration(db, "v1", dbPath);
|
|
31612
|
+
} catch (error) {
|
|
31613
|
+
closeQuietly(db);
|
|
31614
|
+
throw error;
|
|
31615
|
+
}
|
|
31616
|
+
cachedReadOnlyDb = { path: dbPath, db };
|
|
31617
|
+
clearOpenCodeDbReadFailure();
|
|
31618
|
+
return db;
|
|
31619
|
+
}
|
|
31620
|
+
function withReadOnlySessionDb(fn) {
|
|
31621
|
+
return fn(getReadOnlySessionDb());
|
|
31622
|
+
}
|
|
31623
|
+
function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
31624
|
+
const row = db.prepare(`SELECT COUNT(*) as count FROM message WHERE session_id = ?
|
|
31625
|
+
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
31626
|
+
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
|
|
31627
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
31628
|
+
}
|
|
31629
|
+
function logProbeFailureOnce(resolution, error) {
|
|
31630
|
+
const failure = recordOpenCodeDbReadFailure(resolution, error);
|
|
31631
|
+
if (!claimOpenCodeDbDiagnosticOnce("session-state-probe", resolution))
|
|
31632
|
+
return;
|
|
31633
|
+
const message = `[magic-context] OpenCode DB probe failed: path=${resolution.path} source=${resolution.source} cause=${failure.message}`;
|
|
31634
|
+
probeLogObserverForTests?.(message);
|
|
31635
|
+
log(message);
|
|
31636
|
+
}
|
|
31637
|
+
function getMessageTimesFromOpenCodeDb(sessionId, messageIds) {
|
|
31638
|
+
const result = new Map;
|
|
31639
|
+
if (messageIds.length === 0 || !harnessOwnsOpenCodeStore())
|
|
31640
|
+
return result;
|
|
31641
|
+
try {
|
|
31642
|
+
withReadOnlySessionDb((db) => {
|
|
31643
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
31644
|
+
const rows = db.prepare(`SELECT id, time_created FROM message WHERE session_id = ? AND id IN (${placeholders})`).all(sessionId, ...messageIds);
|
|
31645
|
+
for (const row of rows) {
|
|
31646
|
+
if (typeof row.id === "string" && typeof row.time_created === "number") {
|
|
31647
|
+
result.set(row.id, row.time_created);
|
|
31648
|
+
}
|
|
31649
|
+
}
|
|
31650
|
+
});
|
|
31651
|
+
} catch (error) {
|
|
31652
|
+
logProbeFailureOnce(resolveOpenCodeDbPath(), error);
|
|
31653
|
+
}
|
|
31654
|
+
return result;
|
|
31655
|
+
}
|
|
31656
|
+
var cachedReadOnlyDb = null, trackedSessions, pendingParts, probeLogObserverForTests;
|
|
31657
|
+
var init_read_session_db = __esm(async () => {
|
|
31658
|
+
init_logger();
|
|
31659
|
+
init_opencode_db_path();
|
|
31660
|
+
await __promiseAll([
|
|
31661
|
+
init_sqlite(),
|
|
31662
|
+
init_read_session_raw()
|
|
31663
|
+
]);
|
|
31664
|
+
trackedSessions = new Map;
|
|
31665
|
+
pendingParts = new Map;
|
|
30490
31666
|
});
|
|
30491
31667
|
|
|
30492
31668
|
// ../plugin/src/hooks/magic-context/read-session-true-raw-tokens.ts
|
|
@@ -30538,7 +31714,7 @@ function callIdFromPart(part) {
|
|
|
30538
31714
|
const state = isRecord2(part.state) ? part.state : null;
|
|
30539
31715
|
return state ? firstStringField(state, ["callID", "callId", "toolCallId", "tool_call_id", "id"]) ?? "" : "";
|
|
30540
31716
|
}
|
|
30541
|
-
function toolSignalFromPart(part) {
|
|
31717
|
+
function toolSignalFromPart(part, withText = true) {
|
|
30542
31718
|
if (!isRecord2(part))
|
|
30543
31719
|
return null;
|
|
30544
31720
|
const type = partType(part);
|
|
@@ -30557,8 +31733,8 @@ function toolSignalFromPart(part) {
|
|
|
30557
31733
|
callId,
|
|
30558
31734
|
hasInput: hasInput || openInvocation,
|
|
30559
31735
|
hasOutput,
|
|
30560
|
-
inputText: hasInput && state ? stringValue(state.input) : "",
|
|
30561
|
-
outputText: hasOutput ? stringValue(outputValue) : ""
|
|
31736
|
+
inputText: withText && hasInput && state ? stringValue(state.input) : "",
|
|
31737
|
+
outputText: withText && hasOutput ? stringValue(outputValue) : ""
|
|
30562
31738
|
};
|
|
30563
31739
|
}
|
|
30564
31740
|
if (type === "tool-invocation") {
|
|
@@ -30567,7 +31743,7 @@ function toolSignalFromPart(part) {
|
|
|
30567
31743
|
callId,
|
|
30568
31744
|
hasInput: args !== undefined,
|
|
30569
31745
|
hasOutput: false,
|
|
30570
|
-
inputText: args !== undefined ? stringValue(args) : "",
|
|
31746
|
+
inputText: withText && args !== undefined ? stringValue(args) : "",
|
|
30571
31747
|
outputText: ""
|
|
30572
31748
|
};
|
|
30573
31749
|
}
|
|
@@ -30577,7 +31753,7 @@ function toolSignalFromPart(part) {
|
|
|
30577
31753
|
callId,
|
|
30578
31754
|
hasInput: input !== undefined,
|
|
30579
31755
|
hasOutput: false,
|
|
30580
|
-
inputText: input !== undefined ? stringValue(input) : "",
|
|
31756
|
+
inputText: withText && input !== undefined ? stringValue(input) : "",
|
|
30581
31757
|
outputText: ""
|
|
30582
31758
|
};
|
|
30583
31759
|
}
|
|
@@ -30588,7 +31764,7 @@ function toolSignalFromPart(part) {
|
|
|
30588
31764
|
hasInput: false,
|
|
30589
31765
|
hasOutput: content !== undefined,
|
|
30590
31766
|
inputText: "",
|
|
30591
|
-
outputText: content !== undefined ? textFromToolResultContent(content) : ""
|
|
31767
|
+
outputText: withText && content !== undefined ? textFromToolResultContent(content) : ""
|
|
30592
31768
|
};
|
|
30593
31769
|
}
|
|
30594
31770
|
return null;
|
|
@@ -30598,7 +31774,7 @@ function buildToolArcs(messages) {
|
|
|
30598
31774
|
const arcs = [];
|
|
30599
31775
|
for (const message of messages) {
|
|
30600
31776
|
for (const part of message.parts) {
|
|
30601
|
-
const signal = toolSignalFromPart(part);
|
|
31777
|
+
const signal = toolSignalFromPart(part, false);
|
|
30602
31778
|
if (!signal || signal.callId.length === 0)
|
|
30603
31779
|
continue;
|
|
30604
31780
|
if (signal.hasInput && signal.hasOutput) {
|
|
@@ -30637,6 +31813,7 @@ function buildToolArcs(messages) {
|
|
|
30637
31813
|
}
|
|
30638
31814
|
var MAX_MESSAGE_CACHE_KEY_BYTES, messageEstimateCache, messageEstimateKeysByField;
|
|
30639
31815
|
var init_read_session_true_raw_tokens = __esm(() => {
|
|
31816
|
+
init_provider_visible_parts();
|
|
30640
31817
|
init_read_session_formatting();
|
|
30641
31818
|
MAX_MESSAGE_CACHE_KEY_BYTES = 64 * 1024 * 1024;
|
|
30642
31819
|
messageEstimateCache = new Map;
|
|
@@ -30798,6 +31975,7 @@ __export(exports_read_session_chunk, {
|
|
|
30798
31975
|
hasMeaningfulUserText: () => hasMeaningfulUserText,
|
|
30799
31976
|
hasRawMessageProvider: () => hasRawMessageProvider,
|
|
30800
31977
|
hasRawSessionMessageById: () => hasRawSessionMessageById,
|
|
31978
|
+
prepareRawSessionOrdinals: () => prepareRawSessionOrdinals,
|
|
30801
31979
|
primeInMemoryTailRawMessageCache: () => primeInMemoryTailRawMessageCache,
|
|
30802
31980
|
primeTailRawMessageCache: () => primeTailRawMessageCache,
|
|
30803
31981
|
readRawSessionMessageById: () => readRawSessionMessageById,
|
|
@@ -31068,6 +32246,36 @@ function readRawSessionMessageRange(sessionId, fromOrdinal, toOrdinal) {
|
|
|
31068
32246
|
}
|
|
31069
32247
|
return messages;
|
|
31070
32248
|
}
|
|
32249
|
+
async function prepareRawSessionOrdinals(sessionId) {
|
|
32250
|
+
if (sessionProviders.get(sessionId)?.provider)
|
|
32251
|
+
return true;
|
|
32252
|
+
if (!openCodeDbExists())
|
|
32253
|
+
return true;
|
|
32254
|
+
const db = withReadOnlySessionDb((connection) => connection);
|
|
32255
|
+
let timer;
|
|
32256
|
+
const deadline = Date.now() + 250;
|
|
32257
|
+
const prepare = async () => {
|
|
32258
|
+
for (let attempt = 0;attempt < 3 && Date.now() < deadline; attempt++) {
|
|
32259
|
+
if (await prewarmRawSessionOrdinalsForDb(db, sessionId) === "warm")
|
|
32260
|
+
return true;
|
|
32261
|
+
}
|
|
32262
|
+
return false;
|
|
32263
|
+
};
|
|
32264
|
+
try {
|
|
32265
|
+
const ready = await Promise.race([
|
|
32266
|
+
prepare(),
|
|
32267
|
+
new Promise((resolve) => {
|
|
32268
|
+
timer = setTimeout(() => resolve(false), 250);
|
|
32269
|
+
})
|
|
32270
|
+
]);
|
|
32271
|
+
if (!ready) {
|
|
32272
|
+
sessionLog(sessionId, "WARN canonical ordinal preparation unavailable within 250ms; exact reads must defer or retry");
|
|
32273
|
+
}
|
|
32274
|
+
return ready;
|
|
32275
|
+
} finally {
|
|
32276
|
+
clearTimeout(timer);
|
|
32277
|
+
}
|
|
32278
|
+
}
|
|
31071
32279
|
function primeTailRawMessageCache(args) {
|
|
31072
32280
|
const { sessionId, lastCompartmentEnd, anchorMessageId } = args;
|
|
31073
32281
|
if (!activeRawMessageCache)
|
|
@@ -31702,22 +32910,28 @@ function readRawSessionSeedTail(sessionId, boundaryId, onQuery) {
|
|
|
31702
32910
|
}
|
|
31703
32911
|
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
32912
|
var init_read_session_chunk = __esm(async () => {
|
|
31705
|
-
init_storage_tags();
|
|
31706
32913
|
init_historian_tool_expansions();
|
|
32914
|
+
init_logger();
|
|
31707
32915
|
init_read_session_formatting();
|
|
31708
|
-
init_read_session_raw();
|
|
31709
32916
|
init_read_session_true_raw_tokens();
|
|
31710
32917
|
init_system_injection_stripper();
|
|
31711
32918
|
init_tag_part_guards();
|
|
31712
32919
|
init_tool_drop_target();
|
|
31713
32920
|
init_read_session_formatting();
|
|
31714
|
-
await
|
|
32921
|
+
await __promiseAll([
|
|
32922
|
+
init_storage_tags(),
|
|
32923
|
+
init_raw_ordinal_warmup(),
|
|
32924
|
+
init_read_session_db(),
|
|
32925
|
+
init_read_session_raw()
|
|
32926
|
+
]);
|
|
31715
32927
|
blockTokenMemo = new Map;
|
|
31716
32928
|
sessionProviders = new Map;
|
|
31717
32929
|
boundedProviderWrappers = new WeakMap;
|
|
31718
32930
|
SYSTEM_REMINDER_BLOCK_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
31719
32931
|
readRawSessionMessages.readPage = readRawSessionMessagePage;
|
|
31720
32932
|
readRawSessionMessages.getCount = getRawSessionMessageOrdinalCount;
|
|
32933
|
+
readRawSessionMessages.prepare = prepareRawSessionOrdinals;
|
|
32934
|
+
readRawSessionMessageById.prepare = prepareRawSessionOrdinals;
|
|
31721
32935
|
});
|
|
31722
32936
|
|
|
31723
32937
|
// ../plugin/src/features/magic-context/message-time-backfill.ts
|
|
@@ -33578,6 +34792,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
33578
34792
|
const version = getPersistedSchemaVersion(db);
|
|
33579
34793
|
if (version === 0 || version >= 95)
|
|
33580
34794
|
installV95PerfSchema(db, false, version === 0);
|
|
34795
|
+
installTagIdentityRevisionTrigger(db);
|
|
33581
34796
|
}
|
|
33582
34797
|
function healWedgedChannel2Claims(db) {
|
|
33583
34798
|
try {
|
|
@@ -33657,6 +34872,7 @@ function openDatabase(dbPathOrOptions) {
|
|
|
33657
34872
|
} else
|
|
33658
34873
|
runMigrations(db);
|
|
33659
34874
|
ensureContextStoreUuid(db);
|
|
34875
|
+
installTagIdentityRevisionTrigger(db);
|
|
33660
34876
|
return finishDatabaseOpen(db, dbPath, explicitDbPath, latestSupportedVersion);
|
|
33661
34877
|
} catch (error) {
|
|
33662
34878
|
if (db)
|
|
@@ -33691,6 +34907,7 @@ var init_storage_db = __esm(async () => {
|
|
|
33691
34907
|
init_migration_v95_perf_indexes();
|
|
33692
34908
|
init_migration_worker_client();
|
|
33693
34909
|
init_storage_schema_helpers();
|
|
34910
|
+
init_storage_tag_identity_revision();
|
|
33694
34911
|
init_tool_definition_tokens();
|
|
33695
34912
|
init_tool_owner_backfill();
|
|
33696
34913
|
await __promiseAll([
|
|
@@ -33896,6 +35113,9 @@ var init_config_location_migration = __esm(() => {
|
|
|
33896
35113
|
});
|
|
33897
35114
|
|
|
33898
35115
|
// ../plugin/src/features/magic-context/dreamer/task-registry.ts
|
|
35116
|
+
function availableDreamTasks(smartNotesEnabled = true) {
|
|
35117
|
+
return CANONICAL_DREAM_TASKS.filter((task) => smartNotesEnabled || task !== "evaluate-smart-notes");
|
|
35118
|
+
}
|
|
33899
35119
|
var CANONICAL_DREAM_TASKS, DREAM_TOOL_LOOP_TOKEN_BUDGETS, MEMORY_DOMAIN_TASKS, MEMORY_DOMAIN_SET;
|
|
33900
35120
|
var init_task_registry = __esm(() => {
|
|
33901
35121
|
CANONICAL_DREAM_TASKS = [
|
|
@@ -34646,8 +35866,10 @@ function openCodeConfigFileChain(directory, hostGeneration) {
|
|
|
34646
35866
|
const globalSupplementary = getOpenCodeConfigDirs().filter((dir) => dir !== globalDir).flatMap((dir) => [join17(dir, "opencode.json"), join17(dir, "opencode.jsonc")]);
|
|
34647
35867
|
const explicitConfig = process.env.OPENCODE_CONFIG?.trim();
|
|
34648
35868
|
const explicit = explicitConfig ? [explicitConfig] : [];
|
|
34649
|
-
const
|
|
34650
|
-
const
|
|
35869
|
+
const disableProjectConfig = process.env.OPENCODE_DISABLE_PROJECT_CONFIG?.toLowerCase();
|
|
35870
|
+
const skipProject = hostGeneration === "v1" && (disableProjectConfig === "true" || disableProjectConfig === "1");
|
|
35871
|
+
const direct = skipProject ? [] : [join17(directory, "opencode.json"), join17(directory, "opencode.jsonc")];
|
|
35872
|
+
const projectSupplementary = skipProject ? [] : [
|
|
34651
35873
|
join17(directory, ".opencode", "opencode.json"),
|
|
34652
35874
|
join17(directory, ".opencode", "opencode.jsonc")
|
|
34653
35875
|
];
|
|
@@ -35877,6 +37099,24 @@ function readCachedPluginVersion(pluginCacheDir) {
|
|
|
35877
37099
|
return;
|
|
35878
37100
|
}
|
|
35879
37101
|
}
|
|
37102
|
+
function readOpenCodePluginConfigUse(config, configDir) {
|
|
37103
|
+
const use = {
|
|
37104
|
+
referencedSpecs: {
|
|
37105
|
+
opencode1: readReferencedOpenCodePluginSpecs(config, "opencode1"),
|
|
37106
|
+
opencode2: readReferencedOpenCodePluginSpecs(config, "opencode2")
|
|
37107
|
+
},
|
|
37108
|
+
loadedFrom: {}
|
|
37109
|
+
};
|
|
37110
|
+
for (const { key, entry } of readPluginEntries(config)) {
|
|
37111
|
+
if (!isDevPathPluginEntry(entry, configDir))
|
|
37112
|
+
continue;
|
|
37113
|
+
const specifier = pluginEntryPackage(entry) ?? undefined;
|
|
37114
|
+
if (key === "plugin")
|
|
37115
|
+
use.loadedFrom.opencode1 ??= specifier;
|
|
37116
|
+
use.loadedFrom.opencode2 ??= specifier;
|
|
37117
|
+
}
|
|
37118
|
+
return use;
|
|
37119
|
+
}
|
|
35880
37120
|
async function clearPluginCache(options = {}, deps = {}) {
|
|
35881
37121
|
const remove = deps.remove ?? ((path) => rmSync6(path, { recursive: true, force: true }));
|
|
35882
37122
|
const pluginCacheRoots = getOpenCodePluginCacheRoots();
|
|
@@ -35889,6 +37129,15 @@ async function clearPluginCache(options = {}, deps = {}) {
|
|
|
35889
37129
|
path,
|
|
35890
37130
|
cached: readCachedPluginVersion(path)
|
|
35891
37131
|
}));
|
|
37132
|
+
if (options.referencedSpecs !== undefined && !options.referencedSpecs.has("latest")) {
|
|
37133
|
+
const firstEntry = cacheEntries[0];
|
|
37134
|
+
return {
|
|
37135
|
+
action: "unused",
|
|
37136
|
+
path: firstEntry?.path ?? pluginCacheRoots[0] ?? "",
|
|
37137
|
+
paths: cacheEntries.map((entry) => entry.path),
|
|
37138
|
+
cached: firstEntry?.cached
|
|
37139
|
+
};
|
|
37140
|
+
}
|
|
35892
37141
|
if (options.force !== true && latestVersion === undefined) {
|
|
35893
37142
|
const firstEntry = cacheEntries[0];
|
|
35894
37143
|
return {
|
|
@@ -35960,15 +37209,24 @@ async function clearPluginCache(options = {}, deps = {}) {
|
|
|
35960
37209
|
}
|
|
35961
37210
|
var init_doctor_opencode_cache = __esm(async () => {
|
|
35962
37211
|
init_opencode_plugin_cache();
|
|
35963
|
-
|
|
37212
|
+
init_opencode_plugin_registration();
|
|
37213
|
+
await __promiseAll([
|
|
37214
|
+
init_opencode(),
|
|
37215
|
+
init_doctor_opencode2_cache()
|
|
37216
|
+
]);
|
|
35964
37217
|
});
|
|
35965
37218
|
|
|
35966
37219
|
// src/commands/doctor-cached-plugin-fence.ts
|
|
35967
37220
|
import { existsSync as existsSync29 } from "node:fs";
|
|
35968
37221
|
import { dirname as dirname15 } from "node:path";
|
|
37222
|
+
function isReferenced(sources, host, spec) {
|
|
37223
|
+
const specs = sources.referencedSpecs?.[host];
|
|
37224
|
+
return specs === undefined || specs.has(spec);
|
|
37225
|
+
}
|
|
35969
37226
|
function listCachedOpenCodePluginFences(sources = {}) {
|
|
35970
37227
|
const fences = [];
|
|
35971
|
-
|
|
37228
|
+
const v1Referenced = isReferenced(sources, "opencode1", "latest");
|
|
37229
|
+
for (const root of v1Referenced ? sources.openCodeV1Roots ?? getOpenCodePluginCacheRoots() : []) {
|
|
35972
37230
|
const packageJson = getOpenCodePluginPackageJsonPath(root);
|
|
35973
37231
|
if (!existsSync29(packageJson))
|
|
35974
37232
|
continue;
|
|
@@ -35982,6 +37240,8 @@ function listCachedOpenCodePluginFences(sources = {}) {
|
|
|
35982
37240
|
for (const slot of listOpenCodeV2PluginCacheSlots(sources.openCodeV2NpmCacheDir)) {
|
|
35983
37241
|
if (!isOpenCodePluginDistTag(slot.spec))
|
|
35984
37242
|
continue;
|
|
37243
|
+
if (!isReferenced(sources, "opencode2", slot.spec))
|
|
37244
|
+
continue;
|
|
35985
37245
|
const generation = getOpenCodeV2ActiveGeneration(slot.slot);
|
|
35986
37246
|
if (!generation)
|
|
35987
37247
|
continue;
|
|
@@ -41170,11 +42430,6 @@ var init_user_facing_codes = __esm(() => {
|
|
|
41170
42430
|
sentence: "Magic Context has no context.db.",
|
|
41171
42431
|
action: "Run `npx @cortexkit/magic-context doctor store init`, then restart ck-mc."
|
|
41172
42432
|
},
|
|
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
42433
|
single_store_migration_required: {
|
|
41179
42434
|
code: "MC-C14",
|
|
41180
42435
|
sentence: "Magic Context's Rust mode needs a one-time migration of its store.",
|
|
@@ -42765,7 +44020,9 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
42765
44020
|
delete configToMigrate.protected_tags;
|
|
42766
44021
|
}
|
|
42767
44022
|
const agentMigrated = migrateLegacyAgentEnabledInMemory(configToMigrate, preMigrationWarnings);
|
|
42768
|
-
const
|
|
44023
|
+
const migratedExperimental = migrateLegacyExperimental(agentMigrated, preMigrationWarnings);
|
|
44024
|
+
warnDeprecatedMuralModel(migratedExperimental, preMigrationWarnings);
|
|
44025
|
+
const migrated = migrateDreamerV2(migratedExperimental, preMigrationWarnings);
|
|
42769
44026
|
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
42770
44027
|
if (parsed.success) {
|
|
42771
44028
|
return { config: parsed.data, warnings: preMigrationWarnings };
|
|
@@ -43607,64 +44864,66 @@ async function runHealthChecks(options) {
|
|
|
43607
44864
|
add(results, "fail", "OMP binary not found on PATH or in standard user bin directories");
|
|
43608
44865
|
} else {
|
|
43609
44866
|
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
44867
|
const plugins = options.deps.listOmpPlugins(omp.path);
|
|
43617
44868
|
if (!plugins) {
|
|
43618
44869
|
add(results, "fail", "`omp plugin list --json` failed or returned invalid JSON");
|
|
43619
44870
|
} else {
|
|
43620
44871
|
const plugin = plugins.find((entry) => entry.name === OMP_PLUGIN_PACKAGE);
|
|
43621
44872
|
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`);
|
|
44873
|
+
add(results, "info", `${version ? `Oh My Pi ${version}` : "Oh My Pi"} found; Magic Context is not installed there (run setup to add it)`);
|
|
43626
44874
|
repairPlan.installPlugin = true;
|
|
43627
44875
|
} 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
|
-
|
|
44876
|
+
if (!version) {
|
|
44877
|
+
add(results, "fail", `OMP at ${omp.path} could not report its version`);
|
|
44878
|
+
} else if (isOlderThan(version, MIN_OMP_VERSION)) {
|
|
44879
|
+
add(results, "fail", `OMP ${version} is older than tested minimum ${MIN_OMP_VERSION}`);
|
|
44880
|
+
} else
|
|
44881
|
+
add(results, "pass", `OMP ${version} detected at ${omp.path}`);
|
|
44882
|
+
if (!plugin.enabled) {
|
|
44883
|
+
add(results, "fail", `${OMP_PLUGIN_PACKAGE} is installed but disabled in OMP`);
|
|
44884
|
+
repairPlan.installPlugin = true;
|
|
44885
|
+
} else {
|
|
44886
|
+
add(results, "pass", `${OMP_PLUGIN_PACKAGE} ${plugin.version} is enabled`);
|
|
44887
|
+
const manifest = pluginDeclaresOmp(plugin.path);
|
|
44888
|
+
if (manifest === true)
|
|
44889
|
+
add(results, "pass", "Plugin exposes an OMP/Pi extension manifest");
|
|
44890
|
+
else if (manifest === false)
|
|
44891
|
+
add(results, "fail", "Installed plugin has no OMP/Pi extension manifest");
|
|
44892
|
+
else
|
|
44893
|
+
add(results, "warn", "Could not inspect the installed plugin manifest");
|
|
44894
|
+
}
|
|
44895
|
+
const compaction = options.deps.getOmpSetting(omp.path, "compaction.enabled");
|
|
44896
|
+
if (compaction === false)
|
|
44897
|
+
add(results, "pass", "OMP native compaction is disabled");
|
|
44898
|
+
else if (compaction === true) {
|
|
44899
|
+
add(results, "fail", "OMP native compaction is enabled and conflicts with Magic Context");
|
|
44900
|
+
repairPlan.disableCompaction = true;
|
|
44901
|
+
} else
|
|
44902
|
+
add(results, "fail", "Could not read OMP compaction.enabled");
|
|
44903
|
+
const memory = options.deps.getOmpSetting(omp.path, "memory.backend");
|
|
44904
|
+
if (memory === "off")
|
|
44905
|
+
add(results, "pass", "OMP automatic memory backend is disabled");
|
|
44906
|
+
else if (typeof memory === "string") {
|
|
44907
|
+
add(results, "fail", `OMP memory.backend=${memory} duplicates Magic Context memory injection`);
|
|
44908
|
+
repairPlan.disableMemory = true;
|
|
44909
|
+
} else
|
|
44910
|
+
add(results, "fail", "Could not read OMP memory.backend");
|
|
44911
|
+
const nonGlobalSources = getOmpNonGlobalConfigSources(options.cwd);
|
|
44912
|
+
if (nonGlobalSources.length > 0 && (repairPlan.disableCompaction || repairPlan.disableMemory)) {
|
|
44913
|
+
add(results, "warn", "OMP project/overlay config owns effective conflicting settings; automatic global repair is disabled: " + nonGlobalSources.join(", "));
|
|
44914
|
+
}
|
|
44915
|
+
const reportedAgentDir = options.deps.runOmpCommand(omp.path, ["config", "path"], 1e4);
|
|
44916
|
+
if (!reportedAgentDir.ok) {
|
|
44917
|
+
add(results, "warn", "Could not verify OMP active agent directory");
|
|
44918
|
+
} else {
|
|
44919
|
+
const reportedPath = resolve15(reportedAgentDir.stdout);
|
|
44920
|
+
const expectedPath = resolve15(getOmpAgentDir());
|
|
44921
|
+
if (reportedPath === expectedPath) {
|
|
44922
|
+
add(results, "pass", `OMP agent directory resolved to ${getOmpAgentDir()}`);
|
|
44923
|
+
} else {
|
|
44924
|
+
add(results, "fail", `OMP reports agent directory ${reportedAgentDir.stdout}, but Magic Context resolved ${getOmpAgentDir()}`);
|
|
44925
|
+
}
|
|
44926
|
+
}
|
|
43668
44927
|
}
|
|
43669
44928
|
}
|
|
43670
44929
|
}
|
|
@@ -46665,6 +47924,16 @@ function listDanglingCompartmentBoundaries(contextDb, openCodeDb, hostGeneration
|
|
|
46665
47924
|
ORDER BY c.session_id ASC, c.sequence ASC`).all();
|
|
46666
47925
|
const statement = openCodeDb.prepare(`SELECT 1 AS found FROM ${selection.table} WHERE session_id = ? AND id = ? LIMIT 1`);
|
|
46667
47926
|
const exists = (sessionId, messageId) => statement.get(sessionId, messageId) != null;
|
|
47927
|
+
const sessionStatement = openCodeDb.prepare(`SELECT 1 AS found FROM ${selection.table} WHERE session_id = ? LIMIT 1`);
|
|
47928
|
+
const sessionPresence = new Map;
|
|
47929
|
+
const sessionInStore = (sessionId) => {
|
|
47930
|
+
let present = sessionPresence.get(sessionId);
|
|
47931
|
+
if (present === undefined) {
|
|
47932
|
+
present = sessionStatement.get(sessionId) != null;
|
|
47933
|
+
sessionPresence.set(sessionId, present);
|
|
47934
|
+
}
|
|
47935
|
+
return present;
|
|
47936
|
+
};
|
|
46668
47937
|
return rows.flatMap((row) => {
|
|
46669
47938
|
const missingStart = !exists(row.session_id, row.start_message_id);
|
|
46670
47939
|
const missingEnd = !exists(row.session_id, row.end_message_id);
|
|
@@ -46675,7 +47944,8 @@ function listDanglingCompartmentBoundaries(contextDb, openCodeDb, hostGeneration
|
|
|
46675
47944
|
sessionId: row.session_id,
|
|
46676
47945
|
sequence: row.sequence,
|
|
46677
47946
|
missingStartMessageId: missingStart ? row.start_message_id : null,
|
|
46678
|
-
missingEndMessageId: missingEnd ? row.end_message_id : null
|
|
47947
|
+
missingEndMessageId: missingEnd ? row.end_message_id : null,
|
|
47948
|
+
sessionInStore: sessionInStore(row.session_id)
|
|
46679
47949
|
}
|
|
46680
47950
|
];
|
|
46681
47951
|
});
|
|
@@ -46687,6 +47957,52 @@ function formatDanglingCompartmentBoundary(boundary) {
|
|
|
46687
47957
|
].filter((value) => value !== null);
|
|
46688
47958
|
return `session=${boundary.sessionId} sequence=${boundary.sequence} missing ${missing.join(" ")}`;
|
|
46689
47959
|
}
|
|
47960
|
+
function countDanglingCompartmentBoundariesBySession(boundaries) {
|
|
47961
|
+
const bySession = new Map;
|
|
47962
|
+
for (const boundary of boundaries) {
|
|
47963
|
+
const entry = bySession.get(boundary.sessionId);
|
|
47964
|
+
if (entry)
|
|
47965
|
+
entry.count++;
|
|
47966
|
+
else
|
|
47967
|
+
bySession.set(boundary.sessionId, {
|
|
47968
|
+
sessionId: boundary.sessionId,
|
|
47969
|
+
count: 1,
|
|
47970
|
+
sessionInStore: boundary.sessionInStore
|
|
47971
|
+
});
|
|
47972
|
+
}
|
|
47973
|
+
return [...bySession.values()].sort((a, b) => b.count - a.count || a.sessionId.localeCompare(b.sessionId));
|
|
47974
|
+
}
|
|
47975
|
+
function formatDanglingCompartmentBoundaryHeadline(boundaries, store) {
|
|
47976
|
+
const sessions = countDanglingCompartmentBoundariesBySession(boundaries);
|
|
47977
|
+
const absent = sessions.filter((session) => !session.sessionInStore).length;
|
|
47978
|
+
const scope = `${boundaries.length} compartment(s) in ${sessions.length} session(s)`;
|
|
47979
|
+
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.` : "";
|
|
47980
|
+
if (store === "opencode2") {
|
|
47981
|
+
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.`;
|
|
47982
|
+
}
|
|
47983
|
+
return `${scope} have dangling OpenCode boundary ids.${absentNote}`;
|
|
47984
|
+
}
|
|
47985
|
+
function formatDanglingCompartmentBoundaryDetails(boundaries, options = {}) {
|
|
47986
|
+
const limit = options.verbose ? Number.POSITIVE_INFINITY : options.limit ?? DANGLING_BOUNDARY_EXAMPLE_LIMIT;
|
|
47987
|
+
const sessions = countDanglingCompartmentBoundariesBySession(boundaries);
|
|
47988
|
+
const lines = [];
|
|
47989
|
+
lines.push(options.verbose || sessions.length <= limit ? "By session:" : `By session (largest ${limit} of ${sessions.length}):`);
|
|
47990
|
+
for (const session of sessions.slice(0, limit)) {
|
|
47991
|
+
lines.push(` session=${session.sessionId}: ${session.count} compartment(s)${session.sessionInStore ? "" : " (session has no messages in this store)"}`);
|
|
47992
|
+
}
|
|
47993
|
+
if (sessions.length > limit) {
|
|
47994
|
+
lines.push(` … and ${sessions.length - limit} more session(s)`);
|
|
47995
|
+
}
|
|
47996
|
+
lines.push(options.verbose || boundaries.length <= limit ? "Compartments:" : `Examples (${limit} of ${boundaries.length}):`);
|
|
47997
|
+
for (const boundary of boundaries.slice(0, limit)) {
|
|
47998
|
+
lines.push(` ${formatDanglingCompartmentBoundary(boundary)}`);
|
|
47999
|
+
}
|
|
48000
|
+
if (sessions.length > limit || boundaries.length > limit) {
|
|
48001
|
+
lines.push(`Run \`magic-context doctor --verbose\` for the full list of ${boundaries.length} compartment(s).`);
|
|
48002
|
+
}
|
|
48003
|
+
return lines;
|
|
48004
|
+
}
|
|
48005
|
+
var DANGLING_BOUNDARY_EXAMPLE_LIMIT = 10;
|
|
46690
48006
|
|
|
46691
48007
|
// src/commands/doctor-harness-relabel.ts
|
|
46692
48008
|
function reportUnresolvedHarnessRelabel(args) {
|
|
@@ -46840,6 +48156,9 @@ function withPluginEntrySpecifier(entry, specifier) {
|
|
|
46840
48156
|
}
|
|
46841
48157
|
return specifier;
|
|
46842
48158
|
}
|
|
48159
|
+
function isOpenCodePluginRegistered(config, configDir) {
|
|
48160
|
+
return readPluginEntries(config).some(({ entry }) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry, configDir));
|
|
48161
|
+
}
|
|
46843
48162
|
function checkOpenCodePluginEntry(config, configName, options, report) {
|
|
46844
48163
|
const allEntries = readPluginEntries(config);
|
|
46845
48164
|
const found = allEntries.find(({ entry }) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry, options.configDir));
|
|
@@ -47497,6 +48816,21 @@ function logOpenCodeInstallationTable(installations) {
|
|
|
47497
48816
|
function describeOpenCode2SessionAPIRequirement(hostVersion) {
|
|
47498
48817
|
return `OpenCode host ${hostVersion}; Magic Context requires OpenCode 2.0.22 or newer with session.remove and session.compact.`;
|
|
47499
48818
|
}
|
|
48819
|
+
function getOpenCodePluginHostStatus(hostLabel, hostVersion, installed) {
|
|
48820
|
+
if (!installed) {
|
|
48821
|
+
return {
|
|
48822
|
+
status: "info",
|
|
48823
|
+
message: `${hostLabel} found; Magic Context is not installed there (run setup to add it)`
|
|
48824
|
+
};
|
|
48825
|
+
}
|
|
48826
|
+
if (openCodeHostGenerationFromVersion(hostVersion) === "v2" && compareVersions(hostVersion, "2.0.22") === -1) {
|
|
48827
|
+
return {
|
|
48828
|
+
status: "fail",
|
|
48829
|
+
message: describeOpenCode2SessionAPIRequirement(hostVersion)
|
|
48830
|
+
};
|
|
48831
|
+
}
|
|
48832
|
+
return null;
|
|
48833
|
+
}
|
|
47500
48834
|
async function runDoctor2(options = {}) {
|
|
47501
48835
|
migrateConfigLocationsForCli(process.cwd(), log3);
|
|
47502
48836
|
if (options.issue) {
|
|
@@ -47572,8 +48906,15 @@ async function runDoctor2(options = {}) {
|
|
|
47572
48906
|
pass(installationReports.length > 1 ? `OpenCode ${activeInstallation.version} installed (active install marked above)` : `OpenCode ${activeInstallation.version} installed`);
|
|
47573
48907
|
}
|
|
47574
48908
|
const hostGeneration = openCodeHostGenerationFromVersion(activeInstallation.version);
|
|
47575
|
-
|
|
47576
|
-
|
|
48909
|
+
const paths = detectConfigPaths();
|
|
48910
|
+
let magicContextInstalled = false;
|
|
48911
|
+
let magicContextStatusKnown = paths.opencodeConfigFormat === "none";
|
|
48912
|
+
if (!magicContextStatusKnown) {
|
|
48913
|
+
try {
|
|
48914
|
+
const config = import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8"));
|
|
48915
|
+
magicContextInstalled = isOpenCodePluginRegistered(config, dirname25(paths.opencodeConfig));
|
|
48916
|
+
magicContextStatusKnown = true;
|
|
48917
|
+
} catch {}
|
|
47577
48918
|
}
|
|
47578
48919
|
const storeHostSelection = selectOpenCodeStoreHost(installationReports, openCodeHostGenerationFromVersion);
|
|
47579
48920
|
const storeHost = storeHostSelection?.host ?? activeInstallation;
|
|
@@ -47591,7 +48932,9 @@ async function runDoctor2(options = {}) {
|
|
|
47591
48932
|
const openCodeDbCheck = describeOpenCodeDatabaseDoctorCheck(openCodeDbResolution);
|
|
47592
48933
|
if (openCodeDbCheck.ok)
|
|
47593
48934
|
pass(openCodeDbCheck.message);
|
|
47594
|
-
else
|
|
48935
|
+
else if (magicContextStatusKnown && !magicContextInstalled) {
|
|
48936
|
+
log3.info("OpenCode session database not yet created (will be created on first OpenCode session)");
|
|
48937
|
+
} else
|
|
47595
48938
|
fail(openCodeDbCheck.message);
|
|
47596
48939
|
if (openCodeDbCheck.ok) {
|
|
47597
48940
|
let markerDb = null;
|
|
@@ -47612,7 +48955,7 @@ async function runDoctor2(options = {}) {
|
|
|
47612
48955
|
} else if (options.fix) {
|
|
47613
48956
|
warn(`${summary}; repaired=${report.repaired}, but some rows remain unconvertible`);
|
|
47614
48957
|
} else if (report.migrationCompleted) {
|
|
47615
|
-
log3.info(`${summary}; OpenCode 2 already converted this store`);
|
|
48958
|
+
log3.info(`${summary}; OpenCode 2 already converted this store, so these markers no longer matter (informational, no action needed)`);
|
|
47616
48959
|
} else {
|
|
47617
48960
|
warn(`${summary}; run \`magic-context doctor --fix\` before upgrading OpenCode`);
|
|
47618
48961
|
}
|
|
@@ -47640,14 +48983,18 @@ async function runDoctor2(options = {}) {
|
|
|
47640
48983
|
if (dangling.length === 0) {
|
|
47641
48984
|
pass("Compartment boundary ids resolve in the OpenCode session store");
|
|
47642
48985
|
} else if (storeGeneration === "v2" && /\d/.test(storeHost.version)) {
|
|
47643
|
-
log3.info(
|
|
47644
|
-
for (const
|
|
47645
|
-
|
|
48986
|
+
log3.info(formatDanglingCompartmentBoundaryHeadline(dangling, "opencode2"));
|
|
48987
|
+
for (const line of formatDanglingCompartmentBoundaryDetails(dangling, {
|
|
48988
|
+
verbose: options.verbose
|
|
48989
|
+
})) {
|
|
48990
|
+
log3.info(` ${line}`);
|
|
47646
48991
|
}
|
|
47647
48992
|
} else {
|
|
47648
|
-
warn(
|
|
47649
|
-
for (const
|
|
47650
|
-
|
|
48993
|
+
warn(formatDanglingCompartmentBoundaryHeadline(dangling, "other"));
|
|
48994
|
+
for (const line of formatDanglingCompartmentBoundaryDetails(dangling, {
|
|
48995
|
+
verbose: options.verbose
|
|
48996
|
+
})) {
|
|
48997
|
+
log3.warn(` ${line}`);
|
|
47651
48998
|
}
|
|
47652
48999
|
}
|
|
47653
49000
|
if (!supportsCoordinateGenerationReporting(contextDb)) {
|
|
@@ -47683,10 +49030,7 @@ async function runDoctor2(options = {}) {
|
|
|
47683
49030
|
}
|
|
47684
49031
|
}
|
|
47685
49032
|
const selfVersion = getSelfVersion2();
|
|
47686
|
-
const
|
|
47687
|
-
fetchNpmLatest(CLI_PACKAGE_NAME),
|
|
47688
|
-
fetchNpmLatest(OPENCODE_PLUGIN_NAME)
|
|
47689
|
-
]);
|
|
49033
|
+
const npmLatest = await fetchNpmLatest(CLI_PACKAGE_NAME);
|
|
47690
49034
|
const cliComparison = npmLatest ? compareVersions(selfVersion, npmLatest) : null;
|
|
47691
49035
|
if (!npmLatest) {
|
|
47692
49036
|
log3.info(`Magic Context CLI v${selfVersion}; npm latest check unavailable`);
|
|
@@ -47697,9 +49041,8 @@ async function runDoctor2(options = {}) {
|
|
|
47697
49041
|
} else {
|
|
47698
49042
|
pass(`Magic Context CLI v${selfVersion} is current (npm latest v${npmLatest})`);
|
|
47699
49043
|
}
|
|
47700
|
-
const paths = detectConfigPaths();
|
|
47701
49044
|
if (paths.opencodeConfigFormat === "none") {
|
|
47702
|
-
|
|
49045
|
+
magicContextStatusKnown = true;
|
|
47703
49046
|
} else {
|
|
47704
49047
|
pass(`OpenCode config: ${paths.opencodeConfig}`);
|
|
47705
49048
|
}
|
|
@@ -47869,6 +49212,7 @@ async function runDoctor2(options = {}) {
|
|
|
47869
49212
|
log3.warn("Could not migrate deprecated config keys in magic-context.jsonc");
|
|
47870
49213
|
}
|
|
47871
49214
|
}
|
|
49215
|
+
const openCodeHostLabel = activeInstallation.kind === "desktop" ? "OpenCode Desktop" : activeInstallation.version === "unknown" ? "OpenCode" : `OpenCode ${activeInstallation.version}`;
|
|
47872
49216
|
const reportedAutoUpdateStalls = new Set;
|
|
47873
49217
|
const reportAutoUpdateStall = (specifier) => {
|
|
47874
49218
|
const message = describeAutoUpdateStall(specifier, autoUpdateEnabled);
|
|
@@ -47883,71 +49227,90 @@ async function runDoctor2(options = {}) {
|
|
|
47883
49227
|
const config = import_comment_json11.parse(raw);
|
|
47884
49228
|
const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
|
|
47885
49229
|
const configDir = dirname25(paths.opencodeConfig);
|
|
47886
|
-
|
|
47887
|
-
|
|
47888
|
-
|
|
47889
|
-
|
|
47890
|
-
|
|
47891
|
-
|
|
47892
|
-
|
|
47893
|
-
|
|
47894
|
-
|
|
49230
|
+
magicContextInstalled = isOpenCodePluginRegistered(config, configDir);
|
|
49231
|
+
magicContextStatusKnown = true;
|
|
49232
|
+
if (magicContextInstalled) {
|
|
49233
|
+
if (checkPluginDuplicates(config, configName, { fix: options.fix, configDir }, {
|
|
49234
|
+
warn,
|
|
49235
|
+
pass: (message) => {
|
|
49236
|
+
pass(message);
|
|
49237
|
+
fixed++;
|
|
49238
|
+
},
|
|
49239
|
+
info: (message) => log3.info(message)
|
|
49240
|
+
})) {
|
|
49241
|
+
writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config, null, 2)}
|
|
47895
49242
|
`);
|
|
47896
|
-
|
|
47897
|
-
|
|
47898
|
-
|
|
47899
|
-
|
|
47900
|
-
|
|
47901
|
-
|
|
47902
|
-
|
|
47903
|
-
|
|
47904
|
-
|
|
47905
|
-
|
|
47906
|
-
|
|
47907
|
-
|
|
47908
|
-
|
|
47909
|
-
|
|
47910
|
-
|
|
47911
|
-
|
|
47912
|
-
|
|
47913
|
-
|
|
47914
|
-
|
|
49243
|
+
}
|
|
49244
|
+
const allEntries = readPluginEntries(config);
|
|
49245
|
+
if (allEntries.some(({ entry }) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry, configDir))) {
|
|
49246
|
+
warn("An unverifiable local OpenCode plugin path was ignored because its package name is not Magic Context");
|
|
49247
|
+
}
|
|
49248
|
+
if (checkOpenCodePluginEntry(config, configName, {
|
|
49249
|
+
force: options.force,
|
|
49250
|
+
registrationKey: pluginConfigKeyFor(hostGeneration),
|
|
49251
|
+
configDir
|
|
49252
|
+
}, {
|
|
49253
|
+
pass,
|
|
49254
|
+
warn,
|
|
49255
|
+
fixed: (message) => {
|
|
49256
|
+
pass(message);
|
|
49257
|
+
fixed++;
|
|
49258
|
+
},
|
|
49259
|
+
autoUpdateStall: reportAutoUpdateStall
|
|
49260
|
+
})) {
|
|
49261
|
+
writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config, null, 2)}
|
|
47915
49262
|
`);
|
|
49263
|
+
}
|
|
47916
49264
|
}
|
|
47917
49265
|
} catch {
|
|
47918
49266
|
warn("Could not parse opencode config to verify plugin entry");
|
|
47919
49267
|
}
|
|
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
49268
|
} else {
|
|
47938
|
-
|
|
47939
|
-
|
|
47940
|
-
|
|
47941
|
-
|
|
47942
|
-
|
|
49269
|
+
magicContextStatusKnown = true;
|
|
49270
|
+
}
|
|
49271
|
+
if (!magicContextStatusKnown)
|
|
49272
|
+
magicContextInstalled = true;
|
|
49273
|
+
const hostPluginStatus = magicContextStatusKnown ? getOpenCodePluginHostStatus(openCodeHostLabel, activeInstallation.version, magicContextInstalled) : null;
|
|
49274
|
+
if (hostPluginStatus?.status === "info")
|
|
49275
|
+
log3.info(hostPluginStatus.message);
|
|
49276
|
+
else if (hostPluginStatus?.status === "fail")
|
|
49277
|
+
fail(hostPluginStatus.message);
|
|
49278
|
+
else if (magicContextInstalled && hostGeneration === "v2") {
|
|
49279
|
+
log3.info(describeOpenCode2SessionAPIRequirement(activeInstallation.version));
|
|
49280
|
+
}
|
|
49281
|
+
const pluginNpmLatest = magicContextInstalled ? await fetchNpmLatest(OPENCODE_PLUGIN_NAME) : null;
|
|
49282
|
+
if (magicContextInstalled) {
|
|
49283
|
+
const cwd = process.cwd();
|
|
49284
|
+
const compactionEnabled = resolveCompactionEnabledForDoctor();
|
|
49285
|
+
const conflictResult = detectConflicts(cwd, { compactionEnabled });
|
|
49286
|
+
log3.info("Compaction check: file-based; the running server's resolved config may differ — `opencode debug config` is authoritative");
|
|
49287
|
+
if (conflictResult.hasConflict) {
|
|
49288
|
+
for (const reason of conflictResult.reasons) {
|
|
49289
|
+
fail(`Conflict: ${reason}`);
|
|
49290
|
+
}
|
|
49291
|
+
const actions = fixConflicts(cwd, conflictResult.conflicts, { compactionEnabled });
|
|
49292
|
+
for (const action of actions) {
|
|
49293
|
+
pass(`Fixed: ${action}`);
|
|
49294
|
+
fixed++;
|
|
49295
|
+
}
|
|
49296
|
+
if (actions.length > 0) {
|
|
49297
|
+
warn("Restart OpenCode for conflict fixes to take effect");
|
|
47943
49298
|
}
|
|
47944
49299
|
} else {
|
|
47945
|
-
|
|
49300
|
+
if (!compactionEnabled) {
|
|
49301
|
+
if (conflictResult.nativeCompaction.auto || conflictResult.nativeCompaction.prune) {
|
|
49302
|
+
pass("No conflicts detected (compaction, DCP, OMO hooks) — native compaction active (compaction-off mode)");
|
|
49303
|
+
} else {
|
|
49304
|
+
warn("No compaction manager is active: Magic Context compaction is off and OpenCode auto-compaction is disabled");
|
|
49305
|
+
}
|
|
49306
|
+
} else {
|
|
49307
|
+
pass("No conflicts detected (compaction, DCP, OMO hooks)");
|
|
49308
|
+
}
|
|
47946
49309
|
}
|
|
47947
49310
|
}
|
|
47948
|
-
if (hostGeneration === "v2") {
|
|
49311
|
+
if (magicContextInstalled && hostGeneration === "v2") {
|
|
47949
49312
|
pass("TUI sidebar loads from the plugin entry on OpenCode 2 (tui.json not used)");
|
|
47950
|
-
} else {
|
|
49313
|
+
} else if (magicContextInstalled) {
|
|
47951
49314
|
const tuiAdded = ensureTuiPluginEntry();
|
|
47952
49315
|
if (tuiAdded) {
|
|
47953
49316
|
pass("Added TUI sidebar plugin to tui.json");
|
|
@@ -48097,65 +49460,88 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
48097
49460
|
warn(`RPC discovery check unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
48098
49461
|
issues++;
|
|
48099
49462
|
}
|
|
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(", ")}`);
|
|
49463
|
+
if (magicContextInstalled) {
|
|
49464
|
+
let pluginConfigUse;
|
|
49465
|
+
if (paths.opencodeConfigFormat !== "none") {
|
|
49466
|
+
try {
|
|
49467
|
+
pluginConfigUse = readOpenCodePluginConfigUse(import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8")), dirname25(paths.opencodeConfig));
|
|
49468
|
+
} catch {}
|
|
48127
49469
|
}
|
|
48128
|
-
|
|
48129
|
-
|
|
48130
|
-
|
|
48131
|
-
|
|
49470
|
+
const cacheResult = await clearPluginCache({
|
|
49471
|
+
force: options.force,
|
|
49472
|
+
latestVersion: pluginNpmLatest,
|
|
49473
|
+
hostFiles: openCodeHostDatabaseFiles([openCodeDbResolution.path]),
|
|
49474
|
+
referencedSpecs: pluginConfigUse?.referencedSpecs.opencode1
|
|
49475
|
+
});
|
|
49476
|
+
if (cacheResult.action === "unused") {
|
|
49477
|
+
log3.info(describeUnusedOpenCodePluginCache({
|
|
49478
|
+
host: "OpenCode 1",
|
|
49479
|
+
spec: "latest",
|
|
49480
|
+
cached: cacheResult.cached,
|
|
49481
|
+
paths: cacheResult.paths ?? [cacheResult.path],
|
|
49482
|
+
loadedFrom: pluginConfigUse?.loadedFrom.opencode1
|
|
49483
|
+
}));
|
|
49484
|
+
} else if (cacheResult.action === "cleared") {
|
|
49485
|
+
const versionInfo = cacheResult.cached ? ` (cached: ${cacheResult.cached}${cacheResult.latest ? `, latest: ${cacheResult.latest}` : ""})` : "";
|
|
49486
|
+
const reason = cacheResult.latest ? "outdated plugin cache" : "plugin cache (latest version check unavailable)";
|
|
49487
|
+
pass(`Cleared ${reason}${versionInfo} — latest will download on restart`);
|
|
49488
|
+
log3.info(` ${cacheResult.path}`);
|
|
49489
|
+
fixed++;
|
|
49490
|
+
} else if (cacheResult.action === "up_to_date") {
|
|
49491
|
+
pass(`Plugin cache up to date (v${cacheResult.cached})`);
|
|
49492
|
+
} else if (cacheResult.action === "check_unavailable") {
|
|
49493
|
+
warn(`Plugin cache version check unavailable; preserving cached plugin${cacheResult.cached ? ` (cached: ${cacheResult.cached})` : ""}. Use doctor --force to reinstall it.`);
|
|
49494
|
+
} else if (cacheResult.action === "in_use" || cacheResult.action === "in_use_unknown") {
|
|
49495
|
+
const versionInfo = cacheResult.cached ? ` (cached: ${cacheResult.cached}${cacheResult.latest ? `, latest: ${cacheResult.latest}` : ""})` : "";
|
|
49496
|
+
const why = cacheResult.action === "in_use" ? `OpenCode is running (pid ${cacheResult.pids?.join(", ")})` : cacheResult.reason ?? "could not tell whether OpenCode is running";
|
|
49497
|
+
warn(`Plugin cache${versionInfo} was not cleared: ${why}`);
|
|
49498
|
+
log3.info(" Quit OpenCode and rerun doctor to clear it.");
|
|
49499
|
+
for (const path of cacheResult.paths ?? [cacheResult.path])
|
|
49500
|
+
log3.info(` ${path}`);
|
|
49501
|
+
issues++;
|
|
49502
|
+
} else if (cacheResult.action === "error") {
|
|
49503
|
+
warn(`Could not clear plugin cache: ${cacheResult.error}`);
|
|
49504
|
+
if (cacheResult.clearedPaths && cacheResult.clearedPaths.length > 0) {
|
|
49505
|
+
log3.info(` Cleared roots: ${cacheResult.clearedPaths.join(", ")}`);
|
|
49506
|
+
}
|
|
49507
|
+
if (cacheResult.failedPaths && cacheResult.failedPaths.length > 0) {
|
|
49508
|
+
log3.info(` Failed roots: ${cacheResult.failedPaths.join(", ")}`);
|
|
49509
|
+
} else {
|
|
49510
|
+
log3.info(` Manually delete: ${cacheResult.path}`);
|
|
49511
|
+
}
|
|
49512
|
+
issues++;
|
|
49513
|
+
} else if (hostGeneration !== "v2") {
|
|
49514
|
+
pass("Plugin cache clean (no cached version found)");
|
|
49515
|
+
}
|
|
49516
|
+
let v2DistTag;
|
|
49517
|
+
if (paths.opencodeConfigFormat !== "none") {
|
|
49518
|
+
try {
|
|
49519
|
+
v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8")));
|
|
49520
|
+
} catch {}
|
|
49521
|
+
}
|
|
49522
|
+
const v2Cache = reportOpenCodeV2PluginCache(checkOpenCodeV2PluginCache({
|
|
49523
|
+
fix: options.fix,
|
|
49524
|
+
force: options.force,
|
|
49525
|
+
latestVersion: v2DistTag ? await fetchNpmLatest(OPENCODE_PLUGIN_NAME, v2DistTag) : pluginNpmLatest,
|
|
49526
|
+
distTag: v2DistTag,
|
|
49527
|
+
hostFiles: openCodeHostDatabaseFiles([openCodeDbResolution.path]),
|
|
49528
|
+
referencedSpecs: pluginConfigUse?.referencedSpecs.opencode2
|
|
49529
|
+
}), { pass, warn, info: (message) => log3.info(message) }, {
|
|
49530
|
+
reportMissing: hostGeneration === "v2",
|
|
49531
|
+
loadedFrom: pluginConfigUse?.loadedFrom.opencode2
|
|
49532
|
+
});
|
|
49533
|
+
if (v2Cache.fixed)
|
|
49534
|
+
fixed++;
|
|
49535
|
+
if (v2Cache.issue)
|
|
49536
|
+
issues++;
|
|
49537
|
+
const sharedDbVersion = readContextDbSchemaVersion(dbPath);
|
|
49538
|
+
if (sharedDbVersion !== null) {
|
|
49539
|
+
reportCachedPluginFences(compareCachedPluginFences(listCachedOpenCodePluginFences({
|
|
49540
|
+
referencedSpecs: pluginConfigUse?.referencedSpecs
|
|
49541
|
+
}), sharedDbVersion), { pass, fail, info: (message) => log3.info(message) });
|
|
48132
49542
|
}
|
|
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
49543
|
}
|
|
48158
|
-
{
|
|
49544
|
+
if (magicContextInstalled) {
|
|
48159
49545
|
const ageWarnings = collectNpmReleaseAgeWarnings();
|
|
48160
49546
|
if (ageWarnings.length > 0) {
|
|
48161
49547
|
log3.warn("npm min-release-age restriction detected — this can prevent OpenCode from installing the latest plugin version");
|
|
@@ -48167,17 +49553,19 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
48167
49553
|
issues++;
|
|
48168
49554
|
}
|
|
48169
49555
|
}
|
|
48170
|
-
|
|
48171
|
-
|
|
48172
|
-
|
|
48173
|
-
|
|
48174
|
-
|
|
48175
|
-
|
|
48176
|
-
|
|
48177
|
-
|
|
48178
|
-
|
|
48179
|
-
|
|
48180
|
-
|
|
49556
|
+
if (magicContextInstalled) {
|
|
49557
|
+
const logHarnesses = [
|
|
49558
|
+
...hostGeneration === "v1" ? ["opencode"] : [],
|
|
49559
|
+
...hostGeneration === "v2" || storeGeneration === "v2" ? ["opencode2"] : []
|
|
49560
|
+
];
|
|
49561
|
+
const logFiles = logHarnesses.flatMap((harness) => inspectMagicContextLogs(harness)).filter((file, index, all) => all.findIndex((other) => other.path === file.path) === index);
|
|
49562
|
+
const existingLogFiles = logFiles.filter((file) => file.exists);
|
|
49563
|
+
if (existingLogFiles.length === 0) {
|
|
49564
|
+
log3.info(`No plugin log file yet; checked: ${logFiles.map((file) => file.path).join(", ")}`);
|
|
49565
|
+
} else {
|
|
49566
|
+
for (const file of existingLogFiles) {
|
|
49567
|
+
log3.info(`Log file read: ${formatLogFileInspection(file)}`);
|
|
49568
|
+
}
|
|
48181
49569
|
}
|
|
48182
49570
|
}
|
|
48183
49571
|
const diagnostics = await collectDiagnostics();
|
|
@@ -48358,13 +49746,12 @@ function resolveDreamerTaskModel(args) {
|
|
|
48358
49746
|
const taskQualifier = taskBlock?.[args.harness === "opencode" ? "variant" : "thinking_level"];
|
|
48359
49747
|
const harnessQualifier = harnessBlock[args.harness === "opencode" ? "variant" : "thinking_level"] ?? normalizeModelEntry(harnessBlock.model, args.harness)?.qualifier;
|
|
48360
49748
|
const taskHasModel = taskBlock !== undefined && hasOwn2(taskBlock, "model");
|
|
48361
|
-
const
|
|
48362
|
-
const primarySource = taskHasModel ? taskBlock?.model : usesMuralModel ? args.muralModel : harnessBlock.model;
|
|
49749
|
+
const primarySource = taskHasModel ? taskBlock?.model : harnessBlock.model;
|
|
48363
49750
|
const fallbackSource = taskBlock !== undefined && hasOwn2(taskBlock, "fallback_models") ? taskBlock.fallback_models : harnessBlock.fallback_models;
|
|
48364
49751
|
return {
|
|
48365
49752
|
primary: resolvePrimaryEntry({
|
|
48366
49753
|
entry: primarySource,
|
|
48367
|
-
defaultQualifier:
|
|
49754
|
+
defaultQualifier: taskQualifier ?? harnessQualifier,
|
|
48368
49755
|
harness: args.harness
|
|
48369
49756
|
}),
|
|
48370
49757
|
fallbacks: resolveFallbackEntries(fallbackSource, args.harness),
|
|
@@ -48375,13 +49762,12 @@ function resolveDreamerTaskModel(args) {
|
|
|
48375
49762
|
}
|
|
48376
49763
|
|
|
48377
49764
|
// ../plugin/src/features/magic-context/dreamer/task-config.ts
|
|
48378
|
-
function buildDreamTaskRuntimeConfigs(dreamer, harness, language,
|
|
48379
|
-
return
|
|
49765
|
+
function buildDreamTaskRuntimeConfigs(dreamer, harness, language, smartNotesEnabled = true) {
|
|
49766
|
+
return availableDreamTasks(smartNotesEnabled).map((task) => {
|
|
48380
49767
|
const resolved = resolveDreamerTaskModel({
|
|
48381
49768
|
config: { dreamer },
|
|
48382
49769
|
harness,
|
|
48383
|
-
task
|
|
48384
|
-
muralModel
|
|
49770
|
+
task
|
|
48385
49771
|
});
|
|
48386
49772
|
return {
|
|
48387
49773
|
task,
|
|
@@ -48489,7 +49875,7 @@ function runnablePiModelChains(config, harness) {
|
|
|
48489
49875
|
});
|
|
48490
49876
|
}
|
|
48491
49877
|
if (isDreamerRunnable(config)) {
|
|
48492
|
-
for (const task of buildDreamTaskRuntimeConfigs(config.dreamer, harness, config.language, config.
|
|
49878
|
+
for (const task of buildDreamTaskRuntimeConfigs(config.dreamer, harness, config.language, config.smart_notes?.enabled)) {
|
|
48493
49879
|
if (task.schedule.trim() === "")
|
|
48494
49880
|
continue;
|
|
48495
49881
|
const chain = [task.model, ...task.fallbackModels ?? []].filter((entry) => entry !== undefined);
|
|
@@ -49283,22 +50669,9 @@ async function runHealthChecks2(options) {
|
|
|
49283
50669
|
};
|
|
49284
50670
|
const self = options.deps.selfVersion();
|
|
49285
50671
|
const pi = options.deps.detectPiBinary();
|
|
49286
|
-
|
|
50672
|
+
const piVersion = pi ? options.deps.getPiVersion(pi.path) : null;
|
|
50673
|
+
if (!pi)
|
|
49287
50674
|
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
50675
|
const latest = options.deps.getLatestNpmVersion();
|
|
49303
50676
|
const latestCompare = latest ? compareSemver(self, latest) : null;
|
|
49304
50677
|
if (latest && latestCompare === -1) {
|
|
@@ -49312,8 +50685,11 @@ async function runHealthChecks2(options) {
|
|
|
49312
50685
|
}
|
|
49313
50686
|
const settingsPath = getPiUserExtensionsPath();
|
|
49314
50687
|
let packages = [];
|
|
50688
|
+
let piPluginInstalled = false;
|
|
49315
50689
|
if (!existsSync47(settingsPath)) {
|
|
49316
|
-
|
|
50690
|
+
if (pi) {
|
|
50691
|
+
add2(results, "info", `${piVersion ? `Pi ${piVersion}` : "Pi"} found; Magic Context is not installed there (run setup to add it)`);
|
|
50692
|
+
}
|
|
49317
50693
|
repairPlan.addPackageEntry = true;
|
|
49318
50694
|
} else {
|
|
49319
50695
|
const parsed = readJsonc2(settingsPath);
|
|
@@ -49321,15 +50697,31 @@ async function runHealthChecks2(options) {
|
|
|
49321
50697
|
add2(results, "fail", `Could not parse Pi settings ${settingsPath}: ${parsed.error}`);
|
|
49322
50698
|
} else {
|
|
49323
50699
|
packages = packagesFrom(parsed.value);
|
|
49324
|
-
add2(results, "pass", `Pi settings found at ${settingsPath}`);
|
|
49325
50700
|
if (hasPiMagicContextPackage(packages)) {
|
|
50701
|
+
piPluginInstalled = true;
|
|
50702
|
+
add2(results, "pass", `Pi settings found at ${settingsPath}`);
|
|
49326
50703
|
add2(results, "pass", `${PI_PACKAGE_SOURCE} is registered in packages[]`);
|
|
49327
50704
|
} else {
|
|
49328
|
-
|
|
50705
|
+
if (pi) {
|
|
50706
|
+
add2(results, "info", `${piVersion ? `Pi ${piVersion}` : "Pi"} found; Magic Context is not installed there (run setup to add it)`);
|
|
50707
|
+
}
|
|
49329
50708
|
repairPlan.addPackageEntry = true;
|
|
49330
50709
|
}
|
|
49331
50710
|
}
|
|
49332
50711
|
}
|
|
50712
|
+
if (pi && piPluginInstalled) {
|
|
50713
|
+
if (piVersion === null) {
|
|
50714
|
+
add2(results, "fail", `Pi CLI was found at ${pi.path} but could not be executed`);
|
|
50715
|
+
} else {
|
|
50716
|
+
add2(results, "pass", `Pi ${piVersion} detected at ${pi.path}`);
|
|
50717
|
+
}
|
|
50718
|
+
const compare = compareSemver(piVersion, MIN_PI_VERSION);
|
|
50719
|
+
if (compare !== null && compare < 0) {
|
|
50720
|
+
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\`).`);
|
|
50721
|
+
} else if (piVersion) {
|
|
50722
|
+
add2(results, "pass", `Pi version meets minimum ${MIN_PI_VERSION} requirement`);
|
|
50723
|
+
}
|
|
50724
|
+
}
|
|
49333
50725
|
const userConfigPath = getPiUserConfigPath();
|
|
49334
50726
|
const projectPath = projectConfigPath(options.cwd);
|
|
49335
50727
|
for (const [label, path, required] of [
|
|
@@ -49378,7 +50770,8 @@ async function runHealthChecks2(options) {
|
|
|
49378
50770
|
} else if (historianModel.startsWith("github-copilot/") && historianThinkingLevel) {
|
|
49379
50771
|
add2(results, "pass", `historian.model "${historianModel}" has thinking_level "${historianThinkingLevel}" configured`);
|
|
49380
50772
|
}
|
|
49381
|
-
|
|
50773
|
+
if (piPluginInstalled)
|
|
50774
|
+
checkPiModelChains(results, pi, loadedConfig.config, options.deps);
|
|
49382
50775
|
const storage = getMagicContextStorageResolution();
|
|
49383
50776
|
const storageDir = storage.path;
|
|
49384
50777
|
const dbPath = join41(storageDir, "context.db");
|
|
@@ -49501,7 +50894,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
49501
50894
|
}
|
|
49502
50895
|
} else if (loadedConfig.config.embedding.provider === "off") {
|
|
49503
50896
|
add2(results, "info", "Embedding provider disabled");
|
|
49504
|
-
} else {
|
|
50897
|
+
} else if (piPluginInstalled) {
|
|
49505
50898
|
let runtimeReported = false;
|
|
49506
50899
|
let firstFallback = null;
|
|
49507
50900
|
const brokenWarnings = [];
|
|
@@ -49540,38 +50933,40 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
49540
50933
|
}
|
|
49541
50934
|
}
|
|
49542
50935
|
}
|
|
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
|
-
|
|
50936
|
+
if (piPluginInstalled) {
|
|
50937
|
+
const piEntries = packages.filter(isConfiguredPiMagicContextEntry2).map(describePiPackageEntry);
|
|
50938
|
+
if (piEntries.length > 1) {
|
|
50939
|
+
add2(results, "fail", `Multiple magic-context entries in Pi packages[] — this loads the plugin twice: ${piEntries.join(", ")}`);
|
|
50940
|
+
} else {
|
|
50941
|
+
add2(results, "pass", "No conflicting magic-context entries in Pi packages[]");
|
|
50942
|
+
}
|
|
50943
|
+
const otherExtensions = packages.filter((entry) => !isConfiguredPiMagicContextEntry2(entry)).map(describePiPackageEntry);
|
|
50944
|
+
if (otherExtensions.length > 0) {
|
|
50945
|
+
add2(results, "info", `Other Pi extensions registered: ${otherExtensions.join(", ")}`);
|
|
50946
|
+
} else {
|
|
50947
|
+
add2(results, "info", "No other Pi extensions listed in settings.json");
|
|
50948
|
+
}
|
|
50949
|
+
const configuredEntry = packages.find(isPiMagicContextPackageEntry);
|
|
50950
|
+
const configuredSpecifier = getPiMagicContextPackageSpecifier(configuredEntry);
|
|
50951
|
+
const expectedPluginVersion = pinnedVersionFromPackageSpecifier(configuredSpecifier) ?? latest ?? null;
|
|
50952
|
+
const staleCaches = findPiMagicContextCacheDirs(options.cwd, expectedPluginVersion, options.force === true);
|
|
50953
|
+
if (staleCaches.length > 0) {
|
|
50954
|
+
repairPlan.clearCachePaths = staleCaches.map((entry) => entry.path);
|
|
50955
|
+
add2(results, "warn", `Stale Pi extension cache found: ${staleCaches.map((entry) => `${entry.path}${entry.version ? ` (v${entry.version})` : ""}`).join(", ")}`);
|
|
50956
|
+
} else {
|
|
50957
|
+
add2(results, "pass", "Pi extension cache clean (no stale cached package found)");
|
|
50958
|
+
}
|
|
50959
|
+
const logFiles = inspectMagicContextLogs("pi");
|
|
50960
|
+
const existingLogFiles = logFiles.filter((file) => file.exists);
|
|
50961
|
+
if (existingLogFiles.length === 0) {
|
|
50962
|
+
add2(results, "info", `No plugin log file yet; checked: ${logFiles.map((file) => file.path).join(", ")}`);
|
|
50963
|
+
} else {
|
|
50964
|
+
for (const file of existingLogFiles) {
|
|
50965
|
+
add2(results, "info", `Log file read: ${formatLogFileInspection(file)}`);
|
|
50966
|
+
}
|
|
50967
|
+
const lastLine = readLogLines(existingLogFiles).at(-1);
|
|
50968
|
+
add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
|
|
49572
50969
|
}
|
|
49573
|
-
const lastLine = readLogLines(existingLogFiles).at(-1);
|
|
49574
|
-
add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
|
|
49575
50970
|
}
|
|
49576
50971
|
const diagnosticsForDumps = await collectDiagnostics2(options.cwd);
|
|
49577
50972
|
const dumpBuckets = diagnosticsForDumps.historianDumps.byProject;
|
|
@@ -49967,7 +51362,8 @@ async function dispatchDoctor(adapter, options) {
|
|
|
49967
51362
|
force: options.force,
|
|
49968
51363
|
fix: options.fix,
|
|
49969
51364
|
issue: options.issue,
|
|
49970
|
-
report: options.report
|
|
51365
|
+
report: options.report,
|
|
51366
|
+
verbose: options.verbose
|
|
49971
51367
|
});
|
|
49972
51368
|
}
|
|
49973
51369
|
case "pi": {
|
|
@@ -50131,6 +51527,7 @@ var DOCTOR_HELP = [
|
|
|
50131
51527
|
" --fix Repair safe, Magic Context-owned store rows and clear an outdated OpenCode 2 plugin cache",
|
|
50132
51528
|
" --force Force-clear the plugin cache",
|
|
50133
51529
|
" --clear Interactive cache cleanup picker",
|
|
51530
|
+
" --verbose Print long listings in full instead of a capped summary",
|
|
50134
51531
|
" --prune-discovery [--yes] List RPC discovery records that block offline maintenance, then remove them after confirmation",
|
|
50135
51532
|
" --issue Collect diagnostics and open a GitHub issue",
|
|
50136
51533
|
" --report <path> Write the issue diagnostics to <path> without prompting",
|
|
@@ -50389,6 +51786,7 @@ async function runCommand(command, rest) {
|
|
|
50389
51786
|
issue: rest.includes("--issue") || report !== null,
|
|
50390
51787
|
...report !== null ? { report } : {},
|
|
50391
51788
|
clear: rest.includes("--clear"),
|
|
51789
|
+
verbose: rest.includes("--verbose"),
|
|
50392
51790
|
checkV22Backfill: rest.includes("--check-v22-backfill"),
|
|
50393
51791
|
retryV22Backfill: rest.includes("--retry-v22-backfill"),
|
|
50394
51792
|
...rekeyV22DirIdentity !== null ? { rekeyV22DirIdentity } : {},
|