@cortexkit/magic-context 0.43.2 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1167 -695
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -13037,6 +13037,15 @@ function extraCliCandidates(d) {
|
|
|
13037
13037
|
join11(d.home, ".volta", "bin", "opencode")
|
|
13038
13038
|
];
|
|
13039
13039
|
}
|
|
13040
|
+
function openChamberCliCandidates(d) {
|
|
13041
|
+
if (d.platform !== "darwin")
|
|
13042
|
+
return [];
|
|
13043
|
+
const bundled = ["Contents", "Resources", "opencode-cli", "opencode"];
|
|
13044
|
+
return [
|
|
13045
|
+
join11("/Applications", "OpenChamber.app", ...bundled),
|
|
13046
|
+
join11(d.home, "Applications", "OpenChamber.app", ...bundled)
|
|
13047
|
+
];
|
|
13048
|
+
}
|
|
13040
13049
|
function canonicalPath(d, path) {
|
|
13041
13050
|
try {
|
|
13042
13051
|
return d.realpath ? d.realpath(path) : realpathSync(path);
|
|
@@ -13098,6 +13107,11 @@ function detectOpenCodeInstallations(deps) {
|
|
|
13098
13107
|
addCandidate(installations, seenRealpaths, d, candidate, "PATH", "cli");
|
|
13099
13108
|
}
|
|
13100
13109
|
}
|
|
13110
|
+
for (const candidate of openChamberCliCandidates(d)) {
|
|
13111
|
+
if (d.isExecutable(candidate)) {
|
|
13112
|
+
addCandidate(installations, seenRealpaths, d, candidate, "openchamber", "cli");
|
|
13113
|
+
}
|
|
13114
|
+
}
|
|
13101
13115
|
for (const appId of OPENCODE_DESKTOP_APP_IDS) {
|
|
13102
13116
|
const marker = join11(desktopUserDataDir(d, appId), OPENCODE_DESKTOP_SETTINGS_FILE);
|
|
13103
13117
|
if (d.exists(marker)) {
|
|
@@ -13171,6 +13185,17 @@ function describeOpenCodeInstallations(installations, deps = {}) {
|
|
|
13171
13185
|
active: index === 0
|
|
13172
13186
|
}));
|
|
13173
13187
|
}
|
|
13188
|
+
function selectOpenCodeStoreHost(reports, generationOf) {
|
|
13189
|
+
const active = reports[0];
|
|
13190
|
+
if (!active)
|
|
13191
|
+
return null;
|
|
13192
|
+
const hasVersion = (report) => /\d/.test(report.version);
|
|
13193
|
+
if (!hasVersion(active) || generationOf(active.version) === "v2") {
|
|
13194
|
+
return { host: active, shadowed: false };
|
|
13195
|
+
}
|
|
13196
|
+
const v2 = reports.find((report) => report.kind === "cli" && hasVersion(report) && generationOf(report.version) === "v2");
|
|
13197
|
+
return v2 ? { host: v2, shadowed: true } : { host: active, shadowed: false };
|
|
13198
|
+
}
|
|
13174
13199
|
function getAvailableModels2(binary) {
|
|
13175
13200
|
const output = runOpenCode(["models"], binary);
|
|
13176
13201
|
if (output === null)
|
|
@@ -15523,6 +15548,12 @@ var init_redaction = __esm(() => {
|
|
|
15523
15548
|
// ../plugin/src/shared/logger.ts
|
|
15524
15549
|
import * as fs from "node:fs";
|
|
15525
15550
|
import * as path2 from "node:path";
|
|
15551
|
+
function boundBuffer() {
|
|
15552
|
+
while (bufferedBytes > MAX_BUFFERED_BYTES && buffer.length > 0) {
|
|
15553
|
+
bufferedBytes -= Buffer.byteLength(buffer.shift() ?? "");
|
|
15554
|
+
droppedLines++;
|
|
15555
|
+
}
|
|
15556
|
+
}
|
|
15526
15557
|
function recordSwallowedWrite(error) {
|
|
15527
15558
|
try {
|
|
15528
15559
|
swallowedWriteCount++;
|
|
@@ -15605,12 +15636,12 @@ function flush() {
|
|
|
15605
15636
|
clearTimeout(flushTimer);
|
|
15606
15637
|
flushTimer = null;
|
|
15607
15638
|
}
|
|
15608
|
-
if (buffer.length === 0)
|
|
15639
|
+
if (buffer.length === 0 && droppedLines === 0)
|
|
15609
15640
|
return;
|
|
15610
|
-
const
|
|
15611
|
-
|
|
15641
|
+
const notice = droppedLines ? `[${new Date().toISOString()}] [magic-context][global] logger dropped ${droppedLines} ${droppedLines === 1 ? "line" : "lines"}: buffer exceeded ${MAX_BUFFERED_BYTES} bytes while writes were pending
|
|
15642
|
+
` : "";
|
|
15612
15643
|
try {
|
|
15613
|
-
const data = capLogData(
|
|
15644
|
+
const data = capLogData(notice + buffer.join(""));
|
|
15614
15645
|
const logFile = getMagicContextLogPath();
|
|
15615
15646
|
ensureDir4(logFile);
|
|
15616
15647
|
let currentSize = getCurrentLogSize(logFile);
|
|
@@ -15620,6 +15651,9 @@ function flush() {
|
|
|
15620
15651
|
currentSize = 0;
|
|
15621
15652
|
}
|
|
15622
15653
|
fs.appendFileSync(logFile, data, { encoding: "utf8", mode: 384 });
|
|
15654
|
+
buffer = [];
|
|
15655
|
+
bufferedBytes = 0;
|
|
15656
|
+
droppedLines = 0;
|
|
15623
15657
|
activeLogFile = logFile;
|
|
15624
15658
|
activeLogSize = currentSize + dataSize;
|
|
15625
15659
|
flushesSinceSizeCheck++;
|
|
@@ -15628,6 +15662,7 @@ function flush() {
|
|
|
15628
15662
|
activeLogSize = null;
|
|
15629
15663
|
flushesSinceSizeCheck = 0;
|
|
15630
15664
|
recordSwallowedWrite(error);
|
|
15665
|
+
boundBuffer();
|
|
15631
15666
|
}
|
|
15632
15667
|
}
|
|
15633
15668
|
function scheduleFlush() {
|
|
@@ -15645,8 +15680,11 @@ function log3(message, data) {
|
|
|
15645
15680
|
const timestamp = new Date().toISOString();
|
|
15646
15681
|
const serialized = data === undefined ? "" : data instanceof Error ? ` ${sanitizeDiagnosticText(`${data.message}${data.stack ? `
|
|
15647
15682
|
${data.stack}` : ""}`)}` : ` ${JSON.stringify(sanitizeConfigValue(data))}`;
|
|
15648
|
-
|
|
15649
|
-
|
|
15683
|
+
const line = `[${timestamp}] ${sanitizeDiagnosticText(message)}${serialized}
|
|
15684
|
+
`;
|
|
15685
|
+
buffer.push(line);
|
|
15686
|
+
bufferedBytes += Buffer.byteLength(line);
|
|
15687
|
+
boundBuffer();
|
|
15650
15688
|
if (buffer.length >= BUFFER_SIZE_LIMIT) {
|
|
15651
15689
|
flush();
|
|
15652
15690
|
} else {
|
|
@@ -15654,11 +15692,12 @@ ${data.stack}` : ""}`)}` : ` ${JSON.stringify(sanitizeConfigValue(data))}`;
|
|
|
15654
15692
|
}
|
|
15655
15693
|
} catch {}
|
|
15656
15694
|
}
|
|
15657
|
-
var isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50, MAX_LOG_FILE_BYTES, SIZE_CHECK_INTERVAL_FLUSHES = 64, activeLogFile = null, activeLogSize = null, flushesSinceSizeCheck = 0, swallowedWriteCount = 0, lastErrorMessage = null, lastErrorTime = null;
|
|
15695
|
+
var isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50, MAX_BUFFERED_BYTES, bufferedBytes = 0, droppedLines = 0, MAX_LOG_FILE_BYTES, SIZE_CHECK_INTERVAL_FLUSHES = 64, activeLogFile = null, activeLogSize = null, flushesSinceSizeCheck = 0, swallowedWriteCount = 0, lastErrorMessage = null, lastErrorTime = null;
|
|
15658
15696
|
var init_logger = __esm(() => {
|
|
15659
15697
|
init_data_path();
|
|
15660
15698
|
init_redaction();
|
|
15661
15699
|
buffer = [];
|
|
15700
|
+
MAX_BUFFERED_BYTES = 1024 * 1024;
|
|
15662
15701
|
MAX_LOG_FILE_BYTES = 32 * 1024 * 1024;
|
|
15663
15702
|
if (!isTestEnv) {
|
|
15664
15703
|
process.on("exit", flush);
|
|
@@ -21370,6 +21409,7 @@ var init_magic_context = __esm(() => {
|
|
|
21370
21409
|
maxTokens: true
|
|
21371
21410
|
});
|
|
21372
21411
|
DreamerConfigSchema = AgentMetadataSchema.extend({
|
|
21412
|
+
runner: _enum(["broca", "host"]).optional().describe(`Which side runs the dreamer completions the Rust module routes (classify-memories) in Rust transform mode: "host" runs them on this process's carrier, "broca" routes them to the Broca module. When unset, historian.runner applies, and when that is unset too the harness decides the same way it does for the historian. User-level config only.`),
|
|
21373
21413
|
opencode: DreamerOpenCodeHarnessBlockSchema.optional(),
|
|
21374
21414
|
pi: DreamerPiHarnessBlockSchema.optional(),
|
|
21375
21415
|
omp: DreamerOmpHarnessBlockSchema.optional(),
|
|
@@ -21380,12 +21420,16 @@ var init_magic_context = __esm(() => {
|
|
|
21380
21420
|
opencode: OpenCodeHarnessBlockSchema.optional(),
|
|
21381
21421
|
pi: PiHarnessBlockSchema.optional(),
|
|
21382
21422
|
omp: OmpHarnessBlockSchema.optional(),
|
|
21423
|
+
runner: _enum(["broca", "host"]).optional().describe('Which side runs the historian completion in Rust transform mode: "host" queues it for this process to run on the configured historian model, "broca" routes it to the Broca module. When unset the harness decides: OpenCode 1 and OpenCode 2 use "host", Claude Code (through the Thalamus gateway, which has no host to run a completion) uses "broca". User-level config only — it decides whose provider account pays for the call.'),
|
|
21424
|
+
host_runner: object({
|
|
21425
|
+
enabled: boolean2().optional().describe("Whether this process answers historian runs queued for a claimant (default true). Setting it to false stops the pull loop without changing historian.runner, so an operator can take one machine out of the lane and leave the queued runs for another claimant or for the runner setting to be changed deliberately.")
|
|
21426
|
+
}).optional().describe("Controls for this process's historian pull loop, which answers runs the Rust module queues for the host runner (`historian.runner: \"host\"`, or unset on OpenCode 1 and OpenCode 2). User-level config only — it decides whether this machine's provider account is spent on folds."),
|
|
21383
21427
|
two_pass: boolean2().default(false).describe("Run a second editor pass over historian output to clean low-signal U: lines and cross-compartment duplicates. Adds ~1 extra API call and ~1.3x cost per historian run. Useful for models without extended thinking support. (default: false)"),
|
|
21384
21428
|
disallowed_tools: array(_enum(["*", "read", "aft_outline", "aft_zoom", "aft_search"])).default([]).describe(`OpenCode only. Tools to REMOVE from the historian's default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])`)
|
|
21385
21429
|
}).optional();
|
|
21386
21430
|
EmbeddingFallbackProviderSchema = _enum(["local", "openai-compatible", "off"]);
|
|
21387
21431
|
BaseEmbeddingConfigSchema = object({
|
|
21388
|
-
provider: _enum(["local", "openai-compatible", "off", "synapse"]).default("local").describe("Embedding provider. 'local' uses Xenova/all-MiniLM-L6-v2, 'openai-compatible' requires endpoint and model, 'synapse' uses the certified local Synapse lane with an explicit fallback provider, and 'off' disables embeddings."),
|
|
21432
|
+
provider: _enum(["local", "openai-compatible", "off", "synapse"]).default("local").describe("Embedding provider. 'local' uses Xenova/all-MiniLM-L6-v2, 'openai-compatible' requires endpoint and model, 'synapse' uses the certified local Synapse lane with an explicit fallback provider, and 'off' disables embeddings. Session history is embedded for semantic ctx_search whenever the provider is not 'off', regardless of memory.enabled; memories are embedded only while memory.enabled is true."),
|
|
21389
21433
|
fallback_provider: EmbeddingFallbackProviderSchema.optional().describe("Fallback provider for the Synapse lane. Required when provider is 'synapse'; local, openai-compatible, and off are valid."),
|
|
21390
21434
|
model: string2().optional().describe("Embedding model name. Required for openai-compatible, ignored for local."),
|
|
21391
21435
|
endpoint: string2().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
|
|
@@ -21497,7 +21541,7 @@ var init_magic_context = __esm(() => {
|
|
|
21497
21541
|
smart_notes: object({
|
|
21498
21542
|
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.")
|
|
21499
21543
|
}).default({ retina_handoff: false }).describe("Smart-note ownership transition controls."),
|
|
21500
|
-
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,
|
|
21544
|
+
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). Explicit per-model entries win; otherwise GPT-5.6 and later (including gpt-6*, through any provider prefix) use a built-in 30m lifetime before the object default or 5m fallback. An unset or global "5m" opts into built-in defaults; any other global string is an explicit policy and wins. Policy is frozen per session, including across restarts; a model switch resolves against that frozen policy. /ctx-status shows the effective value and source. 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).`),
|
|
21501
21545
|
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."),
|
|
21502
21546
|
output_reserve: union([
|
|
21503
21547
|
number2().min(0),
|
|
@@ -21556,9 +21600,9 @@ var init_magic_context = __esm(() => {
|
|
|
21556
21600
|
enabled: boolean2().default(true).describe("When false, Magic Context stops managing the context window and keeps its knowledge layer: memory and docs/user-profile/key-files injection through additive m[0]/m[1], raw-message FTS indexing, dreamer, notes, ctx_search, ctx_expand, ctx_memory, and /ctx-embed remain available. MC's historian/compartment preparation, tagging, markers, pruning, folding, drops, strips, splicing, synthetic context-management todos, temporal markers, nudges, and fail-closed blocking stop; ctx_expand remains a knowledge-surface tool. fail_closed_blocking is inert: a transform failure passes the input messages through without blocking or cancelling. This setting does not enable native compaction: OpenCode's compaction.auto / compaction.prune or Pi's equivalent owns the window, or nothing does. MC's compaction.enabled in magic-context.jsonc is distinct from OpenCode's compaction.auto / compaction.prune in opencode.jsonc; they are different files and different owners. On the first turn after disabling, a long session may trigger one native compaction cycle; MC removes only its own marker boundary, leaves native boundaries and stored compartments intact, and does no pre-trimming mitigation. Marker cleanup is lazy per session, so an unresumed session is cleaned when it is next resumed. If compaction is enabled again, run /ctx-wrapup when the historian is runnable to catch up. OpenCode peer verification against v1.18.4 confirms native compaction covers child sessions: subagents receive additive memory/docs injection and no MC reclaim in this mode, so keep subagent tasks small or leave compaction.enabled on for long subagent runs. This is boot-resolved and requires a process restart; project-tier compaction.enabled is stripped so a cloned repository cannot disable the user's setting. The sidebar reports raw usage as Context: <pct>% · native compaction or Context: <pct>% · no active compaction and does not show an MC execute-threshold fill. /ctx-wrapup, /ctx-recomp, and /ctx-flush refuse without context-management side effects; /ctx-embed remains functional. Raw content hidden by a native boundary before Magic Context's first pass is not retroactively indexed.")
|
|
21557
21601
|
}).default({ enabled: true }).describe("Compaction-off mode gate. Default true (MC manages the context window as today). Set compaction.enabled=false to keep the knowledge layer while letting native compaction (or nothing) own the window. Boot-resolved; requires a restart to change."),
|
|
21558
21602
|
todowrite: object({
|
|
21559
|
-
enabled: boolean2().default(
|
|
21603
|
+
enabled: boolean2().default(false).describe("Pi only: off by default. Set todowrite.enabled=true to register Magic Context's todowrite task-list tool and /todos command. OpenCode ships its own built-in todowrite; this setting has no effect there."),
|
|
21560
21604
|
overlay: boolean2().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
|
|
21561
|
-
}).default({ enabled:
|
|
21605
|
+
}).default({ enabled: false, overlay: true }).describe("Pi-only todowrite tool and overlay controls. Pi registers tools and widgets at extension boot, so changing this after /cd requires /reload or restart."),
|
|
21562
21606
|
pi: PiConfigSchema.describe("Pi-only child-process extension controls. This setting is user-level only; project configuration cannot choose which extensions a user's subagent children load."),
|
|
21563
21607
|
smart_drops: boolean2().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 3), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
|
|
21564
21608
|
caveman_text_compression: object({
|
|
@@ -21566,7 +21610,7 @@ var init_magic_context = __esm(() => {
|
|
|
21566
21610
|
min_chars: number2().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
|
|
21567
21611
|
}).default({ enabled: false, min_chars: 500 }).describe("Age-tier caveman compression for long user/assistant text parts. Active for primary sessions when enabled; never for subagents. Oldest 20% of eligible tags (outside protected tail) go to ultra, next 20% to full, next 20% to lite, newest 40% untouched. Graduated from experimental.caveman_text_compression; opt-in, default off (lossy)."),
|
|
21568
21612
|
memory: object({
|
|
21569
|
-
enabled: boolean2().default(true).describe("Enable cross-session memory (default: true)"),
|
|
21613
|
+
enabled: boolean2().default(true).describe("Enable cross-session memory (default: true). Does not affect history embedding or semantic ctx_search over session history; set embedding.provider to 'off' to stop all embedding."),
|
|
21570
21614
|
injection_budget_tokens: number2().min(500).max(20000).default(4000).describe("Token budget for memory injection on session start (min: 500, max: 20000, default: 4000)"),
|
|
21571
21615
|
auto_promote: boolean2().default(true).describe("Automatically promote eligible session facts into memory (default: true)"),
|
|
21572
21616
|
retrieval_count_promotion_threshold: number2().min(1).default(3).describe("retrieval_count threshold for promoting memory to permanent status (min: 1, default: 3)"),
|
|
@@ -21607,10 +21651,12 @@ var init_magic_context = __esm(() => {
|
|
|
21607
21651
|
"historian.omp.fallback_models",
|
|
21608
21652
|
"historian.omp.thinking_level",
|
|
21609
21653
|
"historian.two_pass",
|
|
21654
|
+
"historian.maxTokens",
|
|
21610
21655
|
"historian_timeout_ms",
|
|
21611
21656
|
"commit_cluster_trigger.enabled",
|
|
21612
21657
|
"commit_cluster_trigger.min_clusters",
|
|
21613
21658
|
"memory.auto_promote",
|
|
21659
|
+
"dreamer.maxTokens",
|
|
21614
21660
|
"dreamer.opencode.model",
|
|
21615
21661
|
"dreamer.opencode.fallback_models",
|
|
21616
21662
|
"dreamer.opencode.variant",
|
|
@@ -22015,6 +22061,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
22015
22061
|
warnings.push(`Ignoring ${removed.map((path) => `historian.${path}`).join(", ")} from project config ` + "(security: historian model selection is user-level only; a repository cannot force extra compaction cost).");
|
|
22016
22062
|
}
|
|
22017
22063
|
}
|
|
22064
|
+
const dreamer = projectRaw.dreamer;
|
|
22065
|
+
if (isPlainObject3(dreamer) && "runner" in dreamer) {
|
|
22066
|
+
delete dreamer.runner;
|
|
22067
|
+
warnings.push("Ignoring dreamer.runner from project config (security: which process and provider account run dreamer completions is a user-level setting).");
|
|
22068
|
+
}
|
|
22018
22069
|
const mural = projectRaw.mural;
|
|
22019
22070
|
if (isPlainObject3(mural) && "model" in mural) {
|
|
22020
22071
|
delete mural.model;
|
|
@@ -22196,7 +22247,11 @@ var init_project_security = __esm(() => {
|
|
|
22196
22247
|
init_magic_context();
|
|
22197
22248
|
HIDDEN_AGENT_KEYS = ["historian", "dreamer"];
|
|
22198
22249
|
HARNESS_KEYS = PER_HARNESS_MODEL_KEYS;
|
|
22199
|
-
HISTORIAN_USER_ONLY_FIELDS =
|
|
22250
|
+
HISTORIAN_USER_ONLY_FIELDS = [
|
|
22251
|
+
...PER_HARNESS_MIGRATION_INVENTORY.historian.migrated_execution,
|
|
22252
|
+
"runner",
|
|
22253
|
+
"host_runner"
|
|
22254
|
+
];
|
|
22200
22255
|
PROMPT_SURFACE_USER_ONLY_FIELDS = ["guidance_override_path", "tool_descriptions"];
|
|
22201
22256
|
AGENT_ESCALATION_FIELDS = ["prompt", "permission", "tools"];
|
|
22202
22257
|
EMBEDDING_USER_ONLY_FIELDS = [
|
|
@@ -22511,6 +22566,25 @@ function redactConfigValue(value) {
|
|
|
22511
22566
|
function formatProtectedTokensBelowMinWarning(value) {
|
|
22512
22567
|
return `protected_tokens is a token floor (minimum ${PROTECTED_TOKENS_MIN}, default derived from the context window); ${value} looks like the old protected_tags count. Remove the key to use the default, or set a token count such as 16000.`;
|
|
22513
22568
|
}
|
|
22569
|
+
function misplacedAgentModelWarnings(rawConfig) {
|
|
22570
|
+
const warnings = [];
|
|
22571
|
+
for (const agent of ["historian", "dreamer"]) {
|
|
22572
|
+
const block = rawConfig[agent];
|
|
22573
|
+
if (!block || typeof block !== "object" || Array.isArray(block))
|
|
22574
|
+
continue;
|
|
22575
|
+
const record = block;
|
|
22576
|
+
if (!Object.hasOwn(record, "model"))
|
|
22577
|
+
continue;
|
|
22578
|
+
const harnessWithModel = MODEL_HARNESS_BLOCKS.find((harness) => {
|
|
22579
|
+
const sub = record[harness];
|
|
22580
|
+
return sub !== null && typeof sub === "object" && !Array.isArray(sub) && Object.hasOwn(sub, "model");
|
|
22581
|
+
});
|
|
22582
|
+
if (harnessWithModel)
|
|
22583
|
+
continue;
|
|
22584
|
+
warnings.push(`${agent}.model is not read: the ${agent} model is resolved per harness, so it has to be ${agent}.opencode.model (OpenCode 1 and 2), ${agent}.pi.model, or ${agent}.omp.model. As written the ${agent} resolves to no models and never runs.`);
|
|
22585
|
+
}
|
|
22586
|
+
return warnings;
|
|
22587
|
+
}
|
|
22514
22588
|
function warnProtectedTagsDeprecationOnce() {
|
|
22515
22589
|
if (!warnedProtectedTagsDeprecation) {
|
|
22516
22590
|
warnedProtectedTagsDeprecation = true;
|
|
@@ -22524,6 +22598,7 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
22524
22598
|
warnProtectedTagsDeprecationOnce();
|
|
22525
22599
|
preMigrationWarnings.push("protected_tags is deprecated and ignored; use protected_tokens instead.");
|
|
22526
22600
|
}
|
|
22601
|
+
preMigrationWarnings.push(...misplacedAgentModelWarnings(rawConfig));
|
|
22527
22602
|
const migratedExperimental = migrateLegacyExperimental(configWithoutRemovedAgent, preMigrationWarnings);
|
|
22528
22603
|
const migratedDreamer = migrateDreamerV2(migratedExperimental, preMigrationWarnings);
|
|
22529
22604
|
const migrated = migrateLegacyAgentEnabledInMemory(migratedDreamer, preMigrationWarnings);
|
|
@@ -22804,7 +22879,7 @@ function loadPluginConfigDetailed(directory, applyRuntimeGlobals = true) {
|
|
|
22804
22879
|
cacheTtlConfigured
|
|
22805
22880
|
};
|
|
22806
22881
|
}
|
|
22807
|
-
var warnedProtectedTagsDeprecation = false;
|
|
22882
|
+
var warnedProtectedTagsDeprecation = false, MODEL_HARNESS_BLOCKS;
|
|
22808
22883
|
var init_config = __esm(() => {
|
|
22809
22884
|
init_config_diagnostics();
|
|
22810
22885
|
init_jsonc_parser();
|
|
@@ -22819,6 +22894,7 @@ var init_config = __esm(() => {
|
|
|
22819
22894
|
init_removed_agent_config();
|
|
22820
22895
|
init_magic_context();
|
|
22821
22896
|
init_variable();
|
|
22897
|
+
MODEL_HARNESS_BLOCKS = ["opencode", "pi", "omp"];
|
|
22822
22898
|
});
|
|
22823
22899
|
|
|
22824
22900
|
// ../plugin/src/shared/opencode-config-dir.ts
|
|
@@ -26747,232 +26823,523 @@ function isRecord3(value) {
|
|
|
26747
26823
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26748
26824
|
}
|
|
26749
26825
|
|
|
26750
|
-
// ../plugin/src/
|
|
26751
|
-
|
|
26752
|
-
|
|
26753
|
-
function getDefaultSubcConnectionFile() {
|
|
26754
|
-
return join17(getDataDir(), "cortexkit", "run", "subc-connection.json");
|
|
26755
|
-
}
|
|
26756
|
-
function errorChainSome(error, predicate) {
|
|
26757
|
-
let current = error;
|
|
26758
|
-
const seen = new Set;
|
|
26759
|
-
while (isRecord3(current) && !seen.has(current)) {
|
|
26760
|
-
seen.add(current);
|
|
26761
|
-
if (predicate(current))
|
|
26762
|
-
return true;
|
|
26763
|
-
current = current.cause;
|
|
26764
|
-
}
|
|
26765
|
-
return false;
|
|
26766
|
-
}
|
|
26767
|
-
function isStaleOrDeadRouteFailure(error) {
|
|
26768
|
-
return errorChainSome(error, (current) => {
|
|
26769
|
-
const code = typeof current.code === "string" ? current.code : "";
|
|
26770
|
-
const name = typeof current.name === "string" ? current.name : "";
|
|
26771
|
-
const message = typeof current.message === "string" ? current.message : "";
|
|
26772
|
-
return [
|
|
26773
|
-
"stale_route_handle",
|
|
26774
|
-
"route_closed",
|
|
26775
|
-
"unknown_channel",
|
|
26776
|
-
"unrecognized_channel",
|
|
26777
|
-
"route_gone"
|
|
26778
|
-
].includes(code) || name === "StaleRouteHandleError" || /route handle \(\d+,\s*\d+\) is not live on the current connection/i.test(message) || /\b(?:unknown|unrecognized) channel\b/i.test(message);
|
|
26779
|
-
});
|
|
26780
|
-
}
|
|
26781
|
-
function isDeadlineFailure(error) {
|
|
26782
|
-
if (error instanceof SocketTimeoutError)
|
|
26783
|
-
return true;
|
|
26784
|
-
return errorChainSome(error, (current) => {
|
|
26785
|
-
const code = typeof current.code === "string" ? current.code : "";
|
|
26786
|
-
return ["ETIMEDOUT", "request_deadline", "deadline_exceeded_no_drop_observed"].includes(code);
|
|
26787
|
-
});
|
|
26788
|
-
}
|
|
26789
|
-
function isConnectionFailure(error) {
|
|
26790
|
-
if (error instanceof SocketClosedError || error instanceof SocketTimeoutError || error instanceof StaleRouteHandleError || isConsumerReconnectTransient(error) || isStaleOrDeadRouteFailure(error)) {
|
|
26791
|
-
return true;
|
|
26792
|
-
}
|
|
26793
|
-
return errorChainSome(error, (current) => {
|
|
26794
|
-
const code = typeof current.code === "string" ? current.code : "";
|
|
26795
|
-
const message = typeof current.message === "string" ? current.message : "";
|
|
26796
|
-
return [
|
|
26797
|
-
"ENOENT",
|
|
26798
|
-
"ECONNREFUSED",
|
|
26799
|
-
"ECONNRESET",
|
|
26800
|
-
"EPIPE",
|
|
26801
|
-
"ETIMEDOUT",
|
|
26802
|
-
"request_deadline",
|
|
26803
|
-
"deadline_exceeded_no_drop_observed",
|
|
26804
|
-
"connection_dropped",
|
|
26805
|
-
"SUBC_CONNECTION_BACKOFF"
|
|
26806
|
-
].includes(code) || /\bclient closed\b|\bconnection closed\b|\bclosed the connection\b/i.test(message);
|
|
26807
|
-
});
|
|
26808
|
-
}
|
|
26809
|
-
function routeOpenWithoutAmbientConsumerIdentity(client, target, identity, options = {}) {
|
|
26810
|
-
return client.routeOpen(target, identity, {
|
|
26811
|
-
...options,
|
|
26812
|
-
consumerIdentity: null
|
|
26813
|
-
});
|
|
26826
|
+
// ../plugin/src/shared/user-facing-codes.ts
|
|
26827
|
+
function userFacingFailureCode(key) {
|
|
26828
|
+
return USER_FACING_FAILURES[key].code;
|
|
26814
26829
|
}
|
|
26815
|
-
|
|
26816
|
-
|
|
26817
|
-
|
|
26818
|
-
|
|
26819
|
-
|
|
26820
|
-
|
|
26821
|
-
|
|
26822
|
-
|
|
26823
|
-
|
|
26824
|
-
|
|
26825
|
-
|
|
26826
|
-
|
|
26827
|
-
|
|
26828
|
-
|
|
26829
|
-
|
|
26830
|
-
|
|
26831
|
-
|
|
26832
|
-
|
|
26833
|
-
|
|
26834
|
-
|
|
26835
|
-
|
|
26836
|
-
|
|
26837
|
-
|
|
26838
|
-
|
|
26839
|
-
|
|
26840
|
-
|
|
26841
|
-
|
|
26842
|
-
|
|
26843
|
-
|
|
26844
|
-
|
|
26845
|
-
|
|
26846
|
-
|
|
26847
|
-
|
|
26848
|
-
|
|
26849
|
-
|
|
26850
|
-
|
|
26851
|
-
|
|
26852
|
-
|
|
26853
|
-
|
|
26854
|
-
|
|
26855
|
-
|
|
26856
|
-
|
|
26857
|
-
|
|
26858
|
-
|
|
26859
|
-
|
|
26860
|
-
|
|
26861
|
-
|
|
26862
|
-
|
|
26863
|
-
|
|
26864
|
-
|
|
26865
|
-
|
|
26866
|
-
|
|
26867
|
-
|
|
26868
|
-
|
|
26869
|
-
|
|
26870
|
-
|
|
26871
|
-
|
|
26872
|
-
|
|
26873
|
-
|
|
26874
|
-
|
|
26875
|
-
|
|
26876
|
-
|
|
26877
|
-
|
|
26878
|
-
|
|
26879
|
-
|
|
26880
|
-
|
|
26881
|
-
|
|
26882
|
-
|
|
26883
|
-
|
|
26884
|
-
|
|
26885
|
-
|
|
26886
|
-
|
|
26887
|
-
|
|
26888
|
-
|
|
26889
|
-
|
|
26890
|
-
|
|
26891
|
-
|
|
26892
|
-
|
|
26893
|
-
|
|
26894
|
-
|
|
26895
|
-
|
|
26896
|
-
|
|
26897
|
-
|
|
26898
|
-
|
|
26899
|
-
|
|
26900
|
-
|
|
26901
|
-
|
|
26902
|
-
|
|
26903
|
-
|
|
26904
|
-
|
|
26905
|
-
|
|
26906
|
-
|
|
26907
|
-
|
|
26908
|
-
|
|
26909
|
-
|
|
26910
|
-
|
|
26911
|
-
|
|
26912
|
-
|
|
26913
|
-
|
|
26914
|
-
|
|
26915
|
-
|
|
26916
|
-
|
|
26917
|
-
|
|
26918
|
-
|
|
26919
|
-
|
|
26920
|
-
|
|
26921
|
-
|
|
26922
|
-
|
|
26923
|
-
|
|
26924
|
-
|
|
26925
|
-
|
|
26926
|
-
|
|
26927
|
-
|
|
26928
|
-
|
|
26929
|
-
|
|
26930
|
-
|
|
26931
|
-
|
|
26932
|
-
|
|
26933
|
-
|
|
26934
|
-
|
|
26935
|
-
|
|
26936
|
-
|
|
26937
|
-
|
|
26938
|
-
|
|
26939
|
-
|
|
26940
|
-
|
|
26941
|
-
|
|
26942
|
-
|
|
26943
|
-
|
|
26944
|
-
|
|
26945
|
-
|
|
26946
|
-
|
|
26947
|
-
|
|
26948
|
-
|
|
26949
|
-
|
|
26950
|
-
|
|
26951
|
-
|
|
26952
|
-
|
|
26953
|
-
|
|
26954
|
-
|
|
26955
|
-
|
|
26956
|
-
|
|
26957
|
-
|
|
26958
|
-
|
|
26959
|
-
|
|
26960
|
-
|
|
26961
|
-
|
|
26962
|
-
|
|
26963
|
-
|
|
26964
|
-
|
|
26965
|
-
|
|
26966
|
-
|
|
26967
|
-
|
|
26968
|
-
|
|
26969
|
-
|
|
26970
|
-
|
|
26971
|
-
|
|
26972
|
-
|
|
26973
|
-
|
|
26974
|
-
|
|
26975
|
-
|
|
26830
|
+
var USER_FACING_FAILURES;
|
|
26831
|
+
var init_user_facing_codes = __esm(() => {
|
|
26832
|
+
USER_FACING_FAILURES = {
|
|
26833
|
+
historian_unavailable: {
|
|
26834
|
+
code: "MC-H01",
|
|
26835
|
+
sentence: "History compression could not finish this turn.",
|
|
26836
|
+
action: "It will retry automatically."
|
|
26837
|
+
},
|
|
26838
|
+
hidden_cleanup_unbound: {
|
|
26839
|
+
code: "MC-H02",
|
|
26840
|
+
sentence: "Some finished background sessions could not be removed from this host.",
|
|
26841
|
+
action: "They are removed automatically the next time Magic Context runs inside a registered OpenCode service."
|
|
26842
|
+
},
|
|
26843
|
+
historian_saved_history_misaligned: {
|
|
26844
|
+
code: "MC-H03",
|
|
26845
|
+
sentence: "History compression is paused because this session's saved summaries no longer line up with its messages.",
|
|
26846
|
+
action: "Run /ctx-recomp to rebuild them."
|
|
26847
|
+
},
|
|
26848
|
+
recomp_unavailable: {
|
|
26849
|
+
code: "MC-R01",
|
|
26850
|
+
sentence: "History compression could not be rebuilt.",
|
|
26851
|
+
action: "Run /ctx-recomp again."
|
|
26852
|
+
},
|
|
26853
|
+
dream_provider_timeout: {
|
|
26854
|
+
code: "MC-D01",
|
|
26855
|
+
sentence: "Memory maintenance took too long to respond.",
|
|
26856
|
+
action: "Run /ctx-dream again."
|
|
26857
|
+
},
|
|
26858
|
+
dream_provider_error: {
|
|
26859
|
+
code: "MC-D02",
|
|
26860
|
+
sentence: "Memory maintenance could not reach its model.",
|
|
26861
|
+
action: "Check the model connection, then run /ctx-dream again."
|
|
26862
|
+
},
|
|
26863
|
+
dream_step_limit: {
|
|
26864
|
+
code: "MC-D10",
|
|
26865
|
+
sentence: "Memory maintenance stopped at its hidden agent step limit.",
|
|
26866
|
+
action: "This task needs less work per run; changing the model connection will not help."
|
|
26867
|
+
},
|
|
26868
|
+
dream_empty_completion: {
|
|
26869
|
+
code: "MC-D03",
|
|
26870
|
+
sentence: "Memory maintenance received no usable response.",
|
|
26871
|
+
action: "Run /ctx-dream again."
|
|
26872
|
+
},
|
|
26873
|
+
dream_no_models: {
|
|
26874
|
+
code: "MC-D04",
|
|
26875
|
+
sentence: "Memory maintenance has no model available.",
|
|
26876
|
+
action: "Check the model settings, then run /ctx-dream again."
|
|
26877
|
+
},
|
|
26878
|
+
dream_child_aborted: {
|
|
26879
|
+
code: "MC-D05",
|
|
26880
|
+
sentence: "Memory maintenance was interrupted.",
|
|
26881
|
+
action: "Run /ctx-dream again."
|
|
26882
|
+
},
|
|
26883
|
+
dream_parse_failed: {
|
|
26884
|
+
code: "MC-D06",
|
|
26885
|
+
sentence: "Memory maintenance could not use the model response.",
|
|
26886
|
+
action: "Run /ctx-dream again."
|
|
26887
|
+
},
|
|
26888
|
+
dream_unknown: {
|
|
26889
|
+
code: "MC-D07",
|
|
26890
|
+
sentence: "Memory maintenance could not finish.",
|
|
26891
|
+
action: "Run /ctx-dream again."
|
|
26892
|
+
},
|
|
26893
|
+
dreamer_tick_blocked: {
|
|
26894
|
+
code: "MC-D09",
|
|
26895
|
+
sentence: "Background maintenance is not running: its last pass stopped before it reached the scheduled tasks.",
|
|
26896
|
+
action: "It is retried automatically; if it keeps happening, check the Magic Context log for the stage that stopped and run `npx @cortexkit/magic-context doctor`."
|
|
26897
|
+
},
|
|
26898
|
+
dream_task_needs_tool_loop: {
|
|
26899
|
+
code: "MC-D08",
|
|
26900
|
+
sentence: "Some memory maintenance tasks need a tool loop this host does not provide.",
|
|
26901
|
+
action: "The remaining tasks still run; the listed ones are skipped on this host."
|
|
26902
|
+
},
|
|
26903
|
+
embedding_substitution_rejected: {
|
|
26904
|
+
code: "MC-E01",
|
|
26905
|
+
sentence: "Search indexing could not use the selected model.",
|
|
26906
|
+
action: "Check the embedding model setting, then run /ctx-embed start again."
|
|
26907
|
+
},
|
|
26908
|
+
embedding_http_error: {
|
|
26909
|
+
code: "MC-E02",
|
|
26910
|
+
sentence: "The search indexing provider refused the request.",
|
|
26911
|
+
action: "Check the provider connection and credentials, then run /ctx-embed start again."
|
|
26912
|
+
},
|
|
26913
|
+
embedding_transport_error: {
|
|
26914
|
+
code: "MC-E03",
|
|
26915
|
+
sentence: "Search indexing could not reach its provider.",
|
|
26916
|
+
action: "Check the connection, then run /ctx-embed start again."
|
|
26917
|
+
},
|
|
26918
|
+
embedding_invalid_envelope: {
|
|
26919
|
+
code: "MC-E04",
|
|
26920
|
+
sentence: "Search indexing received an unsupported response.",
|
|
26921
|
+
action: "Check the embedding endpoint, then run /ctx-embed start again."
|
|
26922
|
+
},
|
|
26923
|
+
embedding_empty_result: {
|
|
26924
|
+
code: "MC-E05",
|
|
26925
|
+
sentence: "Search indexing received no usable result.",
|
|
26926
|
+
action: "Run /ctx-embed start again."
|
|
26927
|
+
},
|
|
26928
|
+
embedding_certification_refusal: {
|
|
26929
|
+
code: "MC-E06",
|
|
26930
|
+
sentence: "Search indexing is not ready for this provider.",
|
|
26931
|
+
action: "Finish the provider setup, or set a fallback provider in the embedding settings, then run /ctx-embed start again."
|
|
26932
|
+
},
|
|
26933
|
+
embedding_credential_required: {
|
|
26934
|
+
code: "MC-E07",
|
|
26935
|
+
sentence: "Search indexing needs provider credentials.",
|
|
26936
|
+
action: "Sign in to the provider, then run /ctx-embed start again."
|
|
26937
|
+
},
|
|
26938
|
+
embedding_local_binding_missing: {
|
|
26939
|
+
code: "MC-E08",
|
|
26940
|
+
sentence: "Local search indexing is unavailable on this system.",
|
|
26941
|
+
action: "Run `npx @cortexkit/magic-context doctor`, then retry."
|
|
26942
|
+
},
|
|
26943
|
+
embedding_local_fs_unavailable: {
|
|
26944
|
+
code: "MC-E09",
|
|
26945
|
+
sentence: "Local search indexing cannot save its model files.",
|
|
26946
|
+
action: "Update or reinstall Magic Context, then retry."
|
|
26947
|
+
},
|
|
26948
|
+
embedding_local_download_failure: {
|
|
26949
|
+
code: "MC-E10",
|
|
26950
|
+
sentence: "Local search indexing could not download its model.",
|
|
26951
|
+
action: "Check the network connection, then retry."
|
|
26952
|
+
},
|
|
26953
|
+
embedding_local_runtime_error: {
|
|
26954
|
+
code: "MC-E11",
|
|
26955
|
+
sentence: "Local search indexing could not start.",
|
|
26956
|
+
action: "Run `npx @cortexkit/magic-context doctor`, then retry."
|
|
26957
|
+
},
|
|
26958
|
+
embedding_unavailable: {
|
|
26959
|
+
code: "MC-E12",
|
|
26960
|
+
sentence: "Search indexing could not finish.",
|
|
26961
|
+
action: "Run /ctx-embed start again."
|
|
26962
|
+
},
|
|
26963
|
+
status_unavailable: {
|
|
26964
|
+
code: "MC-S01",
|
|
26965
|
+
sentence: "Magic Context status is temporarily unavailable.",
|
|
26966
|
+
action: "Retry /ctx-status in a moment."
|
|
26967
|
+
},
|
|
26968
|
+
transform_update_failed: {
|
|
26969
|
+
code: "MC-S02",
|
|
26970
|
+
sentence: "The last context update did not finish.",
|
|
26971
|
+
action: "Send another message to retry."
|
|
26972
|
+
},
|
|
26973
|
+
configuration_warning: {
|
|
26974
|
+
code: "MC-S03",
|
|
26975
|
+
sentence: "Some configuration settings could not be applied.",
|
|
26976
|
+
action: "Fix the configuration warning shown in /ctx-status, then restart."
|
|
26977
|
+
},
|
|
26978
|
+
status_log_unavailable: {
|
|
26979
|
+
code: "MC-S04",
|
|
26980
|
+
sentence: "Some diagnostic details could not be saved.",
|
|
26981
|
+
action: "Retry /ctx-status in a moment."
|
|
26982
|
+
},
|
|
26983
|
+
memory_writes_paused: {
|
|
26984
|
+
code: "MC-C01",
|
|
26985
|
+
sentence: "Memory writes are paused while the engine syncs.",
|
|
26986
|
+
action: "Retry in a moment."
|
|
26987
|
+
},
|
|
26988
|
+
memory_access_unavailable: {
|
|
26989
|
+
code: "MC-C02",
|
|
26990
|
+
sentence: "Memory access is temporarily unavailable.",
|
|
26991
|
+
action: "Retry in a moment."
|
|
26992
|
+
},
|
|
26993
|
+
note_changes_paused: {
|
|
26994
|
+
code: "MC-C03",
|
|
26995
|
+
sentence: "Note changes are paused while the engine syncs.",
|
|
26996
|
+
action: "Retry in a moment."
|
|
26997
|
+
},
|
|
26998
|
+
note_access_unavailable: {
|
|
26999
|
+
code: "MC-C04",
|
|
27000
|
+
sentence: "Notes are temporarily unavailable.",
|
|
27001
|
+
action: "Retry in a moment."
|
|
27002
|
+
},
|
|
27003
|
+
context_cleanup_paused: {
|
|
27004
|
+
code: "MC-C05",
|
|
27005
|
+
sentence: "Context cleanup is paused while the engine syncs.",
|
|
27006
|
+
action: "Retry in a moment."
|
|
27007
|
+
},
|
|
27008
|
+
partial_history_unavailable: {
|
|
27009
|
+
code: "MC-C06",
|
|
27010
|
+
sentence: "Partial history compression is not available in the current mode.",
|
|
27011
|
+
action: "Run /ctx-recomp without a range."
|
|
27012
|
+
},
|
|
27013
|
+
smart_note_conditions_unavailable: {
|
|
27014
|
+
code: "MC-C08",
|
|
27015
|
+
sentence: "Conditional notes are not available in the current mode.",
|
|
27016
|
+
action: "Save a regular note without a condition."
|
|
27017
|
+
},
|
|
27018
|
+
history_compression_paused: {
|
|
27019
|
+
code: "MC-C09",
|
|
27020
|
+
sentence: "History compression is paused while the engine syncs.",
|
|
27021
|
+
action: "Retry in a moment."
|
|
27022
|
+
},
|
|
27023
|
+
history_compression_needs_message: {
|
|
27024
|
+
code: "MC-C12",
|
|
27025
|
+
sentence: "History compression has not seen this session since Magic Context reconnected.",
|
|
27026
|
+
action: "Send a message in this session first, then run /ctx-wrapup again."
|
|
27027
|
+
},
|
|
27028
|
+
context_service_unavailable: {
|
|
27029
|
+
code: "MC-C10",
|
|
27030
|
+
sentence: "Magic Context is temporarily unavailable.",
|
|
27031
|
+
action: "Retry in a moment."
|
|
27032
|
+
},
|
|
27033
|
+
store_ahead_of_binary: {
|
|
27034
|
+
code: "MC-C13",
|
|
27035
|
+
sentence: "Magic Context refused to start: its store (store.db) was migrated by a newer ck-mc build than the one running.",
|
|
27036
|
+
action: "Update ck-mc, or roll back by restoring ck-mc together with context.db and store.db from the same backup."
|
|
27037
|
+
},
|
|
27038
|
+
compaction_marker_missing: {
|
|
27039
|
+
code: "MC-C11",
|
|
27040
|
+
sentence: "The history boundary marker is missing from the OpenCode store, so requests carry the full session.",
|
|
27041
|
+
action: "It is retried on every message; if this persists, run `/ctx-flush`."
|
|
27042
|
+
},
|
|
27043
|
+
memory_mirror_stalled: {
|
|
27044
|
+
code: "MC-M01",
|
|
27045
|
+
sentence: "Memory synchronization stopped before the host mirror caught up.",
|
|
27046
|
+
action: "Send another message to resume it, or run `ck doctor drain-authority`."
|
|
27047
|
+
},
|
|
27048
|
+
memory_authority_mismatch: {
|
|
27049
|
+
code: "MC-M02",
|
|
27050
|
+
sentence: "Memory authority is inconsistent between the host and module.",
|
|
27051
|
+
action: "Run `ck doctor drain-authority` before changing Rust mode."
|
|
27052
|
+
},
|
|
27053
|
+
dreamer_task_failing: {
|
|
27054
|
+
code: "MC-S05",
|
|
27055
|
+
sentence: "A background maintenance task keeps failing on its schedule.",
|
|
27056
|
+
action: "Check the Magic Context log for the failing task and its error."
|
|
27057
|
+
}
|
|
27058
|
+
};
|
|
27059
|
+
});
|
|
27060
|
+
|
|
27061
|
+
// ../plugin/src/hooks/magic-context/store-ahead-refusal.ts
|
|
27062
|
+
function renderStoreAheadOfBinaryRefusal(versions) {
|
|
27063
|
+
const failure = USER_FACING_FAILURES.store_ahead_of_binary;
|
|
27064
|
+
const sentence = versions ? `Magic Context refused to start: its store (store.db) is at schema v${versions.dbVersion} but this ck-mc build only knows up to v${versions.binaryMax}.` : failure.sentence;
|
|
27065
|
+
return `${sentence} ${failure.action} (${failure.code})`;
|
|
27066
|
+
}
|
|
27067
|
+
function isRecord4(value) {
|
|
27068
|
+
return value !== null && typeof value === "object";
|
|
27069
|
+
}
|
|
27070
|
+
function nonNegativeInteger(value) {
|
|
27071
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
27072
|
+
}
|
|
27073
|
+
function versionsFromDetail(detail) {
|
|
27074
|
+
if (!isRecord4(detail))
|
|
27075
|
+
return null;
|
|
27076
|
+
const dbVersion = nonNegativeInteger(detail.db_version);
|
|
27077
|
+
const binaryMax = nonNegativeInteger(detail.binary_max);
|
|
27078
|
+
return dbVersion !== null && binaryMax !== null ? { dbVersion, binaryMax } : null;
|
|
27079
|
+
}
|
|
27080
|
+
function versionsFromMessage(message) {
|
|
27081
|
+
if (typeof message !== "string")
|
|
27082
|
+
return null;
|
|
27083
|
+
const match = /db_version=(\d+) binary_max=(\d+)/.exec(message) ?? /schema v(\d+) but this ck-mc build only knows up to v(\d+)/.exec(message);
|
|
27084
|
+
if (!match)
|
|
27085
|
+
return null;
|
|
27086
|
+
return { dbVersion: Number(match[1]), binaryMax: Number(match[2]) };
|
|
27087
|
+
}
|
|
27088
|
+
function storeAheadOfBinaryFailure(error) {
|
|
27089
|
+
let current = error;
|
|
27090
|
+
const seen = new Set;
|
|
27091
|
+
while (isRecord4(current) && !seen.has(current)) {
|
|
27092
|
+
seen.add(current);
|
|
27093
|
+
if (current instanceof StoreAheadOfBinaryError)
|
|
27094
|
+
return current;
|
|
27095
|
+
if (current.code === STORE_AHEAD_OF_BINARY_CODE) {
|
|
27096
|
+
const versions = versionsFromDetail(current.detail) ?? versionsFromMessage(current.message);
|
|
27097
|
+
return new StoreAheadOfBinaryError(versions, { cause: error });
|
|
27098
|
+
}
|
|
27099
|
+
current = current.cause;
|
|
27100
|
+
}
|
|
27101
|
+
return null;
|
|
27102
|
+
}
|
|
27103
|
+
var STORE_AHEAD_OF_BINARY_CODE = "store_ahead_of_binary", StoreAheadOfBinaryError;
|
|
27104
|
+
var init_store_ahead_refusal = __esm(() => {
|
|
27105
|
+
init_user_facing_codes();
|
|
27106
|
+
StoreAheadOfBinaryError = class StoreAheadOfBinaryError extends Error {
|
|
27107
|
+
code = STORE_AHEAD_OF_BINARY_CODE;
|
|
27108
|
+
versions;
|
|
27109
|
+
constructor(versions, options) {
|
|
27110
|
+
super(renderStoreAheadOfBinaryRefusal(versions), options);
|
|
27111
|
+
this.name = "StoreAheadOfBinaryError";
|
|
27112
|
+
this.versions = versions;
|
|
27113
|
+
}
|
|
27114
|
+
};
|
|
27115
|
+
});
|
|
27116
|
+
|
|
27117
|
+
// ../plugin/src/hooks/magic-context/module-transport.ts
|
|
27118
|
+
import { realpathSync as realpathSync3 } from "node:fs";
|
|
27119
|
+
import { join as join17 } from "node:path";
|
|
27120
|
+
function getDefaultSubcConnectionFile() {
|
|
27121
|
+
return join17(getDataDir(), "cortexkit", "run", "subc-connection.json");
|
|
27122
|
+
}
|
|
27123
|
+
function errorChainSome(error, predicate) {
|
|
27124
|
+
let current = error;
|
|
27125
|
+
const seen = new Set;
|
|
27126
|
+
while (isRecord3(current) && !seen.has(current)) {
|
|
27127
|
+
seen.add(current);
|
|
27128
|
+
if (predicate(current))
|
|
27129
|
+
return true;
|
|
27130
|
+
current = current.cause;
|
|
27131
|
+
}
|
|
27132
|
+
return false;
|
|
27133
|
+
}
|
|
27134
|
+
function isStaleOrDeadRouteFailure(error) {
|
|
27135
|
+
return errorChainSome(error, (current) => {
|
|
27136
|
+
const code = typeof current.code === "string" ? current.code : "";
|
|
27137
|
+
const name = typeof current.name === "string" ? current.name : "";
|
|
27138
|
+
const message = typeof current.message === "string" ? current.message : "";
|
|
27139
|
+
return [
|
|
27140
|
+
"stale_route_handle",
|
|
27141
|
+
"route_closed",
|
|
27142
|
+
"unknown_channel",
|
|
27143
|
+
"unrecognized_channel",
|
|
27144
|
+
"route_gone"
|
|
27145
|
+
].includes(code) || name === "StaleRouteHandleError" || /route handle \(\d+,\s*\d+\) is not live on the current connection/i.test(message) || /\b(?:unknown|unrecognized) channel\b/i.test(message);
|
|
27146
|
+
});
|
|
27147
|
+
}
|
|
27148
|
+
function isDeadlineFailure(error) {
|
|
27149
|
+
if (error instanceof SocketTimeoutError)
|
|
27150
|
+
return true;
|
|
27151
|
+
return errorChainSome(error, (current) => {
|
|
27152
|
+
const code = typeof current.code === "string" ? current.code : "";
|
|
27153
|
+
return ["ETIMEDOUT", "request_deadline", "deadline_exceeded_no_drop_observed"].includes(code);
|
|
27154
|
+
});
|
|
27155
|
+
}
|
|
27156
|
+
function isConnectionFailure(error) {
|
|
27157
|
+
if (error instanceof SocketClosedError || error instanceof SocketTimeoutError || error instanceof StaleRouteHandleError || isConsumerReconnectTransient(error) || isStaleOrDeadRouteFailure(error)) {
|
|
27158
|
+
return true;
|
|
27159
|
+
}
|
|
27160
|
+
return errorChainSome(error, (current) => {
|
|
27161
|
+
const code = typeof current.code === "string" ? current.code : "";
|
|
27162
|
+
const message = typeof current.message === "string" ? current.message : "";
|
|
27163
|
+
return [
|
|
27164
|
+
"ENOENT",
|
|
27165
|
+
"ECONNREFUSED",
|
|
27166
|
+
"ECONNRESET",
|
|
27167
|
+
"EPIPE",
|
|
27168
|
+
"ETIMEDOUT",
|
|
27169
|
+
"request_deadline",
|
|
27170
|
+
"deadline_exceeded_no_drop_observed",
|
|
27171
|
+
"connection_dropped",
|
|
27172
|
+
"SUBC_CONNECTION_BACKOFF"
|
|
27173
|
+
].includes(code) || /\bclient closed\b|\bconnection closed\b|\bclosed the connection\b/i.test(message);
|
|
27174
|
+
});
|
|
27175
|
+
}
|
|
27176
|
+
function routeOpenWithoutAmbientConsumerIdentity(client, target, identity, options = {}) {
|
|
27177
|
+
return client.routeOpen(target, identity, {
|
|
27178
|
+
...options,
|
|
27179
|
+
consumerIdentity: null
|
|
27180
|
+
});
|
|
27181
|
+
}
|
|
27182
|
+
|
|
27183
|
+
class SubcModuleTransport {
|
|
27184
|
+
connectionFile;
|
|
27185
|
+
moduleId;
|
|
27186
|
+
requestTimeoutMs;
|
|
27187
|
+
routeSessionPrefix;
|
|
27188
|
+
client = null;
|
|
27189
|
+
routes = new Map;
|
|
27190
|
+
routeOpenings = new Map;
|
|
27191
|
+
canonicalRootCache = new Map;
|
|
27192
|
+
sessionLanes = new Map;
|
|
27193
|
+
queuedLaneWaiters = 0;
|
|
27194
|
+
wrapupSessions = new Map;
|
|
27195
|
+
nextProbeMs = 0;
|
|
27196
|
+
connectionPromise = null;
|
|
27197
|
+
authorityProjectRoot = "";
|
|
27198
|
+
authorityBindRoot = "";
|
|
27199
|
+
backoffMs = CONNECT_BACKOFF_INITIAL_MS;
|
|
27200
|
+
connectionGeneration = 0;
|
|
27201
|
+
stateSyncCapabilityCache = null;
|
|
27202
|
+
getCachedStateSyncCapabilities() {
|
|
27203
|
+
const cached = this.stateSyncCapabilityCache;
|
|
27204
|
+
if (!cached || cached.generation !== this.connectionGeneration)
|
|
27205
|
+
return;
|
|
27206
|
+
return cached.capabilities;
|
|
27207
|
+
}
|
|
27208
|
+
invalidateStateSyncCapabilities() {
|
|
27209
|
+
this.stateSyncCapabilityCache = null;
|
|
27210
|
+
}
|
|
27211
|
+
async stateSyncCapabilities(args) {
|
|
27212
|
+
const cached = this.getCachedStateSyncCapabilities();
|
|
27213
|
+
if (cached)
|
|
27214
|
+
return cached;
|
|
27215
|
+
const response = await this.call({
|
|
27216
|
+
sessionId: args.sessionId,
|
|
27217
|
+
projectRoot: args.projectRoot,
|
|
27218
|
+
method: "session.status",
|
|
27219
|
+
body: { method: "session.status", v: 1, session_id: args.sessionId }
|
|
27220
|
+
});
|
|
27221
|
+
const raw = isRecord3(response) ? response : {};
|
|
27222
|
+
const value = isRecord3(raw.result) ? raw.result : raw;
|
|
27223
|
+
const epochs = isRecord3(value.epochs) ? value.epochs : {};
|
|
27224
|
+
const capabilities = {
|
|
27225
|
+
state_sync_deltas: epochs.state_sync_deltas === true,
|
|
27226
|
+
...epochs.state_sync_resume === true ? { state_sync_resume: true } : {}
|
|
27227
|
+
};
|
|
27228
|
+
this.stateSyncCapabilityCache = { generation: this.connectionGeneration, capabilities };
|
|
27229
|
+
return capabilities;
|
|
27230
|
+
}
|
|
27231
|
+
constructor(connectionFile, moduleId = DEFAULT_MODULE_ID, requestTimeoutMs = MODULE_SEND_TIMEOUT_MS, routeSessionPrefix = "") {
|
|
27232
|
+
this.connectionFile = connectionFile;
|
|
27233
|
+
this.moduleId = moduleId;
|
|
27234
|
+
this.requestTimeoutMs = requestTimeoutMs;
|
|
27235
|
+
this.routeSessionPrefix = routeSessionPrefix;
|
|
27236
|
+
}
|
|
27237
|
+
deadlineError(detail) {
|
|
27238
|
+
const error = new Error(`module transport deadline expired ${detail}`);
|
|
27239
|
+
error.code = "ETIMEDOUT";
|
|
27240
|
+
return error;
|
|
27241
|
+
}
|
|
27242
|
+
laneTimeoutError() {
|
|
27243
|
+
return this.deadlineError("while queued");
|
|
27244
|
+
}
|
|
27245
|
+
connectionChangedError(detail) {
|
|
27246
|
+
const error = new Error(detail);
|
|
27247
|
+
error.code = "ECONNRESET";
|
|
27248
|
+
return error;
|
|
27249
|
+
}
|
|
27250
|
+
async beforeDeadline(operation, deadlineMs, detail) {
|
|
27251
|
+
operation.catch(() => {});
|
|
27252
|
+
const remainingMs = deadlineMs - Date.now();
|
|
27253
|
+
if (remainingMs <= 0)
|
|
27254
|
+
throw this.deadlineError(detail);
|
|
27255
|
+
let timer;
|
|
27256
|
+
try {
|
|
27257
|
+
return await Promise.race([
|
|
27258
|
+
operation,
|
|
27259
|
+
new Promise((_resolve, reject) => {
|
|
27260
|
+
timer = setTimeout(() => reject(this.deadlineError(detail)), remainingMs);
|
|
27261
|
+
})
|
|
27262
|
+
]);
|
|
27263
|
+
} finally {
|
|
27264
|
+
if (timer)
|
|
27265
|
+
clearTimeout(timer);
|
|
27266
|
+
}
|
|
27267
|
+
}
|
|
27268
|
+
cleanupLane(sessionId, lane) {
|
|
27269
|
+
if (!lane.active && lane.waiters.length === 0 && this.sessionLanes.get(sessionId) === lane) {
|
|
27270
|
+
this.sessionLanes.delete(sessionId);
|
|
27271
|
+
}
|
|
27272
|
+
}
|
|
27273
|
+
laneRelease(sessionId, lane) {
|
|
27274
|
+
let released = false;
|
|
27275
|
+
return () => {
|
|
27276
|
+
if (released)
|
|
27277
|
+
return;
|
|
27278
|
+
released = true;
|
|
27279
|
+
lane.active = false;
|
|
27280
|
+
this.dispatchNextLaneWaiter(sessionId, lane);
|
|
27281
|
+
};
|
|
27282
|
+
}
|
|
27283
|
+
dispatchNextLaneWaiter(sessionId, lane) {
|
|
27284
|
+
if (lane.active)
|
|
27285
|
+
return;
|
|
27286
|
+
while (lane.waiters.length > 0) {
|
|
27287
|
+
const waiter = lane.waiters.shift();
|
|
27288
|
+
if (!waiter)
|
|
27289
|
+
continue;
|
|
27290
|
+
this.queuedLaneWaiters = Math.max(0, this.queuedLaneWaiters - 1);
|
|
27291
|
+
if (waiter.settled)
|
|
27292
|
+
continue;
|
|
27293
|
+
waiter.settled = true;
|
|
27294
|
+
clearTimeout(waiter.timer);
|
|
27295
|
+
waiter.signal?.removeEventListener("abort", waiter.onAbort);
|
|
27296
|
+
if (waiter.signal?.aborted) {
|
|
27297
|
+
waiter.reject(waiter.signal.reason ?? new Error("module transport call aborted"));
|
|
27298
|
+
continue;
|
|
27299
|
+
}
|
|
27300
|
+
if (waiter.deadlineMs - Date.now() < SERIAL_LANE_MIN_REMAINING_MS) {
|
|
27301
|
+
waiter.reject(this.laneTimeoutError());
|
|
27302
|
+
continue;
|
|
27303
|
+
}
|
|
27304
|
+
lane.active = true;
|
|
27305
|
+
waiter.resolve(this.laneRelease(sessionId, lane));
|
|
27306
|
+
return;
|
|
27307
|
+
}
|
|
27308
|
+
this.cleanupLane(sessionId, lane);
|
|
27309
|
+
}
|
|
27310
|
+
queueFullError() {
|
|
27311
|
+
const error = new Error("module transport queue is full");
|
|
27312
|
+
error.code = "EBUSY";
|
|
27313
|
+
return error;
|
|
27314
|
+
}
|
|
27315
|
+
acquireCorrectnessLane(sessionId, signal, deadlineMs) {
|
|
27316
|
+
if (signal?.aborted) {
|
|
27317
|
+
return Promise.reject(signal.reason ?? new Error("module transport call aborted"));
|
|
27318
|
+
}
|
|
27319
|
+
if (deadlineMs - Date.now() < SERIAL_LANE_MIN_REMAINING_MS) {
|
|
27320
|
+
return Promise.reject(this.laneTimeoutError());
|
|
27321
|
+
}
|
|
27322
|
+
const lane = this.sessionLanes.get(sessionId) ?? { active: false, waiters: [] };
|
|
27323
|
+
this.sessionLanes.set(sessionId, lane);
|
|
27324
|
+
if (!lane.active && lane.waiters.length === 0) {
|
|
27325
|
+
lane.active = true;
|
|
27326
|
+
return Promise.resolve(this.laneRelease(sessionId, lane));
|
|
27327
|
+
}
|
|
27328
|
+
if (this.queuedLaneWaiters >= SERIAL_LANE_MAX_WAITERS || lane.waiters.length >= SERIAL_LANE_MAX_WAITERS_PER_SESSION) {
|
|
27329
|
+
return Promise.reject(this.queueFullError());
|
|
27330
|
+
}
|
|
27331
|
+
return new Promise((resolve, reject) => {
|
|
27332
|
+
const waiter = {};
|
|
27333
|
+
const removeAndReject = (error) => {
|
|
27334
|
+
if (waiter.settled)
|
|
27335
|
+
return;
|
|
27336
|
+
waiter.settled = true;
|
|
27337
|
+
clearTimeout(waiter.timer);
|
|
27338
|
+
signal?.removeEventListener("abort", waiter.onAbort);
|
|
27339
|
+
const index = lane.waiters.indexOf(waiter);
|
|
27340
|
+
if (index >= 0) {
|
|
27341
|
+
lane.waiters.splice(index, 1);
|
|
27342
|
+
this.queuedLaneWaiters = Math.max(0, this.queuedLaneWaiters - 1);
|
|
26976
27343
|
}
|
|
26977
27344
|
reject(error);
|
|
26978
27345
|
this.cleanupLane(sessionId, lane);
|
|
@@ -27017,7 +27384,8 @@ class SubcModuleTransport {
|
|
|
27017
27384
|
const laneDeadlineMs = Date.now() + attemptTimeoutMs;
|
|
27018
27385
|
let releaseLane = () => {};
|
|
27019
27386
|
try {
|
|
27020
|
-
|
|
27387
|
+
const outsideSessionOrder = args.method.startsWith("historian.");
|
|
27388
|
+
if (!args.bypassSessionLane && !outsideSessionOrder) {
|
|
27021
27389
|
releaseLane = await this.acquireCorrectnessLane(args.sessionId, args.signal, laneDeadlineMs);
|
|
27022
27390
|
}
|
|
27023
27391
|
} catch (error) {
|
|
@@ -27077,6 +27445,9 @@ class SubcModuleTransport {
|
|
|
27077
27445
|
} catch (error) {
|
|
27078
27446
|
if (args.signal?.aborted)
|
|
27079
27447
|
throw args.signal.reason ?? error;
|
|
27448
|
+
const storeAhead = storeAheadOfBinaryFailure(error);
|
|
27449
|
+
if (storeAhead)
|
|
27450
|
+
throw storeAhead;
|
|
27080
27451
|
if (args.method === "state_sync" && isDeadlineFailure(error)) {
|
|
27081
27452
|
const body = isRecord3(args.body) ? args.body : {};
|
|
27082
27453
|
throw Object.assign(new Error(`state_sync timeout stage=module_ack page=${body.seed_batch_index ?? 0}/${body.seed_batch_total ?? 1} series=${body.seed_id ?? "delta"} budget_ms=${attemptTimeoutMs}`), {
|
|
@@ -27390,6 +27761,7 @@ var DEFAULT_MODULE_ID = "magic-context", CONNECT_BACKOFF_INITIAL_MS = 1000, CONN
|
|
|
27390
27761
|
var init_module_transport = __esm(() => {
|
|
27391
27762
|
init_dist5();
|
|
27392
27763
|
init_data_path();
|
|
27764
|
+
init_store_ahead_refusal();
|
|
27393
27765
|
});
|
|
27394
27766
|
// ../plugin/src/shared/pi-executable.ts
|
|
27395
27767
|
function piHarnessKindFromExecutable(value) {
|
|
@@ -27406,6 +27778,9 @@ var init_pi_executable = __esm(() => {
|
|
|
27406
27778
|
// ../plugin/src/shared/rpc-utils.ts
|
|
27407
27779
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
27408
27780
|
import { readFileSync as readFileSync14 } from "node:fs";
|
|
27781
|
+
function isOwnRpcServerRecord(record) {
|
|
27782
|
+
return record.pid === process.pid && record.instance_id !== undefined && ownRpcServerInstanceIds.has(record.instance_id);
|
|
27783
|
+
}
|
|
27409
27784
|
function isPidAlive(pid) {
|
|
27410
27785
|
if (!Number.isInteger(pid) || pid <= 0)
|
|
27411
27786
|
return "dead";
|
|
@@ -27928,10 +28303,11 @@ function parseRpcPortFile(content, fallbackPid = 0) {
|
|
|
27928
28303
|
function isValidPort(port) {
|
|
27929
28304
|
return Number.isInteger(port) && port > 0 && port <= 65535;
|
|
27930
28305
|
}
|
|
27931
|
-
var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, WINDOWS_CIM_PROBE_TIMEOUT_MS = 5000, MAX_ANCESTOR_WALK_DEPTH = 16, OPEN_CODE_COMMAND_MARKERS, TASKLIST_NO_TASKS_PATTERN, WINDOWS_CIM_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress", PI_HARNESS_ARC_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityProcessKill, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now(), windowsProcessFactsCache = null;
|
|
28306
|
+
var ownRpcServerInstanceIds, RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, WINDOWS_CIM_PROBE_TIMEOUT_MS = 5000, MAX_ANCESTOR_WALK_DEPTH = 16, OPEN_CODE_COMMAND_MARKERS, TASKLIST_NO_TASKS_PATTERN, WINDOWS_CIM_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress", PI_HARNESS_ARC_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityProcessKill, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now(), windowsProcessFactsCache = null;
|
|
27932
28307
|
var init_rpc_utils = __esm(() => {
|
|
27933
28308
|
init_logger();
|
|
27934
28309
|
init_pi_executable();
|
|
28310
|
+
ownRpcServerInstanceIds = new Set;
|
|
27935
28311
|
OPEN_CODE_COMMAND_MARKERS = ["opencode", "node", "bun", "electron"];
|
|
27936
28312
|
TASKLIST_NO_TASKS_PATTERN = /^INFO:\s+No tasks are running which match the specified criteria\.?$/im;
|
|
27937
28313
|
PI_HARNESS_ARC_MARKERS = [
|
|
@@ -28061,7 +28437,9 @@ function formatFailClosedBlockingMessage(reason) {
|
|
|
28061
28437
|
}
|
|
28062
28438
|
return [
|
|
28063
28439
|
`Magic Context cannot migrate the shared database (one database serves every project on this machine) because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
|
|
28440
|
+
`The database is at upstream migration v${reason.persistedVersion}; this build needs v${reason.supportedVersion}.`,
|
|
28064
28441
|
"Restart the blocking process — even one from a different project — and it will pick up the new build and migrate on start; or shut it down and retry.",
|
|
28442
|
+
"If that host loads a pinned or cached older Magic Context build, a restart alone is not enough: stop it or update its Magic Context build, then start this host once so it migrates the database with nothing older attached.",
|
|
28065
28443
|
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
28066
28444
|
].join(" ");
|
|
28067
28445
|
}
|
|
@@ -28096,6 +28474,47 @@ var init_message_fts_rowid_map = __esm(() => {
|
|
|
28096
28474
|
activeBackfills = new WeakMap;
|
|
28097
28475
|
});
|
|
28098
28476
|
|
|
28477
|
+
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
28478
|
+
var V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
28479
|
+
var init_constants = __esm(() => {
|
|
28480
|
+
V2_MEMORY_CATEGORIES = [
|
|
28481
|
+
"PROJECT_RULES",
|
|
28482
|
+
"ARCHITECTURE",
|
|
28483
|
+
"CONSTRAINTS",
|
|
28484
|
+
"CONFIG_VALUES",
|
|
28485
|
+
"NAMING"
|
|
28486
|
+
];
|
|
28487
|
+
PROMOTABLE_CATEGORIES = [
|
|
28488
|
+
...V2_MEMORY_CATEGORIES,
|
|
28489
|
+
"ARCHITECTURE_DECISIONS",
|
|
28490
|
+
"CONFIG_DEFAULTS",
|
|
28491
|
+
"USER_PREFERENCES",
|
|
28492
|
+
"USER_DIRECTIVES",
|
|
28493
|
+
"ENVIRONMENT",
|
|
28494
|
+
"WORKFLOW_RULES",
|
|
28495
|
+
"KNOWN_ISSUES"
|
|
28496
|
+
];
|
|
28497
|
+
CATEGORY_PRIORITY = [
|
|
28498
|
+
...V2_MEMORY_CATEGORIES,
|
|
28499
|
+
"USER_DIRECTIVES",
|
|
28500
|
+
"USER_PREFERENCES",
|
|
28501
|
+
"CONFIG_DEFAULTS",
|
|
28502
|
+
"ARCHITECTURE_DECISIONS",
|
|
28503
|
+
"ENVIRONMENT",
|
|
28504
|
+
"WORKFLOW_RULES",
|
|
28505
|
+
"KNOWN_ISSUES"
|
|
28506
|
+
];
|
|
28507
|
+
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
28508
|
+
acc[category] = index;
|
|
28509
|
+
return acc;
|
|
28510
|
+
}, {});
|
|
28511
|
+
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
28512
|
+
CATEGORY_DEFAULT_TTL = {
|
|
28513
|
+
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
28514
|
+
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
28515
|
+
};
|
|
28516
|
+
});
|
|
28517
|
+
|
|
28099
28518
|
// ../plugin/src/hooks/magic-context/compartment-parser.ts
|
|
28100
28519
|
function makeTierOpenRegex(n) {
|
|
28101
28520
|
return new RegExp(`<p${n}\\s*(/?)>`);
|
|
@@ -28125,6 +28544,8 @@ function extractTiersFromInner(inner) {
|
|
|
28125
28544
|
function parseCompartmentOutput(text) {
|
|
28126
28545
|
const compartments = [];
|
|
28127
28546
|
const facts = [];
|
|
28547
|
+
let droppedFactBlocks = 0;
|
|
28548
|
+
let droppedFacts = 0;
|
|
28128
28549
|
for (const match of text.matchAll(COMPARTMENT_REGEX)) {
|
|
28129
28550
|
const attrs = match[1];
|
|
28130
28551
|
const inner = match[2];
|
|
@@ -28174,16 +28595,21 @@ function parseCompartmentOutput(text) {
|
|
|
28174
28595
|
}
|
|
28175
28596
|
}
|
|
28176
28597
|
const factsBlockMatch = text.match(FACTS_BLOCK_REGEX);
|
|
28177
|
-
const factsScope = factsBlockMatch ? factsBlockMatch[1] : text.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "");
|
|
28598
|
+
const factsScope = factsBlockMatch ? factsBlockMatch[1] : text.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "").replace(/<(meta|user_observations|primer_candidates)>.*?<\/\1>/gs, "").replace(/<\/?(?:output|compartments)>/g, "");
|
|
28178
28599
|
for (const categoryMatch of factsScope.matchAll(CATEGORY_BLOCK_REGEX)) {
|
|
28179
28600
|
const category = categoryMatch[1];
|
|
28180
28601
|
const blockContent = categoryMatch[2];
|
|
28181
|
-
|
|
28182
|
-
|
|
28183
|
-
if (
|
|
28184
|
-
|
|
28185
|
-
|
|
28602
|
+
const items = [...blockContent.matchAll(FACT_ITEM_REGEX)].map((match) => unescapeXml(match[1].trim())).filter(Boolean);
|
|
28603
|
+
if (!HISTORIAN_CATEGORIES.has(category)) {
|
|
28604
|
+
if (items.length === 0)
|
|
28605
|
+
continue;
|
|
28606
|
+
droppedFactBlocks++;
|
|
28607
|
+
droppedFacts += items.length;
|
|
28608
|
+
log3(`[historian] Dropped <facts> category ${category} (${items.length} facts)`);
|
|
28609
|
+
continue;
|
|
28186
28610
|
}
|
|
28611
|
+
for (const content of items)
|
|
28612
|
+
facts.push({ category, content });
|
|
28187
28613
|
}
|
|
28188
28614
|
const unprocessedMatch = text.match(UNPROCESSED_REGEX);
|
|
28189
28615
|
const unprocessedFrom = unprocessedMatch ? parseInt(unprocessedMatch[1], 10) : null;
|
|
@@ -28221,7 +28647,16 @@ function parseCompartmentOutput(text) {
|
|
|
28221
28647
|
}
|
|
28222
28648
|
const events = parseEvents(text);
|
|
28223
28649
|
compartments.sort((a, b) => a.startMessage - b.startMessage);
|
|
28224
|
-
return {
|
|
28650
|
+
return {
|
|
28651
|
+
compartments,
|
|
28652
|
+
facts,
|
|
28653
|
+
droppedFactBlocks,
|
|
28654
|
+
droppedFacts,
|
|
28655
|
+
events,
|
|
28656
|
+
unprocessedFrom,
|
|
28657
|
+
userObservations,
|
|
28658
|
+
primerCandidates
|
|
28659
|
+
};
|
|
28225
28660
|
}
|
|
28226
28661
|
function parseEvents(text) {
|
|
28227
28662
|
const blockMatch = text.match(EVENTS_BLOCK_REGEX);
|
|
@@ -28247,8 +28682,10 @@ function parseEvents(text) {
|
|
|
28247
28682
|
function unescapeXml(s) {
|
|
28248
28683
|
return s.replace(/&/g, "&").replace(/'/g, "'").replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">");
|
|
28249
28684
|
}
|
|
28250
|
-
var COMPARTMENT_REGEX, ATTR_START_REGEX, ATTR_END_REGEX, ATTR_TITLE_REGEX, ATTR_EPISODE_REGEX, ATTR_IMPORTANCE_REGEX, TIER_OPEN_REGEXES, TIER_CLOSE_ANY_REGEX, TIER_OPEN_ANY_REGEX, CATEGORY_BLOCK_REGEX, FACT_ITEM_REGEX, UNPROCESSED_REGEX, USER_OBSERVATIONS_REGEX, USER_OBS_ITEM_REGEX, PRIMER_CANDIDATES_REGEX, PRIMER_ELEMENT_REGEX, PRIMER_ITEM_REGEX, FACTS_BLOCK_REGEX, EVENTS_BLOCK_REGEX, EVENT_ELEMENT_REGEX, EVENT_FIELD_REGEX;
|
|
28685
|
+
var COMPARTMENT_REGEX, ATTR_START_REGEX, ATTR_END_REGEX, ATTR_TITLE_REGEX, ATTR_EPISODE_REGEX, ATTR_IMPORTANCE_REGEX, TIER_OPEN_REGEXES, TIER_CLOSE_ANY_REGEX, TIER_OPEN_ANY_REGEX, CATEGORY_BLOCK_REGEX, HISTORIAN_CATEGORIES, FACT_ITEM_REGEX, UNPROCESSED_REGEX, USER_OBSERVATIONS_REGEX, USER_OBS_ITEM_REGEX, PRIMER_CANDIDATES_REGEX, PRIMER_ELEMENT_REGEX, PRIMER_ITEM_REGEX, FACTS_BLOCK_REGEX, EVENTS_BLOCK_REGEX, EVENT_ELEMENT_REGEX, EVENT_FIELD_REGEX;
|
|
28251
28686
|
var init_compartment_parser = __esm(() => {
|
|
28687
|
+
init_constants();
|
|
28688
|
+
init_logger();
|
|
28252
28689
|
COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
|
|
28253
28690
|
ATTR_START_REGEX = /\bstart="(\d+)"/;
|
|
28254
28691
|
ATTR_END_REGEX = /\bend="(\d+)"/;
|
|
@@ -28263,7 +28700,8 @@ var init_compartment_parser = __esm(() => {
|
|
|
28263
28700
|
];
|
|
28264
28701
|
TIER_CLOSE_ANY_REGEX = /<\/p\d/;
|
|
28265
28702
|
TIER_OPEN_ANY_REGEX = /<p\d/;
|
|
28266
|
-
CATEGORY_BLOCK_REGEX = /<(
|
|
28703
|
+
CATEGORY_BLOCK_REGEX = /<([A-Za-z_][A-Za-z0-9_-]*)>(.*?)<\/\1>/gs;
|
|
28704
|
+
HISTORIAN_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
28267
28705
|
FACT_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
|
|
28268
28706
|
UNPROCESSED_REGEX = /<unprocessed_from>(\d+)<\/unprocessed_from>/;
|
|
28269
28707
|
USER_OBSERVATIONS_REGEX = /<user_observations>(.*?)<\/user_observations>/s;
|
|
@@ -28617,53 +29055,18 @@ function healAllNullColumns(db) {
|
|
|
28617
29055
|
const nullPredicate = presentFallbacks.map(([column]) => `${column} IS NULL`).join(" OR ");
|
|
28618
29056
|
db.prepare(`UPDATE session_meta SET ${assignments} WHERE ${nullPredicate}`).run(...presentFallbacks.map(([, fallback]) => fallback));
|
|
28619
29057
|
}
|
|
28620
|
-
healMissingMemoryBlockIds(db, existingColumns);
|
|
28621
|
-
}
|
|
28622
|
-
function getSessionMetaColumns(db) {
|
|
28623
|
-
const rows = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
28624
|
-
return new Set(rows.flatMap((row) => typeof row.name === "string" ? [row.name] : []));
|
|
28625
|
-
}
|
|
28626
|
-
function healMissingMemoryBlockIds(db, columns) {
|
|
28627
|
-
if (!columns.has("memory_block_cache") || !columns.has("memory_block_ids") || !columns.has("memory_block_count")) {
|
|
28628
|
-
return;
|
|
28629
|
-
}
|
|
28630
|
-
db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
|
|
28631
|
-
}
|
|
28632
|
-
|
|
28633
|
-
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
28634
|
-
var V2_MEMORY_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
28635
|
-
var init_constants = __esm(() => {
|
|
28636
|
-
V2_MEMORY_CATEGORIES = [
|
|
28637
|
-
"PROJECT_RULES",
|
|
28638
|
-
"ARCHITECTURE",
|
|
28639
|
-
"CONSTRAINTS",
|
|
28640
|
-
"CONFIG_VALUES",
|
|
28641
|
-
"NAMING"
|
|
28642
|
-
];
|
|
28643
|
-
CATEGORY_PRIORITY = [
|
|
28644
|
-
"PROJECT_RULES",
|
|
28645
|
-
"ARCHITECTURE",
|
|
28646
|
-
"CONSTRAINTS",
|
|
28647
|
-
"CONFIG_VALUES",
|
|
28648
|
-
"NAMING",
|
|
28649
|
-
"USER_DIRECTIVES",
|
|
28650
|
-
"USER_PREFERENCES",
|
|
28651
|
-
"CONFIG_DEFAULTS",
|
|
28652
|
-
"ARCHITECTURE_DECISIONS",
|
|
28653
|
-
"ENVIRONMENT",
|
|
28654
|
-
"WORKFLOW_RULES",
|
|
28655
|
-
"KNOWN_ISSUES"
|
|
28656
|
-
];
|
|
28657
|
-
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
28658
|
-
acc[category] = index;
|
|
28659
|
-
return acc;
|
|
28660
|
-
}, {});
|
|
28661
|
-
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
28662
|
-
CATEGORY_DEFAULT_TTL = {
|
|
28663
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
28664
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
28665
|
-
};
|
|
28666
|
-
});
|
|
29058
|
+
healMissingMemoryBlockIds(db, existingColumns);
|
|
29059
|
+
}
|
|
29060
|
+
function getSessionMetaColumns(db) {
|
|
29061
|
+
const rows = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
29062
|
+
return new Set(rows.flatMap((row) => typeof row.name === "string" ? [row.name] : []));
|
|
29063
|
+
}
|
|
29064
|
+
function healMissingMemoryBlockIds(db, columns) {
|
|
29065
|
+
if (!columns.has("memory_block_cache") || !columns.has("memory_block_ids") || !columns.has("memory_block_count")) {
|
|
29066
|
+
return;
|
|
29067
|
+
}
|
|
29068
|
+
db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
|
|
29069
|
+
}
|
|
28667
29070
|
|
|
28668
29071
|
// ../plugin/src/features/magic-context/project-identity.ts
|
|
28669
29072
|
var init_project_identity2 = __esm(() => {
|
|
@@ -31144,6 +31547,20 @@ var init_migrations = __esm(async () => {
|
|
|
31144
31547
|
return;
|
|
31145
31548
|
ensureColumn(db, "compartment_state_lease", "owner_pid", "INTEGER");
|
|
31146
31549
|
}
|
|
31550
|
+
},
|
|
31551
|
+
{
|
|
31552
|
+
version: 91,
|
|
31553
|
+
description: "per-project embedding high-water mark for memories written outside this host",
|
|
31554
|
+
up(db) {
|
|
31555
|
+
db.exec(`
|
|
31556
|
+
CREATE TABLE IF NOT EXISTS memory_embedding_watermarks (
|
|
31557
|
+
project_path TEXT PRIMARY KEY,
|
|
31558
|
+
written_memory_id INTEGER NOT NULL DEFAULT 0,
|
|
31559
|
+
embedded_memory_id INTEGER NOT NULL DEFAULT 0,
|
|
31560
|
+
updated_at INTEGER NOT NULL DEFAULT 0
|
|
31561
|
+
);
|
|
31562
|
+
`);
|
|
31563
|
+
}
|
|
31147
31564
|
}
|
|
31148
31565
|
];
|
|
31149
31566
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -31375,6 +31792,8 @@ function inspectRpcServerDiscovery(storageDir) {
|
|
|
31375
31792
|
return junk;
|
|
31376
31793
|
continue;
|
|
31377
31794
|
}
|
|
31795
|
+
if (isOwnRpcServerRecord(record))
|
|
31796
|
+
continue;
|
|
31378
31797
|
const liveness = isPidAlive(record.pid);
|
|
31379
31798
|
if (liveness === "dead") {
|
|
31380
31799
|
staleFiles.push(portFile);
|
|
@@ -31996,6 +32415,15 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
31996
32415
|
(id, cursor_session_id, cursor_ordinal, completed, updated_at)
|
|
31997
32416
|
VALUES (1, '', 0, 0, 0);
|
|
31998
32417
|
|
|
32418
|
+
-- Highest memory id another writer (the Rust module in single-store mode) put
|
|
32419
|
+
-- into memories for a project, and how far this host has embedded. Migration v91.
|
|
32420
|
+
CREATE TABLE IF NOT EXISTS memory_embedding_watermarks (
|
|
32421
|
+
project_path TEXT PRIMARY KEY,
|
|
32422
|
+
written_memory_id INTEGER NOT NULL DEFAULT 0,
|
|
32423
|
+
embedded_memory_id INTEGER NOT NULL DEFAULT 0,
|
|
32424
|
+
updated_at INTEGER NOT NULL DEFAULT 0
|
|
32425
|
+
);
|
|
32426
|
+
|
|
31999
32427
|
CREATE TABLE IF NOT EXISTS message_history_index (
|
|
32000
32428
|
session_id TEXT PRIMARY KEY,
|
|
32001
32429
|
last_indexed_ordinal INTEGER NOT NULL DEFAULT 0,
|
|
@@ -32655,7 +33083,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
32655
33083
|
`);
|
|
32656
33084
|
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
32657
33085
|
}
|
|
32658
|
-
var databases, pendingAsyncOpens, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, LATEST_SUPPORTED_VERSION =
|
|
33086
|
+
var databases, pendingAsyncOpens, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, LATEST_SUPPORTED_VERSION = 91, BOOT_SQLITE_BUSY_TIMEOUT_MS = 5000, PERMISSIONS_ENFORCEABLE, RPC_DISCOVERY_PARSE_GRACE_MS, defaultRpcDiscoveryFs, rpcDiscoveryFs, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS;
|
|
32659
33087
|
var init_storage_db = __esm(async () => {
|
|
32660
33088
|
init_data_path();
|
|
32661
33089
|
init_logger();
|
|
@@ -35440,7 +35868,7 @@ async function doctorRetryV22Backfill(db) {
|
|
|
35440
35868
|
bumpProjectMemoryEpochInTransaction(db, identity, now);
|
|
35441
35869
|
succeeded += 1;
|
|
35442
35870
|
}
|
|
35443
|
-
})();
|
|
35871
|
+
}).immediate();
|
|
35444
35872
|
} catch (error) {
|
|
35445
35873
|
const classified = classifyBackfillError(error);
|
|
35446
35874
|
db.prepare(`UPDATE v22_backfill_failures
|
|
@@ -35473,7 +35901,7 @@ async function doctorRekeyV22DirIdentity(db, rawProjectPath) {
|
|
|
35473
35901
|
if (changedRows > 0) {
|
|
35474
35902
|
bumpProjectMemoryEpochInTransaction(db, newIdentity, now);
|
|
35475
35903
|
}
|
|
35476
|
-
})();
|
|
35904
|
+
}).immediate();
|
|
35477
35905
|
return { oldIdentity, newIdentity, changedRows };
|
|
35478
35906
|
}
|
|
35479
35907
|
var BACKFILL_META_KEY = "v22_legacy_memory_backfill", BACKFILL_CURSOR_META_KEY = "v22_legacy_memory_backfill_cursor", MEMORIES_TABLE = "memories";
|
|
@@ -35546,236 +35974,6 @@ var init_v22_backfill_commands = __esm(async () => {
|
|
|
35546
35974
|
await init_storage_db();
|
|
35547
35975
|
});
|
|
35548
35976
|
|
|
35549
|
-
// ../plugin/src/shared/user-facing-codes.ts
|
|
35550
|
-
function userFacingFailureCode(key) {
|
|
35551
|
-
return USER_FACING_FAILURES[key].code;
|
|
35552
|
-
}
|
|
35553
|
-
var USER_FACING_FAILURES;
|
|
35554
|
-
var init_user_facing_codes = __esm(() => {
|
|
35555
|
-
USER_FACING_FAILURES = {
|
|
35556
|
-
historian_unavailable: {
|
|
35557
|
-
code: "MC-H01",
|
|
35558
|
-
sentence: "History compression could not finish this turn.",
|
|
35559
|
-
action: "It will retry automatically."
|
|
35560
|
-
},
|
|
35561
|
-
hidden_cleanup_unbound: {
|
|
35562
|
-
code: "MC-H02",
|
|
35563
|
-
sentence: "Some finished background sessions could not be removed from this host.",
|
|
35564
|
-
action: "They are removed automatically the next time Magic Context runs inside a registered OpenCode service."
|
|
35565
|
-
},
|
|
35566
|
-
historian_saved_history_misaligned: {
|
|
35567
|
-
code: "MC-H03",
|
|
35568
|
-
sentence: "History compression is paused because this session's saved summaries no longer line up with its messages.",
|
|
35569
|
-
action: "Run /ctx-recomp to rebuild them."
|
|
35570
|
-
},
|
|
35571
|
-
recomp_unavailable: {
|
|
35572
|
-
code: "MC-R01",
|
|
35573
|
-
sentence: "History compression could not be rebuilt.",
|
|
35574
|
-
action: "Run /ctx-recomp again."
|
|
35575
|
-
},
|
|
35576
|
-
dream_provider_timeout: {
|
|
35577
|
-
code: "MC-D01",
|
|
35578
|
-
sentence: "Memory maintenance took too long to respond.",
|
|
35579
|
-
action: "Run /ctx-dream again."
|
|
35580
|
-
},
|
|
35581
|
-
dream_provider_error: {
|
|
35582
|
-
code: "MC-D02",
|
|
35583
|
-
sentence: "Memory maintenance could not reach its model.",
|
|
35584
|
-
action: "Check the model connection, then run /ctx-dream again."
|
|
35585
|
-
},
|
|
35586
|
-
dream_empty_completion: {
|
|
35587
|
-
code: "MC-D03",
|
|
35588
|
-
sentence: "Memory maintenance received no usable response.",
|
|
35589
|
-
action: "Run /ctx-dream again."
|
|
35590
|
-
},
|
|
35591
|
-
dream_no_models: {
|
|
35592
|
-
code: "MC-D04",
|
|
35593
|
-
sentence: "Memory maintenance has no model available.",
|
|
35594
|
-
action: "Check the model settings, then run /ctx-dream again."
|
|
35595
|
-
},
|
|
35596
|
-
dream_child_aborted: {
|
|
35597
|
-
code: "MC-D05",
|
|
35598
|
-
sentence: "Memory maintenance was interrupted.",
|
|
35599
|
-
action: "Run /ctx-dream again."
|
|
35600
|
-
},
|
|
35601
|
-
dream_parse_failed: {
|
|
35602
|
-
code: "MC-D06",
|
|
35603
|
-
sentence: "Memory maintenance could not use the model response.",
|
|
35604
|
-
action: "Run /ctx-dream again."
|
|
35605
|
-
},
|
|
35606
|
-
dream_unknown: {
|
|
35607
|
-
code: "MC-D07",
|
|
35608
|
-
sentence: "Memory maintenance could not finish.",
|
|
35609
|
-
action: "Run /ctx-dream again."
|
|
35610
|
-
},
|
|
35611
|
-
dreamer_tick_blocked: {
|
|
35612
|
-
code: "MC-D09",
|
|
35613
|
-
sentence: "Background maintenance is not running: its last pass stopped before it reached the scheduled tasks.",
|
|
35614
|
-
action: "It is retried automatically; if it keeps happening, check the Magic Context log for the stage that stopped and run `npx @cortexkit/magic-context doctor`."
|
|
35615
|
-
},
|
|
35616
|
-
dream_task_needs_tool_loop: {
|
|
35617
|
-
code: "MC-D08",
|
|
35618
|
-
sentence: "Some memory maintenance tasks need a tool loop this host does not provide.",
|
|
35619
|
-
action: "The remaining tasks still run; the listed ones are skipped on this host."
|
|
35620
|
-
},
|
|
35621
|
-
embedding_substitution_rejected: {
|
|
35622
|
-
code: "MC-E01",
|
|
35623
|
-
sentence: "Search indexing could not use the selected model.",
|
|
35624
|
-
action: "Check the embedding model setting, then run /ctx-embed start again."
|
|
35625
|
-
},
|
|
35626
|
-
embedding_http_error: {
|
|
35627
|
-
code: "MC-E02",
|
|
35628
|
-
sentence: "The search indexing provider refused the request.",
|
|
35629
|
-
action: "Check the provider connection and credentials, then run /ctx-embed start again."
|
|
35630
|
-
},
|
|
35631
|
-
embedding_transport_error: {
|
|
35632
|
-
code: "MC-E03",
|
|
35633
|
-
sentence: "Search indexing could not reach its provider.",
|
|
35634
|
-
action: "Check the connection, then run /ctx-embed start again."
|
|
35635
|
-
},
|
|
35636
|
-
embedding_invalid_envelope: {
|
|
35637
|
-
code: "MC-E04",
|
|
35638
|
-
sentence: "Search indexing received an unsupported response.",
|
|
35639
|
-
action: "Check the embedding endpoint, then run /ctx-embed start again."
|
|
35640
|
-
},
|
|
35641
|
-
embedding_empty_result: {
|
|
35642
|
-
code: "MC-E05",
|
|
35643
|
-
sentence: "Search indexing received no usable result.",
|
|
35644
|
-
action: "Run /ctx-embed start again."
|
|
35645
|
-
},
|
|
35646
|
-
embedding_certification_refusal: {
|
|
35647
|
-
code: "MC-E06",
|
|
35648
|
-
sentence: "Search indexing is not ready for this provider.",
|
|
35649
|
-
action: "Finish the provider setup, or set a fallback provider in the embedding settings, then run /ctx-embed start again."
|
|
35650
|
-
},
|
|
35651
|
-
embedding_credential_required: {
|
|
35652
|
-
code: "MC-E07",
|
|
35653
|
-
sentence: "Search indexing needs provider credentials.",
|
|
35654
|
-
action: "Sign in to the provider, then run /ctx-embed start again."
|
|
35655
|
-
},
|
|
35656
|
-
embedding_local_binding_missing: {
|
|
35657
|
-
code: "MC-E08",
|
|
35658
|
-
sentence: "Local search indexing is unavailable on this system.",
|
|
35659
|
-
action: "Run `npx @cortexkit/magic-context doctor`, then retry."
|
|
35660
|
-
},
|
|
35661
|
-
embedding_local_fs_unavailable: {
|
|
35662
|
-
code: "MC-E09",
|
|
35663
|
-
sentence: "Local search indexing cannot save its model files.",
|
|
35664
|
-
action: "Update or reinstall Magic Context, then retry."
|
|
35665
|
-
},
|
|
35666
|
-
embedding_local_download_failure: {
|
|
35667
|
-
code: "MC-E10",
|
|
35668
|
-
sentence: "Local search indexing could not download its model.",
|
|
35669
|
-
action: "Check the network connection, then retry."
|
|
35670
|
-
},
|
|
35671
|
-
embedding_local_runtime_error: {
|
|
35672
|
-
code: "MC-E11",
|
|
35673
|
-
sentence: "Local search indexing could not start.",
|
|
35674
|
-
action: "Run `npx @cortexkit/magic-context doctor`, then retry."
|
|
35675
|
-
},
|
|
35676
|
-
embedding_unavailable: {
|
|
35677
|
-
code: "MC-E12",
|
|
35678
|
-
sentence: "Search indexing could not finish.",
|
|
35679
|
-
action: "Run /ctx-embed start again."
|
|
35680
|
-
},
|
|
35681
|
-
status_unavailable: {
|
|
35682
|
-
code: "MC-S01",
|
|
35683
|
-
sentence: "Magic Context status is temporarily unavailable.",
|
|
35684
|
-
action: "Retry /ctx-status in a moment."
|
|
35685
|
-
},
|
|
35686
|
-
transform_update_failed: {
|
|
35687
|
-
code: "MC-S02",
|
|
35688
|
-
sentence: "The last context update did not finish.",
|
|
35689
|
-
action: "Send another message to retry."
|
|
35690
|
-
},
|
|
35691
|
-
configuration_warning: {
|
|
35692
|
-
code: "MC-S03",
|
|
35693
|
-
sentence: "Some configuration settings could not be applied.",
|
|
35694
|
-
action: "Fix the configuration warning shown in /ctx-status, then restart."
|
|
35695
|
-
},
|
|
35696
|
-
status_log_unavailable: {
|
|
35697
|
-
code: "MC-S04",
|
|
35698
|
-
sentence: "Some diagnostic details could not be saved.",
|
|
35699
|
-
action: "Retry /ctx-status in a moment."
|
|
35700
|
-
},
|
|
35701
|
-
memory_writes_paused: {
|
|
35702
|
-
code: "MC-C01",
|
|
35703
|
-
sentence: "Memory writes are paused while the engine syncs.",
|
|
35704
|
-
action: "Retry in a moment."
|
|
35705
|
-
},
|
|
35706
|
-
memory_access_unavailable: {
|
|
35707
|
-
code: "MC-C02",
|
|
35708
|
-
sentence: "Memory access is temporarily unavailable.",
|
|
35709
|
-
action: "Retry in a moment."
|
|
35710
|
-
},
|
|
35711
|
-
note_changes_paused: {
|
|
35712
|
-
code: "MC-C03",
|
|
35713
|
-
sentence: "Note changes are paused while the engine syncs.",
|
|
35714
|
-
action: "Retry in a moment."
|
|
35715
|
-
},
|
|
35716
|
-
note_access_unavailable: {
|
|
35717
|
-
code: "MC-C04",
|
|
35718
|
-
sentence: "Notes are temporarily unavailable.",
|
|
35719
|
-
action: "Retry in a moment."
|
|
35720
|
-
},
|
|
35721
|
-
context_cleanup_paused: {
|
|
35722
|
-
code: "MC-C05",
|
|
35723
|
-
sentence: "Context cleanup is paused while the engine syncs.",
|
|
35724
|
-
action: "Retry in a moment."
|
|
35725
|
-
},
|
|
35726
|
-
partial_history_unavailable: {
|
|
35727
|
-
code: "MC-C06",
|
|
35728
|
-
sentence: "Partial history compression is not available in the current mode.",
|
|
35729
|
-
action: "Run /ctx-recomp without a range."
|
|
35730
|
-
},
|
|
35731
|
-
smart_note_conditions_unavailable: {
|
|
35732
|
-
code: "MC-C08",
|
|
35733
|
-
sentence: "Conditional notes are not available in the current mode.",
|
|
35734
|
-
action: "Save a regular note without a condition."
|
|
35735
|
-
},
|
|
35736
|
-
history_compression_paused: {
|
|
35737
|
-
code: "MC-C09",
|
|
35738
|
-
sentence: "History compression is paused while the engine syncs.",
|
|
35739
|
-
action: "Retry in a moment."
|
|
35740
|
-
},
|
|
35741
|
-
history_compression_needs_message: {
|
|
35742
|
-
code: "MC-C12",
|
|
35743
|
-
sentence: "History compression has not seen this session since Magic Context reconnected.",
|
|
35744
|
-
action: "Send a message in this session first, then run /ctx-wrapup again."
|
|
35745
|
-
},
|
|
35746
|
-
context_service_unavailable: {
|
|
35747
|
-
code: "MC-C10",
|
|
35748
|
-
sentence: "Magic Context is temporarily unavailable.",
|
|
35749
|
-
action: "Retry in a moment."
|
|
35750
|
-
},
|
|
35751
|
-
compaction_marker_missing: {
|
|
35752
|
-
code: "MC-C11",
|
|
35753
|
-
sentence: "The history boundary marker is missing from the OpenCode store, so requests carry the full session.",
|
|
35754
|
-
action: "It is retried on every message; if this persists, run `/ctx-flush`."
|
|
35755
|
-
},
|
|
35756
|
-
memory_mirror_stalled: {
|
|
35757
|
-
code: "MC-M01",
|
|
35758
|
-
sentence: "Memory synchronization stopped before the host mirror caught up.",
|
|
35759
|
-
action: "Send another message to resume it, or run `ck doctor drain-authority`."
|
|
35760
|
-
},
|
|
35761
|
-
memory_authority_mismatch: {
|
|
35762
|
-
code: "MC-M02",
|
|
35763
|
-
sentence: "Memory authority is inconsistent between the host and module.",
|
|
35764
|
-
action: "Run `ck doctor drain-authority` before changing Rust mode."
|
|
35765
|
-
},
|
|
35766
|
-
rust_mode_unsupported: {
|
|
35767
|
-
code: "MC-S06",
|
|
35768
|
-
sentence: "Experimental Rust transform mode is not available on this OpenCode host.",
|
|
35769
|
-
action: 'Magic Context is running its TypeScript mode instead; set `transform_mode` to "ts" to stop requesting Rust.'
|
|
35770
|
-
},
|
|
35771
|
-
dreamer_task_failing: {
|
|
35772
|
-
code: "MC-S05",
|
|
35773
|
-
sentence: "A background maintenance task keeps failing on its schedule.",
|
|
35774
|
-
action: "Check the Magic Context log for the failing task and its error."
|
|
35775
|
-
}
|
|
35776
|
-
};
|
|
35777
|
-
});
|
|
35778
|
-
|
|
35779
35977
|
// ../plugin/src/features/magic-context/dreamer/tick-failure.ts
|
|
35780
35978
|
function parseFailure(value) {
|
|
35781
35979
|
if (!value)
|
|
@@ -38519,6 +38717,9 @@ async function collectHistorianRuns(storageDirPath) {
|
|
|
38519
38717
|
} catch {}
|
|
38520
38718
|
}
|
|
38521
38719
|
}
|
|
38720
|
+
function openCodeIssueLogHarnesses(hostGeneration) {
|
|
38721
|
+
return hostGeneration === "v2" ? ["opencode2", "opencode"] : ["opencode"];
|
|
38722
|
+
}
|
|
38522
38723
|
async function collectDiagnostics() {
|
|
38523
38724
|
const pluginVersion = getSelfVersion();
|
|
38524
38725
|
const configPaths = detectConfigPaths();
|
|
@@ -38528,8 +38729,6 @@ async function collectDiagnostics() {
|
|
|
38528
38729
|
const storageResolution = getStorageResolution();
|
|
38529
38730
|
const storageDirPath = storageResolution.path;
|
|
38530
38731
|
const contextDbPath = join26(storageDirPath, "context.db");
|
|
38531
|
-
const logFiles = inspectMagicContextLogs("opencode");
|
|
38532
|
-
const primaryLog = logFiles.find((file) => file.exists) ?? logFiles[0];
|
|
38533
38732
|
let compactionEnabled = false;
|
|
38534
38733
|
try {
|
|
38535
38734
|
compactionEnabled = isCompactionEnabled(loadPluginConfig(process.cwd()));
|
|
@@ -38539,6 +38738,8 @@ async function collectDiagnostics() {
|
|
|
38539
38738
|
const opencodeInstallations = describeOpenCodeInstallations(detectOpenCodeInstallations());
|
|
38540
38739
|
const activeInstallation = opencodeInstallations[0];
|
|
38541
38740
|
const hostGeneration = openCodeHostGenerationFromVersion(activeInstallation?.version);
|
|
38741
|
+
const logFiles = openCodeIssueLogHarnesses(hostGeneration).flatMap((harness) => inspectMagicContextLogs(harness)).filter((file, index, all) => all.findIndex((other) => other.path === file.path) === index);
|
|
38742
|
+
const primaryLog = logFiles.find((file) => file.exists) ?? logFiles[0];
|
|
38542
38743
|
const conflictResult = detectConflicts(process.cwd(), { compactionEnabled, hostGeneration });
|
|
38543
38744
|
const openCodeDatabaseResolution = resolveOpenCodeDbPath(hostGeneration);
|
|
38544
38745
|
const recentSessions = await collectRecentSessions(openCodeDatabaseResolution, hostGeneration);
|
|
@@ -40046,6 +40247,179 @@ var init_storage_versions = __esm(async () => {
|
|
|
40046
40247
|
await init_storage_db();
|
|
40047
40248
|
});
|
|
40048
40249
|
|
|
40250
|
+
// src/commands/doctor-opencode-cache.ts
|
|
40251
|
+
import { existsSync as existsSync36, readFileSync as readFileSync25, rmSync as rmSync4 } from "node:fs";
|
|
40252
|
+
function readCachedPluginVersion(pluginCacheDir) {
|
|
40253
|
+
try {
|
|
40254
|
+
const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
|
|
40255
|
+
if (!existsSync36(installedPkgPath))
|
|
40256
|
+
return;
|
|
40257
|
+
const pkg = JSON.parse(readFileSync25(installedPkgPath, "utf-8"));
|
|
40258
|
+
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
40259
|
+
} catch {
|
|
40260
|
+
return;
|
|
40261
|
+
}
|
|
40262
|
+
}
|
|
40263
|
+
async function clearPluginCache(options = {}, deps = {}) {
|
|
40264
|
+
const remove = deps.remove ?? ((path) => rmSync4(path, { recursive: true, force: true }));
|
|
40265
|
+
const pluginCacheRoots = getOpenCodePluginCacheRoots();
|
|
40266
|
+
const existingRoots = pluginCacheRoots.filter((root) => existsSync36(root));
|
|
40267
|
+
if (existingRoots.length === 0) {
|
|
40268
|
+
return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
|
|
40269
|
+
}
|
|
40270
|
+
const latestVersion = options.latestVersion ?? undefined;
|
|
40271
|
+
const cacheEntries = existingRoots.map((path) => ({
|
|
40272
|
+
path,
|
|
40273
|
+
cached: readCachedPluginVersion(path)
|
|
40274
|
+
}));
|
|
40275
|
+
if (options.force !== true && latestVersion === undefined) {
|
|
40276
|
+
const firstEntry = cacheEntries[0];
|
|
40277
|
+
return {
|
|
40278
|
+
action: "check_unavailable",
|
|
40279
|
+
path: firstEntry?.path ?? pluginCacheRoots[0] ?? "",
|
|
40280
|
+
paths: cacheEntries.map((entry) => entry.path),
|
|
40281
|
+
cached: firstEntry?.cached
|
|
40282
|
+
};
|
|
40283
|
+
}
|
|
40284
|
+
const clearTargets = cacheEntries.filter((entry) => options.force === true || entry.cached === undefined || entry.cached !== latestVersion);
|
|
40285
|
+
if (clearTargets.length === 0) {
|
|
40286
|
+
const firstEntry = cacheEntries[0];
|
|
40287
|
+
return {
|
|
40288
|
+
action: "up_to_date",
|
|
40289
|
+
path: firstEntry?.path ?? pluginCacheRoots[0] ?? "",
|
|
40290
|
+
paths: cacheEntries.map((entry) => entry.path),
|
|
40291
|
+
cached: firstEntry?.cached,
|
|
40292
|
+
latest: latestVersion
|
|
40293
|
+
};
|
|
40294
|
+
}
|
|
40295
|
+
const cleared = [];
|
|
40296
|
+
const failed = [];
|
|
40297
|
+
for (const entry of clearTargets) {
|
|
40298
|
+
try {
|
|
40299
|
+
remove(entry.path);
|
|
40300
|
+
cleared.push(entry);
|
|
40301
|
+
} catch (err) {
|
|
40302
|
+
failed.push({
|
|
40303
|
+
path: entry.path,
|
|
40304
|
+
error: err instanceof Error ? err.message : String(err)
|
|
40305
|
+
});
|
|
40306
|
+
}
|
|
40307
|
+
}
|
|
40308
|
+
if (failed.length > 0) {
|
|
40309
|
+
const firstFailure = failed[0];
|
|
40310
|
+
return {
|
|
40311
|
+
action: "error",
|
|
40312
|
+
path: firstFailure?.path ?? clearTargets[0]?.path ?? existingRoots[0] ?? "",
|
|
40313
|
+
paths: failed.map((entry) => entry.path),
|
|
40314
|
+
clearedPaths: cleared.map((entry) => entry.path),
|
|
40315
|
+
failedPaths: failed.map((entry) => entry.path),
|
|
40316
|
+
error: firstFailure?.error
|
|
40317
|
+
};
|
|
40318
|
+
}
|
|
40319
|
+
const firstTarget = cleared[0];
|
|
40320
|
+
return {
|
|
40321
|
+
action: "cleared",
|
|
40322
|
+
path: firstTarget?.path ?? pluginCacheRoots[0] ?? "",
|
|
40323
|
+
paths: cleared.map((entry) => entry.path),
|
|
40324
|
+
cached: firstTarget?.cached,
|
|
40325
|
+
latest: latestVersion
|
|
40326
|
+
};
|
|
40327
|
+
}
|
|
40328
|
+
var init_doctor_opencode_cache = __esm(() => {
|
|
40329
|
+
init_opencode_plugin_cache();
|
|
40330
|
+
});
|
|
40331
|
+
|
|
40332
|
+
// src/commands/doctor-cached-plugin-fence.ts
|
|
40333
|
+
import { existsSync as existsSync37 } from "node:fs";
|
|
40334
|
+
import { dirname as dirname18 } from "node:path";
|
|
40335
|
+
function listCachedOpenCodePluginFences(sources = {}) {
|
|
40336
|
+
const fences = [];
|
|
40337
|
+
for (const root of sources.openCodeV1Roots ?? getOpenCodePluginCacheRoots()) {
|
|
40338
|
+
const packageJson = getOpenCodePluginPackageJsonPath(root);
|
|
40339
|
+
if (!existsSync37(packageJson))
|
|
40340
|
+
continue;
|
|
40341
|
+
fences.push({
|
|
40342
|
+
host: "opencode1",
|
|
40343
|
+
directory: root,
|
|
40344
|
+
version: readCachedPluginVersion(root),
|
|
40345
|
+
supportedVersion: readFenceFromDist(dirname18(packageJson))
|
|
40346
|
+
});
|
|
40347
|
+
}
|
|
40348
|
+
for (const slot of listOpenCodeV2PluginCacheSlots(sources.openCodeV2NpmCacheDir)) {
|
|
40349
|
+
if (!isOpenCodePluginDistTag(slot.spec))
|
|
40350
|
+
continue;
|
|
40351
|
+
const generation = getOpenCodeV2ActiveGeneration(slot.slot);
|
|
40352
|
+
if (!generation)
|
|
40353
|
+
continue;
|
|
40354
|
+
fences.push({
|
|
40355
|
+
host: "opencode2",
|
|
40356
|
+
directory: slot.slot,
|
|
40357
|
+
spec: slot.spec,
|
|
40358
|
+
version: slot.version,
|
|
40359
|
+
supportedVersion: readFenceFromDist(dirname18(getOpenCodePluginPackageJsonPath(generation)))
|
|
40360
|
+
});
|
|
40361
|
+
}
|
|
40362
|
+
return fences;
|
|
40363
|
+
}
|
|
40364
|
+
function readContextDbSchemaVersion(path) {
|
|
40365
|
+
let db = null;
|
|
40366
|
+
try {
|
|
40367
|
+
db = openExistingDatabase(path, { readonly: true });
|
|
40368
|
+
return db === null ? null : getPersistedSchemaVersion(db);
|
|
40369
|
+
} catch {
|
|
40370
|
+
return null;
|
|
40371
|
+
} finally {
|
|
40372
|
+
db?.close();
|
|
40373
|
+
}
|
|
40374
|
+
}
|
|
40375
|
+
function compareCachedPluginFences(fences, databaseVersion) {
|
|
40376
|
+
return fences.map((fence) => ({
|
|
40377
|
+
...fence,
|
|
40378
|
+
databaseVersion,
|
|
40379
|
+
status: fence.supportedVersion === null ? "unknown" : fence.supportedVersion < databaseVersion ? "behind" : "supported"
|
|
40380
|
+
}));
|
|
40381
|
+
}
|
|
40382
|
+
function hostLabel(fence) {
|
|
40383
|
+
if (fence.host === "opencode1")
|
|
40384
|
+
return "OpenCode 1";
|
|
40385
|
+
return fence.spec && fence.spec !== "latest" ? `OpenCode 2 (@${fence.spec})` : "OpenCode 2";
|
|
40386
|
+
}
|
|
40387
|
+
function reportCachedPluginFences(findings, report) {
|
|
40388
|
+
const supported = [];
|
|
40389
|
+
let behind = 0;
|
|
40390
|
+
for (const finding of findings) {
|
|
40391
|
+
const label = hostLabel(finding);
|
|
40392
|
+
const version = finding.version ?? "unknown version";
|
|
40393
|
+
if (finding.status === "supported") {
|
|
40394
|
+
supported.push(`${label} ${version} (fence v${finding.supportedVersion})`);
|
|
40395
|
+
continue;
|
|
40396
|
+
}
|
|
40397
|
+
if (finding.status === "unknown") {
|
|
40398
|
+
report.info(`${label} plugin cache: could not read the schema fence of Magic Context ${version}, so doctor cannot tell whether it supports context.db v${finding.databaseVersion}`);
|
|
40399
|
+
report.info(` ${finding.directory}`);
|
|
40400
|
+
continue;
|
|
40401
|
+
}
|
|
40402
|
+
behind++;
|
|
40403
|
+
report.fail(`${label} has Magic Context ${version} cached, which supports context.db only through schema v${finding.supportedVersion}, but the shared context.db is at v${finding.databaseVersion}. A newer Magic Context (usually the other OpenCode host) migrated it, so ${label} fails closed on every prompt; an @latest entry does not refresh this cached copy.`);
|
|
40404
|
+
report.info(` ${finding.directory}`);
|
|
40405
|
+
report.info(finding.host === "opencode1" ? " To fix: quit OpenCode 1 and delete that directory; OpenCode 1 installs the current release on its next start." : ` To fix, ${OPENCODE_V2_PLUGIN_UPDATE_HINT}, then restart OpenCode 2.`);
|
|
40406
|
+
}
|
|
40407
|
+
if (supported.length > 0) {
|
|
40408
|
+
report.pass(`Cached Magic Context copies support context.db v${findings[0]?.databaseVersion}: ${supported.join(", ")}`);
|
|
40409
|
+
}
|
|
40410
|
+
return { behind };
|
|
40411
|
+
}
|
|
40412
|
+
var init_doctor_cached_plugin_fence = __esm(async () => {
|
|
40413
|
+
init_opencode_plugin_cache();
|
|
40414
|
+
init_opencode_plugin_schema_fence();
|
|
40415
|
+
init_doctor_opencode_cache();
|
|
40416
|
+
init_doctor_opencode2_cache();
|
|
40417
|
+
await __promiseAll([
|
|
40418
|
+
init_storage_db(),
|
|
40419
|
+
init_database_access()
|
|
40420
|
+
]);
|
|
40421
|
+
});
|
|
40422
|
+
|
|
40049
40423
|
// src/commands/doctor-compaction-markers.ts
|
|
40050
40424
|
function safeData(column = "data") {
|
|
40051
40425
|
return `CASE WHEN json_valid(${column}) THEN ${column} ELSE '{}' END`;
|
|
@@ -40101,6 +40475,21 @@ function countUnmatchedConvertedMarkers(db, migratedV2Schema) {
|
|
|
40101
40475
|
)`).get();
|
|
40102
40476
|
return Number(row?.count ?? 0);
|
|
40103
40477
|
}
|
|
40478
|
+
function countPostConversionMessages(db, migratedV2Schema) {
|
|
40479
|
+
if (!migratedV2Schema || !tableExists4(db, "message") || !tableExists4(db, "session")) {
|
|
40480
|
+
return { messages: 0, sessions: 0 };
|
|
40481
|
+
}
|
|
40482
|
+
const row = db.prepare(`SELECT COUNT(*) AS messages, COUNT(DISTINCT converted.session_id) AS sessions
|
|
40483
|
+
FROM session_message converted
|
|
40484
|
+
WHERE EXISTS (SELECT 1 FROM session legacy WHERE legacy.id = converted.session_id)
|
|
40485
|
+
AND NOT EXISTS (
|
|
40486
|
+
SELECT 1
|
|
40487
|
+
FROM message source
|
|
40488
|
+
WHERE source.session_id = converted.session_id
|
|
40489
|
+
AND source.time_created = converted.time_created
|
|
40490
|
+
)`).get();
|
|
40491
|
+
return { messages: Number(row?.messages ?? 0), sessions: Number(row?.sessions ?? 0) };
|
|
40492
|
+
}
|
|
40104
40493
|
function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
|
|
40105
40494
|
const missingBefore = countMissingCompleted(db);
|
|
40106
40495
|
let repaired = 0;
|
|
@@ -40121,6 +40510,7 @@ function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
|
|
|
40121
40510
|
const migratedV2Schema = tableExists4(db, "session_v2") && tableExists4(db, "session_message");
|
|
40122
40511
|
const migrationCompleted = migrationV1ToV2Completed(db);
|
|
40123
40512
|
const unmatchedConvertedMarkers = countUnmatchedConvertedMarkers(db, migratedV2Schema);
|
|
40513
|
+
const postConversion = countPostConversionMessages(db, migratedV2Schema);
|
|
40124
40514
|
return {
|
|
40125
40515
|
missingBefore,
|
|
40126
40516
|
missingAfter,
|
|
@@ -40128,21 +40518,23 @@ function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
|
|
|
40128
40518
|
migrationCompleted,
|
|
40129
40519
|
migratedV2Schema,
|
|
40130
40520
|
unmatchedConvertedMarkers,
|
|
40131
|
-
|
|
40521
|
+
postConversionMessages: postConversion.messages,
|
|
40522
|
+
postConversionSessions: postConversion.sessions
|
|
40132
40523
|
};
|
|
40133
40524
|
}
|
|
40134
40525
|
function formatOpenCodeCompactionMarkerConversion(report) {
|
|
40135
40526
|
return `OpenCode compaction markers are convertible to OpenCode 2: before=${report.missingBefore} missing time.completed; after=${report.missingAfter}`;
|
|
40136
40527
|
}
|
|
40137
|
-
function
|
|
40138
|
-
|
|
40139
|
-
|
|
40140
|
-
|
|
40141
|
-
|
|
40142
|
-
|
|
40143
|
-
"
|
|
40144
|
-
'Wait until `SELECT value FROM kv WHERE key = \'migration.v1-v2\';` reads `{"phase":"completed"}` before stopping that manual server'
|
|
40528
|
+
function formatOpenCodeV2MissingMarkerNotice(report) {
|
|
40529
|
+
if (!report.migrationCompleted || !report.migratedV2Schema || report.unmatchedConvertedMarkers === 0) {
|
|
40530
|
+
return null;
|
|
40531
|
+
}
|
|
40532
|
+
const lines = [
|
|
40533
|
+
`OpenCode 2's conversion did not carry over ${report.unmatchedConvertedMarkers} Magic Context compaction marker(s). No action is needed.`,
|
|
40534
|
+
"Magic Context on OpenCode 2 does not use host compaction rows: it keeps its own boundary and re-derives compartment positions from the messages that survived. OpenCode reads these sessions' full history on each turn, as it does for any Magic Context session started on OpenCode 2."
|
|
40145
40535
|
];
|
|
40536
|
+
lines.push(report.postConversionMessages > 0 ? `Do not clear kv.migration.v1-v2 to reconvert: OpenCode 2 would rebuild every converted session from its OpenCode 1 rows and delete the ${report.postConversionMessages} message(s) it added after the conversion, in ${report.postConversionSessions} session(s).` : "Do not clear kv.migration.v1-v2 to reconvert: OpenCode 2 would rebuild every converted session from its OpenCode 1 rows, deleting anything added on OpenCode 2 since.", "If you already reconverted, restore opencode.db (with its -wal and -shm files) from a backup taken before the reconversion.");
|
|
40537
|
+
return lines;
|
|
40146
40538
|
}
|
|
40147
40539
|
|
|
40148
40540
|
// src/commands/doctor-compartment-boundaries.ts
|
|
@@ -40226,88 +40618,6 @@ var init_doctor_harness_relabel = __esm(async () => {
|
|
|
40226
40618
|
await init_opencode2_relabel();
|
|
40227
40619
|
});
|
|
40228
40620
|
|
|
40229
|
-
// src/commands/doctor-opencode-cache.ts
|
|
40230
|
-
import { existsSync as existsSync36, readFileSync as readFileSync25, rmSync as rmSync4 } from "node:fs";
|
|
40231
|
-
function readCachedPluginVersion(pluginCacheDir) {
|
|
40232
|
-
try {
|
|
40233
|
-
const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
|
|
40234
|
-
if (!existsSync36(installedPkgPath))
|
|
40235
|
-
return;
|
|
40236
|
-
const pkg = JSON.parse(readFileSync25(installedPkgPath, "utf-8"));
|
|
40237
|
-
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
40238
|
-
} catch {
|
|
40239
|
-
return;
|
|
40240
|
-
}
|
|
40241
|
-
}
|
|
40242
|
-
async function clearPluginCache(options = {}, deps = {}) {
|
|
40243
|
-
const remove = deps.remove ?? ((path) => rmSync4(path, { recursive: true, force: true }));
|
|
40244
|
-
const pluginCacheRoots = getOpenCodePluginCacheRoots();
|
|
40245
|
-
const existingRoots = pluginCacheRoots.filter((root) => existsSync36(root));
|
|
40246
|
-
if (existingRoots.length === 0) {
|
|
40247
|
-
return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
|
|
40248
|
-
}
|
|
40249
|
-
const latestVersion = options.latestVersion ?? undefined;
|
|
40250
|
-
const cacheEntries = existingRoots.map((path) => ({
|
|
40251
|
-
path,
|
|
40252
|
-
cached: readCachedPluginVersion(path)
|
|
40253
|
-
}));
|
|
40254
|
-
if (options.force !== true && latestVersion === undefined) {
|
|
40255
|
-
const firstEntry = cacheEntries[0];
|
|
40256
|
-
return {
|
|
40257
|
-
action: "check_unavailable",
|
|
40258
|
-
path: firstEntry?.path ?? pluginCacheRoots[0] ?? "",
|
|
40259
|
-
paths: cacheEntries.map((entry) => entry.path),
|
|
40260
|
-
cached: firstEntry?.cached
|
|
40261
|
-
};
|
|
40262
|
-
}
|
|
40263
|
-
const clearTargets = cacheEntries.filter((entry) => options.force === true || entry.cached === undefined || entry.cached !== latestVersion);
|
|
40264
|
-
if (clearTargets.length === 0) {
|
|
40265
|
-
const firstEntry = cacheEntries[0];
|
|
40266
|
-
return {
|
|
40267
|
-
action: "up_to_date",
|
|
40268
|
-
path: firstEntry?.path ?? pluginCacheRoots[0] ?? "",
|
|
40269
|
-
paths: cacheEntries.map((entry) => entry.path),
|
|
40270
|
-
cached: firstEntry?.cached,
|
|
40271
|
-
latest: latestVersion
|
|
40272
|
-
};
|
|
40273
|
-
}
|
|
40274
|
-
const cleared = [];
|
|
40275
|
-
const failed = [];
|
|
40276
|
-
for (const entry of clearTargets) {
|
|
40277
|
-
try {
|
|
40278
|
-
remove(entry.path);
|
|
40279
|
-
cleared.push(entry);
|
|
40280
|
-
} catch (err) {
|
|
40281
|
-
failed.push({
|
|
40282
|
-
path: entry.path,
|
|
40283
|
-
error: err instanceof Error ? err.message : String(err)
|
|
40284
|
-
});
|
|
40285
|
-
}
|
|
40286
|
-
}
|
|
40287
|
-
if (failed.length > 0) {
|
|
40288
|
-
const firstFailure = failed[0];
|
|
40289
|
-
return {
|
|
40290
|
-
action: "error",
|
|
40291
|
-
path: firstFailure?.path ?? clearTargets[0]?.path ?? existingRoots[0] ?? "",
|
|
40292
|
-
paths: failed.map((entry) => entry.path),
|
|
40293
|
-
clearedPaths: cleared.map((entry) => entry.path),
|
|
40294
|
-
failedPaths: failed.map((entry) => entry.path),
|
|
40295
|
-
error: firstFailure?.error
|
|
40296
|
-
};
|
|
40297
|
-
}
|
|
40298
|
-
const firstTarget = cleared[0];
|
|
40299
|
-
return {
|
|
40300
|
-
action: "cleared",
|
|
40301
|
-
path: firstTarget?.path ?? pluginCacheRoots[0] ?? "",
|
|
40302
|
-
paths: cleared.map((entry) => entry.path),
|
|
40303
|
-
cached: firstTarget?.cached,
|
|
40304
|
-
latest: latestVersion
|
|
40305
|
-
};
|
|
40306
|
-
}
|
|
40307
|
-
var init_doctor_opencode_cache = __esm(() => {
|
|
40308
|
-
init_opencode_plugin_cache();
|
|
40309
|
-
});
|
|
40310
|
-
|
|
40311
40621
|
// src/commands/doctor-opencode-plugin-duplicates.ts
|
|
40312
40622
|
import { isDeepStrictEqual } from "node:util";
|
|
40313
40623
|
function entryOptions(entry) {
|
|
@@ -40535,10 +40845,21 @@ function formatUnresolvedCompartmentSession(session) {
|
|
|
40535
40845
|
|
|
40536
40846
|
// src/commands/doctor-opencode.ts
|
|
40537
40847
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
40538
|
-
import { existsSync as
|
|
40848
|
+
import { existsSync as existsSync38, mkdtempSync, readFileSync as readFileSync26, rmSync as rmSync5 } from "node:fs";
|
|
40539
40849
|
import { createRequire as createRequire6 } from "node:module";
|
|
40540
40850
|
import { homedir as homedir16, tmpdir as tmpdir3 } from "node:os";
|
|
40541
40851
|
import { join as join32 } from "node:path";
|
|
40852
|
+
function formatSharedDbRowCounts(db) {
|
|
40853
|
+
return SHARED_DB_ROW_COUNT_TABLES.map((table) => {
|
|
40854
|
+
try {
|
|
40855
|
+
const row = db.prepare(`SELECT COUNT(*) AS c FROM ${table}`).get();
|
|
40856
|
+
return `${table}=${typeof row?.c === "number" ? row.c : "n/a"}`;
|
|
40857
|
+
} catch (error) {
|
|
40858
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
40859
|
+
return `${table}=n/a (${sanitizeDiagnosticText(reason)})`;
|
|
40860
|
+
}
|
|
40861
|
+
}).join(", ");
|
|
40862
|
+
}
|
|
40542
40863
|
function findUndeclaredConfiguredVariants(configured, catalog) {
|
|
40543
40864
|
return configured.filter((entry) => {
|
|
40544
40865
|
const [providerID, id] = entry.model.split("/", 2);
|
|
@@ -40546,6 +40867,18 @@ function findUndeclaredConfiguredVariants(configured, catalog) {
|
|
|
40546
40867
|
return model !== undefined && !Object.hasOwn(model.variants, entry.variant);
|
|
40547
40868
|
});
|
|
40548
40869
|
}
|
|
40870
|
+
function findUnknownConfiguredModels(configured, catalog) {
|
|
40871
|
+
return configured.flatMap((entry) => {
|
|
40872
|
+
const [providerID, id] = entry.model.split("/", 2);
|
|
40873
|
+
if (!catalog.some((item) => item.providerID === providerID)) {
|
|
40874
|
+
return [{ ...entry, unknown: "provider" }];
|
|
40875
|
+
}
|
|
40876
|
+
if (!catalog.some((item) => item.providerID === providerID && item.id === id)) {
|
|
40877
|
+
return [{ ...entry, unknown: "model" }];
|
|
40878
|
+
}
|
|
40879
|
+
return [];
|
|
40880
|
+
});
|
|
40881
|
+
}
|
|
40549
40882
|
function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args, cwd) => spawnSync8("opencode", args, {
|
|
40550
40883
|
cwd,
|
|
40551
40884
|
encoding: "utf8",
|
|
@@ -40553,6 +40886,7 @@ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args
|
|
|
40553
40886
|
maxBuffer: 16 * 1024 * 1024
|
|
40554
40887
|
}), projectDir = process.cwd()) {
|
|
40555
40888
|
const configured = [];
|
|
40889
|
+
const models = [];
|
|
40556
40890
|
const root = config && typeof config === "object" ? config : {};
|
|
40557
40891
|
for (const agent of ["historian", "dreamer"]) {
|
|
40558
40892
|
const section = root[agent];
|
|
@@ -40562,21 +40896,25 @@ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args
|
|
|
40562
40896
|
if (!block || typeof block !== "object")
|
|
40563
40897
|
continue;
|
|
40564
40898
|
const record = block;
|
|
40565
|
-
const add = (entry, defaultVariant) => {
|
|
40899
|
+
const add = (entry, defaultVariant, fallback) => {
|
|
40566
40900
|
const value = entry && typeof entry === "object" ? entry : {};
|
|
40567
40901
|
const model = typeof entry === "string" ? entry : value.model;
|
|
40568
40902
|
const variant = value.variant ?? defaultVariant;
|
|
40569
|
-
if (typeof model
|
|
40570
|
-
|
|
40903
|
+
if (typeof model !== "string" || !model.includes("/"))
|
|
40904
|
+
return;
|
|
40905
|
+
if (!models.some((known) => known.agent === agent && known.model === model)) {
|
|
40906
|
+
models.push({ agent, model, fallback });
|
|
40571
40907
|
}
|
|
40908
|
+
if (typeof variant === "string")
|
|
40909
|
+
configured.push({ agent, model, variant });
|
|
40572
40910
|
};
|
|
40573
|
-
add(record.model, record.variant);
|
|
40911
|
+
add(record.model, record.variant, false);
|
|
40574
40912
|
if (Array.isArray(record.fallback_models)) {
|
|
40575
40913
|
for (const entry of record.fallback_models)
|
|
40576
|
-
add(entry, undefined);
|
|
40914
|
+
add(entry, undefined, true);
|
|
40577
40915
|
}
|
|
40578
40916
|
}
|
|
40579
|
-
if (
|
|
40917
|
+
if (models.length === 0)
|
|
40580
40918
|
return;
|
|
40581
40919
|
const tempRoot = mkdtempSync(join32(tmpdir3(), "magic-context-opencode-catalog-"));
|
|
40582
40920
|
try {
|
|
@@ -40585,9 +40923,14 @@ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args
|
|
|
40585
40923
|
const result = run(command, tempRoot);
|
|
40586
40924
|
const catalog = hostGeneration === "v2" ? parseOpenCodeV2ModelCatalog(result.stdout ?? "") : parseOpenCodeModelCatalog(result.stdout ?? "");
|
|
40587
40925
|
if (result.error || result.status !== 0 || catalog.length === 0) {
|
|
40588
|
-
warn(`Could not verify configured hidden-agent variants: this OpenCode host did not provide a readable model catalog. ${hostGeneration === "v2" ? "Start the background service with opencode service start, then check" : "Check"} ${guidance}.`);
|
|
40926
|
+
warn(`Could not verify configured hidden-agent models and variants: this OpenCode host did not provide a readable model catalog. ${hostGeneration === "v2" ? "Start the background service with opencode service start, then check" : "Check"} ${guidance}.`);
|
|
40589
40927
|
return;
|
|
40590
40928
|
}
|
|
40929
|
+
for (const entry of findUnknownConfiguredModels(models, catalog)) {
|
|
40930
|
+
const [providerID] = entry.model.split("/", 1);
|
|
40931
|
+
const role = `${entry.agent}${entry.fallback ? " fallback" : ""} model ${entry.model}`;
|
|
40932
|
+
warn(entry.unknown === "provider" ? `${role} names provider '${providerID}', which this OpenCode host does not have. The ${entry.agent} cannot run on it; configure that provider in OpenCode or choose a model listed by ${guidance}.` : `${role} is not offered by provider '${providerID}' on this OpenCode host. The ${entry.agent} cannot run on it; choose a model listed by ${guidance}.`);
|
|
40933
|
+
}
|
|
40591
40934
|
for (const entry of findUndeclaredConfiguredVariants(configured, catalog)) {
|
|
40592
40935
|
warn(`${entry.agent} model ${entry.model} requests variant '${entry.variant}', which this host does not offer. Remove the variant or choose one listed by ${guidance}.`);
|
|
40593
40936
|
}
|
|
@@ -40763,7 +41106,7 @@ function getUserNpmrcPath() {
|
|
|
40763
41106
|
function collectNpmReleaseAgeWarnings() {
|
|
40764
41107
|
const ageWarnings = [];
|
|
40765
41108
|
const npmrcPath = getUserNpmrcPath();
|
|
40766
|
-
if (!
|
|
41109
|
+
if (!existsSync38(npmrcPath))
|
|
40767
41110
|
return ageWarnings;
|
|
40768
41111
|
try {
|
|
40769
41112
|
const npmrc = readFileSync26(npmrcPath, "utf-8");
|
|
@@ -40900,7 +41243,7 @@ function checkLocalEmbeddingRuntimeForDoctor(runtimePreference = "auto") {
|
|
|
40900
41243
|
return { issues: 0 };
|
|
40901
41244
|
}
|
|
40902
41245
|
async function checkEmbeddingConfig(magicContextConfigPath) {
|
|
40903
|
-
if (!
|
|
41246
|
+
if (!existsSync38(magicContextConfigPath)) {
|
|
40904
41247
|
return checkLocalEmbeddingRuntimeForDoctor();
|
|
40905
41248
|
}
|
|
40906
41249
|
let rawText;
|
|
@@ -41108,7 +41451,7 @@ async function runDoctor2(options = {}) {
|
|
|
41108
41451
|
const activeInstallation = installationReports[0];
|
|
41109
41452
|
if (!activeInstallation) {
|
|
41110
41453
|
fail("OpenCode is not installed or not in PATH");
|
|
41111
|
-
log2.info("Doctor checked ~/.opencode/bin/opencode
|
|
41454
|
+
log2.info("Doctor checked ~/.opencode/bin/opencode, each entry in $PATH, and the OpenCode CLI bundled in OpenChamber.app.");
|
|
41112
41455
|
log2.info("If `which opencode` succeeds outside doctor, your wrapper or shim may not be readable by Node — please share that wrapper in the issue.");
|
|
41113
41456
|
outro2("Doctor failed — install OpenCode first");
|
|
41114
41457
|
return 1;
|
|
@@ -41124,7 +41467,19 @@ async function runDoctor2(options = {}) {
|
|
|
41124
41467
|
pass(installationReports.length > 1 ? `OpenCode ${activeInstallation.version} installed (active install marked above)` : `OpenCode ${activeInstallation.version} installed`);
|
|
41125
41468
|
}
|
|
41126
41469
|
const hostGeneration = openCodeHostGenerationFromVersion(activeInstallation.version);
|
|
41127
|
-
const
|
|
41470
|
+
const storeHostSelection = selectOpenCodeStoreHost(installationReports, openCodeHostGenerationFromVersion);
|
|
41471
|
+
const storeHost = storeHostSelection?.host ?? activeInstallation;
|
|
41472
|
+
const storeGeneration = openCodeHostGenerationFromVersion(storeHost.version);
|
|
41473
|
+
const openCodeDbResolution = resolveOpenCodeDbPath(storeGeneration);
|
|
41474
|
+
if (storeHostSelection?.shadowed) {
|
|
41475
|
+
const activeStore = resolveOpenCodeDbPath(hostGeneration).path;
|
|
41476
|
+
const shared = activeStore === openCodeDbResolution.path;
|
|
41477
|
+
const versionLabel = (version) => version.replace(/^opencode\s+v?/i, "");
|
|
41478
|
+
const activeVersion = versionLabel(activeInstallation.version);
|
|
41479
|
+
const storeVersion = versionLabel(storeHost.version);
|
|
41480
|
+
warn(`OpenCode ${activeVersion} (${activeInstallation.path}) is first on PATH, and OpenCode ${storeVersion} is also installed (${storeHost.path})${shared ? `; both use ${openCodeDbResolution.path}` : ""}.`);
|
|
41481
|
+
log2.warn(` Store and conversion checks below use OpenCode ${storeVersion}. Plugin configuration checks use OpenCode ${activeVersion}; to check OpenCode ${storeVersion}'s configuration instead, put its binary first on PATH and run doctor again.`);
|
|
41482
|
+
}
|
|
41128
41483
|
const openCodeDbCheck = describeOpenCodeDatabaseDoctorCheck(openCodeDbResolution);
|
|
41129
41484
|
if (openCodeDbCheck.ok)
|
|
41130
41485
|
pass(openCodeDbCheck.message);
|
|
@@ -41148,14 +41503,16 @@ async function runDoctor2(options = {}) {
|
|
|
41148
41503
|
fixed += report.repaired;
|
|
41149
41504
|
} else if (options.fix) {
|
|
41150
41505
|
warn(`${summary}; repaired=${report.repaired}, but some rows remain unconvertible`);
|
|
41506
|
+
} else if (report.migrationCompleted) {
|
|
41507
|
+
log2.info(`${summary}; OpenCode 2 already converted this store`);
|
|
41151
41508
|
} else {
|
|
41152
41509
|
warn(`${summary}; run \`magic-context doctor --fix\` before upgrading OpenCode`);
|
|
41153
41510
|
}
|
|
41154
|
-
|
|
41155
|
-
|
|
41156
|
-
|
|
41157
|
-
|
|
41158
|
-
|
|
41511
|
+
const notice = formatOpenCodeV2MissingMarkerNotice(report);
|
|
41512
|
+
if (notice) {
|
|
41513
|
+
for (const [index, line] of notice.entries()) {
|
|
41514
|
+
log2.info(index === 0 ? line : ` ${line}`);
|
|
41515
|
+
}
|
|
41159
41516
|
}
|
|
41160
41517
|
} catch (error) {
|
|
41161
41518
|
warn(`OpenCode compaction marker conversion check unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -41171,9 +41528,14 @@ async function runDoctor2(options = {}) {
|
|
|
41171
41528
|
readonly: true,
|
|
41172
41529
|
fileMustExist: true
|
|
41173
41530
|
});
|
|
41174
|
-
const dangling = listDanglingCompartmentBoundaries(contextDb, sessionDb, /\d/.test(
|
|
41531
|
+
const dangling = listDanglingCompartmentBoundaries(contextDb, sessionDb, /\d/.test(storeHost.version) ? storeGeneration : undefined, (line) => log2.info(line));
|
|
41175
41532
|
if (dangling.length === 0) {
|
|
41176
41533
|
pass("Compartment boundary ids resolve in the OpenCode session store");
|
|
41534
|
+
} else if (storeGeneration === "v2" && /\d/.test(storeHost.version)) {
|
|
41535
|
+
log2.info(`${dangling.length} compartment(s) point at OpenCode message ids that are not in the OpenCode 2 store. Magic Context places these from the neighbouring compartments; any it cannot place are listed as excluded from range recovery below.`);
|
|
41536
|
+
for (const boundary of dangling) {
|
|
41537
|
+
log2.info(` ${formatDanglingCompartmentBoundary(boundary)}`);
|
|
41538
|
+
}
|
|
41177
41539
|
} else {
|
|
41178
41540
|
warn(`${dangling.length} compartment(s) have dangling OpenCode boundary ids`);
|
|
41179
41541
|
for (const boundary of dangling) {
|
|
@@ -41182,11 +41544,11 @@ async function runDoctor2(options = {}) {
|
|
|
41182
41544
|
}
|
|
41183
41545
|
if (!supportsCoordinateGenerationReporting(contextDb)) {
|
|
41184
41546
|
log2.info("Store projection check: this context database predates the coordinate columns");
|
|
41185
|
-
} else if (!/\d/.test(
|
|
41547
|
+
} else if (!/\d/.test(storeHost.version)) {
|
|
41186
41548
|
log2.info("Store projection check: OpenCode reported no version, so the running projection is unknown");
|
|
41187
41549
|
} else {
|
|
41188
|
-
const pendingRebases = countPendingCoordinateRebases(contextDb,
|
|
41189
|
-
const pendingLine = formatPendingCoordinateRebases(pendingRebases,
|
|
41550
|
+
const pendingRebases = countPendingCoordinateRebases(contextDb, storeGeneration);
|
|
41551
|
+
const pendingLine = formatPendingCoordinateRebases(pendingRebases, storeGeneration);
|
|
41190
41552
|
if (pendingRebases.changed + pendingRebases.unrecorded === 0) {
|
|
41191
41553
|
pass(pendingLine);
|
|
41192
41554
|
} else {
|
|
@@ -41231,7 +41593,7 @@ async function runDoctor2(options = {}) {
|
|
|
41231
41593
|
pass(`OpenCode config: ${paths.opencodeConfig}`);
|
|
41232
41594
|
}
|
|
41233
41595
|
let autoUpdateEnabled = true;
|
|
41234
|
-
if (
|
|
41596
|
+
if (existsSync38(paths.magicContextConfig)) {
|
|
41235
41597
|
pass(`Magic Context config: ${paths.magicContextConfig}`);
|
|
41236
41598
|
try {
|
|
41237
41599
|
const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
|
|
@@ -41267,7 +41629,7 @@ async function runDoctor2(options = {}) {
|
|
|
41267
41629
|
warn(`No magic-context.jsonc found — using defaults`);
|
|
41268
41630
|
log2.info(" Run 'setup' to create one with model recommendations");
|
|
41269
41631
|
}
|
|
41270
|
-
if (
|
|
41632
|
+
if (existsSync38(paths.magicContextConfig)) {
|
|
41271
41633
|
try {
|
|
41272
41634
|
const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
|
|
41273
41635
|
if (!raw)
|
|
@@ -41466,7 +41828,7 @@ async function runDoctor2(options = {}) {
|
|
|
41466
41828
|
pass("Added TUI sidebar plugin to tui.json");
|
|
41467
41829
|
warn("Restart OpenCode to see the sidebar");
|
|
41468
41830
|
fixed++;
|
|
41469
|
-
} else if (
|
|
41831
|
+
} else if (existsSync38(paths.tuiConfig)) {
|
|
41470
41832
|
try {
|
|
41471
41833
|
const tuiRaw = readFileSync26(paths.tuiConfig, "utf-8");
|
|
41472
41834
|
const tuiConfig = import_comment_json11.parse(tuiRaw);
|
|
@@ -41506,7 +41868,7 @@ async function runDoctor2(options = {}) {
|
|
|
41506
41868
|
fail("Could not create or verify the TUI sidebar config");
|
|
41507
41869
|
}
|
|
41508
41870
|
}
|
|
41509
|
-
if (
|
|
41871
|
+
if (existsSync38(paths.magicContextConfig)) {
|
|
41510
41872
|
try {
|
|
41511
41873
|
const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
|
|
41512
41874
|
if (!raw)
|
|
@@ -41530,7 +41892,7 @@ async function runDoctor2(options = {}) {
|
|
|
41530
41892
|
const storage = getMagicContextStorageResolution();
|
|
41531
41893
|
const dbPath = join32(storage.path, "context.db");
|
|
41532
41894
|
log2.info(`Shared storage: ${storage.path} (source: ${storage.source})`);
|
|
41533
|
-
if (!
|
|
41895
|
+
if (!existsSync38(dbPath)) {
|
|
41534
41896
|
log2.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
|
|
41535
41897
|
} else {
|
|
41536
41898
|
log2.info(`Shared context DB exists at ${dbPath}`);
|
|
@@ -41577,25 +41939,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
41577
41939
|
fail(`SQLite integrity_check failed: ${err instanceof Error ? err.message : String(err)}
|
|
41578
41940
|
${formatDatabaseRepairGuidance(dbPath)}`);
|
|
41579
41941
|
}
|
|
41580
|
-
|
|
41581
|
-
const counts = {};
|
|
41582
|
-
for (const table of [
|
|
41583
|
-
"tags",
|
|
41584
|
-
"compartments",
|
|
41585
|
-
"memories",
|
|
41586
|
-
"notes",
|
|
41587
|
-
"dream_runs"
|
|
41588
|
-
]) {
|
|
41589
|
-
try {
|
|
41590
|
-
const row = db.prepare(`SELECT COUNT(*) as c FROM ${table}`).get();
|
|
41591
|
-
counts[table] = row?.c ?? 0;
|
|
41592
|
-
} catch {
|
|
41593
|
-
counts[table] = 0;
|
|
41594
|
-
}
|
|
41595
|
-
}
|
|
41596
|
-
const summary = Object.entries(counts).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
41597
|
-
log2.info(`Shared DB row counts: ${summary}`);
|
|
41598
|
-
} catch {}
|
|
41942
|
+
log2.info(`Shared DB row counts: ${formatSharedDbRowCounts(db)}`);
|
|
41599
41943
|
for (const stall of listShadowBackfillStalls(db)) {
|
|
41600
41944
|
warn(formatShadowBackfillStall(stall));
|
|
41601
41945
|
}
|
|
@@ -41664,6 +42008,10 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
41664
42008
|
fixed++;
|
|
41665
42009
|
if (v2Cache.issue)
|
|
41666
42010
|
issues++;
|
|
42011
|
+
const sharedDbVersion = readContextDbSchemaVersion(dbPath);
|
|
42012
|
+
if (sharedDbVersion !== null) {
|
|
42013
|
+
reportCachedPluginFences(compareCachedPluginFences(listCachedOpenCodePluginFences(), sharedDbVersion), { pass, fail, info: (message) => log2.info(message) });
|
|
42014
|
+
}
|
|
41667
42015
|
{
|
|
41668
42016
|
const ageWarnings = collectNpmReleaseAgeWarnings();
|
|
41669
42017
|
if (ageWarnings.length > 0) {
|
|
@@ -41676,7 +42024,11 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
41676
42024
|
issues++;
|
|
41677
42025
|
}
|
|
41678
42026
|
}
|
|
41679
|
-
const
|
|
42027
|
+
const logHarnesses = [
|
|
42028
|
+
...hostGeneration === "v1" ? ["opencode"] : [],
|
|
42029
|
+
...hostGeneration === "v2" || storeGeneration === "v2" ? ["opencode2"] : []
|
|
42030
|
+
];
|
|
42031
|
+
const logFiles = logHarnesses.flatMap((harness) => inspectMagicContextLogs(harness)).filter((file, index, all) => all.findIndex((other) => other.path === file.path) === index);
|
|
41680
42032
|
const existingLogFiles = logFiles.filter((file) => file.exists);
|
|
41681
42033
|
if (existingLogFiles.length === 0) {
|
|
41682
42034
|
log2.info(`No plugin log file yet; checked: ${logFiles.map((file) => file.path).join(", ")}`);
|
|
@@ -41724,7 +42076,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
41724
42076
|
}
|
|
41725
42077
|
return 0;
|
|
41726
42078
|
}
|
|
41727
|
-
var import_comment_json11, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
|
|
42079
|
+
var import_comment_json11, CLI_PACKAGE_NAME = "@cortexkit/magic-context", SHARED_DB_ROW_COUNT_TABLES;
|
|
41728
42080
|
var init_doctor_opencode = __esm(async () => {
|
|
41729
42081
|
init_config();
|
|
41730
42082
|
init_agent_disable();
|
|
@@ -41768,13 +42120,15 @@ var init_doctor_opencode = __esm(async () => {
|
|
|
41768
42120
|
init_storage_versions(),
|
|
41769
42121
|
init_v22_backfill_commands(),
|
|
41770
42122
|
init_doctor_authority(),
|
|
42123
|
+
init_doctor_cached_plugin_fence(),
|
|
41771
42124
|
init_doctor_harness_relabel()
|
|
41772
42125
|
]);
|
|
41773
42126
|
import_comment_json11 = __toESM(require_src3(), 1);
|
|
42127
|
+
SHARED_DB_ROW_COUNT_TABLES = ["tags", "compartments", "memories", "notes", "dream_runs"];
|
|
41774
42128
|
});
|
|
41775
42129
|
|
|
41776
42130
|
// src/lib/diagnostics-pi.ts
|
|
41777
|
-
import { existsSync as
|
|
42131
|
+
import { existsSync as existsSync39, readdirSync as readdirSync7, readFileSync as readFileSync27, statSync as statSync16 } from "node:fs";
|
|
41778
42132
|
import { createRequire as createRequire7 } from "node:module";
|
|
41779
42133
|
import { join as join33 } from "node:path";
|
|
41780
42134
|
function getSelfVersion3() {
|
|
@@ -41791,7 +42145,7 @@ function getSelfVersion3() {
|
|
|
41791
42145
|
}
|
|
41792
42146
|
function fileSize2(path) {
|
|
41793
42147
|
try {
|
|
41794
|
-
return
|
|
42148
|
+
return existsSync39(path) ? statSync16(path).size : 0;
|
|
41795
42149
|
} catch {
|
|
41796
42150
|
return 0;
|
|
41797
42151
|
}
|
|
@@ -41803,7 +42157,7 @@ function sanitizeValue2(value) {
|
|
|
41803
42157
|
return sanitizeConfigValue(value);
|
|
41804
42158
|
}
|
|
41805
42159
|
function readJsonc(path) {
|
|
41806
|
-
if (!
|
|
42160
|
+
if (!existsSync39(path))
|
|
41807
42161
|
return { value: {} };
|
|
41808
42162
|
try {
|
|
41809
42163
|
return {
|
|
@@ -41823,7 +42177,7 @@ function readConfigDiagnostic(path) {
|
|
|
41823
42177
|
const parsed = readJsonc(path);
|
|
41824
42178
|
return {
|
|
41825
42179
|
path,
|
|
41826
|
-
exists:
|
|
42180
|
+
exists: existsSync39(path),
|
|
41827
42181
|
...parsed.parseError ? { parseError: parsed.parseError } : {},
|
|
41828
42182
|
flags: sanitizeValue2(parsed.value)
|
|
41829
42183
|
};
|
|
@@ -41841,7 +42195,7 @@ function reverseSlugToDirectory(slug) {
|
|
|
41841
42195
|
}
|
|
41842
42196
|
function collectPiRecentSessions() {
|
|
41843
42197
|
const sessionsRoot = getPiSessionsRoot();
|
|
41844
|
-
if (!
|
|
42198
|
+
if (!existsSync39(sessionsRoot))
|
|
41845
42199
|
return [];
|
|
41846
42200
|
try {
|
|
41847
42201
|
const slugs = readdirSync7(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
@@ -41910,7 +42264,7 @@ function parseHistorianDumpMeta2(path) {
|
|
|
41910
42264
|
}
|
|
41911
42265
|
}
|
|
41912
42266
|
function listDumpsInDir2(dir, limit) {
|
|
41913
|
-
if (!
|
|
42267
|
+
if (!existsSync39(dir))
|
|
41914
42268
|
return { count: 0, recent: [] };
|
|
41915
42269
|
try {
|
|
41916
42270
|
const entries = readdirSync7(dir).filter((name) => name.endsWith(".xml")).map((name) => {
|
|
@@ -42004,7 +42358,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
42004
42358
|
piVersion: pi ? getPiVersion(pi.path) : null,
|
|
42005
42359
|
settings: {
|
|
42006
42360
|
path: settingsPath,
|
|
42007
|
-
exists:
|
|
42361
|
+
exists: existsSync39(settingsPath),
|
|
42008
42362
|
...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
|
|
42009
42363
|
hasMagicContextPackage: hasPiMagicContextPackage(packages),
|
|
42010
42364
|
packages: sanitizeValue2(packages)
|
|
@@ -42021,7 +42375,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
42021
42375
|
storageDir: {
|
|
42022
42376
|
path: storageDirPath,
|
|
42023
42377
|
source: storageResolution.source,
|
|
42024
|
-
exists:
|
|
42378
|
+
exists: existsSync39(storageDirPath),
|
|
42025
42379
|
contextDbSizeBytes: fileSize2(dbPath)
|
|
42026
42380
|
},
|
|
42027
42381
|
conflicts: {
|
|
@@ -42127,7 +42481,7 @@ var init_diagnostics_pi = __esm(() => {
|
|
|
42127
42481
|
|
|
42128
42482
|
// src/lib/logs-pi.ts
|
|
42129
42483
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "node:fs";
|
|
42130
|
-
import { dirname as
|
|
42484
|
+
import { dirname as dirname19, join as join34 } from "node:path";
|
|
42131
42485
|
function sanitizeLogContent2(content) {
|
|
42132
42486
|
return sanitizeString2(content);
|
|
42133
42487
|
}
|
|
@@ -42198,7 +42552,7 @@ async function bundleIssueReport2(report, description, title, options = {}) {
|
|
|
42198
42552
|
const cwd = options.cwd ?? process.cwd();
|
|
42199
42553
|
const timestamp = formatTimestamp2(options.now ?? new Date);
|
|
42200
42554
|
const path = options.outputPath ?? join34(cwd, `magic-context-pi-issue-${timestamp}.md`);
|
|
42201
|
-
mkdirSync10(
|
|
42555
|
+
mkdirSync10(dirname19(path), { recursive: true });
|
|
42202
42556
|
writeFileSync9(path, `${bodyMarkdown}
|
|
42203
42557
|
`);
|
|
42204
42558
|
const fullPath = truncated ? options.outputPath ? `${options.outputPath}.full.md` : join34(cwd, `magic-context-pi-issue-${timestamp}-full.md`) : undefined;
|
|
@@ -42215,10 +42569,10 @@ var init_logs_pi = __esm(() => {
|
|
|
42215
42569
|
|
|
42216
42570
|
// src/commands/doctor-pi.ts
|
|
42217
42571
|
import { execFileSync as execFileSync6, spawnSync as spawnSync9 } from "node:child_process";
|
|
42218
|
-
import { existsSync as
|
|
42572
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync11, readdirSync as readdirSync8, readFileSync as readFileSync28, rmSync as rmSync6, statSync as statSync17 } from "node:fs";
|
|
42219
42573
|
import { createRequire as createRequire8 } from "node:module";
|
|
42220
42574
|
import { homedir as homedir17 } from "node:os";
|
|
42221
|
-
import { dirname as
|
|
42575
|
+
import { dirname as dirname20, isAbsolute as isAbsolute8, join as join35 } from "node:path";
|
|
42222
42576
|
function depsFrom(options) {
|
|
42223
42577
|
return {
|
|
42224
42578
|
...DEFAULT_DEPS5,
|
|
@@ -42361,13 +42715,13 @@ function piPluginDirCandidates(packages, cwd) {
|
|
|
42361
42715
|
}
|
|
42362
42716
|
dirs.push(join35(agentDir, "npm", "node_modules", PACKAGE_NAME2));
|
|
42363
42717
|
dirs.push(join35(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2));
|
|
42364
|
-
return dirs.filter((dir) =>
|
|
42718
|
+
return dirs.filter((dir) => existsSync40(join35(dir, "package.json")));
|
|
42365
42719
|
}
|
|
42366
42720
|
function projectConfigPath(cwd) {
|
|
42367
42721
|
return resolveCortexKitProjectConfigPath(cwd);
|
|
42368
42722
|
}
|
|
42369
42723
|
function readConfigForEmbedding(path, isProjectConfig) {
|
|
42370
|
-
if (!
|
|
42724
|
+
if (!existsSync40(path))
|
|
42371
42725
|
return null;
|
|
42372
42726
|
try {
|
|
42373
42727
|
const raw = loadRawConfigFile({
|
|
@@ -42468,7 +42822,7 @@ function cacheRoots(cwd) {
|
|
|
42468
42822
|
function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
42469
42823
|
const found = new Map;
|
|
42470
42824
|
const visit = (path, depth) => {
|
|
42471
|
-
if (depth < 0 || !
|
|
42825
|
+
if (depth < 0 || !existsSync40(path))
|
|
42472
42826
|
return;
|
|
42473
42827
|
let stat;
|
|
42474
42828
|
try {
|
|
@@ -42479,7 +42833,7 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
|
42479
42833
|
if (!stat.isDirectory())
|
|
42480
42834
|
return;
|
|
42481
42835
|
const packageJson = join35(path, "package.json");
|
|
42482
|
-
if (
|
|
42836
|
+
if (existsSync40(packageJson)) {
|
|
42483
42837
|
try {
|
|
42484
42838
|
const pkg = JSON.parse(readFileSync28(packageJson, "utf-8"));
|
|
42485
42839
|
const name = typeof pkg.name === "string" ? pkg.name : "";
|
|
@@ -42546,7 +42900,7 @@ async function runHealthChecks2(options) {
|
|
|
42546
42900
|
}
|
|
42547
42901
|
const settingsPath = getPiUserExtensionsPath();
|
|
42548
42902
|
let packages = [];
|
|
42549
|
-
if (!
|
|
42903
|
+
if (!existsSync40(settingsPath)) {
|
|
42550
42904
|
add2(results, "fail", `Pi settings not found at ${settingsPath}`);
|
|
42551
42905
|
repairPlan.addPackageEntry = true;
|
|
42552
42906
|
} else {
|
|
@@ -42570,7 +42924,7 @@ async function runHealthChecks2(options) {
|
|
|
42570
42924
|
["user", userConfigPath, true],
|
|
42571
42925
|
["project", projectPath, false]
|
|
42572
42926
|
]) {
|
|
42573
|
-
if (!
|
|
42927
|
+
if (!existsSync40(path)) {
|
|
42574
42928
|
if (required) {
|
|
42575
42929
|
add2(results, "warn", `No ${label} magic-context.jsonc found at ${path}`);
|
|
42576
42930
|
if (userConfigMigrationRefused) {
|
|
@@ -42612,7 +42966,7 @@ async function runHealthChecks2(options) {
|
|
|
42612
42966
|
const storageDir = storage.path;
|
|
42613
42967
|
const dbPath = join35(storageDir, "context.db");
|
|
42614
42968
|
add2(results, "info", `Shared storage: ${storageDir} (source: ${storage.source})`);
|
|
42615
|
-
const existedBeforeOpen =
|
|
42969
|
+
const existedBeforeOpen = existsSync40(dbPath);
|
|
42616
42970
|
if (existedBeforeOpen)
|
|
42617
42971
|
add2(results, "pass", `Shared context DB exists at ${dbPath}`);
|
|
42618
42972
|
else
|
|
@@ -42830,7 +43184,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
42830
43184
|
return { results, repairPlan, ...summarize(results) };
|
|
42831
43185
|
}
|
|
42832
43186
|
function writeDefaultMagicContextConfig(path) {
|
|
42833
|
-
mkdirSync11(
|
|
43187
|
+
mkdirSync11(dirname20(path), { recursive: true });
|
|
42834
43188
|
const config = {
|
|
42835
43189
|
$schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
|
|
42836
43190
|
...MagicContextConfigSchema.parse({})
|
|
@@ -42852,7 +43206,7 @@ function repair2(plan, prompts) {
|
|
|
42852
43206
|
}
|
|
42853
43207
|
if (plan.writeUserConfig) {
|
|
42854
43208
|
const configPath = getPiUserConfigPath();
|
|
42855
|
-
if (!
|
|
43209
|
+
if (!existsSync40(configPath)) {
|
|
42856
43210
|
try {
|
|
42857
43211
|
writeDefaultMagicContextConfig(configPath);
|
|
42858
43212
|
prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
|
|
@@ -43104,7 +43458,7 @@ var init_doctor_pi = __esm(async () => {
|
|
|
43104
43458
|
});
|
|
43105
43459
|
|
|
43106
43460
|
// src/commands/doctor.ts
|
|
43107
|
-
import { existsSync as
|
|
43461
|
+
import { existsSync as existsSync41, rmSync as rmSync7 } from "node:fs";
|
|
43108
43462
|
import { join as join36 } from "node:path";
|
|
43109
43463
|
async function runDoctor4(options) {
|
|
43110
43464
|
if (options.clear)
|
|
@@ -43251,7 +43605,7 @@ async function runClear() {
|
|
|
43251
43605
|
failed += 1;
|
|
43252
43606
|
continue;
|
|
43253
43607
|
}
|
|
43254
|
-
} else if (
|
|
43608
|
+
} else if (existsSync41(item.path)) {
|
|
43255
43609
|
rmSync7(item.path, { recursive: true, force: true });
|
|
43256
43610
|
}
|
|
43257
43611
|
s.stop(`Cleared ${item.path}`);
|
|
@@ -43288,9 +43642,121 @@ var init_doctor = __esm(async () => {
|
|
|
43288
43642
|
});
|
|
43289
43643
|
|
|
43290
43644
|
// src/index.ts
|
|
43291
|
-
init_prompts();
|
|
43292
43645
|
import { createRequire as createRequire9 } from "node:module";
|
|
43293
43646
|
|
|
43647
|
+
// src/lib/cli-help.ts
|
|
43648
|
+
var HELP_FLAGS = new Set(["--help", "-h"]);
|
|
43649
|
+
function hasHelpFlag(args) {
|
|
43650
|
+
return args.some((arg) => HELP_FLAGS.has(arg));
|
|
43651
|
+
}
|
|
43652
|
+
var DOCTOR_SUBCOMMANDS_WITH_OWN_HELP = new Set([
|
|
43653
|
+
"migrate",
|
|
43654
|
+
"migrate-session",
|
|
43655
|
+
"repair-db"
|
|
43656
|
+
]);
|
|
43657
|
+
var HARNESS_LINES = [
|
|
43658
|
+
" Harness selection:",
|
|
43659
|
+
" --harness opencode Target OpenCode only",
|
|
43660
|
+
" --harness pi Target Pi only",
|
|
43661
|
+
" --harness omp Target Oh My Pi (OMP) only",
|
|
43662
|
+
" (default: auto-detect, prompt if multiple installed)"
|
|
43663
|
+
];
|
|
43664
|
+
var SETUP_HELP = [
|
|
43665
|
+
"",
|
|
43666
|
+
" Usage: magic-context setup [--harness opencode|pi|omp] [--dry-run]",
|
|
43667
|
+
"",
|
|
43668
|
+
" Interactive setup wizard: registers the Magic Context plugin with the",
|
|
43669
|
+
" selected harness and writes its Magic Context config.",
|
|
43670
|
+
"",
|
|
43671
|
+
" Options:",
|
|
43672
|
+
" --dry-run Preview the wizard without writing any files",
|
|
43673
|
+
...HARNESS_LINES,
|
|
43674
|
+
""
|
|
43675
|
+
].join(`
|
|
43676
|
+
`);
|
|
43677
|
+
var DOCTOR_HELP = [
|
|
43678
|
+
"",
|
|
43679
|
+
" Usage: magic-context doctor [options]",
|
|
43680
|
+
" magic-context doctor <subcommand> [options]",
|
|
43681
|
+
"",
|
|
43682
|
+
" Check the installed harnesses and fix configuration issues.",
|
|
43683
|
+
"",
|
|
43684
|
+
" Options:",
|
|
43685
|
+
" --fix Repair safe, Magic Context-owned store rows and clear an outdated OpenCode 2 plugin cache",
|
|
43686
|
+
" --force Force-clear the plugin cache",
|
|
43687
|
+
" --clear Interactive cache cleanup picker",
|
|
43688
|
+
" --issue Collect diagnostics and open a GitHub issue",
|
|
43689
|
+
" --report <path> Write the issue diagnostics to <path> without prompting",
|
|
43690
|
+
" --check-v22-backfill Show v22 memory backfill status",
|
|
43691
|
+
" --retry-v22-backfill Retry failed v22 memory backfill rows",
|
|
43692
|
+
" --rekey-v22-dir-identity <path> Re-key legacy dir identity rows",
|
|
43693
|
+
...HARNESS_LINES,
|
|
43694
|
+
"",
|
|
43695
|
+
" Subcommands (each accepts --help):",
|
|
43696
|
+
" drain-authority <project> Drain module memory/note authority back to TypeScript",
|
|
43697
|
+
" migrate Migrate an OpenCode session to Pi or OMP JSONL",
|
|
43698
|
+
" migrate-session Re-home an OpenCode session to another directory",
|
|
43699
|
+
" merge-identity Merge project rows between identities",
|
|
43700
|
+
" repair-db Back up and salvage a corrupted shared database",
|
|
43701
|
+
" list-hidden-sessions List Magic Context OpenCode 2 roots",
|
|
43702
|
+
""
|
|
43703
|
+
].join(`
|
|
43704
|
+
`);
|
|
43705
|
+
var DRAIN_AUTHORITY_HELP = [
|
|
43706
|
+
"",
|
|
43707
|
+
" Usage: magic-context doctor drain-authority <project>",
|
|
43708
|
+
"",
|
|
43709
|
+
" Drain the module's memory and note authority for <project> back to TypeScript.",
|
|
43710
|
+
""
|
|
43711
|
+
].join(`
|
|
43712
|
+
`);
|
|
43713
|
+
var MERGE_IDENTITY_HELP = [
|
|
43714
|
+
"",
|
|
43715
|
+
" Usage: magic-context doctor merge-identity --from <identity> --to <identity> [--dry-run] [--yes] [--db <path>]",
|
|
43716
|
+
"",
|
|
43717
|
+
" Merge every project-scoped row from one project identity into another.",
|
|
43718
|
+
"",
|
|
43719
|
+
" Options:",
|
|
43720
|
+
" --from <identity> Identity whose rows are moved",
|
|
43721
|
+
" --to <identity> Identity that receives them",
|
|
43722
|
+
" --dry-run Report what would change without writing",
|
|
43723
|
+
" --yes Confirm the write (required unless --dry-run)",
|
|
43724
|
+
" --db <path> Use this context.db instead of the shared one",
|
|
43725
|
+
""
|
|
43726
|
+
].join(`
|
|
43727
|
+
`);
|
|
43728
|
+
var LIST_HIDDEN_SESSIONS_HELP = [
|
|
43729
|
+
"",
|
|
43730
|
+
" Usage: magic-context doctor list-hidden-sessions",
|
|
43731
|
+
"",
|
|
43732
|
+
" List the hidden OpenCode 2 root sessions Magic Context reuses for its",
|
|
43733
|
+
" historian and dreamer runs. Read-only.",
|
|
43734
|
+
""
|
|
43735
|
+
].join(`
|
|
43736
|
+
`);
|
|
43737
|
+
function subcommandHelp(argv) {
|
|
43738
|
+
const [command, ...rest] = argv;
|
|
43739
|
+
if (!hasHelpFlag(rest))
|
|
43740
|
+
return null;
|
|
43741
|
+
if (command === "setup")
|
|
43742
|
+
return SETUP_HELP;
|
|
43743
|
+
if (command !== "doctor")
|
|
43744
|
+
return null;
|
|
43745
|
+
const subcommand = rest[0];
|
|
43746
|
+
if (subcommand === "drain-authority")
|
|
43747
|
+
return DRAIN_AUTHORITY_HELP;
|
|
43748
|
+
if (subcommand === "merge-identity")
|
|
43749
|
+
return MERGE_IDENTITY_HELP;
|
|
43750
|
+
if (subcommand === "list-hidden-sessions")
|
|
43751
|
+
return LIST_HIDDEN_SESSIONS_HELP;
|
|
43752
|
+
if (subcommand !== undefined && DOCTOR_SUBCOMMANDS_WITH_OWN_HELP.has(subcommand))
|
|
43753
|
+
return null;
|
|
43754
|
+
return DOCTOR_HELP;
|
|
43755
|
+
}
|
|
43756
|
+
|
|
43757
|
+
// src/index.ts
|
|
43758
|
+
init_prompts();
|
|
43759
|
+
|
|
43294
43760
|
// src/lib/sqlite-preflight.ts
|
|
43295
43761
|
async function probeSqliteBackend() {
|
|
43296
43762
|
await init_sqlite().then(() => ({}));
|
|
@@ -43300,7 +43766,7 @@ function formatSqlitePreflightFailure(error) {
|
|
|
43300
43766
|
return [
|
|
43301
43767
|
"Magic Context doctor cannot use SQLite in this runtime.",
|
|
43302
43768
|
`SQLite probe: ${detail}`,
|
|
43303
|
-
"Remediation: install Node.js >= 24 or use a Bun build with node:sqlite.",
|
|
43769
|
+
"Remediation: install Node.js 22.16+ (22.x) or >= 24, or use a Bun build with node:sqlite.",
|
|
43304
43770
|
"For Docker, use node:24-slim or a two-runtime image."
|
|
43305
43771
|
].join(`
|
|
43306
43772
|
`);
|
|
@@ -43367,6 +43833,7 @@ function printUsage() {
|
|
|
43367
43833
|
console.log(" (default: auto-detect, prompt if multiple installed)");
|
|
43368
43834
|
console.log("");
|
|
43369
43835
|
console.log(" Usage:");
|
|
43836
|
+
console.log(" npx @cortexkit/magic-context@latest <command> --help # help for one command");
|
|
43370
43837
|
console.log(" npx @cortexkit/magic-context@latest setup");
|
|
43371
43838
|
console.log(" # add --dry-run to preview the wizard without writing any files");
|
|
43372
43839
|
console.log(" npx @cortexkit/magic-context@latest doctor");
|
|
@@ -43386,6 +43853,11 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
43386
43853
|
}
|
|
43387
43854
|
const command = argv[0];
|
|
43388
43855
|
const rest = argv.slice(1);
|
|
43856
|
+
const help = subcommandHelp(argv);
|
|
43857
|
+
if (help !== null) {
|
|
43858
|
+
console.log(help);
|
|
43859
|
+
return 0;
|
|
43860
|
+
}
|
|
43389
43861
|
try {
|
|
43390
43862
|
if (command === "setup") {
|
|
43391
43863
|
await Promise.resolve().then(() => init_setup());
|