@cortexkit/magic-context 0.46.1 → 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 +2059 -488
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2973,7 +2973,7 @@ function sortJson(value) {
|
|
|
2973
2973
|
if (value && typeof value === "object") {
|
|
2974
2974
|
const sorted = {};
|
|
2975
2975
|
for (const key of Object.keys(value).sort()) {
|
|
2976
|
-
if (key === "protected_tags")
|
|
2976
|
+
if (key === "protected_tags" || key === "clear_reasoning_age")
|
|
2977
2977
|
continue;
|
|
2978
2978
|
sorted[key] = sortJson(value[key]);
|
|
2979
2979
|
}
|
|
@@ -3108,7 +3108,9 @@ function migrateConfigFile(opts) {
|
|
|
3108
3108
|
let migratedContent = first.content;
|
|
3109
3109
|
let strippedProtectedTags = false;
|
|
3110
3110
|
try {
|
|
3111
|
-
const stripped = removeJsoncValue(first.content, ["protected_tags"])
|
|
3111
|
+
const stripped = removeJsoncValue(removeJsoncValue(first.content, ["protected_tags"]), [
|
|
3112
|
+
"clear_reasoning_age"
|
|
3113
|
+
]);
|
|
3112
3114
|
if (stripped !== first.content) {
|
|
3113
3115
|
migratedContent = stripped;
|
|
3114
3116
|
strippedProtectedTags = true;
|
|
@@ -3116,7 +3118,10 @@ function migrateConfigFile(opts) {
|
|
|
3116
3118
|
} catch {}
|
|
3117
3119
|
atomicWriteConfigFile(opts.targetPath, migratedContent);
|
|
3118
3120
|
if (strippedProtectedTags) {
|
|
3119
|
-
|
|
3121
|
+
if (first.content.includes('"protected_tags"'))
|
|
3122
|
+
info?.(`Stripped deprecated "protected_tags" key during config location migration`);
|
|
3123
|
+
if (first.content.includes('"clear_reasoning_age"'))
|
|
3124
|
+
info?.(`Stripped deprecated "clear_reasoning_age" key during config location migration`);
|
|
3120
3125
|
}
|
|
3121
3126
|
info?.(`Migrated Magic Context ${opts.scope} config from ${first.path} to ${opts.targetPath}`);
|
|
3122
3127
|
warnings.push(...markLegacySourcesMovedAside(sources, opts.targetPath, opts.logger));
|
|
@@ -3471,6 +3476,15 @@ function migrateLegacyExperimental(rawConfig, warnings) {
|
|
|
3471
3476
|
return patched;
|
|
3472
3477
|
}
|
|
3473
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
|
+
|
|
3474
3488
|
// ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/core/core.js
|
|
3475
3489
|
function $constructor(name, initializer, params) {
|
|
3476
3490
|
function init(inst, def) {
|
|
@@ -8694,7 +8708,7 @@ class Parser {
|
|
|
8694
8708
|
} else
|
|
8695
8709
|
break;
|
|
8696
8710
|
}
|
|
8697
|
-
const expression = { steps
|
|
8711
|
+
const expression = { steps };
|
|
8698
8712
|
if (this.take(".each(")) {
|
|
8699
8713
|
if (relative)
|
|
8700
8714
|
return this.error();
|
|
@@ -8760,9 +8774,23 @@ function compiled(source) {
|
|
|
8760
8774
|
function oneLine(value) {
|
|
8761
8775
|
return value.replace(/[\r\n\u2028\u2029]+/g, " ");
|
|
8762
8776
|
}
|
|
8763
|
-
function truncate(value, cap) {
|
|
8777
|
+
function truncate(value, cap, legacyPreview = false) {
|
|
8764
8778
|
const chars = Array.from(oneLine(value));
|
|
8765
|
-
|
|
8779
|
+
if (cap === undefined || chars.length <= cap)
|
|
8780
|
+
return chars.join("");
|
|
8781
|
+
if (legacyPreview)
|
|
8782
|
+
return `${chars.slice(0, cap).join("")}…`;
|
|
8783
|
+
let end = 0;
|
|
8784
|
+
for (let i = 0;i < Math.min(cap, chars.length); i++) {
|
|
8785
|
+
if (!".!?。!?".includes(chars[i]))
|
|
8786
|
+
continue;
|
|
8787
|
+
let next = i + 1;
|
|
8788
|
+
while (next < chars.length && `"'”’)]`.includes(chars[next]))
|
|
8789
|
+
next++;
|
|
8790
|
+
if (next <= cap && ("。!?".includes(chars[i]) || next === chars.length || /[ \t]/.test(chars[next])))
|
|
8791
|
+
end = next;
|
|
8792
|
+
}
|
|
8793
|
+
return `${end ? `${chars.slice(0, end).join("")} ` : ""}[… ${chars.length - end} more characters]`;
|
|
8766
8794
|
}
|
|
8767
8795
|
function scalar(value) {
|
|
8768
8796
|
if (value === undefined)
|
|
@@ -8779,10 +8807,11 @@ function compactJson(value) {
|
|
|
8779
8807
|
function field(value, key) {
|
|
8780
8808
|
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.hasOwn(value, key) ? value[key] : undefined;
|
|
8781
8809
|
}
|
|
8782
|
-
function render(nodes, root) {
|
|
8810
|
+
function render(nodes, root, legacyPreview) {
|
|
8783
8811
|
return nodes.map((node) => {
|
|
8784
8812
|
if (typeof node === "string")
|
|
8785
8813
|
return node;
|
|
8814
|
+
const cap = node.cap ?? (legacyPreview ? 300 : undefined);
|
|
8786
8815
|
let value = root;
|
|
8787
8816
|
let list = false;
|
|
8788
8817
|
for (const step of node.steps) {
|
|
@@ -8796,19 +8825,19 @@ function render(nodes, root) {
|
|
|
8796
8825
|
}
|
|
8797
8826
|
}
|
|
8798
8827
|
if (node.count)
|
|
8799
|
-
return truncate(Array.isArray(value) ? String(value.length) : "",
|
|
8828
|
+
return truncate(Array.isArray(value) ? String(value.length) : "", cap, legacyPreview);
|
|
8800
8829
|
if (node.each || list || node.join !== undefined) {
|
|
8801
8830
|
if (!Array.isArray(value))
|
|
8802
8831
|
return "";
|
|
8803
|
-
const elements = value.slice(0, 10).map((item) => truncate(node.each ? render(node.each, item) : scalar(item), 300));
|
|
8804
|
-
if (value.length > 10)
|
|
8832
|
+
const elements = value.slice(0, legacyPreview ? 10 : undefined).map((item) => truncate(node.each ? render(node.each, item, legacyPreview) : scalar(item), legacyPreview ? 300 : undefined, legacyPreview));
|
|
8833
|
+
if (legacyPreview && value.length > 10)
|
|
8805
8834
|
elements.push(`… +${value.length - 10} more`);
|
|
8806
|
-
return truncate(elements.join(node.join ?? (node.each ? "; " : ", ")),
|
|
8835
|
+
return truncate(elements.join(node.join ?? (node.each ? "; " : ", ")), cap, legacyPreview);
|
|
8807
8836
|
}
|
|
8808
|
-
return truncate(scalar(value),
|
|
8837
|
+
return truncate(scalar(value), cap, legacyPreview);
|
|
8809
8838
|
}).join("");
|
|
8810
8839
|
}
|
|
8811
|
-
function renderToolTemplate(source, input, output) {
|
|
8840
|
+
function renderToolTemplate(source, input, output, legacyPreview = false) {
|
|
8812
8841
|
const nodes = compiled(source);
|
|
8813
8842
|
if (!nodes)
|
|
8814
8843
|
return null;
|
|
@@ -8823,8 +8852,8 @@ function renderToolTemplate(source, input, output) {
|
|
|
8823
8852
|
}
|
|
8824
8853
|
}
|
|
8825
8854
|
const root = { input, output: structured };
|
|
8826
|
-
const bareOutputNodes = nodes.map((node) => typeof node !== "string" && node.steps.length === 1 && ("field" in node.steps[0]) && node.steps[0].field === "output" && !node.each && !node.count && node.join === undefined ? truncate(text ?? "", node.cap) : node);
|
|
8827
|
-
return truncate(render(bareOutputNodes, root), 1000);
|
|
8855
|
+
const bareOutputNodes = nodes.map((node) => typeof node !== "string" && node.steps.length === 1 && ("field" in node.steps[0]) && node.steps[0].field === "output" && !node.each && !node.count && node.join === undefined ? truncate(text ?? "", node.cap ?? (legacyPreview ? 300 : undefined), legacyPreview) : node);
|
|
8856
|
+
return truncate(render(bareOutputNodes, root, legacyPreview), legacyPreview ? 1000 : undefined, legacyPreview);
|
|
8828
8857
|
}
|
|
8829
8858
|
var templates;
|
|
8830
8859
|
var init_historian_tool_template = __esm(() => {
|
|
@@ -9182,7 +9211,7 @@ var init_magic_context = __esm(() => {
|
|
|
9182
9211
|
ctx.addIssue({ code: "custom", message: error });
|
|
9183
9212
|
}),
|
|
9184
9213
|
literal(false)
|
|
9185
|
-
])).optional().describe('Readable historian tool expansions, keyed by exact host tool name. Templates override built-in defaults; false disables an expansion. Supports ${input.path}, ${output.path}, bare ${output}, array [N], [*].field, .each("${field}"), .join("separator"), .count and final .truncate(N). Missing fields are empty;
|
|
9214
|
+
])).optional().describe('Readable historian tool expansions, keyed by exact host tool name. Templates override built-in defaults; false disables an expansion. Supports ${input.path}, ${output.path}, bare ${output}, array [N], [*].field, .each("${field}"), .join("separator"), .count and final .truncate(N). Missing fields are empty. Historian text and lists have no implicit caps; explicit .truncate(N) keeps complete sentences and marks omitted characters, or emits only the marker if no sentence fits. When the ctx_expand history-recovery tool is called in verbose mode, its tool-call previews retain their original built-in templates and limits (300 characters per placeholder, 10 list elements, 1000 characters per expansion). Valid in user and project config; never changes the wire or default ctx_expand transcript.'),
|
|
9186
9215
|
opencode: OpenCodeHarnessBlockSchema.optional(),
|
|
9187
9216
|
pi: PiHarnessBlockSchema.optional(),
|
|
9188
9217
|
omp: OmpHarnessBlockSchema.optional(),
|
|
@@ -9295,7 +9324,7 @@ var init_magic_context = __esm(() => {
|
|
|
9295
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."),
|
|
9296
9325
|
mural: object({
|
|
9297
9326
|
enabled: boolean2().default(false),
|
|
9298
|
-
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 })
|
|
9299
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."),
|
|
9300
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.'),
|
|
9301
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."),
|
|
@@ -9305,8 +9334,9 @@ var init_magic_context = __esm(() => {
|
|
|
9305
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."),
|
|
9306
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."),
|
|
9307
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."),
|
|
9308
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.")
|
|
9309
|
-
}).default({ retina_handoff: false }).describe("Smart-note ownership transition controls."),
|
|
9339
|
+
}).default({ enabled: true, retina_handoff: false }).describe("Smart-note ownership transition controls."),
|
|
9310
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).`),
|
|
9311
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."),
|
|
9312
9342
|
output_reserve: union([
|
|
@@ -9326,7 +9356,11 @@ var init_magic_context = __esm(() => {
|
|
|
9326
9356
|
}).catchall(number2().min(5000).max(2000000)).optional().describe("Absolute token thresholds per model. When matched, overrides execute_threshold_percentage for that model. Accepts `default` for all models or per-model keys. Values above 90% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000."),
|
|
9327
9357
|
protected_tokens: number2().int().min(PROTECTED_TOKENS_MIN).max(1e6).optional().describe("Positive integer token floor to protect from automatic reclaim (min: 4_000, max: 1_000_000). When omitted, the derived default is clamp(round(0.05 × usableSoft), min(16_000, round(0.08 × usableSoft)), 64_000)."),
|
|
9328
9358
|
protected_tags: unknown().optional().describe("Deprecated: number of recent tags to protect. Ignored for behaviour; use protected_tokens instead.").meta({ deprecated: true }),
|
|
9329
|
-
clear_reasoning_age:
|
|
9359
|
+
clear_reasoning_age: unknown().optional().describe("Deprecated and ignored. Use keep_reasoning_tokens instead.").meta({ deprecated: true }),
|
|
9360
|
+
keep_reasoning_tokens: union([
|
|
9361
|
+
number2().int().min(0).max(1e6),
|
|
9362
|
+
object({ default: number2().int().min(0).max(1e6).optional() }).catchall(number2().int().min(0).max(1e6))
|
|
9363
|
+
]).optional().describe("Reasoning tokens to keep on rebuilding passes. Number or per-model object; exact, shorter model keys, provider/*, then default. Omitted: fixed 10,000. 0 removes all eligible historical reasoning; newest and exempt steps always stay."),
|
|
9330
9364
|
history_budget_percentage: number2().min(0.05).max(0.5).default(DEFAULT_HISTORY_BUDGET_PERCENTAGE).describe("Fraction of usable context (context_limit × execute_threshold) reserved for the session history block (default: 0.15)"),
|
|
9331
9365
|
historian_timeout_ms: number2().min(60000).default(DEFAULT_HISTORIAN_TIMEOUT_MS).describe("Timeout for each historian prompt call in both TypeScript and Rust transform modes, in milliseconds (default: 600000)"),
|
|
9332
9366
|
commit_cluster_trigger: object({
|
|
@@ -9407,7 +9441,6 @@ var init_magic_context = __esm(() => {
|
|
|
9407
9441
|
});
|
|
9408
9442
|
LIVE_RELOAD_CONFIG_PATHS = [
|
|
9409
9443
|
"cache_ttl",
|
|
9410
|
-
"mural.model",
|
|
9411
9444
|
"toast_duration_ms",
|
|
9412
9445
|
"historian.opencode.model",
|
|
9413
9446
|
"historian.opencode.fallback_models",
|
|
@@ -9588,16 +9621,6 @@ function stripEscalationAtExecutableSite(block, path, removed) {
|
|
|
9588
9621
|
}
|
|
9589
9622
|
}
|
|
9590
9623
|
}
|
|
9591
|
-
function stripNestedMuralModels(node, path, removed) {
|
|
9592
|
-
for (const [key, value] of Object.entries(node)) {
|
|
9593
|
-
if (key === "mural" && isPlainObject2(value) && "model" in value) {
|
|
9594
|
-
delete value.model;
|
|
9595
|
-
removed.push(`${path}.${key}.model`);
|
|
9596
|
-
} else if (isPlainObject2(value)) {
|
|
9597
|
-
stripNestedMuralModels(value, `${path}.${key}`, removed);
|
|
9598
|
-
}
|
|
9599
|
-
}
|
|
9600
|
-
}
|
|
9601
9624
|
function isValidPercentageThreshold(value) {
|
|
9602
9625
|
return typeof value === "number" && Number.isFinite(value) && value >= 20 && value <= 90;
|
|
9603
9626
|
}
|
|
@@ -9738,6 +9761,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
9738
9761
|
delete storage.enforce_private_permissions;
|
|
9739
9762
|
warnings.push("Ignoring storage.enforce_private_permissions from project config (security: only user-level config may opt into externally managed shared storage permissions).");
|
|
9740
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
|
+
}
|
|
9741
9769
|
const promptSurface = projectRaw.prompt_surface;
|
|
9742
9770
|
if (isPlainObject2(promptSurface)) {
|
|
9743
9771
|
const removed = [];
|
|
@@ -9836,27 +9864,6 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
9836
9864
|
delete dreamer.runner;
|
|
9837
9865
|
warnings.push("Ignoring dreamer.runner from project config (security: which process and provider account run dreamer completions is a user-level setting).");
|
|
9838
9866
|
}
|
|
9839
|
-
const mural = projectRaw.mural;
|
|
9840
|
-
if (isPlainObject2(mural) && "model" in mural) {
|
|
9841
|
-
delete mural.model;
|
|
9842
|
-
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).");
|
|
9843
|
-
}
|
|
9844
|
-
const experimental = projectRaw.experimental;
|
|
9845
|
-
const legacyMural = isPlainObject2(experimental) ? experimental.mural : undefined;
|
|
9846
|
-
if (isPlainObject2(legacyMural) && "model" in legacyMural) {
|
|
9847
|
-
delete legacyMural.model;
|
|
9848
|
-
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).");
|
|
9849
|
-
}
|
|
9850
|
-
const nestedMuralRemoved = [];
|
|
9851
|
-
for (const agentKey of HIDDEN_AGENT_KEYS) {
|
|
9852
|
-
const block = projectRaw[agentKey];
|
|
9853
|
-
if (!isPlainObject2(block))
|
|
9854
|
-
continue;
|
|
9855
|
-
stripNestedMuralModels(block, agentKey, nestedMuralRemoved);
|
|
9856
|
-
}
|
|
9857
|
-
if (nestedMuralRemoved.length > 0) {
|
|
9858
|
-
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).`);
|
|
9859
|
-
}
|
|
9860
9867
|
return warnings;
|
|
9861
9868
|
}
|
|
9862
9869
|
function constrainProjectThresholdOverrides(args) {
|
|
@@ -10891,6 +10898,11 @@ function warnProtectedTagsDeprecationOnce() {
|
|
|
10891
10898
|
function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
10892
10899
|
const preMigrationWarnings = [];
|
|
10893
10900
|
const configWithoutRemovedAgent = stripRemovedAgentConfig(rawConfig, preMigrationWarnings);
|
|
10901
|
+
if (Object.hasOwn(rawConfig, "clear_reasoning_age")) {
|
|
10902
|
+
const warning = "clear_reasoning_age is deprecated and ignored. Magic Context now keeps reasoning up to a token budget, keep_reasoning_tokens (default 10,000). Remove the key, or set keep_reasoning_tokens to a token count.";
|
|
10903
|
+
preMigrationWarnings.push(warning);
|
|
10904
|
+
log(`[magic-context] ${warning}`);
|
|
10905
|
+
}
|
|
10894
10906
|
if (Object.hasOwn(rawConfig, "protected_tags")) {
|
|
10895
10907
|
warnProtectedTagsDeprecationOnce();
|
|
10896
10908
|
preMigrationWarnings.push("protected_tags is deprecated and ignored; use protected_tokens instead.");
|
|
@@ -10900,6 +10912,7 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
10900
10912
|
}
|
|
10901
10913
|
preMigrationWarnings.push(...misplacedAgentModelWarnings(rawConfig));
|
|
10902
10914
|
const migratedExperimental = migrateLegacyExperimental(configWithoutRemovedAgent, preMigrationWarnings);
|
|
10915
|
+
warnDeprecatedMuralModel(migratedExperimental, preMigrationWarnings);
|
|
10903
10916
|
const migratedDreamer = migrateDreamerV2(migratedExperimental, preMigrationWarnings);
|
|
10904
10917
|
const migrated = migrateLegacyAgentEnabledInMemory(migratedDreamer, preMigrationWarnings);
|
|
10905
10918
|
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
@@ -12822,19 +12835,28 @@ __export(exports_sqlite, {
|
|
|
12822
12835
|
Database: () => Database,
|
|
12823
12836
|
SqliteAcquisitionBusyError: () => SqliteAcquisitionBusyError,
|
|
12824
12837
|
SqliteRuntimeUnavailableError: () => SqliteRuntimeUnavailableError,
|
|
12838
|
+
assertTransformWrite: () => assertTransformWrite,
|
|
12825
12839
|
beginSqliteWriterAsync: () => beginSqliteWriterAsync,
|
|
12826
12840
|
detectSqliteRuntime: () => detectSqliteRuntime,
|
|
12841
|
+
getSqliteDatabasePath: () => getSqliteDatabasePath,
|
|
12827
12842
|
getSqliteMemoryStats: () => getSqliteMemoryStats,
|
|
12843
|
+
getTagIdentityWriteGeneration: () => getTagIdentityWriteGeneration,
|
|
12844
|
+
guardSqliteTransformPass: () => guardSqliteTransformPass,
|
|
12845
|
+
indexCoordinationInput: () => indexCoordinationInput,
|
|
12828
12846
|
isTransientSqliteError: () => isTransientSqliteError,
|
|
12829
12847
|
loadSqliteModule: () => loadSqliteModule,
|
|
12848
|
+
mayChangeTagIdentity: () => mayChangeTagIdentity,
|
|
12830
12849
|
prepareCachedStatement: () => prepareCachedStatement,
|
|
12831
12850
|
registerSlowWriteReporter: () => registerSlowWriteReporter,
|
|
12832
12851
|
registerSqliteDiagnosticSink: () => registerSqliteDiagnosticSink,
|
|
12852
|
+
releaseIndexOwner: () => releaseIndexOwner,
|
|
12833
12853
|
withAsyncPrivilegedWriter: () => withAsyncPrivilegedWriter,
|
|
12854
|
+
withIndexChunk: () => withIndexChunk,
|
|
12834
12855
|
withPrivilegedWriter: () => withPrivilegedWriter,
|
|
12835
12856
|
withSqliteBackgroundWriter: () => withSqliteBackgroundWriter,
|
|
12836
12857
|
withSqliteTransformPass: () => withSqliteTransformPass,
|
|
12837
|
-
withoutSqliteTransformPass: () => withoutSqliteTransformPass
|
|
12858
|
+
withoutSqliteTransformPass: () => withoutSqliteTransformPass,
|
|
12859
|
+
yieldIndexChunk: () => yieldIndexChunk
|
|
12838
12860
|
});
|
|
12839
12861
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
12840
12862
|
import { statSync as statSync4 } from "node:fs";
|
|
@@ -12868,10 +12890,31 @@ function isModuleNotFoundError(error, specifier) {
|
|
|
12868
12890
|
return false;
|
|
12869
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");
|
|
12870
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
|
+
}
|
|
12871
12914
|
async function loadSqliteModule(runtime = detectSqliteRuntime(), importer = importSqliteModule) {
|
|
12872
12915
|
const specifier = runtime === "Bun" ? bunSpec : nodeSpec;
|
|
12873
12916
|
try {
|
|
12874
|
-
return await
|
|
12917
|
+
return await importSqliteModuleForRuntime(runtime, specifier, importer);
|
|
12875
12918
|
} catch (error) {
|
|
12876
12919
|
if (isModuleNotFoundError(error, specifier)) {
|
|
12877
12920
|
throw new SqliteRuntimeUnavailableError(runtime, specifier, error);
|
|
@@ -12879,12 +12922,75 @@ async function loadSqliteModule(runtime = detectSqliteRuntime(), importer = impo
|
|
|
12879
12922
|
throw error;
|
|
12880
12923
|
}
|
|
12881
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
|
+
}
|
|
12882
12986
|
function installTransactionRouting(db, readonly) {
|
|
12883
12987
|
const nativeExec = db.exec.bind(db);
|
|
12884
12988
|
Object.defineProperty(db, "exec", {
|
|
12885
12989
|
configurable: true,
|
|
12886
12990
|
writable: true,
|
|
12887
12991
|
value: (sql) => {
|
|
12992
|
+
if (/^\s*(?:COMMIT|END)\b/i.test(sql))
|
|
12993
|
+
assertTransformWrite();
|
|
12888
12994
|
if (/^\s*BEGIN\s+(?:IMMEDIATE|EXCLUSIVE)(?:\s+TRANSACTION)?\s*;?\s*$/i.test(sql)) {
|
|
12889
12995
|
openWriterTransactions.delete(db);
|
|
12890
12996
|
if (transformPassScope.getStore()?.active || backgroundWriterScope.getStore())
|
|
@@ -12895,8 +13001,14 @@ function installTransactionRouting(db, readonly) {
|
|
|
12895
13001
|
}
|
|
12896
13002
|
if (WRITER_TRANSACTION_END.test(sql) && openWriterTransactions.has(db))
|
|
12897
13003
|
return endWriterTransaction(db, () => nativeExec(sql), sql);
|
|
12898
|
-
if (!/^\s*(?:SELECT|EXPLAIN|PRAGMA|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i.test(sql))
|
|
12899
|
-
|
|
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
|
+
}
|
|
12900
13012
|
return nativeExec(sql);
|
|
12901
13013
|
}
|
|
12902
13014
|
});
|
|
@@ -12907,13 +13019,23 @@ function installTransactionRouting(db, readonly) {
|
|
|
12907
13019
|
value: (sql) => {
|
|
12908
13020
|
const statement = nativePrepare(sql);
|
|
12909
13021
|
if (!readonly && !/^\s*(?:SELECT|EXPLAIN|PRAGMA)\b/i.test(sql)) {
|
|
13022
|
+
const changesTagIdentity = mayChangeTagIdentity(sql);
|
|
12910
13023
|
for (const method of ["run", "get", "all"]) {
|
|
12911
13024
|
const execute = statement[method].bind(statement);
|
|
12912
13025
|
Object.defineProperty(statement, method, {
|
|
12913
13026
|
configurable: true,
|
|
12914
|
-
value: (...args) =>
|
|
13027
|
+
value: (...args) => {
|
|
13028
|
+
try {
|
|
13029
|
+
return withAutocommitTimeout(db, () => execute(...args));
|
|
13030
|
+
} finally {
|
|
13031
|
+
if (changesTagIdentity)
|
|
13032
|
+
tagIdentityWriteGeneration += 1;
|
|
13033
|
+
}
|
|
13034
|
+
}
|
|
12915
13035
|
});
|
|
12916
13036
|
}
|
|
13037
|
+
if (changesTagIdentity)
|
|
13038
|
+
wrapRemainingTagWriteForms(statement);
|
|
12917
13039
|
}
|
|
12918
13040
|
return statement;
|
|
12919
13041
|
}
|
|
@@ -12961,6 +13083,35 @@ function installTransactionRouting(db, readonly) {
|
|
|
12961
13083
|
}
|
|
12962
13084
|
});
|
|
12963
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
|
+
}
|
|
12964
13115
|
function trackSqliteConnection(db, filename, options) {
|
|
12965
13116
|
const originalClose = db.close.bind(db);
|
|
12966
13117
|
const sequence = nextSqliteConnectionSequence++;
|
|
@@ -13014,6 +13165,18 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
|
|
|
13014
13165
|
}
|
|
13015
13166
|
return NodeSqliteDatabase;
|
|
13016
13167
|
}
|
|
13168
|
+
function getSqliteDatabasePath(db) {
|
|
13169
|
+
for (const connection of trackedSqliteConnections.values()) {
|
|
13170
|
+
if (connection.reference.deref() === db) {
|
|
13171
|
+
return connection.filename === ":memory:" || connection.filename === "<buffer>" ? null : connection.filename;
|
|
13172
|
+
}
|
|
13173
|
+
}
|
|
13174
|
+
const native = db;
|
|
13175
|
+
const path = native.filename ?? native.name;
|
|
13176
|
+
if (typeof path === "string" && path !== ":memory:" && path !== "")
|
|
13177
|
+
return path;
|
|
13178
|
+
return null;
|
|
13179
|
+
}
|
|
13017
13180
|
function pragmaValue(db, name) {
|
|
13018
13181
|
const row = db.prepare(`PRAGMA ${name}`).get();
|
|
13019
13182
|
if (!row)
|
|
@@ -13093,6 +13256,15 @@ function getSqliteMemoryStats() {
|
|
|
13093
13256
|
connections
|
|
13094
13257
|
};
|
|
13095
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
|
+
}
|
|
13096
13268
|
function ownPreparedStatement(db, statement) {
|
|
13097
13269
|
const finalizable = statement;
|
|
13098
13270
|
if (typeof finalizable.finalize !== "function")
|
|
@@ -13116,7 +13288,7 @@ function ownPreparedStatement(db, statement) {
|
|
|
13116
13288
|
}
|
|
13117
13289
|
}
|
|
13118
13290
|
references.clear();
|
|
13119
|
-
const result = close
|
|
13291
|
+
const result = closeReleasingStatements(close, args);
|
|
13120
13292
|
if (failure)
|
|
13121
13293
|
throw failure;
|
|
13122
13294
|
return result;
|
|
@@ -13146,26 +13318,42 @@ function withSqliteTransformPass(operation) {
|
|
|
13146
13318
|
const existing = transformPassScope.getStore();
|
|
13147
13319
|
if (existing?.active)
|
|
13148
13320
|
return operation();
|
|
13149
|
-
const
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
|
|
13153
|
-
|
|
13154
|
-
|
|
13155
|
-
|
|
13156
|
-
|
|
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;
|
|
13157
13340
|
}
|
|
13158
|
-
|
|
13159
|
-
|
|
13160
|
-
|
|
13161
|
-
lease.active = false;
|
|
13162
|
-
throw error;
|
|
13163
|
-
}
|
|
13164
|
-
});
|
|
13341
|
+
});
|
|
13342
|
+
};
|
|
13343
|
+
return typeof reservation === "function" ? run(reservation) : reservation.then(run);
|
|
13165
13344
|
}
|
|
13166
13345
|
function withoutSqliteTransformPass(operation) {
|
|
13167
13346
|
return transformPassScope.run(undefined, operation);
|
|
13168
13347
|
}
|
|
13348
|
+
function guardSqliteTransformPass(guard) {
|
|
13349
|
+
const lease = transformPassScope.getStore();
|
|
13350
|
+
if (lease)
|
|
13351
|
+
lease.guard = guard;
|
|
13352
|
+
}
|
|
13353
|
+
function assertTransformWrite() {
|
|
13354
|
+
if (!backgroundWriterScope.getStore())
|
|
13355
|
+
transformPassScope.getStore()?.guard?.assert();
|
|
13356
|
+
}
|
|
13169
13357
|
function isTransientSqliteError(error) {
|
|
13170
13358
|
if (!error || typeof error !== "object")
|
|
13171
13359
|
return false;
|
|
@@ -13177,6 +13365,7 @@ function foregroundWaitLease() {
|
|
|
13177
13365
|
return lease?.active && !admissionScope.getStore() && !backgroundWriterScope.getStore() ? lease : undefined;
|
|
13178
13366
|
}
|
|
13179
13367
|
function withAutocommitTimeout(db, operation) {
|
|
13368
|
+
assertTransformWrite();
|
|
13180
13369
|
const lease = foregroundWaitLease();
|
|
13181
13370
|
if (isInTransaction(db) || !lease && !backgroundWriterScope.getStore())
|
|
13182
13371
|
return operation();
|
|
@@ -13197,6 +13386,7 @@ function withAutocommitTimeout(db, operation) {
|
|
|
13197
13386
|
}
|
|
13198
13387
|
}
|
|
13199
13388
|
function acquireShort(db, acquire, site) {
|
|
13389
|
+
assertTransformWrite();
|
|
13200
13390
|
const started = performance.now();
|
|
13201
13391
|
const previous = pragmaNumber(db, "busy_timeout");
|
|
13202
13392
|
const outer = writerAcquisitionScope.getStore();
|
|
@@ -13208,7 +13398,7 @@ function acquireShort(db, acquire, site) {
|
|
|
13208
13398
|
let acquiredAt;
|
|
13209
13399
|
try {
|
|
13210
13400
|
const lease = foregroundWaitLease();
|
|
13211
|
-
const timeout =
|
|
13401
|
+
const timeout = Math.floor(Math.min(lease ? lease.remainingWaitMs : SHORT_BUSY_TIMEOUT_MS, owner?.remainingMs?.() ?? lease?.guard?.remainingMs() ?? Infinity));
|
|
13212
13402
|
db.exec(`PRAGMA busy_timeout=${timeout}`);
|
|
13213
13403
|
acquire();
|
|
13214
13404
|
acquiredAt = performance.now();
|
|
@@ -13238,18 +13428,20 @@ function acquireShort(db, acquire, site) {
|
|
|
13238
13428
|
}
|
|
13239
13429
|
function endWriterTransaction(db, end, sql) {
|
|
13240
13430
|
let ended = false;
|
|
13431
|
+
const endStarted = performance.now();
|
|
13241
13432
|
try {
|
|
13242
13433
|
const result = end();
|
|
13243
13434
|
ended = true;
|
|
13244
13435
|
return result;
|
|
13245
13436
|
} finally {
|
|
13246
13437
|
const open = openWriterTransactions.get(db);
|
|
13438
|
+
const endMs = performance.now() - endStarted;
|
|
13247
13439
|
if (open && !isInTransaction(db)) {
|
|
13248
13440
|
openWriterTransactions.delete(db);
|
|
13249
13441
|
const holdMs = performance.now() - open.acquiredAt;
|
|
13250
13442
|
if (open.acquireMs >= SLOW_WRITER_LOG_MS || holdMs >= SLOW_WRITER_LOG_MS) {
|
|
13251
13443
|
const outcome = /^\s*ROLLBACK/i.test(sql) ? "rolled_back" : ended ? "committed" : "failed";
|
|
13252
|
-
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}`);
|
|
13253
13445
|
}
|
|
13254
13446
|
}
|
|
13255
13447
|
}
|
|
@@ -13281,29 +13473,53 @@ async function beginSqliteWriterAsync(db, site) {
|
|
|
13281
13473
|
}
|
|
13282
13474
|
}
|
|
13283
13475
|
}
|
|
13284
|
-
async function withAsyncPrivilegedWriter(db, operation) {
|
|
13476
|
+
async function withAsyncPrivilegedWriter(db, operation, options = {}) {
|
|
13285
13477
|
const started = performance.now();
|
|
13478
|
+
const budgetMs = Math.max(0, Math.min(FOREGROUND_ACQUISITION_BUDGET_MS, options.budgetMs ?? Infinity));
|
|
13286
13479
|
let attempts = 0;
|
|
13287
13480
|
for (;; ) {
|
|
13481
|
+
options.signal?.throwIfAborted();
|
|
13482
|
+
options.assertCurrentPass?.();
|
|
13288
13483
|
attempts++;
|
|
13484
|
+
let entered = false;
|
|
13289
13485
|
try {
|
|
13290
13486
|
const acquisition = {
|
|
13291
13487
|
site: "privileged_writer",
|
|
13292
13488
|
lane: "foreground",
|
|
13293
13489
|
startedAt: started,
|
|
13294
13490
|
attempts,
|
|
13295
|
-
claimed: false
|
|
13491
|
+
claimed: false,
|
|
13492
|
+
remainingMs: () => Math.max(0, budgetMs - (performance.now() - started))
|
|
13296
13493
|
};
|
|
13297
|
-
return admissionScope.run(true, () => withSqliteTransformPass(() => writerAcquisitionScope.run(acquisition, () => withPrivilegedWriter(db,
|
|
13494
|
+
return admissionScope.run(true, () => withSqliteTransformPass(() => writerAcquisitionScope.run(acquisition, () => withPrivilegedWriter(db, () => {
|
|
13495
|
+
entered = true;
|
|
13496
|
+
return operation();
|
|
13497
|
+
}))));
|
|
13298
13498
|
} catch (error) {
|
|
13299
|
-
if (!(error instanceof SqliteAcquisitionBusyError))
|
|
13499
|
+
if (entered || !(error instanceof SqliteAcquisitionBusyError))
|
|
13300
13500
|
throw error;
|
|
13501
|
+
options.beforeRetry?.(error);
|
|
13301
13502
|
const elapsed = performance.now() - started;
|
|
13302
|
-
if (elapsed >=
|
|
13503
|
+
if (elapsed >= budgetMs) {
|
|
13303
13504
|
reportSqliteDiagnostic(`sqlite writer site=privileged_writer lane=foreground acquire_ms=${Math.round(elapsed)} attempts=${attempts} outcome=busy`);
|
|
13304
13505
|
throw error;
|
|
13305
13506
|
}
|
|
13306
|
-
|
|
13507
|
+
const backoff = attempts === 1 ? 500 : 1000;
|
|
13508
|
+
const delay = Math.min(options.jitter ? backoff * (0.8 + Math.random() * 0.4) : backoff, budgetMs - elapsed);
|
|
13509
|
+
await new Promise((resolve, reject) => {
|
|
13510
|
+
const abort = () => {
|
|
13511
|
+
clearTimeout(timer);
|
|
13512
|
+
options.signal?.removeEventListener("abort", abort);
|
|
13513
|
+
reject(options.signal?.reason ?? new Error("Writer wait aborted"));
|
|
13514
|
+
};
|
|
13515
|
+
const timer = setTimeout(() => {
|
|
13516
|
+
options.signal?.removeEventListener("abort", abort);
|
|
13517
|
+
resolve();
|
|
13518
|
+
}, delay);
|
|
13519
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
13520
|
+
if (options.signal?.aborted)
|
|
13521
|
+
abort();
|
|
13522
|
+
});
|
|
13307
13523
|
}
|
|
13308
13524
|
}
|
|
13309
13525
|
}
|
|
@@ -13365,7 +13581,55 @@ function withPrivilegedWriter(db, operation) {
|
|
|
13365
13581
|
throw error;
|
|
13366
13582
|
}
|
|
13367
13583
|
}
|
|
13368
|
-
|
|
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));
|
|
13369
13633
|
var init_sqlite = __esm(async () => {
|
|
13370
13634
|
bunSpec = "bun:" + "sqlite";
|
|
13371
13635
|
nodeSpec = "node:" + "sqlite";
|
|
@@ -13385,6 +13649,19 @@ var init_sqlite = __esm(async () => {
|
|
|
13385
13649
|
sqliteModule = await loadSqliteModule(detectedRuntime);
|
|
13386
13650
|
DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
|
|
13387
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
|
+
]);
|
|
13388
13665
|
TrackedDatabase = new Proxy(DatabaseImpl, {
|
|
13389
13666
|
construct(target, args) {
|
|
13390
13667
|
const db = Reflect.construct(target, args, target);
|
|
@@ -13409,6 +13686,11 @@ var init_sqlite = __esm(async () => {
|
|
|
13409
13686
|
WRITER_TRANSACTION_END = /^\s*(?:COMMIT|END|ROLLBACK)(?:\s+TRANSACTION)?\s*;?\s*$/i;
|
|
13410
13687
|
writerAcquisitionScope = new AsyncLocalStorage;
|
|
13411
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);
|
|
13412
13694
|
});
|
|
13413
13695
|
|
|
13414
13696
|
// src/lib/docs-proposal-gitignore.ts
|
|
@@ -22856,6 +23138,22 @@ function readConfiguredOpenCodePluginSpec(config) {
|
|
|
22856
23138
|
}
|
|
22857
23139
|
return "latest";
|
|
22858
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
|
+
}
|
|
22859
23157
|
function pluginEntrySpecifier(entry) {
|
|
22860
23158
|
if (typeof entry === "string")
|
|
22861
23159
|
return entry;
|
|
@@ -23081,6 +23379,9 @@ function checkOpenCodeV2PluginCache(options, deps = {}) {
|
|
|
23081
23379
|
const distTag = options.distTag && options.distTag !== "latest" ? options.distTag : undefined;
|
|
23082
23380
|
const slot = deps.slot ?? getOpenCodeV2PluginCacheSlot(undefined, distTag ?? "latest");
|
|
23083
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
|
+
}
|
|
23084
23385
|
if (!existsSync13(slot))
|
|
23085
23386
|
return { action: "not_found", slot, ...tagged };
|
|
23086
23387
|
const cached = readOpenCodeV2CachedPluginVersion(slot);
|
|
@@ -23120,7 +23421,7 @@ function reportOpenCodeV2PluginCache(result, report, options) {
|
|
|
23120
23421
|
const slotName = result.distTag ? ` @${result.distTag}` : "";
|
|
23121
23422
|
switch (result.action) {
|
|
23122
23423
|
case "not_found":
|
|
23123
|
-
if (options.reportMissing) {
|
|
23424
|
+
if (options.reportMissing && !result.unused) {
|
|
23124
23425
|
report.pass(`OpenCode 2 plugin cache has no Magic Context${slotName} install yet (OpenCode installs it on next start)`);
|
|
23125
23426
|
}
|
|
23126
23427
|
return { fixed: false, issue: false };
|
|
@@ -23148,6 +23449,15 @@ function reportOpenCodeV2PluginCache(result, report, options) {
|
|
|
23148
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`);
|
|
23149
23450
|
report.info(` ${result.slot}`);
|
|
23150
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 };
|
|
23151
23461
|
case "error":
|
|
23152
23462
|
report.warn(`Could not clear the OpenCode 2 plugin cache: ${result.error}`);
|
|
23153
23463
|
report.info(` Manually delete: ${result.slot}`);
|
|
@@ -28683,6 +28993,26 @@ var init_migrations = __esm(async () => {
|
|
|
28683
28993
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
28684
28994
|
});
|
|
28685
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
|
+
|
|
28686
29016
|
// ../plugin/src/shared/commit-detection.ts
|
|
28687
29017
|
function createCommitHashExtractPattern() {
|
|
28688
29018
|
return new RegExp(`\`?\\b(${HASH_HEX})\\b\`?`, "gi");
|
|
@@ -28705,6 +29035,271 @@ function removeSystemReminders(text) {
|
|
|
28705
29035
|
}
|
|
28706
29036
|
var SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: MAGIC-CONTEXT";
|
|
28707
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
|
+
|
|
28708
29303
|
// ../plugin/src/hooks/magic-context/read-session-formatting.ts
|
|
28709
29304
|
import { createRequire as createRequire2 } from "node:module";
|
|
28710
29305
|
function hasMeaningfulUserText(parts) {
|
|
@@ -28847,7 +29442,7 @@ function estimateTokens(text) {
|
|
|
28847
29442
|
if (!activeTokenizer)
|
|
28848
29443
|
return estimateTokensHeuristically(text);
|
|
28849
29444
|
try {
|
|
28850
|
-
return activeTokenizer
|
|
29445
|
+
return countTokensExactly(activeTokenizer, text);
|
|
28851
29446
|
} catch (error) {
|
|
28852
29447
|
tokenizer = undefined;
|
|
28853
29448
|
tokenizerLoadAttempted = true;
|
|
@@ -28938,21 +29533,41 @@ var MAX_COMMITS_PER_BLOCK = 5, tokenizer, tokenizerLoadAttempted = false, tokeni
|
|
|
28938
29533
|
var init_read_session_formatting = __esm(() => {
|
|
28939
29534
|
init_commit_detection();
|
|
28940
29535
|
init_logger();
|
|
29536
|
+
init_token_count_exact();
|
|
28941
29537
|
promptTokenCounts = new Map;
|
|
28942
29538
|
PROMPT_TOKEN_COUNT_BYTES = 8 * 1024 * 1024;
|
|
28943
29539
|
});
|
|
28944
29540
|
|
|
28945
29541
|
// ../plugin/src/shared/stable-json.ts
|
|
28946
29542
|
function stableStringify(value, seen = new WeakSet) {
|
|
28947
|
-
|
|
28948
|
-
|
|
28949
|
-
|
|
28950
|
-
|
|
28951
|
-
|
|
28952
|
-
|
|
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
|
+
}
|
|
28953
29560
|
seen.add(value);
|
|
28954
29561
|
if (Array.isArray(value)) {
|
|
28955
|
-
|
|
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;
|
|
28956
29571
|
}
|
|
28957
29572
|
const entries = Object.entries(value).sort(([a], [b]) => {
|
|
28958
29573
|
if (a < b)
|
|
@@ -28961,7 +29576,14 @@ function stableStringify(value, seen = new WeakSet) {
|
|
|
28961
29576
|
return 1;
|
|
28962
29577
|
return 0;
|
|
28963
29578
|
});
|
|
28964
|
-
|
|
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("}");
|
|
28965
29587
|
}
|
|
28966
29588
|
|
|
28967
29589
|
// ../plugin/src/features/magic-context/tool-definition-tokens.ts
|
|
@@ -29647,6 +30269,19 @@ var init_image_token_estimate = __esm(() => {
|
|
|
29647
30269
|
JPEG_SCAN_LIMIT_BYTES = 256 * 1024;
|
|
29648
30270
|
});
|
|
29649
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
|
+
|
|
29650
30285
|
// ../plugin/src/hooks/magic-context/todo-view.ts
|
|
29651
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;
|
|
29652
30287
|
var init_todo_view = __esm(() => {
|
|
@@ -29676,10 +30311,11 @@ var init_tail_hygiene_walk = __esm(() => {
|
|
|
29676
30311
|
init_reclaim_protection();
|
|
29677
30312
|
init_tag_owner_id();
|
|
29678
30313
|
init_image_token_estimate();
|
|
30314
|
+
init_provider_visible_parts();
|
|
29679
30315
|
init_read_session_formatting();
|
|
29680
30316
|
init_todo_view();
|
|
29681
30317
|
init_reclaim_protection();
|
|
29682
|
-
MAX_CONTENT_MEMO_BYTES =
|
|
30318
|
+
MAX_CONTENT_MEMO_BYTES = 256 * 1024 * 1024;
|
|
29683
30319
|
contentMemo = new Map;
|
|
29684
30320
|
contentMemoOrder = new Set;
|
|
29685
30321
|
baselineMeasurementMemo = new Map;
|
|
@@ -29745,12 +30381,14 @@ function pickNearestPriorOwner(candidates, currentMessageId, times) {
|
|
|
29745
30381
|
}
|
|
29746
30382
|
return best?.id ?? null;
|
|
29747
30383
|
}
|
|
29748
|
-
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;
|
|
29749
|
-
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 () => {
|
|
29750
30386
|
init_emergency_drop();
|
|
29751
30387
|
init_tag_owner_id();
|
|
29752
30388
|
init_migration_v95_perf_indexes();
|
|
29753
30389
|
init_storage_ops();
|
|
30390
|
+
init_storage_tag_identity_revision();
|
|
30391
|
+
await init_sqlite();
|
|
29754
30392
|
insertTagStatements = new WeakMap;
|
|
29755
30393
|
updateTagStatusStatements = new WeakMap;
|
|
29756
30394
|
updateTagDropModeStatements = new WeakMap;
|
|
@@ -29778,6 +30416,12 @@ var init_storage_tags = __esm(() => {
|
|
|
29778
30416
|
scopedActiveTokenTotalStatements = new WeakMap;
|
|
29779
30417
|
updateTagTokenCountStatements = new WeakMap;
|
|
29780
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 = ?`;
|
|
29781
30425
|
inertWhitespaceStatements = new WeakMap;
|
|
29782
30426
|
foldStatements = new WeakMap;
|
|
29783
30427
|
getOwnerScopedToolTagNumbersStatements = new WeakMap;
|
|
@@ -29800,6 +30444,24 @@ var init_storage_tags = __esm(() => {
|
|
|
29800
30444
|
var historian_tool_defaults_default;
|
|
29801
30445
|
var init_historian_tool_defaults = __esm(() => {
|
|
29802
30446
|
historian_tool_defaults_default = {
|
|
30447
|
+
ctx_note: "Note ${input.action} ${input.note_ids}: ${input.content} → ${output.truncate(160)}",
|
|
30448
|
+
ctx_memory: "Memory ${input.action} ${input.category} ${input.ids}: ${input.content} → ${output.truncate(160)}",
|
|
30449
|
+
todowrite: 'Todos (${input.todos.count}): ${input.todos.each("${status}: ${content}")}',
|
|
30450
|
+
question: 'Asked user: ${input.questions[*].question.join(" / ")} → ${output}',
|
|
30451
|
+
task: "Task ${input.subagent_type}: ${input.prompt.truncate(600)} → ${output.truncate(200)}",
|
|
30452
|
+
ask: 'Asked: ${input.question} [options: ${input.options.join(" / ")}] ${input.text}${input.resolution} → ${output.truncate(300)}',
|
|
30453
|
+
peer_send: "PM ${input.recipient}: ${input.message}",
|
|
30454
|
+
board: 'Board ${input.verb}${input.board_lane}: ${input.ops.each("${op} ${lane_label} ${item}${props.text}${lane.items} ${state}${props.state}${lane.status}${id}${title}")}',
|
|
30455
|
+
room: "Room ${input.action} ${input.room_label}: ${input.room_detail}",
|
|
30456
|
+
work: "Work ${input.action} ${input.title}${input.id}: ${input.prompt.truncate(600)}${input.notes.truncate(600)} → ${output.truncate(160)}",
|
|
30457
|
+
knowhow: "Looked up how-to: ${input.query}${input.id}"
|
|
30458
|
+
};
|
|
30459
|
+
});
|
|
30460
|
+
|
|
30461
|
+
// ../plugin/src/shared/historian-tool-preview-defaults.json
|
|
30462
|
+
var historian_tool_preview_defaults_default;
|
|
30463
|
+
var init_historian_tool_preview_defaults = __esm(() => {
|
|
30464
|
+
historian_tool_preview_defaults_default = {
|
|
29803
30465
|
ctx_note: "Note ${input.action} ${input.note_ids}: ${input.content} → ${output.truncate(160)}",
|
|
29804
30466
|
ctx_memory: "Memory ${input.action} ${input.category} ${input.ids}: ${input.content} → ${output.truncate(160)}",
|
|
29805
30467
|
todowrite: 'Todos (${input.todos.count}): ${input.todos.each("${status}: ${content}")}',
|
|
@@ -29815,20 +30477,52 @@ var init_historian_tool_defaults = __esm(() => {
|
|
|
29815
30477
|
});
|
|
29816
30478
|
|
|
29817
30479
|
// ../plugin/src/shared/historian-tool-expansions.ts
|
|
29818
|
-
function
|
|
30480
|
+
function builtinInput(tool, input) {
|
|
30481
|
+
if (!input || typeof input !== "object")
|
|
30482
|
+
return input;
|
|
30483
|
+
const i = input;
|
|
30484
|
+
if (tool === "peer_send") {
|
|
30485
|
+
const external = i.external;
|
|
30486
|
+
const recipient = i.reply_to_pmid ? `reply to ${i.reply_to_pmid}` : i.agent || i.agent_id ? `to ${i.agent || i.agent_id}` : external?.session_id || i.session_id ? `to session ${external?.session_id || i.session_id}` : "to unknown recipient";
|
|
30487
|
+
return { ...i, recipient };
|
|
30488
|
+
}
|
|
30489
|
+
if (tool === "room") {
|
|
30490
|
+
return {
|
|
30491
|
+
...i,
|
|
30492
|
+
room_label: i.room_id || i.title,
|
|
30493
|
+
room_detail: i.action === "create" || i.action === "invite" ? `invitees: ${renderToolTemplate("${input.invitees}", i)}` : i.text
|
|
30494
|
+
};
|
|
30495
|
+
}
|
|
30496
|
+
if (tool === "board") {
|
|
30497
|
+
return {
|
|
30498
|
+
...i,
|
|
30499
|
+
board_lane: i.lane ? ` ${i.lane}` : "",
|
|
30500
|
+
ops: Array.isArray(i.ops) ? i.ops.map((op) => op && typeof op === "object" ? {
|
|
30501
|
+
...op,
|
|
30502
|
+
lane_label: typeof op.lane === "string" ? op.lane : op.lane?.title || op.lane?.id
|
|
30503
|
+
} : op) : i.ops
|
|
30504
|
+
};
|
|
30505
|
+
}
|
|
30506
|
+
return input;
|
|
30507
|
+
}
|
|
30508
|
+
function expandToolPart(part, overrides, legacyPreview = false) {
|
|
29819
30509
|
if (!part || typeof part !== "object")
|
|
29820
30510
|
return null;
|
|
29821
30511
|
const p = part;
|
|
29822
30512
|
if (p.type !== "tool" || typeof p.tool !== "string")
|
|
29823
30513
|
return null;
|
|
29824
|
-
const
|
|
30514
|
+
const builtinDefaults = legacyPreview ? historian_tool_preview_defaults_default : historian_tool_defaults_default;
|
|
30515
|
+
const overridden = overrides && Object.hasOwn(overrides, p.tool);
|
|
30516
|
+
const template = overridden ? overrides[p.tool] : Object.hasOwn(builtinDefaults, p.tool) ? builtinDefaults[p.tool] : undefined;
|
|
29825
30517
|
if (typeof template !== "string")
|
|
29826
30518
|
return null;
|
|
29827
30519
|
const state = p.state;
|
|
29828
|
-
|
|
30520
|
+
const input = overridden || legacyPreview ? state?.input : builtinInput(p.tool, state?.input);
|
|
30521
|
+
return renderToolTemplate(template, input, state?.output ?? state?.error, legacyPreview);
|
|
29829
30522
|
}
|
|
29830
30523
|
var init_historian_tool_expansions = __esm(() => {
|
|
29831
30524
|
init_historian_tool_defaults();
|
|
30525
|
+
init_historian_tool_preview_defaults();
|
|
29832
30526
|
init_historian_tool_template();
|
|
29833
30527
|
});
|
|
29834
30528
|
|
|
@@ -29846,92 +30540,28 @@ function isHostUnservedRow(value) {
|
|
|
29846
30540
|
}
|
|
29847
30541
|
var HOST_UNSERVED_ROW = "hostUnservedRow";
|
|
29848
30542
|
|
|
29849
|
-
// ../plugin/src/
|
|
29850
|
-
function
|
|
29851
|
-
|
|
29852
|
-
|
|
29853
|
-
|
|
29854
|
-
|
|
29855
|
-
return;
|
|
29856
|
-
}
|
|
29857
|
-
try {
|
|
29858
|
-
closeQuietly(cachedReadOnlyDb.db);
|
|
29859
|
-
} catch (error) {
|
|
29860
|
-
log("[magic-context] failed to close cached OpenCode read-only DB:", error);
|
|
29861
|
-
} finally {
|
|
29862
|
-
cachedReadOnlyDb = null;
|
|
29863
|
-
}
|
|
29864
|
-
}
|
|
29865
|
-
function getReadOnlySessionDb() {
|
|
29866
|
-
if (!harnessOwnsOpenCodeStore()) {
|
|
29867
|
-
throw new Error("OpenCode session database is not readable from a Pi-compatible process; its history lives in Pi sessions");
|
|
29868
|
-
}
|
|
29869
|
-
const resolution = resolveOpenCodeDbPath();
|
|
29870
|
-
const dbPath = resolution.path;
|
|
29871
|
-
if (!openCodeDbPathExists(resolution)) {
|
|
29872
|
-
throw new Error(`OpenCode session database is unavailable at ${dbPath} (source=${resolution.source})`);
|
|
29873
|
-
}
|
|
29874
|
-
if (cachedReadOnlyDb?.path === dbPath) {
|
|
29875
|
-
return cachedReadOnlyDb.db;
|
|
29876
|
-
}
|
|
29877
|
-
closeCachedReadOnlyDb();
|
|
29878
|
-
const db = new Database(dbPath, { readonly: true });
|
|
29879
|
-
try {
|
|
29880
|
-
assertOpenCodeStoreGeneration(db, "v1", dbPath);
|
|
29881
|
-
} catch (error) {
|
|
29882
|
-
closeQuietly(db);
|
|
29883
|
-
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 {}
|
|
29884
30549
|
}
|
|
29885
|
-
cachedReadOnlyDb = { path: dbPath, db };
|
|
29886
|
-
clearOpenCodeDbReadFailure();
|
|
29887
|
-
return db;
|
|
29888
30550
|
}
|
|
29889
|
-
function
|
|
29890
|
-
|
|
29891
|
-
|
|
29892
|
-
function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
29893
|
-
const row = db.prepare(`SELECT COUNT(*) as count FROM message WHERE session_id = ?
|
|
29894
|
-
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
29895
|
-
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
|
|
29896
|
-
return typeof row?.count === "number" ? row.count : 0;
|
|
29897
|
-
}
|
|
29898
|
-
function logProbeFailureOnce(resolution, error) {
|
|
29899
|
-
const failure = recordOpenCodeDbReadFailure(resolution, error);
|
|
29900
|
-
if (!claimOpenCodeDbDiagnosticOnce("session-state-probe", resolution))
|
|
30551
|
+
function registerExitAbort(controller) {
|
|
30552
|
+
controllers.add(controller);
|
|
30553
|
+
if (listenerRegistered)
|
|
29901
30554
|
return;
|
|
29902
|
-
|
|
29903
|
-
|
|
29904
|
-
log(message);
|
|
30555
|
+
listenerRegistered = true;
|
|
30556
|
+
process.once("exit", abortAll);
|
|
29905
30557
|
}
|
|
29906
|
-
|
|
29907
|
-
|
|
29908
|
-
|
|
29909
|
-
return result;
|
|
29910
|
-
try {
|
|
29911
|
-
withReadOnlySessionDb((db) => {
|
|
29912
|
-
const placeholders = messageIds.map(() => "?").join(",");
|
|
29913
|
-
const rows = db.prepare(`SELECT id, time_created FROM message WHERE session_id = ? AND id IN (${placeholders})`).all(sessionId, ...messageIds);
|
|
29914
|
-
for (const row of rows) {
|
|
29915
|
-
if (typeof row.id === "string" && typeof row.time_created === "number") {
|
|
29916
|
-
result.set(row.id, row.time_created);
|
|
29917
|
-
}
|
|
29918
|
-
}
|
|
29919
|
-
});
|
|
29920
|
-
} catch (error) {
|
|
29921
|
-
logProbeFailureOnce(resolveOpenCodeDbPath(), error);
|
|
29922
|
-
}
|
|
29923
|
-
return result;
|
|
29924
|
-
}
|
|
29925
|
-
var cachedReadOnlyDb = null, trackedSessions, pendingParts, probeLogObserverForTests;
|
|
29926
|
-
var init_read_session_db = __esm(async () => {
|
|
29927
|
-
init_logger();
|
|
29928
|
-
init_opencode_db_path();
|
|
29929
|
-
await init_sqlite();
|
|
29930
|
-
trackedSessions = new Map;
|
|
29931
|
-
pendingParts = new Map;
|
|
30558
|
+
var controllers, listenerRegistered = false;
|
|
30559
|
+
var init_exit_abort_registry = __esm(() => {
|
|
30560
|
+
controllers = new Set;
|
|
29932
30561
|
});
|
|
29933
30562
|
|
|
29934
30563
|
// ../plugin/src/hooks/magic-context/read-session-raw.ts
|
|
30564
|
+
import { isMainThread as isMainThread2 } from "node:worker_threads";
|
|
29935
30565
|
function isRawMessageRow(row) {
|
|
29936
30566
|
if (row === null || typeof row !== "object")
|
|
29937
30567
|
return false;
|
|
@@ -29991,7 +30621,7 @@ function readRawSessionMessagesFromDb(db, sessionId) {
|
|
|
29991
30621
|
if (messageIds.length === 0)
|
|
29992
30622
|
continue;
|
|
29993
30623
|
const placeholders = messageIds.map(() => "?").join(", ");
|
|
29994
|
-
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
|
|
29995
30625
|
FROM part
|
|
29996
30626
|
WHERE +session_id = ?
|
|
29997
30627
|
AND likelihood(message_id IN (${placeholders}), 0.000001)
|
|
@@ -30023,7 +30653,7 @@ function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, fin
|
|
|
30023
30653
|
if (messageRows.length === 0)
|
|
30024
30654
|
return [];
|
|
30025
30655
|
const placeholders = messageRows.map(() => "?").join(", ");
|
|
30026
|
-
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
|
|
30027
30657
|
FROM part
|
|
30028
30658
|
WHERE +session_id = ?
|
|
30029
30659
|
AND likelihood(message_id IN (${placeholders}), 0.000001)
|
|
@@ -30096,6 +30726,9 @@ function readRawSessionMessageSummaryPageFromDb(db, sessionId, afterOrdinal, lim
|
|
|
30096
30726
|
return assembleRawMessagePage(messageRows, partRows);
|
|
30097
30727
|
}
|
|
30098
30728
|
function countRawSessionMessageOrdinalsFromDb(db, sessionId) {
|
|
30729
|
+
const indexed = countCanonicalOrdinalsIndexed(db, sessionId, null, null);
|
|
30730
|
+
if (indexed !== null)
|
|
30731
|
+
return indexed;
|
|
30099
30732
|
const row = db.prepare(`SELECT COUNT(*) AS count
|
|
30100
30733
|
FROM message
|
|
30101
30734
|
WHERE session_id = ?
|
|
@@ -30182,7 +30815,7 @@ function readRawSessionTailFromDb(db, sessionId, baseOrdinal, anchorMessageId) {
|
|
|
30182
30815
|
for (let i = 0;i < ids.length; i += CHUNK) {
|
|
30183
30816
|
const slice = ids.slice(i, i + CHUNK);
|
|
30184
30817
|
const placeholders = slice.map(() => "?").join(",");
|
|
30185
|
-
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);
|
|
30186
30819
|
for (const part of partRows) {
|
|
30187
30820
|
const list = partsByMessageId.get(part.message_id) ?? [];
|
|
30188
30821
|
list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
|
|
@@ -30228,49 +30861,431 @@ function readRawSessionMessagePartsByIdFromDb(db, sessionId, messageId, onQuery)
|
|
|
30228
30861
|
version: row.time_updated ?? null
|
|
30229
30862
|
};
|
|
30230
30863
|
}
|
|
30231
|
-
function
|
|
30232
|
-
|
|
30233
|
-
|
|
30234
|
-
|
|
30235
|
-
|
|
30236
|
-
|
|
30237
|
-
|
|
30238
|
-
|
|
30239
|
-
ELSE 0 END = 1
|
|
30240
|
-
AND CASE WHEN json_valid(candidate.data) = 1
|
|
30241
|
-
THEN COALESCE(json_extract(candidate.data, '$.finish'), '')
|
|
30242
|
-
ELSE '' END = 'stop'
|
|
30243
|
-
)
|
|
30244
|
-
AND (candidate.time_created < target.time_created
|
|
30245
|
-
OR (candidate.time_created = target.time_created AND candidate.id <= target.id))
|
|
30246
|
-
WHERE target.session_id = ?
|
|
30247
|
-
AND target.id = ?
|
|
30248
|
-
AND NOT (
|
|
30249
|
-
CASE WHEN json_valid(target.data) = 1
|
|
30250
|
-
THEN COALESCE(json_extract(target.data, '$.summary'), 0)
|
|
30251
|
-
ELSE 0 END = 1
|
|
30252
|
-
AND CASE WHEN json_valid(target.data) = 1
|
|
30253
|
-
THEN COALESCE(json_extract(target.data, '$.finish'), '')
|
|
30254
|
-
ELSE '' END = 'stop'
|
|
30255
|
-
)`).get(sessionId, messageId);
|
|
30256
|
-
const ordinal = row?.ordinal;
|
|
30257
|
-
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) <= (?, ?)`;
|
|
30258
30872
|
}
|
|
30259
|
-
function
|
|
30260
|
-
|
|
30261
|
-
|
|
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 {
|
|
30262
30886
|
return null;
|
|
30263
30887
|
}
|
|
30264
|
-
|
|
30265
|
-
|
|
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)
|
|
30266
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);
|
|
30267
31089
|
}
|
|
30268
|
-
|
|
30269
|
-
|
|
30270
|
-
|
|
30271
|
-
|
|
30272
|
-
|
|
30273
|
-
|
|
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;
|
|
30274
31289
|
if (ordinal <= 0) {
|
|
30275
31290
|
return null;
|
|
30276
31291
|
}
|
|
@@ -30334,8 +31349,34 @@ function readRawSeedTailFromDb(db, sessionId, boundaryId) {
|
|
|
30334
31349
|
throw new Error("state_sync materialized boundary is missing from raw storage");
|
|
30335
31350
|
return messages;
|
|
30336
31351
|
}
|
|
30337
|
-
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
|
|
30338
|
-
|
|
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`;
|
|
30339
31380
|
RAW_SUMMARY_TOOL_INPUT_KEYS = [
|
|
30340
31381
|
"description",
|
|
30341
31382
|
"filePath",
|
|
@@ -30360,6 +31401,268 @@ var init_read_session_raw = __esm(() => {
|
|
|
30360
31401
|
)
|
|
30361
31402
|
)
|
|
30362
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;
|
|
30363
31666
|
});
|
|
30364
31667
|
|
|
30365
31668
|
// ../plugin/src/hooks/magic-context/read-session-true-raw-tokens.ts
|
|
@@ -30411,7 +31714,7 @@ function callIdFromPart(part) {
|
|
|
30411
31714
|
const state = isRecord2(part.state) ? part.state : null;
|
|
30412
31715
|
return state ? firstStringField(state, ["callID", "callId", "toolCallId", "tool_call_id", "id"]) ?? "" : "";
|
|
30413
31716
|
}
|
|
30414
|
-
function toolSignalFromPart(part) {
|
|
31717
|
+
function toolSignalFromPart(part, withText = true) {
|
|
30415
31718
|
if (!isRecord2(part))
|
|
30416
31719
|
return null;
|
|
30417
31720
|
const type = partType(part);
|
|
@@ -30430,8 +31733,8 @@ function toolSignalFromPart(part) {
|
|
|
30430
31733
|
callId,
|
|
30431
31734
|
hasInput: hasInput || openInvocation,
|
|
30432
31735
|
hasOutput,
|
|
30433
|
-
inputText: hasInput && state ? stringValue(state.input) : "",
|
|
30434
|
-
outputText: hasOutput ? stringValue(outputValue) : ""
|
|
31736
|
+
inputText: withText && hasInput && state ? stringValue(state.input) : "",
|
|
31737
|
+
outputText: withText && hasOutput ? stringValue(outputValue) : ""
|
|
30435
31738
|
};
|
|
30436
31739
|
}
|
|
30437
31740
|
if (type === "tool-invocation") {
|
|
@@ -30440,7 +31743,7 @@ function toolSignalFromPart(part) {
|
|
|
30440
31743
|
callId,
|
|
30441
31744
|
hasInput: args !== undefined,
|
|
30442
31745
|
hasOutput: false,
|
|
30443
|
-
inputText: args !== undefined ? stringValue(args) : "",
|
|
31746
|
+
inputText: withText && args !== undefined ? stringValue(args) : "",
|
|
30444
31747
|
outputText: ""
|
|
30445
31748
|
};
|
|
30446
31749
|
}
|
|
@@ -30450,7 +31753,7 @@ function toolSignalFromPart(part) {
|
|
|
30450
31753
|
callId,
|
|
30451
31754
|
hasInput: input !== undefined,
|
|
30452
31755
|
hasOutput: false,
|
|
30453
|
-
inputText: input !== undefined ? stringValue(input) : "",
|
|
31756
|
+
inputText: withText && input !== undefined ? stringValue(input) : "",
|
|
30454
31757
|
outputText: ""
|
|
30455
31758
|
};
|
|
30456
31759
|
}
|
|
@@ -30461,7 +31764,7 @@ function toolSignalFromPart(part) {
|
|
|
30461
31764
|
hasInput: false,
|
|
30462
31765
|
hasOutput: content !== undefined,
|
|
30463
31766
|
inputText: "",
|
|
30464
|
-
outputText: content !== undefined ? textFromToolResultContent(content) : ""
|
|
31767
|
+
outputText: withText && content !== undefined ? textFromToolResultContent(content) : ""
|
|
30465
31768
|
};
|
|
30466
31769
|
}
|
|
30467
31770
|
return null;
|
|
@@ -30471,7 +31774,7 @@ function buildToolArcs(messages) {
|
|
|
30471
31774
|
const arcs = [];
|
|
30472
31775
|
for (const message of messages) {
|
|
30473
31776
|
for (const part of message.parts) {
|
|
30474
|
-
const signal = toolSignalFromPart(part);
|
|
31777
|
+
const signal = toolSignalFromPart(part, false);
|
|
30475
31778
|
if (!signal || signal.callId.length === 0)
|
|
30476
31779
|
continue;
|
|
30477
31780
|
if (signal.hasInput && signal.hasOutput) {
|
|
@@ -30510,6 +31813,7 @@ function buildToolArcs(messages) {
|
|
|
30510
31813
|
}
|
|
30511
31814
|
var MAX_MESSAGE_CACHE_KEY_BYTES, messageEstimateCache, messageEstimateKeysByField;
|
|
30512
31815
|
var init_read_session_true_raw_tokens = __esm(() => {
|
|
31816
|
+
init_provider_visible_parts();
|
|
30513
31817
|
init_read_session_formatting();
|
|
30514
31818
|
MAX_MESSAGE_CACHE_KEY_BYTES = 64 * 1024 * 1024;
|
|
30515
31819
|
messageEstimateCache = new Map;
|
|
@@ -30591,7 +31895,8 @@ var init_overflow_detection = __esm(() => {
|
|
|
30591
31895
|
PREFIX_BOUND_THINKING_MODELS = [
|
|
30592
31896
|
["fable", 5, 1],
|
|
30593
31897
|
["opus", 5, 5],
|
|
30594
|
-
["sonnet", 5, 5]
|
|
31898
|
+
["sonnet", 5, 5],
|
|
31899
|
+
["haiku", 5, 5]
|
|
30595
31900
|
];
|
|
30596
31901
|
PREFIX_BOUND_THINKING_PATTERN = new RegExp(`(?:^|[-_.:/])(?:${PREFIX_BOUND_THINKING_MODELS.map(([family, major, minor]) => `${family}[-_.]?${major}[-_.]${minor}`).join("|")})(?:$|[-_.:/@])`, "i");
|
|
30597
31902
|
});
|
|
@@ -30670,6 +31975,7 @@ __export(exports_read_session_chunk, {
|
|
|
30670
31975
|
hasMeaningfulUserText: () => hasMeaningfulUserText,
|
|
30671
31976
|
hasRawMessageProvider: () => hasRawMessageProvider,
|
|
30672
31977
|
hasRawSessionMessageById: () => hasRawSessionMessageById,
|
|
31978
|
+
prepareRawSessionOrdinals: () => prepareRawSessionOrdinals,
|
|
30673
31979
|
primeInMemoryTailRawMessageCache: () => primeInMemoryTailRawMessageCache,
|
|
30674
31980
|
primeTailRawMessageCache: () => primeTailRawMessageCache,
|
|
30675
31981
|
readRawSessionMessageById: () => readRawSessionMessageById,
|
|
@@ -30940,6 +32246,36 @@ function readRawSessionMessageRange(sessionId, fromOrdinal, toOrdinal) {
|
|
|
30940
32246
|
}
|
|
30941
32247
|
return messages;
|
|
30942
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
|
+
}
|
|
30943
32279
|
function primeTailRawMessageCache(args) {
|
|
30944
32280
|
const { sessionId, lastCompartmentEnd, anchorMessageId } = args;
|
|
30945
32281
|
if (!activeRawMessageCache)
|
|
@@ -31574,22 +32910,28 @@ function readRawSessionSeedTail(sessionId, boundaryId, onQuery) {
|
|
|
31574
32910
|
}
|
|
31575
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;
|
|
31576
32912
|
var init_read_session_chunk = __esm(async () => {
|
|
31577
|
-
init_storage_tags();
|
|
31578
32913
|
init_historian_tool_expansions();
|
|
32914
|
+
init_logger();
|
|
31579
32915
|
init_read_session_formatting();
|
|
31580
|
-
init_read_session_raw();
|
|
31581
32916
|
init_read_session_true_raw_tokens();
|
|
31582
32917
|
init_system_injection_stripper();
|
|
31583
32918
|
init_tag_part_guards();
|
|
31584
32919
|
init_tool_drop_target();
|
|
31585
32920
|
init_read_session_formatting();
|
|
31586
|
-
await
|
|
32921
|
+
await __promiseAll([
|
|
32922
|
+
init_storage_tags(),
|
|
32923
|
+
init_raw_ordinal_warmup(),
|
|
32924
|
+
init_read_session_db(),
|
|
32925
|
+
init_read_session_raw()
|
|
32926
|
+
]);
|
|
31587
32927
|
blockTokenMemo = new Map;
|
|
31588
32928
|
sessionProviders = new Map;
|
|
31589
32929
|
boundedProviderWrappers = new WeakMap;
|
|
31590
32930
|
SYSTEM_REMINDER_BLOCK_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
31591
32931
|
readRawSessionMessages.readPage = readRawSessionMessagePage;
|
|
31592
32932
|
readRawSessionMessages.getCount = getRawSessionMessageOrdinalCount;
|
|
32933
|
+
readRawSessionMessages.prepare = prepareRawSessionOrdinals;
|
|
32934
|
+
readRawSessionMessageById.prepare = prepareRawSessionOrdinals;
|
|
31593
32935
|
});
|
|
31594
32936
|
|
|
31595
32937
|
// ../plugin/src/features/magic-context/message-time-backfill.ts
|
|
@@ -33450,6 +34792,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
33450
34792
|
const version = getPersistedSchemaVersion(db);
|
|
33451
34793
|
if (version === 0 || version >= 95)
|
|
33452
34794
|
installV95PerfSchema(db, false, version === 0);
|
|
34795
|
+
installTagIdentityRevisionTrigger(db);
|
|
33453
34796
|
}
|
|
33454
34797
|
function healWedgedChannel2Claims(db) {
|
|
33455
34798
|
try {
|
|
@@ -33529,6 +34872,7 @@ function openDatabase(dbPathOrOptions) {
|
|
|
33529
34872
|
} else
|
|
33530
34873
|
runMigrations(db);
|
|
33531
34874
|
ensureContextStoreUuid(db);
|
|
34875
|
+
installTagIdentityRevisionTrigger(db);
|
|
33532
34876
|
return finishDatabaseOpen(db, dbPath, explicitDbPath, latestSupportedVersion);
|
|
33533
34877
|
} catch (error) {
|
|
33534
34878
|
if (db)
|
|
@@ -33563,6 +34907,7 @@ var init_storage_db = __esm(async () => {
|
|
|
33563
34907
|
init_migration_v95_perf_indexes();
|
|
33564
34908
|
init_migration_worker_client();
|
|
33565
34909
|
init_storage_schema_helpers();
|
|
34910
|
+
init_storage_tag_identity_revision();
|
|
33566
34911
|
init_tool_definition_tokens();
|
|
33567
34912
|
init_tool_owner_backfill();
|
|
33568
34913
|
await __promiseAll([
|
|
@@ -33768,6 +35113,9 @@ var init_config_location_migration = __esm(() => {
|
|
|
33768
35113
|
});
|
|
33769
35114
|
|
|
33770
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
|
+
}
|
|
33771
35119
|
var CANONICAL_DREAM_TASKS, DREAM_TOOL_LOOP_TOKEN_BUDGETS, MEMORY_DOMAIN_TASKS, MEMORY_DOMAIN_SET;
|
|
33772
35120
|
var init_task_registry = __esm(() => {
|
|
33773
35121
|
CANONICAL_DREAM_TASKS = [
|
|
@@ -34518,8 +35866,10 @@ function openCodeConfigFileChain(directory, hostGeneration) {
|
|
|
34518
35866
|
const globalSupplementary = getOpenCodeConfigDirs().filter((dir) => dir !== globalDir).flatMap((dir) => [join17(dir, "opencode.json"), join17(dir, "opencode.jsonc")]);
|
|
34519
35867
|
const explicitConfig = process.env.OPENCODE_CONFIG?.trim();
|
|
34520
35868
|
const explicit = explicitConfig ? [explicitConfig] : [];
|
|
34521
|
-
const
|
|
34522
|
-
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 ? [] : [
|
|
34523
35873
|
join17(directory, ".opencode", "opencode.json"),
|
|
34524
35874
|
join17(directory, ".opencode", "opencode.jsonc")
|
|
34525
35875
|
];
|
|
@@ -35749,6 +37099,24 @@ function readCachedPluginVersion(pluginCacheDir) {
|
|
|
35749
37099
|
return;
|
|
35750
37100
|
}
|
|
35751
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
|
+
}
|
|
35752
37120
|
async function clearPluginCache(options = {}, deps = {}) {
|
|
35753
37121
|
const remove = deps.remove ?? ((path) => rmSync6(path, { recursive: true, force: true }));
|
|
35754
37122
|
const pluginCacheRoots = getOpenCodePluginCacheRoots();
|
|
@@ -35761,6 +37129,15 @@ async function clearPluginCache(options = {}, deps = {}) {
|
|
|
35761
37129
|
path,
|
|
35762
37130
|
cached: readCachedPluginVersion(path)
|
|
35763
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
|
+
}
|
|
35764
37141
|
if (options.force !== true && latestVersion === undefined) {
|
|
35765
37142
|
const firstEntry = cacheEntries[0];
|
|
35766
37143
|
return {
|
|
@@ -35832,15 +37209,24 @@ async function clearPluginCache(options = {}, deps = {}) {
|
|
|
35832
37209
|
}
|
|
35833
37210
|
var init_doctor_opencode_cache = __esm(async () => {
|
|
35834
37211
|
init_opencode_plugin_cache();
|
|
35835
|
-
|
|
37212
|
+
init_opencode_plugin_registration();
|
|
37213
|
+
await __promiseAll([
|
|
37214
|
+
init_opencode(),
|
|
37215
|
+
init_doctor_opencode2_cache()
|
|
37216
|
+
]);
|
|
35836
37217
|
});
|
|
35837
37218
|
|
|
35838
37219
|
// src/commands/doctor-cached-plugin-fence.ts
|
|
35839
37220
|
import { existsSync as existsSync29 } from "node:fs";
|
|
35840
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
|
+
}
|
|
35841
37226
|
function listCachedOpenCodePluginFences(sources = {}) {
|
|
35842
37227
|
const fences = [];
|
|
35843
|
-
|
|
37228
|
+
const v1Referenced = isReferenced(sources, "opencode1", "latest");
|
|
37229
|
+
for (const root of v1Referenced ? sources.openCodeV1Roots ?? getOpenCodePluginCacheRoots() : []) {
|
|
35844
37230
|
const packageJson = getOpenCodePluginPackageJsonPath(root);
|
|
35845
37231
|
if (!existsSync29(packageJson))
|
|
35846
37232
|
continue;
|
|
@@ -35854,6 +37240,8 @@ function listCachedOpenCodePluginFences(sources = {}) {
|
|
|
35854
37240
|
for (const slot of listOpenCodeV2PluginCacheSlots(sources.openCodeV2NpmCacheDir)) {
|
|
35855
37241
|
if (!isOpenCodePluginDistTag(slot.spec))
|
|
35856
37242
|
continue;
|
|
37243
|
+
if (!isReferenced(sources, "opencode2", slot.spec))
|
|
37244
|
+
continue;
|
|
35857
37245
|
const generation = getOpenCodeV2ActiveGeneration(slot.slot);
|
|
35858
37246
|
if (!generation)
|
|
35859
37247
|
continue;
|
|
@@ -41042,11 +42430,6 @@ var init_user_facing_codes = __esm(() => {
|
|
|
41042
42430
|
sentence: "Magic Context has no context.db.",
|
|
41043
42431
|
action: "Run `npx @cortexkit/magic-context doctor store init`, then restart ck-mc."
|
|
41044
42432
|
},
|
|
41045
|
-
checkout_claim_held_elsewhere: {
|
|
41046
|
-
code: "MC-C16",
|
|
41047
|
-
sentence: "This request was not sent: this agent is checked out on another machine, so Magic Context will not work on its sessions here.",
|
|
41048
|
-
action: "Move the agent back to this machine, then send your message again."
|
|
41049
|
-
},
|
|
41050
42433
|
single_store_migration_required: {
|
|
41051
42434
|
code: "MC-C14",
|
|
41052
42435
|
sentence: "Magic Context's Rust mode needs a one-time migration of its store.",
|
|
@@ -42624,6 +44007,9 @@ function mergeRawConfigs(base, override) {
|
|
|
42624
44007
|
}
|
|
42625
44008
|
function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
42626
44009
|
const preMigrationWarnings = [];
|
|
44010
|
+
if (Object.hasOwn(rawConfig, "clear_reasoning_age")) {
|
|
44011
|
+
preMigrationWarnings.push("clear_reasoning_age is deprecated and ignored. Magic Context now keeps reasoning up to a token budget, keep_reasoning_tokens (default 10,000). Remove the key, or set keep_reasoning_tokens to a token count.");
|
|
44012
|
+
}
|
|
42627
44013
|
const configWithoutRemovedAgent = stripRemovedAgentConfig(rawConfig, preMigrationWarnings);
|
|
42628
44014
|
const hasDeprecatedProtectedTags = Object.hasOwn(rawConfig, "protected_tags");
|
|
42629
44015
|
if (hasDeprecatedProtectedTags) {
|
|
@@ -42634,7 +44020,9 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
42634
44020
|
delete configToMigrate.protected_tags;
|
|
42635
44021
|
}
|
|
42636
44022
|
const agentMigrated = migrateLegacyAgentEnabledInMemory(configToMigrate, preMigrationWarnings);
|
|
42637
|
-
const
|
|
44023
|
+
const migratedExperimental = migrateLegacyExperimental(agentMigrated, preMigrationWarnings);
|
|
44024
|
+
warnDeprecatedMuralModel(migratedExperimental, preMigrationWarnings);
|
|
44025
|
+
const migrated = migrateDreamerV2(migratedExperimental, preMigrationWarnings);
|
|
42638
44026
|
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
42639
44027
|
if (parsed.success) {
|
|
42640
44028
|
return { config: parsed.data, warnings: preMigrationWarnings };
|
|
@@ -43476,64 +44864,66 @@ async function runHealthChecks(options) {
|
|
|
43476
44864
|
add(results, "fail", "OMP binary not found on PATH or in standard user bin directories");
|
|
43477
44865
|
} else {
|
|
43478
44866
|
const version = options.deps.getOmpVersion(omp.path);
|
|
43479
|
-
if (!version)
|
|
43480
|
-
add(results, "fail", `OMP at ${omp.path} could not report its version`);
|
|
43481
|
-
else if (isOlderThan(version, MIN_OMP_VERSION)) {
|
|
43482
|
-
add(results, "fail", `OMP ${version} is older than tested minimum ${MIN_OMP_VERSION}`);
|
|
43483
|
-
} else
|
|
43484
|
-
add(results, "pass", `OMP ${version} detected at ${omp.path}`);
|
|
43485
44867
|
const plugins = options.deps.listOmpPlugins(omp.path);
|
|
43486
44868
|
if (!plugins) {
|
|
43487
44869
|
add(results, "fail", "`omp plugin list --json` failed or returned invalid JSON");
|
|
43488
44870
|
} else {
|
|
43489
44871
|
const plugin = plugins.find((entry) => entry.name === OMP_PLUGIN_PACKAGE);
|
|
43490
44872
|
if (!plugin) {
|
|
43491
|
-
add(results, "
|
|
43492
|
-
repairPlan.installPlugin = true;
|
|
43493
|
-
} else if (!plugin.enabled) {
|
|
43494
|
-
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)`);
|
|
43495
44874
|
repairPlan.installPlugin = true;
|
|
43496
44875
|
} else {
|
|
43497
|
-
|
|
43498
|
-
|
|
43499
|
-
if (
|
|
43500
|
-
add(results, "
|
|
43501
|
-
else
|
|
43502
|
-
add(results, "
|
|
43503
|
-
|
|
43504
|
-
add(results, "
|
|
43505
|
-
|
|
43506
|
-
|
|
43507
|
-
|
|
43508
|
-
|
|
43509
|
-
|
|
43510
|
-
|
|
43511
|
-
|
|
43512
|
-
|
|
43513
|
-
|
|
43514
|
-
|
|
43515
|
-
|
|
43516
|
-
|
|
43517
|
-
|
|
43518
|
-
|
|
43519
|
-
|
|
43520
|
-
|
|
43521
|
-
|
|
43522
|
-
|
|
43523
|
-
|
|
43524
|
-
|
|
43525
|
-
|
|
43526
|
-
|
|
43527
|
-
|
|
43528
|
-
|
|
43529
|
-
|
|
43530
|
-
|
|
43531
|
-
|
|
43532
|
-
|
|
43533
|
-
|
|
43534
|
-
|
|
43535
|
-
|
|
43536
|
-
|
|
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
|
+
}
|
|
43537
44927
|
}
|
|
43538
44928
|
}
|
|
43539
44929
|
}
|
|
@@ -46534,6 +47924,16 @@ function listDanglingCompartmentBoundaries(contextDb, openCodeDb, hostGeneration
|
|
|
46534
47924
|
ORDER BY c.session_id ASC, c.sequence ASC`).all();
|
|
46535
47925
|
const statement = openCodeDb.prepare(`SELECT 1 AS found FROM ${selection.table} WHERE session_id = ? AND id = ? LIMIT 1`);
|
|
46536
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
|
+
};
|
|
46537
47937
|
return rows.flatMap((row) => {
|
|
46538
47938
|
const missingStart = !exists(row.session_id, row.start_message_id);
|
|
46539
47939
|
const missingEnd = !exists(row.session_id, row.end_message_id);
|
|
@@ -46544,7 +47944,8 @@ function listDanglingCompartmentBoundaries(contextDb, openCodeDb, hostGeneration
|
|
|
46544
47944
|
sessionId: row.session_id,
|
|
46545
47945
|
sequence: row.sequence,
|
|
46546
47946
|
missingStartMessageId: missingStart ? row.start_message_id : null,
|
|
46547
|
-
missingEndMessageId: missingEnd ? row.end_message_id : null
|
|
47947
|
+
missingEndMessageId: missingEnd ? row.end_message_id : null,
|
|
47948
|
+
sessionInStore: sessionInStore(row.session_id)
|
|
46548
47949
|
}
|
|
46549
47950
|
];
|
|
46550
47951
|
});
|
|
@@ -46556,6 +47957,52 @@ function formatDanglingCompartmentBoundary(boundary) {
|
|
|
46556
47957
|
].filter((value) => value !== null);
|
|
46557
47958
|
return `session=${boundary.sessionId} sequence=${boundary.sequence} missing ${missing.join(" ")}`;
|
|
46558
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;
|
|
46559
48006
|
|
|
46560
48007
|
// src/commands/doctor-harness-relabel.ts
|
|
46561
48008
|
function reportUnresolvedHarnessRelabel(args) {
|
|
@@ -46709,6 +48156,9 @@ function withPluginEntrySpecifier(entry, specifier) {
|
|
|
46709
48156
|
}
|
|
46710
48157
|
return specifier;
|
|
46711
48158
|
}
|
|
48159
|
+
function isOpenCodePluginRegistered(config, configDir) {
|
|
48160
|
+
return readPluginEntries(config).some(({ entry }) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry, configDir));
|
|
48161
|
+
}
|
|
46712
48162
|
function checkOpenCodePluginEntry(config, configName, options, report) {
|
|
46713
48163
|
const allEntries = readPluginEntries(config);
|
|
46714
48164
|
const found = allEntries.find(({ entry }) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry, options.configDir));
|
|
@@ -46799,6 +48249,20 @@ function formatUnresolvedCompartmentSession(session) {
|
|
|
46799
48249
|
return `session=${session.sessionId} unresolved=${session.count}`;
|
|
46800
48250
|
}
|
|
46801
48251
|
|
|
48252
|
+
// src/commands/reasoning-config-migration.ts
|
|
48253
|
+
function removeDeprecatedReasoningAge(config) {
|
|
48254
|
+
if (!Object.hasOwn(config, "clear_reasoning_age"))
|
|
48255
|
+
return [];
|
|
48256
|
+
const age = config.clear_reasoning_age;
|
|
48257
|
+
delete config.clear_reasoning_age;
|
|
48258
|
+
const messages = [
|
|
48259
|
+
"Removed deprecated clear_reasoning_age (reasoning is now kept up to a token budget, keep_reasoning_tokens, default 10,000)."
|
|
48260
|
+
];
|
|
48261
|
+
if (typeof age === "number" && age < 50)
|
|
48262
|
+
messages.push("You had set a lower age to keep less reasoning; set keep_reasoning_tokens (for example 8000) to keep less than the default.");
|
|
48263
|
+
return messages;
|
|
48264
|
+
}
|
|
48265
|
+
|
|
46802
48266
|
// src/commands/doctor-opencode.ts
|
|
46803
48267
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
46804
48268
|
import { existsSync as existsSync45, mkdtempSync as mkdtempSync3, readFileSync as readFileSync28, rmSync as rmSync8 } from "node:fs";
|
|
@@ -47352,6 +48816,21 @@ function logOpenCodeInstallationTable(installations) {
|
|
|
47352
48816
|
function describeOpenCode2SessionAPIRequirement(hostVersion) {
|
|
47353
48817
|
return `OpenCode host ${hostVersion}; Magic Context requires OpenCode 2.0.22 or newer with session.remove and session.compact.`;
|
|
47354
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
|
+
}
|
|
47355
48834
|
async function runDoctor2(options = {}) {
|
|
47356
48835
|
migrateConfigLocationsForCli(process.cwd(), log3);
|
|
47357
48836
|
if (options.issue) {
|
|
@@ -47427,8 +48906,15 @@ async function runDoctor2(options = {}) {
|
|
|
47427
48906
|
pass(installationReports.length > 1 ? `OpenCode ${activeInstallation.version} installed (active install marked above)` : `OpenCode ${activeInstallation.version} installed`);
|
|
47428
48907
|
}
|
|
47429
48908
|
const hostGeneration = openCodeHostGenerationFromVersion(activeInstallation.version);
|
|
47430
|
-
|
|
47431
|
-
|
|
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 {}
|
|
47432
48918
|
}
|
|
47433
48919
|
const storeHostSelection = selectOpenCodeStoreHost(installationReports, openCodeHostGenerationFromVersion);
|
|
47434
48920
|
const storeHost = storeHostSelection?.host ?? activeInstallation;
|
|
@@ -47446,7 +48932,9 @@ async function runDoctor2(options = {}) {
|
|
|
47446
48932
|
const openCodeDbCheck = describeOpenCodeDatabaseDoctorCheck(openCodeDbResolution);
|
|
47447
48933
|
if (openCodeDbCheck.ok)
|
|
47448
48934
|
pass(openCodeDbCheck.message);
|
|
47449
|
-
else
|
|
48935
|
+
else if (magicContextStatusKnown && !magicContextInstalled) {
|
|
48936
|
+
log3.info("OpenCode session database not yet created (will be created on first OpenCode session)");
|
|
48937
|
+
} else
|
|
47450
48938
|
fail(openCodeDbCheck.message);
|
|
47451
48939
|
if (openCodeDbCheck.ok) {
|
|
47452
48940
|
let markerDb = null;
|
|
@@ -47467,7 +48955,7 @@ async function runDoctor2(options = {}) {
|
|
|
47467
48955
|
} else if (options.fix) {
|
|
47468
48956
|
warn(`${summary}; repaired=${report.repaired}, but some rows remain unconvertible`);
|
|
47469
48957
|
} else if (report.migrationCompleted) {
|
|
47470
|
-
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)`);
|
|
47471
48959
|
} else {
|
|
47472
48960
|
warn(`${summary}; run \`magic-context doctor --fix\` before upgrading OpenCode`);
|
|
47473
48961
|
}
|
|
@@ -47495,14 +48983,18 @@ async function runDoctor2(options = {}) {
|
|
|
47495
48983
|
if (dangling.length === 0) {
|
|
47496
48984
|
pass("Compartment boundary ids resolve in the OpenCode session store");
|
|
47497
48985
|
} else if (storeGeneration === "v2" && /\d/.test(storeHost.version)) {
|
|
47498
|
-
log3.info(
|
|
47499
|
-
for (const
|
|
47500
|
-
|
|
48986
|
+
log3.info(formatDanglingCompartmentBoundaryHeadline(dangling, "opencode2"));
|
|
48987
|
+
for (const line of formatDanglingCompartmentBoundaryDetails(dangling, {
|
|
48988
|
+
verbose: options.verbose
|
|
48989
|
+
})) {
|
|
48990
|
+
log3.info(` ${line}`);
|
|
47501
48991
|
}
|
|
47502
48992
|
} else {
|
|
47503
|
-
warn(
|
|
47504
|
-
for (const
|
|
47505
|
-
|
|
48993
|
+
warn(formatDanglingCompartmentBoundaryHeadline(dangling, "other"));
|
|
48994
|
+
for (const line of formatDanglingCompartmentBoundaryDetails(dangling, {
|
|
48995
|
+
verbose: options.verbose
|
|
48996
|
+
})) {
|
|
48997
|
+
log3.warn(` ${line}`);
|
|
47506
48998
|
}
|
|
47507
48999
|
}
|
|
47508
49000
|
if (!supportsCoordinateGenerationReporting(contextDb)) {
|
|
@@ -47538,10 +49030,7 @@ async function runDoctor2(options = {}) {
|
|
|
47538
49030
|
}
|
|
47539
49031
|
}
|
|
47540
49032
|
const selfVersion = getSelfVersion2();
|
|
47541
|
-
const
|
|
47542
|
-
fetchNpmLatest(CLI_PACKAGE_NAME),
|
|
47543
|
-
fetchNpmLatest(OPENCODE_PLUGIN_NAME)
|
|
47544
|
-
]);
|
|
49033
|
+
const npmLatest = await fetchNpmLatest(CLI_PACKAGE_NAME);
|
|
47545
49034
|
const cliComparison = npmLatest ? compareVersions(selfVersion, npmLatest) : null;
|
|
47546
49035
|
if (!npmLatest) {
|
|
47547
49036
|
log3.info(`Magic Context CLI v${selfVersion}; npm latest check unavailable`);
|
|
@@ -47552,9 +49041,8 @@ async function runDoctor2(options = {}) {
|
|
|
47552
49041
|
} else {
|
|
47553
49042
|
pass(`Magic Context CLI v${selfVersion} is current (npm latest v${npmLatest})`);
|
|
47554
49043
|
}
|
|
47555
|
-
const paths = detectConfigPaths();
|
|
47556
49044
|
if (paths.opencodeConfigFormat === "none") {
|
|
47557
|
-
|
|
49045
|
+
magicContextStatusKnown = true;
|
|
47558
49046
|
} else {
|
|
47559
49047
|
pass(`OpenCode config: ${paths.opencodeConfig}`);
|
|
47560
49048
|
}
|
|
@@ -47615,6 +49103,13 @@ async function runDoctor2(options = {}) {
|
|
|
47615
49103
|
log3.success("Removed deprecated compaction_markers (always-on since v0.21.4)");
|
|
47616
49104
|
fixed++;
|
|
47617
49105
|
}
|
|
49106
|
+
const reasoningMessages = removeDeprecatedReasoningAge(mcConfig);
|
|
49107
|
+
if (reasoningMessages.length > 0) {
|
|
49108
|
+
mcChanged = true;
|
|
49109
|
+
fixed++;
|
|
49110
|
+
for (const message of reasoningMessages)
|
|
49111
|
+
log3.success(message);
|
|
49112
|
+
}
|
|
47618
49113
|
for (const deadKey of ["auto_drop_tool_age", "drop_tool_structure"]) {
|
|
47619
49114
|
if (deadKey in mcConfig) {
|
|
47620
49115
|
delete mcConfig[deadKey];
|
|
@@ -47717,6 +49212,7 @@ async function runDoctor2(options = {}) {
|
|
|
47717
49212
|
log3.warn("Could not migrate deprecated config keys in magic-context.jsonc");
|
|
47718
49213
|
}
|
|
47719
49214
|
}
|
|
49215
|
+
const openCodeHostLabel = activeInstallation.kind === "desktop" ? "OpenCode Desktop" : activeInstallation.version === "unknown" ? "OpenCode" : `OpenCode ${activeInstallation.version}`;
|
|
47720
49216
|
const reportedAutoUpdateStalls = new Set;
|
|
47721
49217
|
const reportAutoUpdateStall = (specifier) => {
|
|
47722
49218
|
const message = describeAutoUpdateStall(specifier, autoUpdateEnabled);
|
|
@@ -47731,71 +49227,90 @@ async function runDoctor2(options = {}) {
|
|
|
47731
49227
|
const config = import_comment_json11.parse(raw);
|
|
47732
49228
|
const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
|
|
47733
49229
|
const configDir = dirname25(paths.opencodeConfig);
|
|
47734
|
-
|
|
47735
|
-
|
|
47736
|
-
|
|
47737
|
-
|
|
47738
|
-
|
|
47739
|
-
|
|
47740
|
-
|
|
47741
|
-
|
|
47742
|
-
|
|
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)}
|
|
47743
49242
|
`);
|
|
47744
|
-
|
|
47745
|
-
|
|
47746
|
-
|
|
47747
|
-
|
|
47748
|
-
|
|
47749
|
-
|
|
47750
|
-
|
|
47751
|
-
|
|
47752
|
-
|
|
47753
|
-
|
|
47754
|
-
|
|
47755
|
-
|
|
47756
|
-
|
|
47757
|
-
|
|
47758
|
-
|
|
47759
|
-
|
|
47760
|
-
|
|
47761
|
-
|
|
47762
|
-
|
|
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)}
|
|
47763
49262
|
`);
|
|
49263
|
+
}
|
|
47764
49264
|
}
|
|
47765
49265
|
} catch {
|
|
47766
49266
|
warn("Could not parse opencode config to verify plugin entry");
|
|
47767
49267
|
}
|
|
47768
|
-
}
|
|
47769
|
-
const cwd = process.cwd();
|
|
47770
|
-
const compactionEnabled = resolveCompactionEnabledForDoctor();
|
|
47771
|
-
const conflictResult = detectConflicts(cwd, { compactionEnabled });
|
|
47772
|
-
log3.info("Compaction check: file-based; the running server's resolved config may differ — `opencode debug config` is authoritative");
|
|
47773
|
-
if (conflictResult.hasConflict) {
|
|
47774
|
-
for (const reason of conflictResult.reasons) {
|
|
47775
|
-
fail(`Conflict: ${reason}`);
|
|
47776
|
-
}
|
|
47777
|
-
const actions = fixConflicts(cwd, conflictResult.conflicts, { compactionEnabled });
|
|
47778
|
-
for (const action of actions) {
|
|
47779
|
-
pass(`Fixed: ${action}`);
|
|
47780
|
-
fixed++;
|
|
47781
|
-
}
|
|
47782
|
-
if (actions.length > 0) {
|
|
47783
|
-
warn("Restart OpenCode for conflict fixes to take effect");
|
|
47784
|
-
}
|
|
47785
49268
|
} else {
|
|
47786
|
-
|
|
47787
|
-
|
|
47788
|
-
|
|
47789
|
-
|
|
47790
|
-
|
|
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");
|
|
47791
49298
|
}
|
|
47792
49299
|
} else {
|
|
47793
|
-
|
|
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
|
+
}
|
|
47794
49309
|
}
|
|
47795
49310
|
}
|
|
47796
|
-
if (hostGeneration === "v2") {
|
|
49311
|
+
if (magicContextInstalled && hostGeneration === "v2") {
|
|
47797
49312
|
pass("TUI sidebar loads from the plugin entry on OpenCode 2 (tui.json not used)");
|
|
47798
|
-
} else {
|
|
49313
|
+
} else if (magicContextInstalled) {
|
|
47799
49314
|
const tuiAdded = ensureTuiPluginEntry();
|
|
47800
49315
|
if (tuiAdded) {
|
|
47801
49316
|
pass("Added TUI sidebar plugin to tui.json");
|
|
@@ -47945,65 +49460,88 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
47945
49460
|
warn(`RPC discovery check unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
47946
49461
|
issues++;
|
|
47947
49462
|
}
|
|
47948
|
-
|
|
47949
|
-
|
|
47950
|
-
|
|
47951
|
-
|
|
47952
|
-
|
|
47953
|
-
|
|
47954
|
-
const versionInfo = cacheResult.cached ? ` (cached: ${cacheResult.cached}${cacheResult.latest ? `, latest: ${cacheResult.latest}` : ""})` : "";
|
|
47955
|
-
const reason = cacheResult.latest ? "outdated plugin cache" : "plugin cache (latest version check unavailable)";
|
|
47956
|
-
pass(`Cleared ${reason}${versionInfo} — latest will download on restart`);
|
|
47957
|
-
log3.info(` ${cacheResult.path}`);
|
|
47958
|
-
fixed++;
|
|
47959
|
-
} else if (cacheResult.action === "up_to_date") {
|
|
47960
|
-
pass(`Plugin cache up to date (v${cacheResult.cached})`);
|
|
47961
|
-
} else if (cacheResult.action === "check_unavailable") {
|
|
47962
|
-
warn(`Plugin cache version check unavailable; preserving cached plugin${cacheResult.cached ? ` (cached: ${cacheResult.cached})` : ""}. Use doctor --force to reinstall it.`);
|
|
47963
|
-
} else if (cacheResult.action === "in_use" || cacheResult.action === "in_use_unknown") {
|
|
47964
|
-
const versionInfo = cacheResult.cached ? ` (cached: ${cacheResult.cached}${cacheResult.latest ? `, latest: ${cacheResult.latest}` : ""})` : "";
|
|
47965
|
-
const why = cacheResult.action === "in_use" ? `OpenCode is running (pid ${cacheResult.pids?.join(", ")})` : cacheResult.reason ?? "could not tell whether OpenCode is running";
|
|
47966
|
-
warn(`Plugin cache${versionInfo} was not cleared: ${why}`);
|
|
47967
|
-
log3.info(" Quit OpenCode and rerun doctor to clear it.");
|
|
47968
|
-
for (const path of cacheResult.paths ?? [cacheResult.path])
|
|
47969
|
-
log3.info(` ${path}`);
|
|
47970
|
-
issues++;
|
|
47971
|
-
} else if (cacheResult.action === "error") {
|
|
47972
|
-
warn(`Could not clear plugin cache: ${cacheResult.error}`);
|
|
47973
|
-
if (cacheResult.clearedPaths && cacheResult.clearedPaths.length > 0) {
|
|
47974
|
-
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 {}
|
|
47975
49469
|
}
|
|
47976
|
-
|
|
47977
|
-
|
|
47978
|
-
|
|
47979
|
-
|
|
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) });
|
|
47980
49542
|
}
|
|
47981
|
-
issues++;
|
|
47982
|
-
} else if (hostGeneration !== "v2") {
|
|
47983
|
-
pass("Plugin cache clean (no cached version found)");
|
|
47984
|
-
}
|
|
47985
|
-
let v2DistTag;
|
|
47986
|
-
if (paths.opencodeConfigFormat !== "none") {
|
|
47987
|
-
try {
|
|
47988
|
-
v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8")));
|
|
47989
|
-
} catch {}
|
|
47990
|
-
}
|
|
47991
|
-
const v2Cache = reportOpenCodeV2PluginCache(checkOpenCodeV2PluginCache({
|
|
47992
|
-
fix: options.fix,
|
|
47993
|
-
force: options.force,
|
|
47994
|
-
latestVersion: v2DistTag ? await fetchNpmLatest(OPENCODE_PLUGIN_NAME, v2DistTag) : pluginNpmLatest,
|
|
47995
|
-
distTag: v2DistTag,
|
|
47996
|
-
hostFiles: openCodeHostDatabaseFiles([openCodeDbResolution.path])
|
|
47997
|
-
}), { pass, warn, info: (message) => log3.info(message) }, { reportMissing: hostGeneration === "v2" });
|
|
47998
|
-
if (v2Cache.fixed)
|
|
47999
|
-
fixed++;
|
|
48000
|
-
if (v2Cache.issue)
|
|
48001
|
-
issues++;
|
|
48002
|
-
const sharedDbVersion = readContextDbSchemaVersion(dbPath);
|
|
48003
|
-
if (sharedDbVersion !== null) {
|
|
48004
|
-
reportCachedPluginFences(compareCachedPluginFences(listCachedOpenCodePluginFences(), sharedDbVersion), { pass, fail, info: (message) => log3.info(message) });
|
|
48005
49543
|
}
|
|
48006
|
-
{
|
|
49544
|
+
if (magicContextInstalled) {
|
|
48007
49545
|
const ageWarnings = collectNpmReleaseAgeWarnings();
|
|
48008
49546
|
if (ageWarnings.length > 0) {
|
|
48009
49547
|
log3.warn("npm min-release-age restriction detected — this can prevent OpenCode from installing the latest plugin version");
|
|
@@ -48015,17 +49553,19 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
48015
49553
|
issues++;
|
|
48016
49554
|
}
|
|
48017
49555
|
}
|
|
48018
|
-
|
|
48019
|
-
|
|
48020
|
-
|
|
48021
|
-
|
|
48022
|
-
|
|
48023
|
-
|
|
48024
|
-
|
|
48025
|
-
|
|
48026
|
-
|
|
48027
|
-
|
|
48028
|
-
|
|
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
|
+
}
|
|
48029
49569
|
}
|
|
48030
49570
|
}
|
|
48031
49571
|
const diagnostics = await collectDiagnostics();
|
|
@@ -48206,13 +49746,12 @@ function resolveDreamerTaskModel(args) {
|
|
|
48206
49746
|
const taskQualifier = taskBlock?.[args.harness === "opencode" ? "variant" : "thinking_level"];
|
|
48207
49747
|
const harnessQualifier = harnessBlock[args.harness === "opencode" ? "variant" : "thinking_level"] ?? normalizeModelEntry(harnessBlock.model, args.harness)?.qualifier;
|
|
48208
49748
|
const taskHasModel = taskBlock !== undefined && hasOwn2(taskBlock, "model");
|
|
48209
|
-
const
|
|
48210
|
-
const primarySource = taskHasModel ? taskBlock?.model : usesMuralModel ? args.muralModel : harnessBlock.model;
|
|
49749
|
+
const primarySource = taskHasModel ? taskBlock?.model : harnessBlock.model;
|
|
48211
49750
|
const fallbackSource = taskBlock !== undefined && hasOwn2(taskBlock, "fallback_models") ? taskBlock.fallback_models : harnessBlock.fallback_models;
|
|
48212
49751
|
return {
|
|
48213
49752
|
primary: resolvePrimaryEntry({
|
|
48214
49753
|
entry: primarySource,
|
|
48215
|
-
defaultQualifier:
|
|
49754
|
+
defaultQualifier: taskQualifier ?? harnessQualifier,
|
|
48216
49755
|
harness: args.harness
|
|
48217
49756
|
}),
|
|
48218
49757
|
fallbacks: resolveFallbackEntries(fallbackSource, args.harness),
|
|
@@ -48223,13 +49762,12 @@ function resolveDreamerTaskModel(args) {
|
|
|
48223
49762
|
}
|
|
48224
49763
|
|
|
48225
49764
|
// ../plugin/src/features/magic-context/dreamer/task-config.ts
|
|
48226
|
-
function buildDreamTaskRuntimeConfigs(dreamer, harness, language,
|
|
48227
|
-
return
|
|
49765
|
+
function buildDreamTaskRuntimeConfigs(dreamer, harness, language, smartNotesEnabled = true) {
|
|
49766
|
+
return availableDreamTasks(smartNotesEnabled).map((task) => {
|
|
48228
49767
|
const resolved = resolveDreamerTaskModel({
|
|
48229
49768
|
config: { dreamer },
|
|
48230
49769
|
harness,
|
|
48231
|
-
task
|
|
48232
|
-
muralModel
|
|
49770
|
+
task
|
|
48233
49771
|
});
|
|
48234
49772
|
return {
|
|
48235
49773
|
task,
|
|
@@ -48337,7 +49875,7 @@ function runnablePiModelChains(config, harness) {
|
|
|
48337
49875
|
});
|
|
48338
49876
|
}
|
|
48339
49877
|
if (isDreamerRunnable(config)) {
|
|
48340
|
-
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)) {
|
|
48341
49879
|
if (task.schedule.trim() === "")
|
|
48342
49880
|
continue;
|
|
48343
49881
|
const chain = [task.model, ...task.fallbackModels ?? []].filter((entry) => entry !== undefined);
|
|
@@ -49126,26 +50664,14 @@ async function runHealthChecks2(options) {
|
|
|
49126
50664
|
const repairPlan = {
|
|
49127
50665
|
addPackageEntry: false,
|
|
49128
50666
|
writeUserConfig: false,
|
|
49129
|
-
clearCachePaths: []
|
|
50667
|
+
clearCachePaths: [],
|
|
50668
|
+
reasoningAgeConfigPaths: []
|
|
49130
50669
|
};
|
|
49131
50670
|
const self = options.deps.selfVersion();
|
|
49132
50671
|
const pi = options.deps.detectPiBinary();
|
|
49133
|
-
|
|
50672
|
+
const piVersion = pi ? options.deps.getPiVersion(pi.path) : null;
|
|
50673
|
+
if (!pi)
|
|
49134
50674
|
add2(results, "fail", "Pi binary not found on PATH or at ~/.pi/bin/pi");
|
|
49135
|
-
} else {
|
|
49136
|
-
const version = options.deps.getPiVersion(pi.path);
|
|
49137
|
-
if (version === null) {
|
|
49138
|
-
add2(results, "fail", `Pi CLI was found at ${pi.path} but could not be executed`);
|
|
49139
|
-
} else {
|
|
49140
|
-
add2(results, "pass", `Pi ${version} detected at ${pi.path}`);
|
|
49141
|
-
}
|
|
49142
|
-
const compare = compareSemver(version, MIN_PI_VERSION);
|
|
49143
|
-
if (compare !== null && compare < 0) {
|
|
49144
|
-
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\`).`);
|
|
49145
|
-
} else if (version) {
|
|
49146
|
-
add2(results, "pass", `Pi version meets minimum ${MIN_PI_VERSION} requirement`);
|
|
49147
|
-
}
|
|
49148
|
-
}
|
|
49149
50675
|
const latest = options.deps.getLatestNpmVersion();
|
|
49150
50676
|
const latestCompare = latest ? compareSemver(self, latest) : null;
|
|
49151
50677
|
if (latest && latestCompare === -1) {
|
|
@@ -49159,8 +50685,11 @@ async function runHealthChecks2(options) {
|
|
|
49159
50685
|
}
|
|
49160
50686
|
const settingsPath = getPiUserExtensionsPath();
|
|
49161
50687
|
let packages = [];
|
|
50688
|
+
let piPluginInstalled = false;
|
|
49162
50689
|
if (!existsSync47(settingsPath)) {
|
|
49163
|
-
|
|
50690
|
+
if (pi) {
|
|
50691
|
+
add2(results, "info", `${piVersion ? `Pi ${piVersion}` : "Pi"} found; Magic Context is not installed there (run setup to add it)`);
|
|
50692
|
+
}
|
|
49164
50693
|
repairPlan.addPackageEntry = true;
|
|
49165
50694
|
} else {
|
|
49166
50695
|
const parsed = readJsonc2(settingsPath);
|
|
@@ -49168,15 +50697,31 @@ async function runHealthChecks2(options) {
|
|
|
49168
50697
|
add2(results, "fail", `Could not parse Pi settings ${settingsPath}: ${parsed.error}`);
|
|
49169
50698
|
} else {
|
|
49170
50699
|
packages = packagesFrom(parsed.value);
|
|
49171
|
-
add2(results, "pass", `Pi settings found at ${settingsPath}`);
|
|
49172
50700
|
if (hasPiMagicContextPackage(packages)) {
|
|
50701
|
+
piPluginInstalled = true;
|
|
50702
|
+
add2(results, "pass", `Pi settings found at ${settingsPath}`);
|
|
49173
50703
|
add2(results, "pass", `${PI_PACKAGE_SOURCE} is registered in packages[]`);
|
|
49174
50704
|
} else {
|
|
49175
|
-
|
|
50705
|
+
if (pi) {
|
|
50706
|
+
add2(results, "info", `${piVersion ? `Pi ${piVersion}` : "Pi"} found; Magic Context is not installed there (run setup to add it)`);
|
|
50707
|
+
}
|
|
49176
50708
|
repairPlan.addPackageEntry = true;
|
|
49177
50709
|
}
|
|
49178
50710
|
}
|
|
49179
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
|
+
}
|
|
49180
50725
|
const userConfigPath = getPiUserConfigPath();
|
|
49181
50726
|
const projectPath = projectConfigPath(options.cwd);
|
|
49182
50727
|
for (const [label, path, required] of [
|
|
@@ -49197,6 +50742,10 @@ async function runHealthChecks2(options) {
|
|
|
49197
50742
|
continue;
|
|
49198
50743
|
}
|
|
49199
50744
|
const parsed = readMagicContextJsonc(path, label);
|
|
50745
|
+
if (!parsed.error && Object.hasOwn(parsed.value, "clear_reasoning_age")) {
|
|
50746
|
+
repairPlan.reasoningAgeConfigPaths.push(path);
|
|
50747
|
+
add2(results, "warn", `${label} clear_reasoning_age is deprecated and ignored; doctor removes it`);
|
|
50748
|
+
}
|
|
49200
50749
|
if (parsed.error)
|
|
49201
50750
|
add2(results, "fail", `${label} magic-context.jsonc is invalid JSONC: ${parsed.error}`);
|
|
49202
50751
|
else
|
|
@@ -49221,7 +50770,8 @@ async function runHealthChecks2(options) {
|
|
|
49221
50770
|
} else if (historianModel.startsWith("github-copilot/") && historianThinkingLevel) {
|
|
49222
50771
|
add2(results, "pass", `historian.model "${historianModel}" has thinking_level "${historianThinkingLevel}" configured`);
|
|
49223
50772
|
}
|
|
49224
|
-
|
|
50773
|
+
if (piPluginInstalled)
|
|
50774
|
+
checkPiModelChains(results, pi, loadedConfig.config, options.deps);
|
|
49225
50775
|
const storage = getMagicContextStorageResolution();
|
|
49226
50776
|
const storageDir = storage.path;
|
|
49227
50777
|
const dbPath = join41(storageDir, "context.db");
|
|
@@ -49344,7 +50894,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
49344
50894
|
}
|
|
49345
50895
|
} else if (loadedConfig.config.embedding.provider === "off") {
|
|
49346
50896
|
add2(results, "info", "Embedding provider disabled");
|
|
49347
|
-
} else {
|
|
50897
|
+
} else if (piPluginInstalled) {
|
|
49348
50898
|
let runtimeReported = false;
|
|
49349
50899
|
let firstFallback = null;
|
|
49350
50900
|
const brokenWarnings = [];
|
|
@@ -49383,38 +50933,40 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
49383
50933
|
}
|
|
49384
50934
|
}
|
|
49385
50935
|
}
|
|
49386
|
-
|
|
49387
|
-
|
|
49388
|
-
|
|
49389
|
-
|
|
49390
|
-
|
|
49391
|
-
|
|
49392
|
-
|
|
49393
|
-
|
|
49394
|
-
|
|
49395
|
-
|
|
49396
|
-
|
|
49397
|
-
|
|
49398
|
-
|
|
49399
|
-
|
|
49400
|
-
|
|
49401
|
-
|
|
49402
|
-
|
|
49403
|
-
|
|
49404
|
-
|
|
49405
|
-
|
|
49406
|
-
|
|
49407
|
-
|
|
49408
|
-
|
|
49409
|
-
|
|
49410
|
-
|
|
49411
|
-
|
|
49412
|
-
|
|
49413
|
-
|
|
49414
|
-
|
|
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>"}`);
|
|
49415
50969
|
}
|
|
49416
|
-
const lastLine = readLogLines(existingLogFiles).at(-1);
|
|
49417
|
-
add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
|
|
49418
50970
|
}
|
|
49419
50971
|
const diagnosticsForDumps = await collectDiagnostics2(options.cwd);
|
|
49420
50972
|
const dumpBuckets = diagnosticsForDumps.historianDumps.byProject;
|
|
@@ -49452,6 +51004,21 @@ function writeDefaultMagicContextConfig(path) {
|
|
|
49452
51004
|
}
|
|
49453
51005
|
function repair2(plan, prompts) {
|
|
49454
51006
|
let fixed = 0;
|
|
51007
|
+
for (const path of plan.reasoningAgeConfigPaths) {
|
|
51008
|
+
const content = readFileSync30(path, "utf8");
|
|
51009
|
+
const parsed = readJsonc2(path);
|
|
51010
|
+
if (parsed.error)
|
|
51011
|
+
continue;
|
|
51012
|
+
const messages = removeDeprecatedReasoningAge(parsed.value);
|
|
51013
|
+
if (messages.length === 0)
|
|
51014
|
+
continue;
|
|
51015
|
+
writeFileAtomic(path, removeJsoncValue(content, ["clear_reasoning_age"]), {
|
|
51016
|
+
ownerOnly: true
|
|
51017
|
+
});
|
|
51018
|
+
for (const message of messages)
|
|
51019
|
+
prompts.log.success(message);
|
|
51020
|
+
fixed++;
|
|
51021
|
+
}
|
|
49455
51022
|
if (plan.addPackageEntry) {
|
|
49456
51023
|
const settingsPath = getPiUserExtensionsPath();
|
|
49457
51024
|
try {
|
|
@@ -49678,6 +51245,7 @@ var init_doctor_pi = __esm(async () => {
|
|
|
49678
51245
|
init_tick_failure();
|
|
49679
51246
|
init_embedding_synapse();
|
|
49680
51247
|
init_data_path();
|
|
51248
|
+
init_jsonc_edit();
|
|
49681
51249
|
init_jsonc_parser();
|
|
49682
51250
|
init_config2();
|
|
49683
51251
|
init_model_chain_health();
|
|
@@ -49794,7 +51362,8 @@ async function dispatchDoctor(adapter, options) {
|
|
|
49794
51362
|
force: options.force,
|
|
49795
51363
|
fix: options.fix,
|
|
49796
51364
|
issue: options.issue,
|
|
49797
|
-
report: options.report
|
|
51365
|
+
report: options.report,
|
|
51366
|
+
verbose: options.verbose
|
|
49798
51367
|
});
|
|
49799
51368
|
}
|
|
49800
51369
|
case "pi": {
|
|
@@ -49958,6 +51527,7 @@ var DOCTOR_HELP = [
|
|
|
49958
51527
|
" --fix Repair safe, Magic Context-owned store rows and clear an outdated OpenCode 2 plugin cache",
|
|
49959
51528
|
" --force Force-clear the plugin cache",
|
|
49960
51529
|
" --clear Interactive cache cleanup picker",
|
|
51530
|
+
" --verbose Print long listings in full instead of a capped summary",
|
|
49961
51531
|
" --prune-discovery [--yes] List RPC discovery records that block offline maintenance, then remove them after confirmation",
|
|
49962
51532
|
" --issue Collect diagnostics and open a GitHub issue",
|
|
49963
51533
|
" --report <path> Write the issue diagnostics to <path> without prompting",
|
|
@@ -50216,6 +51786,7 @@ async function runCommand(command, rest) {
|
|
|
50216
51786
|
issue: rest.includes("--issue") || report !== null,
|
|
50217
51787
|
...report !== null ? { report } : {},
|
|
50218
51788
|
clear: rest.includes("--clear"),
|
|
51789
|
+
verbose: rest.includes("--verbose"),
|
|
50219
51790
|
checkV22Backfill: rest.includes("--check-v22-backfill"),
|
|
50220
51791
|
retryV22Backfill: rest.includes("--retry-v22-backfill"),
|
|
50221
51792
|
...rekeyV22DirIdentity !== null ? { rekeyV22DirIdentity } : {},
|