@cortexkit/magic-context 0.39.0 → 0.40.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.
Files changed (2) hide show
  1. package/dist/index.js +1109 -679
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -29680,7 +29680,7 @@ function expandConfigPath(value) {
29680
29680
  return `${homedir7()}/${trimmed.slice(2)}`;
29681
29681
  return trimmed;
29682
29682
  }
29683
- var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 90% for cache safety: output capacity is reserved from the usable context window, and the remaining 10% absorbs mid-turn growth before the absolute 95% emergency wall. Use a value between 20 and 90.", DEFAULT_HISTORIAN_TIMEOUT_MS = 600000, DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15, DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2", PiThinkingLevelSchema, PiConfigSchema, PromptSurfacePresetSchema, PromptSurfaceModelKeySchema, PromptSurfaceToolKeySchema, PromptSurfaceConfigSchema, PER_HARNESS_MIGRATION_INVENTORY, OcEntryObjectSchema, OcEntrySchema, PiEntryObjectSchema, PiEntrySchema, OpenCodeHarnessBlockSchema, PiHarnessBlockSchema, OpenCodeTaskExecutionSchema, PiTaskExecutionSchema, DreamerOpenCodeHarnessBlockSchema, DreamerPiHarnessBlockSchema, CronScheduleSchema, DreamTaskBaseConfigSchema, PromotionThresholdSchema, PrimerPromotionThresholdSchema, DreamTaskConfigSchema, ReviewUserMemoriesTaskConfigSchema, PromotePrimersTaskConfigSchema, DEFAULT_TASK_SCHEDULES2, DreamTasksSchema, AgentMetadataSchema, DreamerConfigSchema, SidekickConfigSchema, HistorianConfigSchema, EmbeddingFallbackProviderSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema;
29683
+ var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 90% for cache safety: output capacity is reserved from the usable context window, and the remaining 10% absorbs mid-turn growth before the absolute 95% emergency wall. Use a value between 20 and 90.", DEFAULT_HISTORIAN_TIMEOUT_MS = 600000, DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15, DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2", PiThinkingLevelSchema, PiConfigSchema, PromptSurfacePresetSchema, PromptSurfaceModelKeySchema, PromptSurfaceToolKeySchema, PromptSurfaceConfigSchema, PER_HARNESS_MIGRATION_INVENTORY, OcEntryObjectSchema, OcEntrySchema, PiEntryObjectSchema, PiEntrySchema, OpenCodeHarnessBlockSchema, PiHarnessBlockSchema, OpenCodeTaskExecutionSchema, PiTaskExecutionSchema, DreamerOpenCodeHarnessBlockSchema, DreamerPiHarnessBlockSchema, ProfileOpenCodeModelBlockSchema, ProfilePiModelBlockSchema, ProfileHistorianSchema, ProfileDreamerSchema, ProfileSidekickSchema, ConfigProfileSchema, ConfigProfilesSchema, CronScheduleSchema, DreamTaskBaseConfigSchema, PromotionThresholdSchema, PrimerPromotionThresholdSchema, DreamTaskConfigSchema, ReviewUserMemoriesTaskConfigSchema, PromotePrimersTaskConfigSchema, DEFAULT_TASK_SCHEDULES2, DreamTasksSchema, AgentMetadataSchema, DreamerConfigSchema, SidekickConfigSchema, HistorianConfigSchema, EmbeddingFallbackProviderSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema;
29684
29684
  var init_magic_context = __esm(() => {
29685
29685
  init_zod();
29686
29686
  init_language_directive();
@@ -29799,6 +29799,37 @@ var init_magic_context = __esm(() => {
29799
29799
  thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for the primary entry when it declares none. Fallback entries declare thinking levels per-entry."),
29800
29800
  tasks: exports_external.record(exports_external.string(), PiTaskExecutionSchema).optional().describe("Pi task execution overrides. Each named task accepts only model, fallback_models, thinking_level, and timeout_minutes.")
29801
29801
  }).strict().describe("Strict Pi dreamer model-resolution block. It accepts no OpenCode vocabulary.");
29802
+ ProfileOpenCodeModelBlockSchema = exports_external.object({
29803
+ model: OcEntrySchema.optional().describe("Primary OpenCode model entry."),
29804
+ fallback_models: exports_external.array(OcEntrySchema).optional().describe("Ordered fallback OpenCode model entries."),
29805
+ variant: exports_external.string().optional().describe("OpenCode reasoning variant for the primary model entry.")
29806
+ }).strict().describe("Strict profile-only OpenCode model-selection block.");
29807
+ ProfilePiModelBlockSchema = exports_external.object({
29808
+ model: PiEntrySchema.optional().describe("Primary Pi model entry."),
29809
+ fallback_models: exports_external.array(PiEntrySchema).optional().describe("Ordered fallback Pi model entries."),
29810
+ thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for the primary model entry.")
29811
+ }).strict().describe("Strict profile-only Pi model-selection block.");
29812
+ ProfileHistorianSchema = exports_external.object({
29813
+ opencode: ProfileOpenCodeModelBlockSchema.optional(),
29814
+ pi: ProfilePiModelBlockSchema.optional()
29815
+ }).strict();
29816
+ ProfileDreamerSchema = exports_external.object({
29817
+ opencode: ProfileOpenCodeModelBlockSchema.optional(),
29818
+ pi: ProfilePiModelBlockSchema.optional()
29819
+ }).strict();
29820
+ ProfileSidekickSchema = AgentOverrideConfigSchema.pick({
29821
+ model: true,
29822
+ fallback_models: true,
29823
+ variant: true
29824
+ }).extend({
29825
+ thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for the sidekick model selection.")
29826
+ }).strict();
29827
+ ConfigProfileSchema = exports_external.object({
29828
+ historian: ProfileHistorianSchema.optional(),
29829
+ dreamer: ProfileDreamerSchema.optional(),
29830
+ sidekick: ProfileSidekickSchema.optional()
29831
+ }).strict().describe("User-owned model-selection overlay. Only historian/dreamer harness model blocks and sidekick model-selection fields are allowed.");
29832
+ ConfigProfilesSchema = exports_external.record(exports_external.string().trim().min(1, "Profile names must not be empty or whitespace-only."), ConfigProfileSchema);
29802
29833
  CronScheduleSchema = exports_external.string().refine((s) => s.trim() === "" || isValidCron(s), {
29803
29834
  message: 'Invalid schedule: use a 5-field cron expression (e.g. "0 3 * * *" for 3am daily, "0 3 * * 0" for Sunday 3am, "0 */6 * * *" every 6h) or "" to disable.'
29804
29835
  }).describe('5-field cron schedule (e.g. "0 3 * * *"), or "" to disable this task.');
@@ -29973,6 +30004,8 @@ var init_magic_context = __esm(() => {
29973
30004
  transform_mode: exports_external.enum(["ts", "rust"]).default("ts").describe('Experimental: routes the entire Magic Context runtime for the project through the ck-mc Rust module over subc (requires user-level `subc` config); "ts" is the current TypeScript pipeline.'),
29974
30005
  auto_update: exports_external.boolean().optional().describe("Enable automatic npm self-update checks for the OpenCode plugin. Security: USER-only in config loader, so hostile project configs cannot suppress updates."),
29975
30006
  language: exports_external.string().trim().toLowerCase().refine((s) => isValidLanguageCode(s), 'language must be a 2-letter ISO 639-1 code (e.g. "tr", "es", "de")').optional().describe("Output language for Magic Context's generated content and guidance, as a " + '2-letter ISO 639-1 code (e.g. "tr", "es", "de", "ja", "pt"). When set, the ' + "historian, dreamer, sidekick, and the agent-guidance block instruct the model to " + "write its PROSE in this language while keeping all structural tokens (XML tags, " + "the five memory category names, code identifiers, file paths) in English. " + "USER-LEVEL ONLY (ignored in project config for security). Unset = today's " + "behavior (model mirrors the conversation; English scaffolding). Changing it " + "triggers one cache re-materialization; existing compartments/memories keep their " + "original language until naturally rewritten."),
30007
+ profile: exports_external.string().trim().min(1).optional().describe("Select a named user-owned model profile. A valid project name overrides this user default; an empty string, null, or other non-string project value is ignored with a warning so the user selection still applies. Unknown names warn and use the base configuration."),
30008
+ profiles: ConfigProfilesSchema.optional().describe("User-level named model profiles. A profile may contain only historian/dreamer model, fallback_models, OpenCode variant, and Pi thinking_level fields plus sidekick model-selection fields; task execution policy (including timeout_minutes) is excluded. Project configs may select a name but cannot define profiles."),
29976
30009
  historian: HistorianConfigSchema.describe("Historian metadata plus independent strict OpenCode and Pi execution blocks. Retained metadata stays at historian; model, fallback_models, variant, and thinking_level belong only in historian.opencode or historian.pi."),
29977
30010
  dreamer: DreamerConfigSchema.optional().describe("Dreamer metadata and scheduling plus independent strict OpenCode and Pi execution blocks. schedule and promotion_threshold stay at dreamer.tasks; model, fallback_models, variant, thinking_level, and timeout_minutes belong only in the matching harness block."),
29978
30011
  smart_notes: exports_external.object({
@@ -30075,6 +30108,72 @@ var init_magic_context = __esm(() => {
30075
30108
  });
30076
30109
  });
30077
30110
 
30111
+ // ../plugin/src/config/profiles.ts
30112
+ function withoutProfileFields(raw) {
30113
+ const copy = { ...raw };
30114
+ delete copy.profile;
30115
+ delete copy.profiles;
30116
+ return copy;
30117
+ }
30118
+ function readProfileSelection(raw) {
30119
+ if (!Object.hasOwn(raw, "profile"))
30120
+ return { declared: false };
30121
+ const value = raw.profile;
30122
+ if (typeof value !== "string")
30123
+ return { declared: true };
30124
+ const name = value.trim();
30125
+ return name.length > 0 ? { declared: true, name } : { declared: true };
30126
+ }
30127
+ function resolveConfigProfile(args) {
30128
+ const warnings = [];
30129
+ const userSelection = readProfileSelection(args.userRaw);
30130
+ const projectSelection = readProfileSelection(args.projectRaw);
30131
+ const selection = projectSelection.name ? { name: projectSelection.name, source: "project" } : userSelection.name ? { name: userSelection.name, source: "user" } : undefined;
30132
+ if (projectSelection.declared && !projectSelection.name) {
30133
+ warnings.push("Ignoring invalid profile selection from project config; expected a non-empty string.");
30134
+ }
30135
+ if (!projectSelection.declared && userSelection.declared && !userSelection.name) {
30136
+ warnings.push("Ignoring invalid profile selection from user config; expected a non-empty string.");
30137
+ }
30138
+ let profiles = {};
30139
+ if (Object.hasOwn(args.userRaw, "profiles")) {
30140
+ const parsed = ConfigProfilesSchema.safeParse(args.userRaw.profiles);
30141
+ if (parsed.success) {
30142
+ profiles = parsed.data;
30143
+ } else {
30144
+ warnings.push("Ignoring profiles from user config: invalid profile configuration; profiles may contain only historian/dreamer harness model blocks and sidekick model-selection fields.");
30145
+ }
30146
+ }
30147
+ if (!selection) {
30148
+ return {
30149
+ userBase: withoutProfileFields(args.userRaw),
30150
+ projectBase: withoutProfileFields(args.projectRaw),
30151
+ overlay: {},
30152
+ warnings
30153
+ };
30154
+ }
30155
+ if (!Object.hasOwn(profiles, selection.name)) {
30156
+ warnings.push(`Unknown profile "${selection.name}" selected by ${selection.source} config; using base config without a profile.`);
30157
+ return {
30158
+ userBase: withoutProfileFields(args.userRaw),
30159
+ projectBase: withoutProfileFields(args.projectRaw),
30160
+ overlay: {},
30161
+ warnings
30162
+ };
30163
+ }
30164
+ const overlay = profiles[selection.name];
30165
+ return {
30166
+ userBase: withoutProfileFields(args.userRaw),
30167
+ projectBase: withoutProfileFields(args.projectRaw),
30168
+ overlay,
30169
+ activeProfile: selection.name,
30170
+ warnings
30171
+ };
30172
+ }
30173
+ var init_profiles = __esm(() => {
30174
+ init_magic_context();
30175
+ });
30176
+
30078
30177
  // ../plugin/src/config/project-security.ts
30079
30178
  function isPlainObject2(value) {
30080
30179
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -30204,6 +30303,10 @@ function makeProjectThresholdWarning(field, reason) {
30204
30303
  }
30205
30304
  function stripUnsafeProjectConfigFields(projectRaw) {
30206
30305
  const warnings = [];
30306
+ if ("profiles" in projectRaw) {
30307
+ delete projectRaw.profiles;
30308
+ warnings.push("Ignoring profiles from project config (security: profile definitions are user-level only; a repository may select a named user profile with profile).");
30309
+ }
30207
30310
  if ("auto_update" in projectRaw) {
30208
30311
  delete projectRaw.auto_update;
30209
30312
  warnings.push("Ignoring auto_update from project config (security: this setting only honors user-level config).");
@@ -30923,8 +31026,6 @@ function loadPluginConfigDetailed(directory) {
30923
31026
  const userLoaded = userDetected.format !== "none" ? loadConfigFileDetailed(userDetected.path, "user") : userLegacyFallback.source ? loadConfigFileDetailed(userLegacyFallback.source.path, "user") : null;
30924
31027
  const projectLoaded = projectDetected.format !== "none" ? loadConfigFileDetailed(projectDetected.path, "project") : projectLegacyFallback.source ? loadConfigFileDetailed(projectLegacyFallback.source.path, "project") : null;
30925
31028
  const allWarnings = [];
30926
- let mergedRaw = {};
30927
- const trustedBaseConfig = parsePluginConfig(userLoaded?.config ?? {});
30928
31029
  if (userLegacyFallback.source) {
30929
31030
  allWarnings.push(`[user config] reading legacy config from ${userLegacyFallback.source.path} until migration completes; run \`npx @cortexkit/magic-context doctor\` to consolidate into the shared CortexKit location.`);
30930
31031
  } else if (legacyUserUnmigrated) {
@@ -30937,21 +31038,31 @@ function loadPluginConfigDetailed(directory) {
30937
31038
  }
30938
31039
  if (userLoaded) {
30939
31040
  allWarnings.push(...userLoaded.warnings.map((w) => `[user config] ${w}`));
30940
- mergedRaw = deepMergeRawConfig(mergedRaw, userLoaded.config);
30941
31041
  }
31042
+ let projectRaw = {};
30942
31043
  if (projectLoaded) {
30943
31044
  allWarnings.push(...projectLoaded.warnings.map((w) => `[project config] ${w}`));
30944
- const projectRaw = { ...projectLoaded.config };
31045
+ projectRaw = { ...projectLoaded.config };
30945
31046
  for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
30946
31047
  allWarnings.push(`[project config] ${warning}`);
30947
31048
  }
30948
- mergedRaw = deepMergeRawConfig(mergedRaw, projectRaw);
30949
- for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, userLoaded?.config)) {
31049
+ }
31050
+ const profileResolution = resolveConfigProfile({
31051
+ userRaw: userLoaded?.config ?? {},
31052
+ projectRaw
31053
+ });
31054
+ allWarnings.push(...profileResolution.warnings.map((warning) => `[config] ${warning}`));
31055
+ const trustedProfiledRaw = deepMergeRawConfig(profileResolution.userBase, profileResolution.overlay);
31056
+ let mergedRaw = trustedProfiledRaw;
31057
+ const trustedBaseConfig = parsePluginConfig(trustedProfiledRaw);
31058
+ if (projectLoaded) {
31059
+ mergedRaw = deepMergeRawConfig(mergedRaw, profileResolution.projectBase);
31060
+ for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, profileResolution.userBase)) {
30950
31061
  allWarnings.push(`[project config] ${warning}`);
30951
31062
  }
30952
31063
  for (const warning of constrainProjectThresholdOverrides({
30953
31064
  mergedRaw,
30954
- projectRaw,
31065
+ projectRaw: profileResolution.projectBase,
30955
31066
  trustedBaseConfig
30956
31067
  })) {
30957
31068
  allWarnings.push(`[project config] ${warning}`);
@@ -30959,6 +31070,8 @@ function loadPluginConfigDetailed(directory) {
30959
31070
  }
30960
31071
  const recoveredTopLevelKeys = [];
30961
31072
  const config2 = parsePluginConfig(mergedRaw, recoveredTopLevelKeys);
31073
+ if (profileResolution.activeProfile)
31074
+ config2.profile = profileResolution.activeProfile;
30962
31075
  setOutputReserveConfig(config2.output_reserve);
30963
31076
  setWindowOverlayPath(config2.models?.window_overlay_path);
30964
31077
  if (config2.configWarnings?.length) {
@@ -31006,6 +31119,7 @@ var init_config = __esm(() => {
31006
31119
  init_agent_disable();
31007
31120
  init_migrate_config_location();
31008
31121
  init_migrate_dreamer_v2();
31122
+ init_profiles();
31009
31123
  init_project_security();
31010
31124
  init_raw_loader();
31011
31125
  init_magic_context();
@@ -35166,6 +35280,17 @@ function readPsProcessStartTime(pid) {
35166
35280
  return null;
35167
35281
  }
35168
35282
  }
35283
+ function readProcessStartTime(pid) {
35284
+ if (!Number.isInteger(pid) || pid <= 0)
35285
+ return null;
35286
+ return rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(pid) : rpcIdentityPlatform === "win32" ? null : readPsProcessStartTime(pid);
35287
+ }
35288
+ function readProcessProbeEvidence(pid) {
35289
+ return {
35290
+ startTime: readProcessStartTime(pid),
35291
+ commandLine: readProcessCommand(pid)
35292
+ };
35293
+ }
35169
35294
  function parseCsvLine(line) {
35170
35295
  const fields = [];
35171
35296
  let field = "";
@@ -35298,16 +35423,16 @@ function commandLooksLikeOpenCode(command) {
35298
35423
  const normalized = command.toLowerCase();
35299
35424
  return OPEN_CODE_COMMAND_MARKERS.some((marker) => normalized.includes(marker));
35300
35425
  }
35301
- function isPidIdentityPlausible(record2) {
35426
+ function isPidIdentityPlausible(record2, evidence) {
35302
35427
  if (!Number.isInteger(record2.pid) || record2.pid <= 0)
35303
35428
  return "implausible";
35304
35429
  if (Number.isFinite(record2.started_at) && record2.started_at > 0) {
35305
- const processStartTime = rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(record2.pid) : rpcIdentityPlatform === "win32" ? null : readPsProcessStartTime(record2.pid);
35430
+ const processStartTime = evidence ? evidence.startTime : readProcessStartTime(record2.pid);
35306
35431
  if (processStartTime === null)
35307
35432
  return "inconclusive";
35308
35433
  return processStartTime <= record2.started_at + RPC_IDENTITY_SKEW_TOLERANCE_MS ? "plausible" : "implausible";
35309
35434
  }
35310
- const command = rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(record2.pid) : rpcIdentityPlatform === "win32" ? readWindowsProcess(record2.pid).command ?? null : readPsProcessCommand(record2.pid);
35435
+ const command = evidence ? evidence.commandLine : rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(record2.pid) : rpcIdentityPlatform === "win32" ? readWindowsProcess(record2.pid).command ?? null : readPsProcessCommand(record2.pid);
35311
35436
  if (command === null)
35312
35437
  return "inconclusive";
35313
35438
  return commandLooksLikeOpenCode(command) ? "plausible" : "implausible";
@@ -35371,9 +35496,6 @@ function inspectLivePiProcesses() {
35371
35496
  };
35372
35497
  }
35373
35498
  }
35374
- function discoverLivePiProcessIds() {
35375
- return inspectLivePiProcesses().processIds;
35376
- }
35377
35499
  function parseRpcPortFile(content, fallbackPid = 0) {
35378
35500
  const trimmed = content.trim();
35379
35501
  if (!trimmed)
@@ -35417,177 +35539,500 @@ var init_rpc_utils = __esm(() => {
35417
35539
  rpcProcessListExecFileSync = execFileSync4;
35418
35540
  rpcIdentityPlatform = process.platform;
35419
35541
  });
35420
- // ../plugin/src/hooks/magic-context/compartment-parser.ts
35421
- function makeTierOpenRegex(n2) {
35422
- return new RegExp(`<p${n2}\\s*(/?)>`);
35542
+ // ../plugin/src/shared/redaction.ts
35543
+ import { homedir as homedir12, userInfo } from "node:os";
35544
+ function escapeRegex2(value) {
35545
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
35423
35546
  }
35424
- function extractTier(inner, index) {
35425
- const openMatch = TIER_OPEN_REGEXES[index].exec(inner);
35426
- if (!openMatch)
35427
- return;
35428
- if (openMatch[1] === "/")
35429
- return "";
35430
- const rest = inner.slice(openMatch.index + openMatch[0].length);
35431
- const closeAt = rest.search(TIER_CLOSE_ANY_REGEX);
35432
- let body = closeAt === -1 ? rest : rest.slice(0, closeAt);
35433
- const openInside = body.search(TIER_OPEN_ANY_REGEX);
35434
- if (openInside !== -1)
35435
- body = body.slice(0, openInside);
35436
- return unescapeXml(body.trim());
35547
+ function redactionTypeForKey(key) {
35548
+ const normalized = key.trim().toLowerCase().replace(/[^a-z0-9_.-]+/g, "_");
35549
+ const suffix = normalized.split(".").filter(Boolean).at(-1) ?? normalized;
35550
+ return suffix || "secret";
35437
35551
  }
35438
- function extractTiersFromInner(inner) {
35439
- return {
35440
- p1: extractTier(inner, 0),
35441
- p2: extractTier(inner, 1),
35442
- p3: extractTier(inner, 2),
35443
- p4: extractTier(inner, 3)
35444
- };
35552
+ function isNonSecretScalarValue(value) {
35553
+ const v = value.trim();
35554
+ if (v === "true" || v === "false" || v === "null" || v === "undefined")
35555
+ return true;
35556
+ return /^[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(v);
35445
35557
  }
35446
- function parseCompartmentOutput(text3) {
35447
- const compartments = [];
35448
- const facts = [];
35449
- for (const match of text3.matchAll(COMPARTMENT_REGEX)) {
35450
- const attrs = match[1];
35451
- const inner = match[2];
35452
- const startMatch = attrs.match(ATTR_START_REGEX);
35453
- const endMatch = attrs.match(ATTR_END_REGEX);
35454
- const titleMatch = attrs.match(ATTR_TITLE_REGEX);
35455
- if (!startMatch || !endMatch || !titleMatch)
35456
- continue;
35457
- const startMessage = parseInt(startMatch[1], 10);
35458
- const endMessage = parseInt(endMatch[1], 10);
35459
- const title = unescapeXml(titleMatch[1]);
35460
- if (Number.isNaN(startMessage) || Number.isNaN(endMessage) || !title)
35461
- continue;
35462
- const episodeMatch = attrs.match(ATTR_EPISODE_REGEX);
35463
- const importanceMatch = attrs.match(ATTR_IMPORTANCE_REGEX);
35464
- const episodeType = episodeMatch ? unescapeXml(episodeMatch[1]) : undefined;
35465
- const importance = importanceMatch ? parseInt(importanceMatch[1], 10) : undefined;
35466
- const p1 = extractTier(inner, 0);
35467
- if (typeof p1 === "string" && p1.length > 0) {
35468
- const p2 = extractTier(inner, 1);
35469
- const p3 = extractTier(inner, 2);
35470
- const p4 = extractTier(inner, 3);
35471
- compartments.push({
35472
- startMessage,
35473
- endMessage,
35474
- title,
35475
- content: p1,
35476
- p1,
35477
- p2: typeof p2 === "string" ? p2 : p1,
35478
- p3: typeof p3 === "string" ? p3 : typeof p2 === "string" ? p2 : p1,
35479
- p4: typeof p4 === "string" ? p4 : "",
35480
- importance,
35481
- episodeType
35482
- });
35558
+ function isSecretKey(key) {
35559
+ const segments = key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().split(/[._-]+/).filter(Boolean);
35560
+ if (segments.length === 0)
35561
+ return false;
35562
+ if (segments.length === 1) {
35563
+ const first = segments[0];
35564
+ return Boolean(first && SECRET_SEGMENT_PATTERN.test(first));
35565
+ }
35566
+ for (let i2 = 0;i2 < segments.length; i2++) {
35567
+ const seg = segments[i2];
35568
+ if (!seg || !SECRET_SEGMENT_PATTERN.test(seg))
35483
35569
  continue;
35570
+ let trailingOk = true;
35571
+ for (let j = i2 + 1;j < segments.length; j++) {
35572
+ const tail = segments[j];
35573
+ if (!tail)
35574
+ continue;
35575
+ if (TRAILING_DESCRIPTORS.has(tail))
35576
+ continue;
35577
+ if (SECRET_SEGMENT_PATTERN.test(tail))
35578
+ continue;
35579
+ trailingOk = false;
35580
+ break;
35484
35581
  }
35485
- const content = unescapeXml(inner.trim());
35486
- if (content) {
35487
- compartments.push({
35488
- startMessage,
35489
- endMessage,
35490
- title,
35491
- content,
35492
- importance,
35493
- episodeType
35494
- });
35495
- }
35496
- }
35497
- const factsBlockMatch = text3.match(FACTS_BLOCK_REGEX);
35498
- const factsScope = factsBlockMatch ? factsBlockMatch[1] : text3.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "");
35499
- for (const categoryMatch of factsScope.matchAll(CATEGORY_BLOCK_REGEX)) {
35500
- const category = categoryMatch[1];
35501
- const blockContent = categoryMatch[2];
35502
- for (const itemMatch of blockContent.matchAll(FACT_ITEM_REGEX)) {
35503
- const content = unescapeXml(itemMatch[1].trim());
35504
- if (content) {
35505
- facts.push({ category, content });
35506
- }
35582
+ if (!trailingOk)
35583
+ continue;
35584
+ for (let k = i2 - 1;k >= 0; k--) {
35585
+ const lead = segments[k];
35586
+ if (lead && SECRET_QUALIFIERS.has(lead))
35587
+ return true;
35507
35588
  }
35508
35589
  }
35509
- const unprocessedMatch = text3.match(UNPROCESSED_REGEX);
35510
- const unprocessedFrom = unprocessedMatch ? parseInt(unprocessedMatch[1], 10) : null;
35511
- const userObservations = [];
35512
- const userObsMatch = text3.match(USER_OBSERVATIONS_REGEX);
35513
- if (userObsMatch) {
35514
- for (const itemMatch of userObsMatch[1].matchAll(USER_OBS_ITEM_REGEX)) {
35515
- const obs = unescapeXml(itemMatch[1].trim());
35516
- if (obs)
35517
- userObservations.push(obs);
35518
- }
35590
+ return false;
35591
+ }
35592
+ function sanitizePathString(value) {
35593
+ const home = homedir12();
35594
+ const username = userInfo().username;
35595
+ let sanitized = value;
35596
+ if (home) {
35597
+ sanitized = sanitized.replace(new RegExp(escapeRegex2(home), "g"), "~");
35519
35598
  }
35520
- const primerCandidates = [];
35521
- const primerMatch = text3.match(PRIMER_CANDIDATES_REGEX);
35522
- if (primerMatch) {
35523
- const block2 = primerMatch[1];
35524
- let sawElement = false;
35525
- for (const el of block2.matchAll(PRIMER_ELEMENT_REGEX)) {
35526
- sawElement = true;
35527
- const question = unescapeXml(el[2].trim());
35528
- if (question) {
35529
- primerCandidates.push({
35530
- question,
35531
- originCompartmentIndex: Number.parseInt(el[1], 10)
35532
- });
35533
- }
35534
- }
35535
- if (!sawElement) {
35536
- for (const itemMatch of block2.matchAll(PRIMER_ITEM_REGEX)) {
35537
- const question = unescapeXml(itemMatch[1].trim());
35538
- if (question)
35539
- primerCandidates.push({ question });
35540
- }
35541
- }
35599
+ sanitized = sanitized.replace(/\/Users\/[^/]+\//g, "/Users/<USER>/");
35600
+ sanitized = sanitized.replace(/\/home\/[^/]+\//g, "/home/<USER>/");
35601
+ sanitized = sanitized.replace(/C:\\Users\\[^\\]+\\/g, "C:\\Users\\<USER>\\");
35602
+ if (username) {
35603
+ sanitized = sanitized.replace(new RegExp(escapeRegex2(username), "g"), "<USER>");
35542
35604
  }
35543
- const events = parseEvents(text3);
35544
- compartments.sort((a3, b) => a3.startMessage - b.startMessage);
35545
- return { compartments, facts, events, unprocessedFrom, userObservations, primerCandidates };
35605
+ return sanitized;
35546
35606
  }
35547
- function parseEvents(text3) {
35548
- const blockMatch = text3.match(EVENTS_BLOCK_REGEX);
35549
- if (!blockMatch)
35550
- return [];
35551
- const block2 = blockMatch[1];
35552
- const events = [];
35553
- for (const elMatch of block2.matchAll(EVENT_ELEMENT_REGEX)) {
35554
- const kind = elMatch[1];
35555
- const atRaw = parseInt(elMatch[2], 10);
35556
- const atCompartment = Number.isNaN(atRaw) ? null : atRaw;
35557
- const fields = {};
35558
- for (const fieldMatch of elMatch[3].matchAll(EVENT_FIELD_REGEX)) {
35559
- const name = fieldMatch[1];
35560
- const value = unescapeXml(fieldMatch[2].trim());
35561
- if (value)
35562
- fields[name] = value;
35607
+ function redactSecretText(value) {
35608
+ let redacted = value;
35609
+ for (const { pattern, replacement } of SECRET_TEXT_PATTERNS) {
35610
+ if (typeof replacement === "string") {
35611
+ redacted = redacted.replace(pattern, replacement);
35612
+ } else {
35613
+ redacted = redacted.replace(pattern, replacement);
35563
35614
  }
35564
- events.push({ kind, atCompartment, fields });
35565
35615
  }
35566
- return events;
35616
+ return redacted;
35567
35617
  }
35568
- function unescapeXml(s) {
35569
- return s.replace(/&amp;/g, "&").replace(/&apos;/g, "'").replace(/&quot;/g, '"').replace(/&lt;/g, "<").replace(/&gt;/g, ">");
35618
+ function sanitizeDiagnosticText(value) {
35619
+ return redactSecretText(sanitizePathString(value));
35570
35620
  }
35571
- 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;
35572
- var init_compartment_parser = __esm(() => {
35573
- COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
35574
- ATTR_START_REGEX = /\bstart="(\d+)"/;
35575
- ATTR_END_REGEX = /\bend="(\d+)"/;
35576
- ATTR_TITLE_REGEX = /\btitle="([^"]*)"/;
35577
- ATTR_EPISODE_REGEX = /\bepisode_type="([^"]*)"/;
35578
- ATTR_IMPORTANCE_REGEX = /\bimportance="(\d+)"/;
35579
- TIER_OPEN_REGEXES = [
35580
- makeTierOpenRegex(1),
35581
- makeTierOpenRegex(2),
35582
- makeTierOpenRegex(3),
35583
- makeTierOpenRegex(4)
35584
- ];
35585
- TIER_CLOSE_ANY_REGEX = /<\/p\d/;
35586
- TIER_OPEN_ANY_REGEX = /<p\d/;
35587
- CATEGORY_BLOCK_REGEX = /<(PROJECT_RULES|ARCHITECTURE|CONSTRAINTS|CONFIG_VALUES|NAMING)>(.*?)<\/\1>/gs;
35588
- FACT_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
35589
- UNPROCESSED_REGEX = /<unprocessed_from>(\d+)<\/unprocessed_from>/;
35590
- USER_OBSERVATIONS_REGEX = /<user_observations>(.*?)<\/user_observations>/s;
35621
+ function sanitizeConfigValue(value, keyPath = []) {
35622
+ if (value === null || typeof value === "number" || typeof value === "boolean")
35623
+ return value;
35624
+ const key = keyPath.at(-1) ?? "";
35625
+ if (key && isSecretKey(key)) {
35626
+ return `<REDACTED:${redactionTypeForKey(key)}>`;
35627
+ }
35628
+ if (typeof value === "string")
35629
+ return sanitizeDiagnosticText(value);
35630
+ if (Array.isArray(value)) {
35631
+ return value.map((entry, index) => sanitizeConfigValue(entry, [...keyPath, String(index)]));
35632
+ }
35633
+ if (value && typeof value === "object") {
35634
+ return Object.fromEntries(Object.entries(value).map(([entryKey, entry]) => [
35635
+ entryKey,
35636
+ sanitizeConfigValue(entry, [...keyPath, entryKey])
35637
+ ]));
35638
+ }
35639
+ return value;
35640
+ }
35641
+ var SECRET_WORDS, SECRET_SEGMENT_PATTERN, TRAILING_DESCRIPTORS, SECRET_QUALIFIERS, SECRET_TEXT_PATTERNS;
35642
+ var init_redaction = __esm(() => {
35643
+ SECRET_WORDS = [
35644
+ "key",
35645
+ "token",
35646
+ "secret",
35647
+ "password",
35648
+ "auth",
35649
+ "authorization",
35650
+ "bearer",
35651
+ "credential"
35652
+ ];
35653
+ SECRET_SEGMENT_PATTERN = new RegExp(`^(?:${SECRET_WORDS.map((w) => `${w}s?`).join("|")})$`, "i");
35654
+ TRAILING_DESCRIPTORS = new Set(["id", "ids", "value", "values", "header", "headers"]);
35655
+ SECRET_QUALIFIERS = new Set([
35656
+ "api",
35657
+ "access",
35658
+ "private",
35659
+ "client",
35660
+ "auth",
35661
+ "authorization",
35662
+ "secret",
35663
+ "bearer",
35664
+ "session",
35665
+ "refresh",
35666
+ "service",
35667
+ "x",
35668
+ "openai",
35669
+ "anthropic",
35670
+ "google",
35671
+ "github",
35672
+ "huggingface",
35673
+ "aws",
35674
+ "azure"
35675
+ ]);
35676
+ SECRET_TEXT_PATTERNS = [
35677
+ {
35678
+ pattern: /\bsk-ant-(?:api03-)?[A-Za-z0-9_-]{32,}/g,
35679
+ replacement: "<ANTHROPIC_API_KEY_REDACTED>"
35680
+ },
35681
+ {
35682
+ pattern: /\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/g,
35683
+ replacement: "<OPENAI_API_KEY_REDACTED>"
35684
+ },
35685
+ {
35686
+ pattern: /\bgithub_pat_[A-Za-z0-9_]{20,}/g,
35687
+ replacement: "<GITHUB_PAT_REDACTED>"
35688
+ },
35689
+ {
35690
+ pattern: /\b(?:gh[opsu]|ghr)_[A-Za-z0-9]{30,}/g,
35691
+ replacement: "<GITHUB_TOKEN_REDACTED>"
35692
+ },
35693
+ {
35694
+ pattern: /\bhf_[A-Za-z0-9]{30,}/g,
35695
+ replacement: "<HUGGINGFACE_TOKEN_REDACTED>"
35696
+ },
35697
+ {
35698
+ pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
35699
+ replacement: "<AWS_ACCESS_KEY_ID_REDACTED>"
35700
+ },
35701
+ {
35702
+ pattern: /\bxox[abprsuvc]-[A-Za-z0-9-]{10,}/g,
35703
+ replacement: "<SLACK_TOKEN_REDACTED>"
35704
+ },
35705
+ {
35706
+ pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g,
35707
+ replacement: "<GOOGLE_API_KEY_REDACTED>"
35708
+ },
35709
+ {
35710
+ pattern: /\b(Authorization\s*:\s*Bearer\s+)([A-Za-z0-9._~+/=-]{8,})/gi,
35711
+ replacement: (_full, prefix) => `${prefix}<REDACTED:bearer>`
35712
+ },
35713
+ {
35714
+ pattern: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
35715
+ replacement: "<JWT_REDACTED>"
35716
+ },
35717
+ {
35718
+ pattern: /(["'])([^"']*(?:key|token|secret|password|auth|bearer|credential)[^"']*)\1(\s*:\s*)(["'])([^"']*)\4/gi,
35719
+ replacement: (full, quote, key, separator, valueQuote, value) => isNonSecretScalarValue(value) ? full : `${quote}${key}${quote}${separator}${valueQuote}<REDACTED:${redactionTypeForKey(key)}>${valueQuote}`
35720
+ },
35721
+ {
35722
+ pattern: /\b([A-Za-z0-9_.-]*(?:key|token|secret|password|auth|bearer|credential)[A-Za-z0-9_.-]*)\s*=\s*([^\s'"`]+)/gi,
35723
+ replacement: (full, key, value) => isNonSecretScalarValue(value) ? full : `${key}=<REDACTED:${redactionTypeForKey(key)}>`
35724
+ }
35725
+ ];
35726
+ });
35727
+
35728
+ // ../plugin/src/features/magic-context/fail-closed-block.ts
35729
+ function attachFailClosedBlockingProcessEvidence(process3, evidence) {
35730
+ Object.defineProperties(process3, {
35731
+ startTime: { configurable: true, value: evidence.startTime },
35732
+ commandLine: { configurable: true, value: evidence.commandLine }
35733
+ });
35734
+ return process3;
35735
+ }
35736
+ function normalizeFailClosedProcessKind(process3) {
35737
+ switch (process3.kind) {
35738
+ case "OpenCode server":
35739
+ case "OpenCode instance (TUI/CLI)":
35740
+ case "Pi":
35741
+ case "process":
35742
+ return process3.kind;
35743
+ }
35744
+ switch (process3.harness?.trim().toLowerCase()) {
35745
+ case "opencode server":
35746
+ return "OpenCode server";
35747
+ case "opencode instance (tui/cli)":
35748
+ case "opencode instance":
35749
+ return "OpenCode instance (TUI/CLI)";
35750
+ case "pi":
35751
+ case "pi harness":
35752
+ case "omp":
35753
+ return "Pi";
35754
+ default:
35755
+ return "process";
35756
+ }
35757
+ }
35758
+ function formatFailClosedProcessStartTime(startTime) {
35759
+ if (!Number.isFinite(startTime) || startTime <= 0)
35760
+ return "unverified";
35761
+ try {
35762
+ const parts = new Intl.DateTimeFormat("en-US", {
35763
+ day: "numeric",
35764
+ hour: "2-digit",
35765
+ minute: "2-digit",
35766
+ month: "short",
35767
+ hour12: false
35768
+ }).formatToParts(new Date(startTime));
35769
+ const values = Object.fromEntries(parts.map(({ type, value }) => [type, value]));
35770
+ if (!values.month || !values.day || !values.hour || !values.minute)
35771
+ return "unverified";
35772
+ return `${values.month} ${values.day} ${values.hour}:${values.minute}`;
35773
+ } catch {
35774
+ return "unverified";
35775
+ }
35776
+ }
35777
+ function formatFailClosedCommandLine(commandLine) {
35778
+ if (typeof commandLine !== "string" || commandLine.trim().length === 0)
35779
+ return "unverified";
35780
+ try {
35781
+ const normalized = commandLine.replaceAll("\x00", " ").replace(/\s+/g, " ").trim();
35782
+ if (normalized.length === 0)
35783
+ return "unverified";
35784
+ const sanitized = sanitizeDiagnosticText(normalized).trim();
35785
+ if (sanitized.length === 0)
35786
+ return "unverified";
35787
+ return sanitized.length > MAX_FORMATTED_COMMAND_LINE_LENGTH ? `${sanitized.slice(0, MAX_FORMATTED_COMMAND_LINE_LENGTH - 3)}...` : sanitized;
35788
+ } catch {
35789
+ return "unverified";
35790
+ }
35791
+ }
35792
+ function formatFailClosedBlockingProcesses(processes) {
35793
+ const uniqueProcesses = new Map;
35794
+ for (const process3 of processes) {
35795
+ if (!Number.isInteger(process3.pid) || process3.pid <= 0)
35796
+ continue;
35797
+ const candidate = {
35798
+ kind: normalizeFailClosedProcessKind(process3),
35799
+ pid: process3.pid,
35800
+ startTime: process3.startTime,
35801
+ commandLine: process3.commandLine
35802
+ };
35803
+ const previous = uniqueProcesses.get(process3.pid);
35804
+ if (!previous || previous.kind === "process" && candidate.kind !== "process") {
35805
+ uniqueProcesses.set(process3.pid, candidate);
35806
+ } else {
35807
+ uniqueProcesses.set(process3.pid, {
35808
+ ...previous,
35809
+ startTime: previous.startTime ?? candidate.startTime,
35810
+ commandLine: previous.commandLine ?? candidate.commandLine
35811
+ });
35812
+ }
35813
+ }
35814
+ const entries = [...uniqueProcesses.values()];
35815
+ const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
35816
+ const rendered = visible.map(({ kind, pid }) => `${kind} (PID ${pid})`);
35817
+ const omitted = entries.length - visible.length;
35818
+ if (omitted > 0)
35819
+ rendered.push(`${omitted} more blocking process(es)`);
35820
+ if (rendered.length === 0)
35821
+ return "a live process";
35822
+ const summary = rendered.length === 1 ? rendered[0] : `${rendered.slice(0, -1).join(", ")}, and ${rendered.at(-1)}`;
35823
+ const evidence = entries.map(({ kind, pid, startTime, commandLine }) => `- PID ${pid}: ${kind}, started ${formatFailClosedProcessStartTime(startTime)}, cmd: ${formatFailClosedCommandLine(commandLine)}`).join(`
35824
+ `);
35825
+ return `${summary}
35826
+ Blocking process evidence:
35827
+ ${evidence}`;
35828
+ }
35829
+ function formatFailClosedBlockingMessage(reason) {
35830
+ if (reason.kind === "migration_guard") {
35831
+ if (reason.unreadableFile) {
35832
+ const arm = reason.unreadableArm ?? "io";
35833
+ const recovery = arm === "io" ? `If none of these processes are running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop the relevant process before deleting it.`;
35834
+ return [
35835
+ `Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live process cannot be proven.`,
35836
+ recovery,
35837
+ `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
35838
+ ].join(" ");
35839
+ }
35840
+ return [
35841
+ `Magic Context cannot migrate the shared database because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
35842
+ "Restart the blocking process (it will pick up the new build and migrate on start), or shut it down and retry.",
35843
+ `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
35844
+ ].join(" ");
35845
+ }
35846
+ if (reason.kind === "schema_fence") {
35847
+ return [
35848
+ `Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (upstream migration lane v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
35849
+ `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
35850
+ ].join(" ");
35851
+ }
35852
+ const cause = reason.cause.trim().length > 0 ? reason.cause.trim() : "unknown storage error";
35853
+ return [
35854
+ `Magic Context cannot operate: persistent storage failed (${cause}).`,
35855
+ "The plugin will not silently degrade to native compaction while enabled.",
35856
+ `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
35857
+ ].join(" ");
35858
+ }
35859
+ var FAIL_CLOSED_DOCTOR_COMMAND = "npx @cortexkit/magic-context@latest doctor", OPENCODE_INTERNAL_AGENT_NAMES, MAX_FORMATTED_BLOCKING_PROCESSES = 8, MAX_FORMATTED_COMMAND_LINE_LENGTH = 80;
35860
+ var init_fail_closed_block = __esm(() => {
35861
+ init_redaction();
35862
+ OPENCODE_INTERNAL_AGENT_NAMES = new Set(["title", "summary", "compaction"]);
35863
+ });
35864
+
35865
+ // ../plugin/src/hooks/magic-context/compartment-parser.ts
35866
+ function makeTierOpenRegex(n2) {
35867
+ return new RegExp(`<p${n2}\\s*(/?)>`);
35868
+ }
35869
+ function extractTier(inner, index) {
35870
+ const openMatch = TIER_OPEN_REGEXES[index].exec(inner);
35871
+ if (!openMatch)
35872
+ return;
35873
+ if (openMatch[1] === "/")
35874
+ return "";
35875
+ const rest = inner.slice(openMatch.index + openMatch[0].length);
35876
+ const closeAt = rest.search(TIER_CLOSE_ANY_REGEX);
35877
+ let body = closeAt === -1 ? rest : rest.slice(0, closeAt);
35878
+ const openInside = body.search(TIER_OPEN_ANY_REGEX);
35879
+ if (openInside !== -1)
35880
+ body = body.slice(0, openInside);
35881
+ return unescapeXml(body.trim());
35882
+ }
35883
+ function extractTiersFromInner(inner) {
35884
+ return {
35885
+ p1: extractTier(inner, 0),
35886
+ p2: extractTier(inner, 1),
35887
+ p3: extractTier(inner, 2),
35888
+ p4: extractTier(inner, 3)
35889
+ };
35890
+ }
35891
+ function parseCompartmentOutput(text3) {
35892
+ const compartments = [];
35893
+ const facts = [];
35894
+ for (const match of text3.matchAll(COMPARTMENT_REGEX)) {
35895
+ const attrs = match[1];
35896
+ const inner = match[2];
35897
+ const startMatch = attrs.match(ATTR_START_REGEX);
35898
+ const endMatch = attrs.match(ATTR_END_REGEX);
35899
+ const titleMatch = attrs.match(ATTR_TITLE_REGEX);
35900
+ if (!startMatch || !endMatch || !titleMatch)
35901
+ continue;
35902
+ const startMessage = parseInt(startMatch[1], 10);
35903
+ const endMessage = parseInt(endMatch[1], 10);
35904
+ const title = unescapeXml(titleMatch[1]);
35905
+ if (Number.isNaN(startMessage) || Number.isNaN(endMessage) || !title)
35906
+ continue;
35907
+ const episodeMatch = attrs.match(ATTR_EPISODE_REGEX);
35908
+ const importanceMatch = attrs.match(ATTR_IMPORTANCE_REGEX);
35909
+ const episodeType = episodeMatch ? unescapeXml(episodeMatch[1]) : undefined;
35910
+ const importance = importanceMatch ? parseInt(importanceMatch[1], 10) : undefined;
35911
+ const p1 = extractTier(inner, 0);
35912
+ if (typeof p1 === "string" && p1.length > 0) {
35913
+ const p2 = extractTier(inner, 1);
35914
+ const p3 = extractTier(inner, 2);
35915
+ const p4 = extractTier(inner, 3);
35916
+ compartments.push({
35917
+ startMessage,
35918
+ endMessage,
35919
+ title,
35920
+ content: p1,
35921
+ p1,
35922
+ p2: typeof p2 === "string" ? p2 : p1,
35923
+ p3: typeof p3 === "string" ? p3 : typeof p2 === "string" ? p2 : p1,
35924
+ p4: typeof p4 === "string" ? p4 : "",
35925
+ importance,
35926
+ episodeType
35927
+ });
35928
+ continue;
35929
+ }
35930
+ const content = unescapeXml(inner.trim());
35931
+ if (content) {
35932
+ compartments.push({
35933
+ startMessage,
35934
+ endMessage,
35935
+ title,
35936
+ content,
35937
+ importance,
35938
+ episodeType
35939
+ });
35940
+ }
35941
+ }
35942
+ const factsBlockMatch = text3.match(FACTS_BLOCK_REGEX);
35943
+ const factsScope = factsBlockMatch ? factsBlockMatch[1] : text3.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "");
35944
+ for (const categoryMatch of factsScope.matchAll(CATEGORY_BLOCK_REGEX)) {
35945
+ const category = categoryMatch[1];
35946
+ const blockContent = categoryMatch[2];
35947
+ for (const itemMatch of blockContent.matchAll(FACT_ITEM_REGEX)) {
35948
+ const content = unescapeXml(itemMatch[1].trim());
35949
+ if (content) {
35950
+ facts.push({ category, content });
35951
+ }
35952
+ }
35953
+ }
35954
+ const unprocessedMatch = text3.match(UNPROCESSED_REGEX);
35955
+ const unprocessedFrom = unprocessedMatch ? parseInt(unprocessedMatch[1], 10) : null;
35956
+ const userObservations = [];
35957
+ const userObsMatch = text3.match(USER_OBSERVATIONS_REGEX);
35958
+ if (userObsMatch) {
35959
+ for (const itemMatch of userObsMatch[1].matchAll(USER_OBS_ITEM_REGEX)) {
35960
+ const obs = unescapeXml(itemMatch[1].trim());
35961
+ if (obs)
35962
+ userObservations.push(obs);
35963
+ }
35964
+ }
35965
+ const primerCandidates = [];
35966
+ const primerMatch = text3.match(PRIMER_CANDIDATES_REGEX);
35967
+ if (primerMatch) {
35968
+ const block2 = primerMatch[1];
35969
+ let sawElement = false;
35970
+ for (const el of block2.matchAll(PRIMER_ELEMENT_REGEX)) {
35971
+ sawElement = true;
35972
+ const question = unescapeXml(el[2].trim());
35973
+ if (question) {
35974
+ primerCandidates.push({
35975
+ question,
35976
+ originCompartmentIndex: Number.parseInt(el[1], 10)
35977
+ });
35978
+ }
35979
+ }
35980
+ if (!sawElement) {
35981
+ for (const itemMatch of block2.matchAll(PRIMER_ITEM_REGEX)) {
35982
+ const question = unescapeXml(itemMatch[1].trim());
35983
+ if (question)
35984
+ primerCandidates.push({ question });
35985
+ }
35986
+ }
35987
+ }
35988
+ const events = parseEvents(text3);
35989
+ compartments.sort((a3, b) => a3.startMessage - b.startMessage);
35990
+ return { compartments, facts, events, unprocessedFrom, userObservations, primerCandidates };
35991
+ }
35992
+ function parseEvents(text3) {
35993
+ const blockMatch = text3.match(EVENTS_BLOCK_REGEX);
35994
+ if (!blockMatch)
35995
+ return [];
35996
+ const block2 = blockMatch[1];
35997
+ const events = [];
35998
+ for (const elMatch of block2.matchAll(EVENT_ELEMENT_REGEX)) {
35999
+ const kind = elMatch[1];
36000
+ const atRaw = parseInt(elMatch[2], 10);
36001
+ const atCompartment = Number.isNaN(atRaw) ? null : atRaw;
36002
+ const fields = {};
36003
+ for (const fieldMatch of elMatch[3].matchAll(EVENT_FIELD_REGEX)) {
36004
+ const name = fieldMatch[1];
36005
+ const value = unescapeXml(fieldMatch[2].trim());
36006
+ if (value)
36007
+ fields[name] = value;
36008
+ }
36009
+ events.push({ kind, atCompartment, fields });
36010
+ }
36011
+ return events;
36012
+ }
36013
+ function unescapeXml(s) {
36014
+ return s.replace(/&amp;/g, "&").replace(/&apos;/g, "'").replace(/&quot;/g, '"').replace(/&lt;/g, "<").replace(/&gt;/g, ">");
36015
+ }
36016
+ 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;
36017
+ var init_compartment_parser = __esm(() => {
36018
+ COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
36019
+ ATTR_START_REGEX = /\bstart="(\d+)"/;
36020
+ ATTR_END_REGEX = /\bend="(\d+)"/;
36021
+ ATTR_TITLE_REGEX = /\btitle="([^"]*)"/;
36022
+ ATTR_EPISODE_REGEX = /\bepisode_type="([^"]*)"/;
36023
+ ATTR_IMPORTANCE_REGEX = /\bimportance="(\d+)"/;
36024
+ TIER_OPEN_REGEXES = [
36025
+ makeTierOpenRegex(1),
36026
+ makeTierOpenRegex(2),
36027
+ makeTierOpenRegex(3),
36028
+ makeTierOpenRegex(4)
36029
+ ];
36030
+ TIER_CLOSE_ANY_REGEX = /<\/p\d/;
36031
+ TIER_OPEN_ANY_REGEX = /<p\d/;
36032
+ CATEGORY_BLOCK_REGEX = /<(PROJECT_RULES|ARCHITECTURE|CONSTRAINTS|CONFIG_VALUES|NAMING)>(.*?)<\/\1>/gs;
36033
+ FACT_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
36034
+ UNPROCESSED_REGEX = /<unprocessed_from>(\d+)<\/unprocessed_from>/;
36035
+ USER_OBSERVATIONS_REGEX = /<user_observations>(.*?)<\/user_observations>/s;
35591
36036
  USER_OBS_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
35592
36037
  PRIMER_CANDIDATES_REGEX = /<primer_candidates>(.*?)<\/primer_candidates>/s;
35593
36038
  PRIMER_ELEMENT_REGEX = /<primer\s+at_compartment="(\d+)"\s*>(.*?)<\/primer>/gs;
@@ -38100,8 +38545,8 @@ function classifyDiscoveryRecordKind(record2) {
38100
38545
  }
38101
38546
  return null;
38102
38547
  }
38103
- function classifyRpcProcess(record2) {
38104
- return classifyDiscoveryRecordKind(record2) ?? classifyProcessKind(readProcessCommand(record2.pid));
38548
+ function classifyRpcProcess(record2, commandLine) {
38549
+ return classifyDiscoveryRecordKind(record2) ?? classifyProcessKind(commandLine === undefined ? readProcessProbeEvidence(record2.pid).commandLine : commandLine);
38105
38550
  }
38106
38551
  function classifyJunkDiscovery(portFile, raw, staleFiles) {
38107
38552
  let mtimeMs;
@@ -38178,18 +38623,23 @@ function inspectRpcServerDiscovery(storageDir) {
38178
38623
  continue;
38179
38624
  }
38180
38625
  const liveness = isPidAlive(record2.pid);
38181
- const identity = liveness === "dead" ? "implausible" : isPidIdentityPlausible(record2);
38182
- if (liveness === "alive" && identity === "plausible") {
38626
+ if (liveness === "dead") {
38627
+ staleFiles.push(portFile);
38628
+ continue;
38629
+ }
38630
+ const evidence = readProcessProbeEvidence(record2.pid);
38631
+ const identity = isPidIdentityPlausible(record2, evidence);
38632
+ if (identity === "plausible") {
38183
38633
  pids.add(record2.pid);
38184
- const detected = {
38185
- kind: classifyRpcProcess(record2),
38634
+ const detected = attachFailClosedBlockingProcessEvidence({
38635
+ kind: classifyRpcProcess(record2, evidence.commandLine),
38186
38636
  pid: record2.pid
38187
- };
38637
+ }, evidence);
38188
38638
  const previous = processByPid.get(record2.pid);
38189
38639
  if (!previous || previous.kind === "process" && detected.kind !== "process") {
38190
38640
  processByPid.set(record2.pid, detected);
38191
38641
  }
38192
- } else if (liveness === "dead" || identity === "implausible") {
38642
+ } else if (identity === "implausible") {
38193
38643
  staleFiles.push(portFile);
38194
38644
  } else {
38195
38645
  inconclusivePids.add(record2.pid);
@@ -38222,10 +38672,14 @@ function inspectRpcServerDiscovery(storageDir) {
38222
38672
  }
38223
38673
  return { state: "stale", serverPids: [], staleFiles };
38224
38674
  }
38675
+ function createPiBlockingProcess(pid) {
38676
+ return attachFailClosedBlockingProcessEvidence({ kind: "Pi", pid }, readProcessProbeEvidence(pid));
38677
+ }
38225
38678
  function getLiveMigrationBlockingProcesses(storageDir) {
38226
38679
  const discovery = inspectRpcServerDiscovery(storageDir);
38227
38680
  const openCode = discovery.state === "live" ? discovery.serverProcesses ?? [] : [];
38228
- const pi = discoverLivePiProcessIds().map((pid) => ({ kind: "Pi", pid }));
38681
+ const piDiscovery = inspectLivePiProcesses();
38682
+ const pi = piDiscovery.processIds.map(createPiBlockingProcess);
38229
38683
  return [...openCode, ...pi];
38230
38684
  }
38231
38685
  function applySqliteTuningPragmas(db) {
@@ -38764,8 +39218,6 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
38764
39218
  updated_at INTEGER NOT NULL,
38765
39219
  harness TEXT NOT NULL DEFAULT 'opencode'
38766
39220
  );
38767
- CREATE INDEX IF NOT EXISTS idx_message_history_index_orphan_sweep
38768
- ON message_history_index(harness, session_id, updated_at);
38769
39221
 
38770
39222
  CREATE TABLE IF NOT EXISTS message_history_source (
38771
39223
  session_id TEXT NOT NULL,
@@ -39352,6 +39804,10 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
39352
39804
  ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
39353
39805
  ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
39354
39806
  ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
39807
+ db.exec(`
39808
+ CREATE INDEX IF NOT EXISTS idx_message_history_index_orphan_sweep
39809
+ ON message_history_index(harness, session_id, updated_at);
39810
+ `);
39355
39811
  ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
39356
39812
  }
39357
39813
  var databases, pendingAsyncOpens, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, LATEST_SUPPORTED_VERSION = 81, PERMISSIONS_ENFORCEABLE, RPC_DISCOVERY_PARSE_GRACE_MS, defaultRpcDiscoveryFs, rpcDiscoveryFs, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS;
@@ -39359,6 +39815,7 @@ var init_storage_db = __esm(async () => {
39359
39815
  init_data_path();
39360
39816
  init_logger();
39361
39817
  init_rpc_utils();
39818
+ init_fail_closed_block();
39362
39819
  init_migrations();
39363
39820
  init_tool_definition_tokens();
39364
39821
  init_tool_owner_backfill();
@@ -40508,11 +40965,11 @@ var init_doctor_repair_db = __esm(async () => {
40508
40965
  });
40509
40966
 
40510
40967
  // src/lib/migration-paths.ts
40511
- import { homedir as homedir12 } from "node:os";
40968
+ import { homedir as homedir13 } from "node:os";
40512
40969
  import { join as join18 } from "node:path";
40513
40970
  function getOpenCodeDatabasePath() {
40514
40971
  const dataHome = process.env.XDG_DATA_HOME?.trim();
40515
- return join18(dataHome || join18(homedir12(), ".local", "share"), "opencode", "opencode.db");
40972
+ return join18(dataHome || join18(homedir13(), ".local", "share"), "opencode", "opencode.db");
40516
40973
  }
40517
40974
  function projectPathToPiSessionSlug(projectPath, platform = process.platform) {
40518
40975
  const separators = platform === "win32" ? /[:\\/]+/g : /\/+/g;
@@ -41487,7 +41944,7 @@ __export(exports_migrate_session, {
41487
41944
  runMigrateSessionCli: () => runMigrateSessionCli
41488
41945
  });
41489
41946
  import { existsSync as existsSync23, realpathSync as realpathSync4 } from "node:fs";
41490
- import { homedir as homedir13 } from "node:os";
41947
+ import { homedir as homedir14 } from "node:os";
41491
41948
  import path4, { join as join20 } from "node:path";
41492
41949
  function existingSessionColumns(db) {
41493
41950
  const rows = db.prepare("PRAGMA table_info(session)").all();
@@ -41783,7 +42240,7 @@ async function runMigrateSessionCli(args) {
41783
42240
  printMigrateSessionHelp();
41784
42241
  return 1;
41785
42242
  }
41786
- const expandedTo = toDir.startsWith("~") ? join20(homedir13(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
42243
+ const expandedTo = toDir.startsWith("~") ? join20(homedir14(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
41787
42244
  if (!existsSync23(expandedTo)) {
41788
42245
  console.error(`Target directory does not exist: ${expandedTo}`);
41789
42246
  return 1;
@@ -42370,255 +42827,162 @@ function loadPiConfig(opts = {}) {
42370
42827
  } else if (legacyProjectUnmigrated) {
42371
42828
  warnings.push("[project config] legacy Magic Context config exists but the shared CortexKit config is absent; embedding registration is paused until config migration completes.");
42372
42829
  }
42373
- let rawConfig = {};
42374
42830
  const mergeFiles = [...loadedFiles].sort((a3, b) => {
42375
42831
  if (a3.scope === b.scope)
42376
42832
  return 0;
42377
42833
  return a3.scope === "user" ? -1 : 1;
42378
42834
  });
42379
- const userRaw = mergeFiles.find((f) => f.scope === "user")?.config;
42380
- const trustedBaseConfig = parsePiConfig(userRaw ?? {}).config;
42835
+ const userRaw = mergeFiles.find((f) => f.scope === "user")?.config ?? {};
42836
+ const projectLoaded = mergeFiles.find((f) => f.scope === "project");
42837
+ let projectRaw = {};
42381
42838
  for (const loaded of mergeFiles) {
42382
42839
  const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
42383
42840
  warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
42384
- if (loaded.scope === "project") {
42385
- const projectRaw = { ...loaded.config };
42386
- for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
42387
- warnings.push(`${prefix} ${warning}`);
42388
- }
42389
- rawConfig = mergeRawConfigs(rawConfig, projectRaw);
42390
- for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, userRaw)) {
42391
- warnings.push(`${prefix} ${warning}`);
42392
- }
42393
- for (const warning of constrainProjectThresholdOverrides({
42394
- mergedRaw: rawConfig,
42395
- projectRaw,
42396
- trustedBaseConfig
42397
- })) {
42398
- warnings.push(`${prefix} ${warning}`);
42399
- }
42400
- } else {
42401
- rawConfig = mergeRawConfigs(rawConfig, loaded.config);
42402
- }
42403
- }
42404
- const parsed = parsePiConfig(rawConfig);
42405
- setOutputReserveConfig(parsed.config.output_reserve);
42406
- setWindowOverlayPath(parsed.config.models?.window_overlay_path);
42407
- warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
42408
- return {
42409
- config: parsed.config,
42410
- registrationPromptSurface: trustedBaseConfig.prompt_surface,
42411
- warnings,
42412
- loadedFromPaths: loadedFiles.map((loaded) => loaded.path)
42413
- };
42414
- }
42415
- var import_comment_json7;
42416
- var init_config2 = __esm(() => {
42417
- init_migrate_config_location();
42418
- init_agent_disable();
42419
- init_migrate_dreamer_v2();
42420
- init_project_security();
42421
- init_raw_loader();
42422
- init_magic_context();
42423
- init_variable();
42424
- init_jsonc_parser();
42425
- init_models_dev_cache();
42426
- init_window_geometry();
42427
- import_comment_json7 = __toESM(require_src3(), 1);
42428
- });
42429
-
42430
- // src/lib/database-repair-guidance.ts
42431
- function formatDatabaseRepairGuidance(dbPath) {
42432
- return `Database: ${dbPath}. Recovery: run \`${DATABASE_REPAIR_COMMAND}\` (salvage needs a sqlite3 shell built with SQLITE_ENABLE_DBPAGE_VTAB; without one, the command backs up and stops without modifying the database).`;
42433
- }
42434
- var DATABASE_REPAIR_COMMAND = "bunx @cortexkit/magic-context@latest doctor repair-db";
42435
-
42436
- // ../plugin/src/shared/redaction.ts
42437
- import { homedir as homedir14, userInfo } from "node:os";
42438
- function escapeRegex2(value) {
42439
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
42440
- }
42441
- function redactionTypeForKey(key) {
42442
- const normalized = key.trim().toLowerCase().replace(/[^a-z0-9_.-]+/g, "_");
42443
- const suffix = normalized.split(".").filter(Boolean).at(-1) ?? normalized;
42444
- return suffix || "secret";
42445
- }
42446
- function isNonSecretScalarValue(value) {
42447
- const v = value.trim();
42448
- if (v === "true" || v === "false" || v === "null" || v === "undefined")
42449
- return true;
42450
- return /^[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(v);
42451
- }
42452
- function isSecretKey(key) {
42453
- const segments = key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().split(/[._-]+/).filter(Boolean);
42454
- if (segments.length === 0)
42455
- return false;
42456
- if (segments.length === 1) {
42457
- const first = segments[0];
42458
- return Boolean(first && SECRET_SEGMENT_PATTERN.test(first));
42459
- }
42460
- for (let i2 = 0;i2 < segments.length; i2++) {
42461
- const seg = segments[i2];
42462
- if (!seg || !SECRET_SEGMENT_PATTERN.test(seg))
42463
- continue;
42464
- let trailingOk = true;
42465
- for (let j = i2 + 1;j < segments.length; j++) {
42466
- const tail = segments[j];
42467
- if (!tail)
42468
- continue;
42469
- if (TRAILING_DESCRIPTORS.has(tail))
42470
- continue;
42471
- if (SECRET_SEGMENT_PATTERN.test(tail))
42472
- continue;
42473
- trailingOk = false;
42474
- break;
42475
- }
42476
- if (!trailingOk)
42477
- continue;
42478
- for (let k = i2 - 1;k >= 0; k--) {
42479
- const lead = segments[k];
42480
- if (lead && SECRET_QUALIFIERS.has(lead))
42481
- return true;
42482
- }
42483
- }
42484
- return false;
42485
- }
42486
- function sanitizePathString(value) {
42487
- const home = homedir14();
42488
- const username = userInfo().username;
42489
- let sanitized = value;
42490
- if (home) {
42491
- sanitized = sanitized.replace(new RegExp(escapeRegex2(home), "g"), "~");
42492
- }
42493
- sanitized = sanitized.replace(/\/Users\/[^/]+\//g, "/Users/<USER>/");
42494
- sanitized = sanitized.replace(/\/home\/[^/]+\//g, "/home/<USER>/");
42495
- sanitized = sanitized.replace(/C:\\Users\\[^\\]+\\/g, "C:\\Users\\<USER>\\");
42496
- if (username) {
42497
- sanitized = sanitized.replace(new RegExp(escapeRegex2(username), "g"), "<USER>");
42498
- }
42499
- return sanitized;
42500
- }
42501
- function redactSecretText(value) {
42502
- let redacted = value;
42503
- for (const { pattern, replacement } of SECRET_TEXT_PATTERNS) {
42504
- if (typeof replacement === "string") {
42505
- redacted = redacted.replace(pattern, replacement);
42506
- } else {
42507
- redacted = redacted.replace(pattern, replacement);
42508
- }
42509
- }
42510
- return redacted;
42511
- }
42512
- function sanitizeDiagnosticText(value) {
42513
- return redactSecretText(sanitizePathString(value));
42514
- }
42515
- function sanitizeConfigValue(value, keyPath = []) {
42516
- if (value === null || typeof value === "number" || typeof value === "boolean")
42517
- return value;
42518
- const key = keyPath.at(-1) ?? "";
42519
- if (key && isSecretKey(key)) {
42520
- return `<REDACTED:${redactionTypeForKey(key)}>`;
42521
- }
42522
- if (typeof value === "string")
42523
- return sanitizeDiagnosticText(value);
42524
- if (Array.isArray(value)) {
42525
- return value.map((entry, index) => sanitizeConfigValue(entry, [...keyPath, String(index)]));
42526
- }
42527
- if (value && typeof value === "object") {
42528
- return Object.fromEntries(Object.entries(value).map(([entryKey, entry]) => [
42529
- entryKey,
42530
- sanitizeConfigValue(entry, [...keyPath, entryKey])
42531
- ]));
42532
- }
42533
- return value;
42534
- }
42535
- var SECRET_WORDS, SECRET_SEGMENT_PATTERN, TRAILING_DESCRIPTORS, SECRET_QUALIFIERS, SECRET_TEXT_PATTERNS;
42536
- var init_redaction = __esm(() => {
42537
- SECRET_WORDS = [
42538
- "key",
42539
- "token",
42540
- "secret",
42541
- "password",
42542
- "auth",
42543
- "authorization",
42544
- "bearer",
42545
- "credential"
42546
- ];
42547
- SECRET_SEGMENT_PATTERN = new RegExp(`^(?:${SECRET_WORDS.map((w) => `${w}s?`).join("|")})$`, "i");
42548
- TRAILING_DESCRIPTORS = new Set(["id", "ids", "value", "values", "header", "headers"]);
42549
- SECRET_QUALIFIERS = new Set([
42550
- "api",
42551
- "access",
42552
- "private",
42553
- "client",
42554
- "auth",
42555
- "authorization",
42556
- "secret",
42557
- "bearer",
42558
- "session",
42559
- "refresh",
42560
- "service",
42561
- "x",
42562
- "openai",
42563
- "anthropic",
42564
- "google",
42565
- "github",
42566
- "huggingface",
42567
- "aws",
42568
- "azure"
42569
- ]);
42570
- SECRET_TEXT_PATTERNS = [
42571
- {
42572
- pattern: /\bsk-ant-(?:api03-)?[A-Za-z0-9_-]{32,}/g,
42573
- replacement: "<ANTHROPIC_API_KEY_REDACTED>"
42574
- },
42575
- {
42576
- pattern: /\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/g,
42577
- replacement: "<OPENAI_API_KEY_REDACTED>"
42578
- },
42579
- {
42580
- pattern: /\bgithub_pat_[A-Za-z0-9_]{20,}/g,
42581
- replacement: "<GITHUB_PAT_REDACTED>"
42582
- },
42583
- {
42584
- pattern: /\b(?:gh[opsu]|ghr)_[A-Za-z0-9]{30,}/g,
42585
- replacement: "<GITHUB_TOKEN_REDACTED>"
42586
- },
42587
- {
42588
- pattern: /\bhf_[A-Za-z0-9]{30,}/g,
42589
- replacement: "<HUGGINGFACE_TOKEN_REDACTED>"
42590
- },
42591
- {
42592
- pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
42593
- replacement: "<AWS_ACCESS_KEY_ID_REDACTED>"
42594
- },
42595
- {
42596
- pattern: /\bxox[abprsuvc]-[A-Za-z0-9-]{10,}/g,
42597
- replacement: "<SLACK_TOKEN_REDACTED>"
42598
- },
42599
- {
42600
- pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g,
42601
- replacement: "<GOOGLE_API_KEY_REDACTED>"
42602
- },
42603
- {
42604
- pattern: /\b(Authorization\s*:\s*Bearer\s+)([A-Za-z0-9._~+/=-]{8,})/gi,
42605
- replacement: (_full, prefix) => `${prefix}<REDACTED:bearer>`
42606
- },
42607
- {
42608
- pattern: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
42609
- replacement: "<JWT_REDACTED>"
42610
- },
42611
- {
42612
- pattern: /(["'])([^"']*(?:key|token|secret|password|auth|bearer|credential)[^"']*)\1(\s*:\s*)(["'])([^"']*)\4/gi,
42613
- replacement: (full, quote, key, separator, valueQuote, value) => isNonSecretScalarValue(value) ? full : `${quote}${key}${quote}${separator}${valueQuote}<REDACTED:${redactionTypeForKey(key)}>${valueQuote}`
42614
- },
42615
- {
42616
- pattern: /\b([A-Za-z0-9_.-]*(?:key|token|secret|password|auth|bearer|credential)[A-Za-z0-9_.-]*)\s*=\s*([^\s'"`]+)/gi,
42617
- replacement: (full, key, value) => isNonSecretScalarValue(value) ? full : `${key}=<REDACTED:${redactionTypeForKey(key)}>`
42841
+ if (loaded.scope !== "project")
42842
+ continue;
42843
+ projectRaw = { ...loaded.config };
42844
+ for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
42845
+ warnings.push(`${prefix} ${warning}`);
42618
42846
  }
42619
- ];
42847
+ }
42848
+ const profileResolution = resolveConfigProfile({ userRaw, projectRaw });
42849
+ warnings.push(...profileResolution.warnings.map((warning) => `[config] ${warning}`));
42850
+ const trustedProfiledRaw = mergeRawConfigs(profileResolution.userBase, profileResolution.overlay);
42851
+ let rawConfig = trustedProfiledRaw;
42852
+ const trustedBaseConfig = parsePiConfig(trustedProfiledRaw).config;
42853
+ if (projectLoaded) {
42854
+ rawConfig = mergeRawConfigs(rawConfig, profileResolution.projectBase);
42855
+ for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, profileResolution.userBase)) {
42856
+ warnings.push(`[project config] ${warning}`);
42857
+ }
42858
+ for (const warning of constrainProjectThresholdOverrides({
42859
+ mergedRaw: rawConfig,
42860
+ projectRaw: profileResolution.projectBase,
42861
+ trustedBaseConfig
42862
+ })) {
42863
+ warnings.push(`[project config] ${warning}`);
42864
+ }
42865
+ }
42866
+ const parsed = parsePiConfig(rawConfig);
42867
+ if (profileResolution.activeProfile)
42868
+ parsed.config.profile = profileResolution.activeProfile;
42869
+ setOutputReserveConfig(parsed.config.output_reserve);
42870
+ setWindowOverlayPath(parsed.config.models?.window_overlay_path);
42871
+ warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
42872
+ return {
42873
+ config: parsed.config,
42874
+ registrationPromptSurface: trustedBaseConfig.prompt_surface,
42875
+ warnings,
42876
+ loadedFromPaths: loadedFiles.map((loaded) => loaded.path)
42877
+ };
42878
+ }
42879
+ var import_comment_json7;
42880
+ var init_config2 = __esm(() => {
42881
+ init_migrate_config_location();
42882
+ init_agent_disable();
42883
+ init_migrate_dreamer_v2();
42884
+ init_profiles();
42885
+ init_project_security();
42886
+ init_raw_loader();
42887
+ init_magic_context();
42888
+ init_variable();
42889
+ init_jsonc_parser();
42890
+ init_models_dev_cache();
42891
+ init_window_geometry();
42892
+ import_comment_json7 = __toESM(require_src3(), 1);
42620
42893
  });
42621
42894
 
42895
+ // src/lib/database-repair-guidance.ts
42896
+ function formatDatabaseRepairGuidance(dbPath) {
42897
+ return `Database: ${dbPath}. Recovery: run \`${DATABASE_REPAIR_COMMAND}\` (salvage needs a sqlite3 shell built with SQLITE_ENABLE_DBPAGE_VTAB; without one, the command backs up and stops without modifying the database).`;
42898
+ }
42899
+ var DATABASE_REPAIR_COMMAND = "bunx @cortexkit/magic-context@latest doctor repair-db";
42900
+
42901
+ // src/lib/github-issue.ts
42902
+ import { spawnSync as spawnSync4 } from "node:child_process";
42903
+ import { readFileSync as readFileSync14 } from "node:fs";
42904
+ function runGhCommand(args) {
42905
+ try {
42906
+ const result = spawnSync4("gh", args, {
42907
+ encoding: "utf-8",
42908
+ stdio: ["ignore", "pipe", "pipe"]
42909
+ });
42910
+ return {
42911
+ status: result.status,
42912
+ stdout: String(result.stdout ?? ""),
42913
+ stderr: String(result.stderr ?? "")
42914
+ };
42915
+ } catch (error51) {
42916
+ return {
42917
+ status: null,
42918
+ stdout: "",
42919
+ stderr: error51 instanceof Error ? error51.message : String(error51)
42920
+ };
42921
+ }
42922
+ }
42923
+ function failed(result) {
42924
+ return result.status !== 0;
42925
+ }
42926
+ function submitGithubIssue(title, bodyPath, runner = runGhCommand) {
42927
+ let body;
42928
+ try {
42929
+ body = readFileSync14(bodyPath, "utf-8");
42930
+ } catch (error51) {
42931
+ return {
42932
+ ok: false,
42933
+ reason: "body-unreadable",
42934
+ message: `The diagnostics file could not be read (${error51 instanceof Error ? error51.message : String(error51)}).`
42935
+ };
42936
+ }
42937
+ if (Array.from(body).length > MAX_GITHUB_ISSUE_BODY_CHARS || Buffer.byteLength(body, "utf8") > MAX_GITHUB_ISSUE_BODY_CHARS) {
42938
+ return {
42939
+ ok: false,
42940
+ reason: "body-too-large",
42941
+ message: `The GitHub issue body is larger than GitHub's ${MAX_GITHUB_ISSUE_BODY_CHARS.toLocaleString()}-character limit.`
42942
+ };
42943
+ }
42944
+ const installed = runner(["--version"]);
42945
+ if (failed(installed)) {
42946
+ return {
42947
+ ok: false,
42948
+ reason: "gh-not-installed",
42949
+ message: "The GitHub CLI (gh) is not installed or could not be started."
42950
+ };
42951
+ }
42952
+ const auth = runner(["auth", "status", "--hostname", "github.com"]);
42953
+ if (failed(auth)) {
42954
+ return {
42955
+ ok: false,
42956
+ reason: "not-authenticated",
42957
+ message: "gh is not authenticated. Run `gh auth login` before submitting an issue."
42958
+ };
42959
+ }
42960
+ const result = runner([
42961
+ "issue",
42962
+ "create",
42963
+ "-R",
42964
+ "cortexkit/magic-context",
42965
+ "--title",
42966
+ title,
42967
+ "--body-file",
42968
+ bodyPath
42969
+ ]);
42970
+ if (result.status === 0) {
42971
+ return { ok: true, output: result.stdout.trim() };
42972
+ }
42973
+ const details = result.stderr.trim() || result.stdout.trim();
42974
+ return {
42975
+ ok: false,
42976
+ reason: "create-failed",
42977
+ message: details ? `GitHub issue creation failed: ${details}` : "GitHub issue creation failed: gh returned a non-zero status."
42978
+ };
42979
+ }
42980
+ function formatGithubIssueFallback(submission, fallbackPath) {
42981
+ return `${submission.message} The sanitized diagnostics are saved at ${fallbackPath}; open https://github.com/cortexkit/magic-context/issues/new and drag that file into the issue before submitting manually.`;
42982
+ }
42983
+ var MAX_GITHUB_ISSUE_BODY_CHARS = 65536;
42984
+ var init_github_issue = () => {};
42985
+
42622
42986
  // src/lib/redaction.ts
42623
42987
  function sanitizeDiagnosticEndpoint(value) {
42624
42988
  const trimmed = value.trim();
@@ -42642,8 +43006,8 @@ var init_redaction2 = __esm(() => {
42642
43006
  });
42643
43007
 
42644
43008
  // src/commands/doctor-omp.ts
42645
- import { execFileSync as execFileSync5, spawnSync as spawnSync4 } from "node:child_process";
42646
- import { existsSync as existsSync25, mkdirSync as mkdirSync9, readFileSync as readFileSync14 } from "node:fs";
43009
+ import { execFileSync as execFileSync5, spawnSync as spawnSync5 } from "node:child_process";
43010
+ import { existsSync as existsSync25, mkdirSync as mkdirSync9, readFileSync as readFileSync15 } from "node:fs";
42647
43011
  import { createRequire as createRequire2 } from "node:module";
42648
43012
  import { dirname as dirname14, join as join21, resolve as resolve6 } from "node:path";
42649
43013
  function parseSemver(value) {
@@ -42690,7 +43054,7 @@ function readConfig2(path6) {
42690
43054
  if (!existsSync25(path6))
42691
43055
  return {};
42692
43056
  try {
42693
- const parsed = import_comment_json8.parse(readFileSync14(path6, "utf-8"));
43057
+ const parsed = import_comment_json8.parse(readFileSync15(path6, "utf-8"));
42694
43058
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? {} : { error: "top level is not an object" };
42695
43059
  } catch (error51) {
42696
43060
  return { error: error51 instanceof Error ? error51.message : String(error51) };
@@ -42700,7 +43064,7 @@ function pluginDeclaresOmp(path6) {
42700
43064
  if (!path6)
42701
43065
  return null;
42702
43066
  try {
42703
- const pkg = JSON.parse(readFileSync14(join21(path6, "package.json"), "utf-8"));
43067
+ const pkg = JSON.parse(readFileSync15(join21(path6, "package.json"), "utf-8"));
42704
43068
  return Array.isArray(pkg.omp?.extensions) || Array.isArray(pkg.pi?.extensions);
42705
43069
  } catch {
42706
43070
  return null;
@@ -42889,6 +43253,33 @@ async function repair(plan, deps, prompts, cwd) {
42889
43253
  function timestamp2(date5) {
42890
43254
  return date5.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
42891
43255
  }
43256
+ function runGhCommandWithDeps(deps, args) {
43257
+ if (args[0] === "issue") {
43258
+ const result = deps.spawnSync("gh", args, {
43259
+ encoding: "utf-8",
43260
+ stdio: ["ignore", "pipe", "pipe"]
43261
+ });
43262
+ return {
43263
+ status: result.status,
43264
+ stdout: String(result.stdout ?? ""),
43265
+ stderr: String(result.stderr ?? "")
43266
+ };
43267
+ }
43268
+ try {
43269
+ const output = deps.execFileSync("gh", args, {
43270
+ encoding: "utf-8",
43271
+ stdio: ["ignore", "pipe", "pipe"]
43272
+ });
43273
+ return { status: 0, stdout: String(output ?? ""), stderr: "" };
43274
+ } catch (error51) {
43275
+ const result = error51;
43276
+ return {
43277
+ status: typeof result.status === "number" ? result.status : 1,
43278
+ stdout: String(result.stdout ?? ""),
43279
+ stderr: String(result.stderr ?? "")
43280
+ };
43281
+ }
43282
+ }
42892
43283
  async function runIssueFlow(options) {
42893
43284
  const title = await options.prompts.text("Issue title", {
42894
43285
  placeholder: "Short summary of the OMP problem",
@@ -42912,34 +43303,15 @@ async function runIssueFlow(options) {
42912
43303
  writeFileAtomic(path6, `${body}
42913
43304
  `);
42914
43305
  options.prompts.log.success(`Sanitized report written to ${path6}`);
42915
- try {
42916
- options.deps.execFileSync("gh", ["--version"], { stdio: "ignore" });
42917
- } catch {
42918
- options.prompts.log.info("gh CLI unavailable; submit the generated report manually");
42919
- return 0;
42920
- }
42921
- try {
42922
- options.deps.execFileSync("gh", ["auth", "status"], { stdio: "ignore" });
42923
- } catch {
42924
- options.prompts.log.info("gh CLI is installed but not authenticated; submit the generated report manually");
42925
- return 0;
42926
- }
42927
43306
  if (await options.prompts.confirm("Submit this issue on GitHub now?", false)) {
42928
- const result = options.deps.spawnSync("gh", [
42929
- "issue",
42930
- "create",
42931
- "-R",
42932
- "cortexkit/magic-context",
42933
- "--title",
42934
- `[omp] ${title}`,
42935
- "--body-file",
42936
- path6
42937
- ], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
42938
- if (result.status === 0)
42939
- options.prompts.log.success(String(result.stdout).trim());
42940
- else
42941
- options.prompts.log.warn(String(result.stderr).trim());
43307
+ const result = submitGithubIssue(`[omp] ${title}`, path6, (args) => runGhCommandWithDeps(options.deps, args));
43308
+ if (result.ok) {
43309
+ options.prompts.log.success(result.output);
43310
+ } else {
43311
+ options.prompts.log.warn(formatGithubIssueFallback(result, path6));
43312
+ }
42942
43313
  }
43314
+ options.prompts.log.info(`Open https://github.com/cortexkit/magic-context/issues/new and drag ${path6} into the issue`);
42943
43315
  return 0;
42944
43316
  }
42945
43317
  async function runDoctor(options = {}) {
@@ -42979,6 +43351,7 @@ var init_doctor_omp = __esm(async () => {
42979
43351
  init_omp();
42980
43352
  init_atomic_write();
42981
43353
  init_config_location_migration();
43354
+ init_github_issue();
42982
43355
  init_omp_helpers();
42983
43356
  init_paths();
42984
43357
  init_prompts();
@@ -42995,7 +43368,7 @@ var init_doctor_omp = __esm(async () => {
42995
43368
  openExistingContextDatabase,
42996
43369
  now: () => new Date,
42997
43370
  execFileSync: execFileSync5,
42998
- spawnSync: spawnSync4
43371
+ spawnSync: spawnSync5
42999
43372
  };
43000
43373
  });
43001
43374
 
@@ -43115,7 +43488,7 @@ import {
43115
43488
  chmodSync as chmodSync4,
43116
43489
  existsSync as existsSync26,
43117
43490
  mkdirSync as mkdirSync10,
43118
- readFileSync as readFileSync15,
43491
+ readFileSync as readFileSync16,
43119
43492
  renameSync as renameSync6,
43120
43493
  statSync as statSync10,
43121
43494
  writeFileSync as writeFileSync7
@@ -43174,7 +43547,7 @@ function ensureTuiPluginEntry(options = {}) {
43174
43547
  const configPath = resolveTuiConfigPath(options.configDir);
43175
43548
  let config2 = {};
43176
43549
  if (existsSync26(configPath)) {
43177
- const raw = readFileSync15(configPath, "utf-8");
43550
+ const raw = readFileSync16(configPath, "utf-8");
43178
43551
  config2 = import_comment_json9.parse(raw) ?? {};
43179
43552
  }
43180
43553
  const plugins = Array.isArray(config2.plugin) ? [...config2.plugin] : [];
@@ -43226,7 +43599,7 @@ var init_tui_config = __esm(() => {
43226
43599
  });
43227
43600
 
43228
43601
  // src/lib/diagnostics-opencode.ts
43229
- import { existsSync as existsSync27, readdirSync as readdirSync3, readFileSync as readFileSync16, statSync as statSync11 } from "node:fs";
43602
+ import { existsSync as existsSync27, readdirSync as readdirSync3, readFileSync as readFileSync17, statSync as statSync11 } from "node:fs";
43230
43603
  import { createRequire as createRequire3 } from "node:module";
43231
43604
  import { homedir as homedir15 } from "node:os";
43232
43605
  import { join as join23 } from "node:path";
@@ -43248,7 +43621,7 @@ function getPluginCacheInfo() {
43248
43621
  for (const installedPkgPath of getOpenCodePluginPackageJsonPaths()) {
43249
43622
  try {
43250
43623
  if (existsSync27(installedPkgPath)) {
43251
- const pkg = JSON.parse(readFileSync16(installedPkgPath, "utf-8"));
43624
+ const pkg = JSON.parse(readFileSync17(installedPkgPath, "utf-8"));
43252
43625
  cached2 = typeof pkg.version === "string" ? pkg.version : undefined;
43253
43626
  if (cached2)
43254
43627
  break;
@@ -43280,7 +43653,7 @@ function readConfig3(path6) {
43280
43653
  if (!existsSync27(path6))
43281
43654
  return { value: null };
43282
43655
  try {
43283
- const raw = readFileSync16(path6, "utf-8");
43656
+ const raw = readFileSync17(path6, "utf-8");
43284
43657
  const value = import_comment_json10.parse(raw);
43285
43658
  return { value };
43286
43659
  } catch (error51) {
@@ -43305,7 +43678,7 @@ function configHasPluginEntry(config2) {
43305
43678
  }
43306
43679
  function parseHistorianDumpMeta(path6) {
43307
43680
  try {
43308
- const xml = readFileSync16(path6, "utf-8");
43681
+ const xml = readFileSync17(path6, "utf-8");
43309
43682
  const parsed = parseCompartmentOutput(xml);
43310
43683
  const factCountByCategory = {};
43311
43684
  for (const fact of parsed.facts) {
@@ -43405,6 +43778,62 @@ function collectHistorianDumps(recentSessions) {
43405
43778
  }
43406
43779
  };
43407
43780
  }
43781
+ function collectRecentSessionsFromDatabase(database) {
43782
+ const rows = database.prepare(`WITH active AS (
43783
+ SELECT id, directory, title, time_updated, parent_id
43784
+ FROM session
43785
+ WHERE time_archived IS NULL
43786
+ ),
43787
+ root_activity AS (
43788
+ SELECT p.id AS root_id,
43789
+ MAX(
43790
+ CASE
43791
+ WHEN c.time_updated > p.time_updated THEN c.time_updated
43792
+ ELSE p.time_updated
43793
+ END
43794
+ ) AS latest_activity
43795
+ FROM active p
43796
+ LEFT JOIN active c ON c.parent_id = p.id
43797
+ WHERE p.parent_id IS NULL
43798
+ GROUP BY p.id
43799
+ ),
43800
+ selected_roots AS (
43801
+ SELECT p.id, p.directory, p.title, p.time_updated, r.latest_activity
43802
+ FROM active p
43803
+ JOIN root_activity r ON r.root_id = p.id
43804
+ ORDER BY r.latest_activity DESC
43805
+ LIMIT ${RECENT_SESSION_GROUP_LIMIT}
43806
+ ),
43807
+ ranked_children AS (
43808
+ SELECT c.id, c.directory, c.title, c.time_updated, c.parent_id,
43809
+ r.latest_activity,
43810
+ ROW_NUMBER() OVER (
43811
+ PARTITION BY c.parent_id
43812
+ ORDER BY c.time_updated DESC
43813
+ ) AS child_rank
43814
+ FROM active c
43815
+ JOIN selected_roots r ON c.parent_id = r.id
43816
+ )
43817
+ SELECT id, directory, title, time_updated, NULL AS parent_id,
43818
+ latest_activity, 0 AS row_kind, 0 AS child_rank
43819
+ FROM selected_roots
43820
+ UNION ALL
43821
+ SELECT id, directory, title, time_updated, parent_id,
43822
+ latest_activity, 1 AS row_kind, child_rank
43823
+ FROM ranked_children
43824
+ WHERE child_rank <= ${CHILD_SESSIONS_PER_PARENT_LIMIT}
43825
+ ORDER BY latest_activity DESC, row_kind ASC, child_rank ASC, time_updated DESC`).all();
43826
+ return rows.flatMap((row) => {
43827
+ const sessionId = typeof row.id === "string" ? row.id : null;
43828
+ const directory = typeof row.directory === "string" ? row.directory : null;
43829
+ if (!sessionId || !directory)
43830
+ return [];
43831
+ const title = typeof row.title === "string" ? row.title : "";
43832
+ const lastActiveAt = typeof row.time_updated === "number" ? new Date(row.time_updated).toISOString() : "";
43833
+ const parentSessionId = typeof row.parent_id === "string" && row.parent_id.length > 0 ? row.parent_id : null;
43834
+ return [{ sessionId, title, directory, lastActiveAt, parentSessionId }];
43835
+ });
43836
+ }
43408
43837
  async function collectRecentSessions() {
43409
43838
  const dataHome = process.env.XDG_DATA_HOME || join23(process.env.HOME || homedir15(), ".local", "share");
43410
43839
  const opencodeDbPath = join23(dataHome, "opencode", "opencode.db");
@@ -43423,16 +43852,7 @@ async function collectRecentSessions() {
43423
43852
  let db = null;
43424
43853
  try {
43425
43854
  db = new DatabaseClass(opencodeDbPath, { readonly: true });
43426
- const rows = db.prepare("SELECT id, directory, title, time_updated FROM session " + "WHERE time_archived IS NULL AND parent_id IS NULL " + "ORDER BY time_updated DESC LIMIT 5").all();
43427
- return rows.flatMap((row) => {
43428
- const sessionId = typeof row.id === "string" ? row.id : null;
43429
- const directory = typeof row.directory === "string" ? row.directory : null;
43430
- if (!sessionId || !directory)
43431
- return [];
43432
- const title = typeof row.title === "string" ? row.title : "";
43433
- const lastActiveAt = typeof row.time_updated === "number" ? new Date(row.time_updated).toISOString() : "";
43434
- return [{ sessionId, title, directory, lastActiveAt }];
43435
- });
43855
+ return collectRecentSessionsFromDatabase(db);
43436
43856
  } catch {
43437
43857
  return [];
43438
43858
  } finally {
@@ -43658,7 +44078,8 @@ function renderDiagnosticsMarkdown(report) {
43658
44078
  sessionId: session.sessionId,
43659
44079
  title: sanitizeDiagnosticText(session.title),
43660
44080
  directory: sanitizeString(session.directory),
43661
- lastActiveAt: session.lastActiveAt
44081
+ lastActiveAt: session.lastActiveAt,
44082
+ parentSessionId: session.parentSessionId ?? null
43662
44083
  }));
43663
44084
  return [
43664
44085
  `- Timestamp: ${report.timestamp}`,
@@ -43730,7 +44151,7 @@ function renderDiagnosticsMarkdown(report) {
43730
44151
  ].join(`
43731
44152
  `);
43732
44153
  }
43733
- var import_comment_json10;
44154
+ var import_comment_json10, RECENT_SESSION_GROUP_LIMIT = 5, CHILD_SESSIONS_PER_PARENT_LIMIT = 3;
43734
44155
  var init_diagnostics_opencode = __esm(() => {
43735
44156
  init_config();
43736
44157
  init_agent_disable();
@@ -43746,7 +44167,7 @@ var init_diagnostics_opencode = __esm(() => {
43746
44167
  });
43747
44168
 
43748
44169
  // src/lib/embedding-runtime.ts
43749
- import { spawnSync as spawnSync5 } from "node:child_process";
44170
+ import { spawnSync as spawnSync6 } from "node:child_process";
43750
44171
  import { existsSync as existsSync28 } from "node:fs";
43751
44172
  import { createRequire as createRequire4 } from "node:module";
43752
44173
  import { dirname as dirname16, join as join24, sep } from "node:path";
@@ -43756,7 +44177,7 @@ function describeError(error51) {
43756
44177
  return typeof code === "string" && code.length > 0 ? `${code}: ${message}` : message;
43757
44178
  }
43758
44179
  function runOnnxRuntimeNodeLoadProbeChild(packageDir) {
43759
- return spawnSync5(process.execPath, ["-e", ONNX_RUNTIME_NODE_LOAD_PROBE_SCRIPT], {
44180
+ return spawnSync6(process.execPath, ["-e", ONNX_RUNTIME_NODE_LOAD_PROBE_SCRIPT], {
43760
44181
  encoding: "utf8",
43761
44182
  env: { ...process.env, [ONNX_LOAD_PROBE_PACKAGE_DIR_ENV]: packageDir },
43762
44183
  stdio: ["ignore", "pipe", "pipe"],
@@ -43846,12 +44267,23 @@ function probeOnnxRuntimeNodeLoad(packageDir) {
43846
44267
  reason: `probe returned no JSON verdict${stdoutSuffix(result)}${stderrSuffix(result)}`
43847
44268
  };
43848
44269
  }
43849
- function isLocalEmbeddingRuntimeBroken(status) {
44270
+ function isNativeLocalEmbeddingRuntimeFailure(status) {
43850
44271
  return status.state === "package-missing" || status.state === "binary-missing" || status.state === "load-failed";
43851
44272
  }
44273
+ function describeNativeFailure(status) {
44274
+ return status.state === "package-missing" ? "package is not installed" : status.state === "binary-missing" ? "expected platform binding file is absent" : `binding failed to load: ${status.reason}`;
44275
+ }
44276
+ function isLocalEmbeddingRuntimeBroken(status) {
44277
+ return status.state === "both-broken" || isNativeLocalEmbeddingRuntimeFailure(status);
44278
+ }
43852
44279
  function formatLocalEmbeddingRuntimeDoctorWarning(status) {
43853
- const cause = status.state === "package-missing" ? "package is not installed" : status.state === "binary-missing" ? "expected platform binding file is absent" : `binding failed to load: ${status.reason}`;
43854
- return "Embedding provider: local — onnxruntime-node native binding missing — " + `${cause}; its postinstall likely failed. Embeddings will not work. ` + "Reinstall with network access to the npm registry and GitHub releases, " + "or switch `embedding.provider` to an HTTP endpoint (`openai-compatible`).";
44280
+ if (status.state !== "both-broken") {
44281
+ return "Embedding provider: local — onnxruntime-node native binding missing — " + `${describeNativeFailure(status)}; its postinstall likely failed. Embeddings will not work. ` + "Reinstall with network access to the npm registry and GitHub releases, " + "or switch `embedding.provider` to an HTTP endpoint (`openai-compatible`).";
44282
+ }
44283
+ return "Embedding provider: local — native runtime and WASM fallback both unavailable — " + `native: ${describeNativeFailure(status.nativeFailure)}; WASM: ${status.wasmReason}; ` + "their install or postinstall likely failed. Reinstall with network access to the npm registry and GitHub releases, " + "or switch `embedding.provider` to an HTTP endpoint (`openai-compatible`).";
44284
+ }
44285
+ function formatLocalEmbeddingRuntimeWasmFallback(status) {
44286
+ return "Embedding provider: local — onnxruntime-node native binding failed " + `(${describeNativeFailure(status.nativeFailure)}); using onnxruntime-web (WASM) at ${status.wasmPath}. ` + "WASM inference is slower than native; a remote `openai-compatible` provider may be faster.";
43855
44287
  }
43856
44288
  function expectedBinaryRelPath(platform, arch) {
43857
44289
  const supportedPlatform = platform === "linux" || platform === "darwin" || platform === "win32";
@@ -43860,20 +44292,52 @@ function expectedBinaryRelPath(platform, arch) {
43860
44292
  return null;
43861
44293
  return join24("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
43862
44294
  }
44295
+ function probeWasmRuntimeFromRequire(requireFn) {
44296
+ try {
44297
+ const resolved = requireFn.resolve("onnxruntime-web");
44298
+ const packageDir = packageDirFromResolved(resolved, "onnxruntime-web");
44299
+ const loadFailure = probeOnnxRuntimeNodeLoad(packageDir);
44300
+ if (loadFailure === null)
44301
+ return { state: "ok", wasmPath: packageDir };
44302
+ return { state: "failed", reason: loadFailure.reason };
44303
+ } catch (error51) {
44304
+ return {
44305
+ state: "failed",
44306
+ reason: `onnxruntime-web is not resolvable: ${describeError(error51)}`
44307
+ };
44308
+ }
44309
+ }
44310
+ function withWasmFallback(native, probeWasm) {
44311
+ if (!isNativeLocalEmbeddingRuntimeFailure(native))
44312
+ return native;
44313
+ const wasm = probeWasm();
44314
+ if (wasm.state === "ok") {
44315
+ return { state: "wasm-fallback", nativeFailure: native, wasmPath: wasm.wasmPath };
44316
+ }
44317
+ return { state: "both-broken", nativeFailure: native, wasmReason: wasm.reason };
44318
+ }
44319
+ function probeWasmRuntimeAt(installRoot) {
44320
+ const requireFn = createRequire4(join24(installRoot, "package.json"));
44321
+ return probeWasmRuntimeFromRequire(requireFn);
44322
+ }
43863
44323
  function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform, arch = process.arch) {
43864
44324
  const packageDir = join24(installRoot, "node_modules", "onnxruntime-node");
44325
+ let native;
43865
44326
  if (!existsSync28(join24(packageDir, "package.json"))) {
43866
- return { state: "package-missing", packageDir };
43867
- }
43868
- const rel = expectedBinaryRelPath(platform, arch);
43869
- if (rel === null) {
43870
- return probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath: packageDir };
43871
- }
43872
- const binaryPath = join24(packageDir, rel);
43873
- if (!existsSync28(binaryPath)) {
43874
- return { state: "binary-missing", packageDir, expectedBinary: binaryPath };
44327
+ native = { state: "package-missing", packageDir };
44328
+ } else {
44329
+ const rel = expectedBinaryRelPath(platform, arch);
44330
+ if (rel === null) {
44331
+ native = probeOnnxRuntimeNodeLoad(packageDir) ?? {
44332
+ state: "ok",
44333
+ binaryPath: packageDir
44334
+ };
44335
+ } else {
44336
+ const binaryPath = join24(packageDir, rel);
44337
+ native = existsSync28(binaryPath) ? probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath } : { state: "binary-missing", packageDir, expectedBinary: binaryPath };
44338
+ }
43875
44339
  }
43876
- return probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath };
44340
+ return withWasmFallback(native, () => probeWasmRuntimeAt(installRoot));
43877
44341
  }
43878
44342
  function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, arch = process.arch) {
43879
44343
  const existing = installRoots.filter((root) => existsSync28(root));
@@ -43883,21 +44347,44 @@ function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, a
43883
44347
  reason: "no installed plugin tree found to inspect"
43884
44348
  };
43885
44349
  }
44350
+ let firstFallback = null;
43886
44351
  let firstFailure = null;
43887
44352
  for (const root of existing) {
43888
44353
  const status = checkLocalEmbeddingRuntimeAt(root, platform, arch);
43889
44354
  if (status.state === "ok")
43890
44355
  return status;
44356
+ if (status.state === "wasm-fallback") {
44357
+ if (firstFallback === null)
44358
+ firstFallback = status;
44359
+ continue;
44360
+ }
43891
44361
  if (firstFailure === null)
43892
44362
  firstFailure = status;
43893
44363
  }
43894
- return firstFailure ?? { state: "unknown", reason: "no candidate roots" };
44364
+ return firstFallback ?? firstFailure ?? { state: "unknown", reason: "no candidate roots" };
43895
44365
  }
43896
44366
  function packageDirFromResolved(resolvedPath, packageName) {
43897
44367
  const marker = `node_modules${sep}${packageName.split("/").join(sep)}`;
43898
44368
  const idx = resolvedPath.indexOf(marker);
43899
44369
  return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname16(resolvedPath);
43900
44370
  }
44371
+ function probeWasmRuntimeByResolution(pluginDir) {
44372
+ try {
44373
+ const reqPlugin = createRequire4(join24(pluginDir, "package.json"));
44374
+ const direct = probeWasmRuntimeFromRequire(reqPlugin);
44375
+ if (direct.state === "ok" || !direct.reason.startsWith("onnxruntime-web is not resolvable")) {
44376
+ return direct;
44377
+ }
44378
+ const tfResolved = reqPlugin.resolve("@huggingface/transformers");
44379
+ const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
44380
+ return probeWasmRuntimeFromRequire(createRequire4(join24(tfDir, "package.json")));
44381
+ } catch (error51) {
44382
+ return {
44383
+ state: "failed",
44384
+ reason: `could not resolve onnxruntime-web (${describeError(error51)})`
44385
+ };
44386
+ }
44387
+ }
43901
44388
  function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.platform, arch = process.arch) {
43902
44389
  if (!existsSync28(join24(pluginDir, "package.json"))) {
43903
44390
  return { state: "unknown", reason: "plugin package dir not found" };
@@ -43917,10 +44404,10 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
43917
44404
  } catch (error51) {
43918
44405
  resolveError = error51?.code;
43919
44406
  if (resolveError === "ERR_MODULE_NOT_FOUND" || resolveError === "MODULE_NOT_FOUND") {
43920
- return {
44407
+ return withWasmFallback({
43921
44408
  state: "package-missing",
43922
44409
  packageDir: join24(pluginDir, "node_modules", "onnxruntime-node")
43923
- };
44410
+ }, () => probeWasmRuntimeByResolution(pluginDir));
43924
44411
  }
43925
44412
  return {
43926
44413
  state: "unknown",
@@ -43931,14 +44418,14 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
43931
44418
  return { state: "unknown", reason: "onnxruntime-node resolution produced no path" };
43932
44419
  }
43933
44420
  const rel = expectedBinaryRelPath(platform, arch);
44421
+ let native;
43934
44422
  if (rel === null) {
43935
- return probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath: onnxDir };
43936
- }
43937
- const binaryPath = join24(onnxDir, rel);
43938
- if (!existsSync28(binaryPath)) {
43939
- return { state: "binary-missing", packageDir: onnxDir, expectedBinary: binaryPath };
44423
+ native = probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath: onnxDir };
44424
+ } else {
44425
+ const binaryPath = join24(onnxDir, rel);
44426
+ native = existsSync28(binaryPath) ? probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath } : { state: "binary-missing", packageDir: onnxDir, expectedBinary: binaryPath };
43940
44427
  }
43941
- return probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath };
44428
+ return withWasmFallback(native, () => probeWasmRuntimeByResolution(pluginDir));
43942
44429
  }
43943
44430
  var ONNX_LOAD_PROBE_TIMEOUT_MS = 1e4, ONNX_LOAD_PROBE_OUTPUT_LIMIT = 800, ONNX_LOAD_PROBE_PACKAGE_DIR_ENV = "MAGIC_CONTEXT_ONNX_RUNTIME_NODE_PACKAGE_DIR", ONNX_RUNTIME_NODE_LOAD_PROBE_SCRIPT, runOnnxRuntimeNodeLoadProbeChildForRuntime;
43944
44431
  var init_embedding_runtime = __esm(() => {
@@ -44064,7 +44551,7 @@ var init_issue_body = __esm(() => {
44064
44551
  });
44065
44552
 
44066
44553
  // src/lib/logs-opencode.ts
44067
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "node:fs";
44554
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync8 } from "node:fs";
44068
44555
  import { join as join25 } from "node:path";
44069
44556
  function sanitizeLogContent(content) {
44070
44557
  return sanitizeDiagnosticText(content);
@@ -44107,7 +44594,7 @@ function filterLogLinesBySession(lines, sessionId) {
44107
44594
  }
44108
44595
  async function bundleIssueReport(report, description, title, sessionFilter = null) {
44109
44596
  const LOG_TAIL_LINES = 400;
44110
- const allLogLines = report.logFile.exists ? readFileSync17(report.logFile.path, "utf-8").split(/\r?\n/) : [];
44597
+ const allLogLines = report.logFile.exists ? readFileSync18(report.logFile.path, "utf-8").split(/\r?\n/) : [];
44111
44598
  const logLines = filterLogLinesBySession(allLogLines, sessionFilter);
44112
44599
  const recentLog = sanitizeLogContent(logLines.slice(-LOG_TAIL_LINES).join(`
44113
44600
  `)).trim();
@@ -44121,8 +44608,16 @@ async function bundleIssueReport(report, description, title, sessionFilter = nul
44121
44608
  const sanitizedConfigPath = sanitizeDiagnosticText(report.configPaths.magicContextConfig);
44122
44609
  const sanitizedDescription = sanitizeDiagnosticText(description);
44123
44610
  const sanitizedTitle = sanitizeDiagnosticText(title).trim();
44611
+ const selectedSession = sessionFilter ? report.recentSessions.find((session) => session.sessionId === sessionFilter) : undefined;
44612
+ const sessionContext = selectedSession ? [
44613
+ "## Session context",
44614
+ `- Selected session: ${sanitizeDiagnosticText(selectedSession.sessionId)}`,
44615
+ `- Parent session: ${sanitizeDiagnosticText(selectedSession.parentSessionId ?? "none")}`,
44616
+ ""
44617
+ ] : [];
44124
44618
  const rawBodyMarkdown = [
44125
44619
  ...sanitizedTitle ? ["## Title", sanitizedTitle, ""] : [],
44620
+ ...sessionContext,
44126
44621
  "## Description",
44127
44622
  sanitizedDescription,
44128
44623
  "",
@@ -44158,10 +44653,16 @@ async function bundleIssueReport(report, description, title, sessionFilter = nul
44158
44653
  ].join(`
44159
44654
  `);
44160
44655
  const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
44161
- const path6 = join25(process.cwd(), `magic-context-issue-${formatTimestamp(new Date)}.md`);
44656
+ const truncated = bodyMarkdown !== rawBodyMarkdown;
44657
+ const timestamp3 = formatTimestamp(new Date);
44658
+ const path6 = join25(process.cwd(), `magic-context-issue-${timestamp3}.md`);
44162
44659
  writeFileSync8(path6, `${bodyMarkdown}
44163
44660
  `);
44164
- return { path: path6, bodyMarkdown };
44661
+ const fullPath = truncated ? join25(process.cwd(), `magic-context-issue-${timestamp3}-full.md`) : undefined;
44662
+ if (fullPath)
44663
+ writeFileSync8(fullPath, `${rawBodyMarkdown}
44664
+ `);
44665
+ return { path: path6, bodyMarkdown, ...fullPath ? { fullPath } : {}, truncated };
44165
44666
  }
44166
44667
  var HISTORIAN_LOG_PATTERNS;
44167
44668
  var init_logs_opencode = __esm(() => {
@@ -44465,7 +44966,7 @@ import {
44465
44966
  accessSync as accessSync2,
44466
44967
  existsSync as existsSync29,
44467
44968
  constants as fsConstants,
44468
- readFileSync as readFileSync18,
44969
+ readFileSync as readFileSync19,
44469
44970
  renameSync as renameSync7,
44470
44971
  statSync as statSync12,
44471
44972
  writeFileSync as writeFileSync9
@@ -44519,7 +45020,7 @@ function getWinningConfig(directory, surface) {
44519
45020
  try {
44520
45021
  if (!existsSync29(path6))
44521
45022
  continue;
44522
- const parsed = parseJsonConfig(readFileSync18(path6, "utf-8"));
45023
+ const parsed = parseJsonConfig(readFileSync19(path6, "utf-8"));
44523
45024
  const entries = getPluginEntries(parsed);
44524
45025
  if (entries.some((entry) => entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))) {
44525
45026
  if (winner) {
@@ -44555,14 +45056,14 @@ var init_checker = __esm(() => {
44555
45056
  });
44556
45057
 
44557
45058
  // src/lib/opencode-plugin-schema-fence.ts
44558
- import { existsSync as existsSync30, readdirSync as readdirSync4, readFileSync as readFileSync19 } from "node:fs";
45059
+ import { existsSync as existsSync30, readdirSync as readdirSync4, readFileSync as readFileSync20 } from "node:fs";
44559
45060
  import { join as join28 } from "node:path";
44560
45061
  import { gunzipSync } from "node:zlib";
44561
45062
  function readPackageVersion(packageJsonPath) {
44562
45063
  try {
44563
45064
  if (!existsSync30(packageJsonPath))
44564
45065
  return null;
44565
- const packageJson = JSON.parse(readFileSync19(packageJsonPath, "utf-8"));
45066
+ const packageJson = JSON.parse(readFileSync20(packageJsonPath, "utf-8"));
44566
45067
  if (packageJson.name !== OPENCODE_PLUGIN_NAME || typeof packageJson.version !== "string") {
44567
45068
  return null;
44568
45069
  }
@@ -44599,7 +45100,7 @@ function readFenceFromDist(packageDirectory) {
44599
45100
  }
44600
45101
  if (!entry.isFile() || !/\.(?:[cm]?js|ts)$/.test(entry.name))
44601
45102
  continue;
44602
- const fence = readFenceValue(readFileSync19(path6, "utf-8"));
45103
+ const fence = readFenceValue(readFileSync20(path6, "utf-8"));
44603
45104
  if (fence !== null)
44604
45105
  fenceValues.add(fence);
44605
45106
  }
@@ -44767,85 +45268,6 @@ var init_opencode_plugin_schema_fence = __esm(() => {
44767
45268
  EXACT_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
44768
45269
  });
44769
45270
 
44770
- // ../plugin/src/features/magic-context/fail-closed-block.ts
44771
- function normalizeFailClosedProcessKind(process3) {
44772
- switch (process3.kind) {
44773
- case "OpenCode server":
44774
- case "OpenCode instance (TUI/CLI)":
44775
- case "Pi":
44776
- case "process":
44777
- return process3.kind;
44778
- }
44779
- switch (process3.harness?.trim().toLowerCase()) {
44780
- case "opencode server":
44781
- return "OpenCode server";
44782
- case "opencode instance (tui/cli)":
44783
- case "opencode instance":
44784
- return "OpenCode instance (TUI/CLI)";
44785
- case "pi":
44786
- case "pi harness":
44787
- case "omp":
44788
- return "Pi";
44789
- default:
44790
- return "process";
44791
- }
44792
- }
44793
- function formatFailClosedBlockingProcesses(processes) {
44794
- const uniqueProcesses = new Map;
44795
- for (const process3 of processes) {
44796
- if (!Number.isInteger(process3.pid) || process3.pid <= 0)
44797
- continue;
44798
- const kind = normalizeFailClosedProcessKind(process3);
44799
- uniqueProcesses.set(`${kind}\x00${process3.pid}`, { kind, pid: process3.pid });
44800
- }
44801
- const entries = [...uniqueProcesses.values()];
44802
- const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
44803
- const rendered = visible.map(({ kind, pid }) => `${kind} (PID ${pid})`);
44804
- const omitted = entries.length - visible.length;
44805
- if (omitted > 0)
44806
- rendered.push(`${omitted} more blocking process(es)`);
44807
- if (rendered.length === 0)
44808
- return "a live process";
44809
- if (rendered.length === 1)
44810
- return rendered[0];
44811
- const last = rendered.pop();
44812
- return `${rendered.join(", ")}, and ${last}`;
44813
- }
44814
- function formatFailClosedBlockingMessage(reason) {
44815
- if (reason.kind === "migration_guard") {
44816
- if (reason.unreadableFile) {
44817
- const arm = reason.unreadableArm ?? "io";
44818
- const recovery = arm === "io" ? `If none of these processes are running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop the relevant process before deleting it.`;
44819
- return [
44820
- `Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live process cannot be proven.`,
44821
- recovery,
44822
- `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
44823
- ].join(" ");
44824
- }
44825
- return [
44826
- `Magic Context cannot migrate the shared database because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
44827
- "Restart the blocking process (it will pick up the new build and migrate on start), or shut it down and retry.",
44828
- `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
44829
- ].join(" ");
44830
- }
44831
- if (reason.kind === "schema_fence") {
44832
- return [
44833
- `Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (upstream migration lane v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
44834
- `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
44835
- ].join(" ");
44836
- }
44837
- const cause = reason.cause.trim().length > 0 ? reason.cause.trim() : "unknown storage error";
44838
- return [
44839
- `Magic Context cannot operate: persistent storage failed (${cause}).`,
44840
- "The plugin will not silently degrade to native compaction while enabled.",
44841
- `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
44842
- ].join(" ");
44843
- }
44844
- var FAIL_CLOSED_DOCTOR_COMMAND = "npx @cortexkit/magic-context@latest doctor", OPENCODE_INTERNAL_AGENT_NAMES, MAX_FORMATTED_BLOCKING_PROCESSES = 8;
44845
- var init_fail_closed_block = __esm(() => {
44846
- OPENCODE_INTERNAL_AGENT_NAMES = new Set(["title", "summary", "compaction"]);
44847
- });
44848
-
44849
45271
  // src/lib/storage-versions.ts
44850
45272
  function checkStorageVersionFence(versions2, options = {}) {
44851
45273
  const {
@@ -44896,13 +45318,13 @@ var init_storage_versions = __esm(async () => {
44896
45318
  });
44897
45319
 
44898
45320
  // src/commands/doctor-opencode-cache.ts
44899
- import { existsSync as existsSync31, readFileSync as readFileSync20, rmSync as rmSync3 } from "node:fs";
45321
+ import { existsSync as existsSync31, readFileSync as readFileSync21, rmSync as rmSync3 } from "node:fs";
44900
45322
  function readCachedPluginVersion(pluginCacheDir) {
44901
45323
  try {
44902
45324
  const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
44903
45325
  if (!existsSync31(installedPkgPath))
44904
45326
  return;
44905
- const pkg = JSON.parse(readFileSync20(installedPkgPath, "utf-8"));
45327
+ const pkg = JSON.parse(readFileSync21(installedPkgPath, "utf-8"));
44906
45328
  return typeof pkg.version === "string" ? pkg.version : undefined;
44907
45329
  } catch {
44908
45330
  return;
@@ -44941,26 +45363,26 @@ async function clearPluginCache(options = {}, deps = {}) {
44941
45363
  };
44942
45364
  }
44943
45365
  const cleared = [];
44944
- const failed = [];
45366
+ const failed2 = [];
44945
45367
  for (const entry of clearTargets) {
44946
45368
  try {
44947
45369
  remove(entry.path);
44948
45370
  cleared.push(entry);
44949
45371
  } catch (err) {
44950
- failed.push({
45372
+ failed2.push({
44951
45373
  path: entry.path,
44952
45374
  error: err instanceof Error ? err.message : String(err)
44953
45375
  });
44954
45376
  }
44955
45377
  }
44956
- if (failed.length > 0) {
44957
- const firstFailure = failed[0];
45378
+ if (failed2.length > 0) {
45379
+ const firstFailure = failed2[0];
44958
45380
  return {
44959
45381
  action: "error",
44960
45382
  path: firstFailure?.path ?? clearTargets[0]?.path ?? existingRoots[0] ?? "",
44961
- paths: failed.map((entry) => entry.path),
45383
+ paths: failed2.map((entry) => entry.path),
44962
45384
  clearedPaths: cleared.map((entry) => entry.path),
44963
- failedPaths: failed.map((entry) => entry.path),
45385
+ failedPaths: failed2.map((entry) => entry.path),
44964
45386
  error: firstFailure?.error
44965
45387
  };
44966
45388
  }
@@ -44978,8 +45400,8 @@ var init_doctor_opencode_cache = __esm(() => {
44978
45400
  });
44979
45401
 
44980
45402
  // src/commands/doctor-opencode.ts
44981
- import { execSync as execSync2, spawnSync as spawnSync6 } from "node:child_process";
44982
- import { existsSync as existsSync32, readFileSync as readFileSync21, statSync as statSync13 } from "node:fs";
45403
+ import { spawnSync as spawnSync7 } from "node:child_process";
45404
+ import { existsSync as existsSync32, readFileSync as readFileSync22, statSync as statSync13 } from "node:fs";
44983
45405
  import { createRequire as createRequire5 } from "node:module";
44984
45406
  import { homedir as homedir17 } from "node:os";
44985
45407
  import { join as join29 } from "node:path";
@@ -45089,7 +45511,7 @@ function collectNpmReleaseAgeWarnings() {
45089
45511
  if (!existsSync32(npmrcPath))
45090
45512
  return ageWarnings;
45091
45513
  try {
45092
- const npmrc = readFileSync21(npmrcPath, "utf-8");
45514
+ const npmrc = readFileSync22(npmrcPath, "utf-8");
45093
45515
  for (const line of npmrc.split(`
45094
45516
  `)) {
45095
45517
  const trimmed = line.trim();
@@ -45119,26 +45541,18 @@ function compareVersions(a3, b) {
45119
45541
  }
45120
45542
  return 0;
45121
45543
  }
45122
- function isGhInstalled() {
45123
- try {
45124
- execSync2("gh --version", { stdio: "pipe" });
45125
- return true;
45126
- } catch {
45127
- return false;
45128
- }
45129
- }
45130
45544
  function openBrowser(url2) {
45131
45545
  try {
45132
45546
  if (process.platform === "darwin") {
45133
- const child = spawnSync6("open", [url2], { stdio: "ignore" });
45547
+ const child = spawnSync7("open", [url2], { stdio: "ignore" });
45134
45548
  if (child.status === 0)
45135
45549
  return;
45136
45550
  } else if (process.platform === "linux") {
45137
- const child = spawnSync6("xdg-open", [url2], { stdio: "ignore" });
45551
+ const child = spawnSync7("xdg-open", [url2], { stdio: "ignore" });
45138
45552
  if (child.status === 0)
45139
45553
  return;
45140
45554
  } else if (process.platform === "win32") {
45141
- const child = spawnSync6("cmd", ["/c", "start", "", url2], { stdio: "ignore" });
45555
+ const child = spawnSync7("cmd", ["/c", "start", "", url2], { stdio: "ignore" });
45142
45556
  if (child.status === 0)
45143
45557
  return;
45144
45558
  }
@@ -45165,8 +45579,10 @@ async function runIssueFlow2() {
45165
45579
  ...report.recentSessions.map((session, index) => {
45166
45580
  const displayTitle = session.title.trim() || "(no title)";
45167
45581
  const truncatedTitle = displayTitle.length > 50 ? `${displayTitle.slice(0, 47)}...` : displayTitle;
45582
+ const childPrefix = session.parentSessionId ? " ↳ " : "";
45583
+ const parentSuffix = session.parentSessionId ? ` (child of ${session.parentSessionId})` : "";
45168
45584
  return {
45169
- label: `${truncatedTitle} — ${session.sessionId}${index === 0 ? " (most recent)" : ""}`,
45585
+ label: `${childPrefix}${truncatedTitle} — ${session.sessionId}${parentSuffix}${index === 0 ? " (most recent)" : ""}`,
45170
45586
  value: session.sessionId
45171
45587
  };
45172
45588
  }),
@@ -45179,30 +45595,23 @@ async function runIssueFlow2() {
45179
45595
  }
45180
45596
  s.start("Bundling issue report");
45181
45597
  const bundled = await bundleIssueReport(report, description, title, sessionFilter);
45182
- s.stop(`Report written to ${bundled.path}`);
45598
+ s.stop(bundled.fullPath ? `Report written to ${bundled.path}; full bundle at ${bundled.fullPath}` : `Report written to ${bundled.path}`);
45183
45599
  const shouldSubmit = await confirm2("Submit this issue on GitHub now?", true);
45184
- if (shouldSubmit && isGhInstalled()) {
45185
- const result = spawnSync6("gh", [
45186
- "issue",
45187
- "create",
45188
- "-R",
45189
- "cortexkit/magic-context",
45190
- "--title",
45191
- title,
45192
- "--body-file",
45193
- bundled.path
45194
- ], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
45195
- if (result.status === 0) {
45196
- log2.success(result.stdout.trim());
45600
+ if (shouldSubmit) {
45601
+ const result = submitGithubIssue(title, bundled.path);
45602
+ if (result.ok) {
45603
+ log2.success(result.output);
45604
+ if (bundled.fullPath) {
45605
+ log2.info(`Full diagnostics bundle available to drag onto the issue: ${bundled.fullPath}`);
45606
+ }
45197
45607
  outro2("Issue submitted — thanks for the report!");
45198
45608
  return 0;
45199
45609
  }
45200
- log2.warn(result.stderr.trim() || "gh issue create failed");
45201
- } else if (shouldSubmit && !isGhInstalled()) {
45202
- log2.warn("gh CLI not found — falling back to browser");
45610
+ const fallbackPath = bundled.fullPath ?? bundled.path;
45611
+ log2.warn(formatGithubIssueFallback(result, fallbackPath));
45203
45612
  }
45204
45613
  const url2 = `https://github.com/cortexkit/magic-context/issues/new?title=${encodeURIComponent(title)}&template=bug_report.yml`;
45205
- log2.info(`Open this URL and paste the contents of ${bundled.path} into the Diagnostics field:`);
45614
+ log2.info(`Open this URL and drag ${bundled.fullPath ?? bundled.path} into the Diagnostics field:`);
45206
45615
  log2.info(url2);
45207
45616
  openBrowser(url2);
45208
45617
  outro2("Issue report ready");
@@ -45216,6 +45625,10 @@ async function runIssueFlow2() {
45216
45625
  }
45217
45626
  function checkLocalEmbeddingRuntimeForDoctor() {
45218
45627
  const runtime = checkLocalEmbeddingRuntime(getOpenCodePluginCacheRoots());
45628
+ if (runtime.state === "wasm-fallback") {
45629
+ log2.warn(formatLocalEmbeddingRuntimeWasmFallback(runtime));
45630
+ return { issues: 0 };
45631
+ }
45219
45632
  if (isLocalEmbeddingRuntimeBroken(runtime)) {
45220
45633
  log2.warn(formatLocalEmbeddingRuntimeDoctorWarning(runtime));
45221
45634
  return { issues: 1, localRuntimeBroken: true };
@@ -45224,7 +45637,7 @@ function checkLocalEmbeddingRuntimeForDoctor() {
45224
45637
  log2.warn(`Local embedding runtime unverified: ${runtime.reason}`);
45225
45638
  return { issues: 0, unverified: true };
45226
45639
  }
45227
- log2.success("Embedding provider: local (Xenova/all-MiniLM-L6-v2 bundled)");
45640
+ log2.success("Embedding provider: local (native runtime OK; Xenova/all-MiniLM-L6-v2 bundled)");
45228
45641
  return { issues: 0 };
45229
45642
  }
45230
45643
  async function checkEmbeddingConfig(magicContextConfigPath) {
@@ -45594,7 +46007,7 @@ async function runDoctor2(options = {}) {
45594
46007
  }
45595
46008
  if (paths.opencodeConfigFormat !== "none") {
45596
46009
  try {
45597
- const raw = readFileSync21(paths.opencodeConfig, "utf-8");
46010
+ const raw = readFileSync22(paths.opencodeConfig, "utf-8");
45598
46011
  const config2 = import_comment_json12.parse(raw);
45599
46012
  const rawPlugins = Array.isArray(config2?.plugin) ? config2.plugin : [];
45600
46013
  const existingIdx = rawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
@@ -45681,7 +46094,7 @@ async function runDoctor2(options = {}) {
45681
46094
  fixed++;
45682
46095
  } else if (existsSync32(paths.tuiConfig)) {
45683
46096
  try {
45684
- const tuiRaw = readFileSync21(paths.tuiConfig, "utf-8");
46097
+ const tuiRaw = readFileSync22(paths.tuiConfig, "utf-8");
45685
46098
  const tuiConfig = import_comment_json12.parse(tuiRaw);
45686
46099
  const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
45687
46100
  const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
@@ -45935,6 +46348,7 @@ var init_doctor_opencode = __esm(async () => {
45935
46348
  init_config_location_migration();
45936
46349
  init_diagnostics_opencode();
45937
46350
  init_embedding_runtime();
46351
+ init_github_issue();
45938
46352
  init_logs_opencode();
45939
46353
  init_migrate_dreamer_v2_doctor();
45940
46354
  init_opencode_detect();
@@ -45957,7 +46371,7 @@ var init_doctor_opencode = __esm(async () => {
45957
46371
 
45958
46372
  // src/lib/diagnostics-pi.ts
45959
46373
  import { createHash as createHash5 } from "node:crypto";
45960
- import { existsSync as existsSync33, readdirSync as readdirSync5, readFileSync as readFileSync22, statSync as statSync14 } from "node:fs";
46374
+ import { existsSync as existsSync33, readdirSync as readdirSync5, readFileSync as readFileSync23, statSync as statSync14 } from "node:fs";
45961
46375
  import { createRequire as createRequire6 } from "node:module";
45962
46376
  import { homedir as homedir18, userInfo as userInfo2 } from "node:os";
45963
46377
  import { join as join30 } from "node:path";
@@ -46031,7 +46445,7 @@ function readJsonc(path6) {
46031
46445
  return { value: {} };
46032
46446
  try {
46033
46447
  return {
46034
- value: import_comment_json13.parse(readFileSync22(path6, "utf-8"))
46448
+ value: import_comment_json13.parse(readFileSync23(path6, "utf-8"))
46035
46449
  };
46036
46450
  } catch (error51) {
46037
46451
  return {
@@ -46101,7 +46515,7 @@ function collectPiRecentSessions() {
46101
46515
  }
46102
46516
  function parseHistorianDumpMeta2(path6) {
46103
46517
  try {
46104
- const xml = readFileSync22(path6, "utf-8");
46518
+ const xml = readFileSync23(path6, "utf-8");
46105
46519
  const parsed = parseCompartmentOutput(xml);
46106
46520
  const factCountByCategory = {};
46107
46521
  for (const fact of parsed.facts) {
@@ -46346,7 +46760,7 @@ var init_diagnostics_pi = __esm(() => {
46346
46760
  });
46347
46761
 
46348
46762
  // src/lib/logs-pi.ts
46349
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync10 } from "node:fs";
46763
+ import { readFileSync as readFileSync24, writeFileSync as writeFileSync10 } from "node:fs";
46350
46764
  import { join as join31 } from "node:path";
46351
46765
  function sanitizeLogContent2(content) {
46352
46766
  return sanitizeString2(content);
@@ -46376,7 +46790,7 @@ function filterLogLinesBySession2(lines, sessionId) {
46376
46790
  }
46377
46791
  async function bundleIssueReport2(report, description, title, options = {}) {
46378
46792
  const LOG_TAIL_LINES = 400;
46379
- const allLogLines = report.logFile.exists ? readFileSync23(report.logFile.path, "utf-8").split(/\r?\n/) : [];
46793
+ const allLogLines = report.logFile.exists ? readFileSync24(report.logFile.path, "utf-8").split(/\r?\n/) : [];
46380
46794
  const logLines = filterLogLinesBySession2(allLogLines, options.sessionFilter ?? null);
46381
46795
  const recentLog = sanitizeLogContent2(logLines.slice(-LOG_TAIL_LINES).join(`
46382
46796
  `)).trim();
@@ -46411,11 +46825,17 @@ async function bundleIssueReport2(report, description, title, options = {}) {
46411
46825
  ].join(`
46412
46826
  `);
46413
46827
  const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
46828
+ const truncated = bodyMarkdown !== rawBodyMarkdown;
46414
46829
  const cwd = options.cwd ?? process.cwd();
46415
- const path6 = join31(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
46830
+ const timestamp3 = formatTimestamp2(options.now ?? new Date);
46831
+ const path6 = join31(cwd, `magic-context-pi-issue-${timestamp3}.md`);
46416
46832
  writeFileSync10(path6, `${bodyMarkdown}
46417
46833
  `);
46418
- return { path: path6, bodyMarkdown };
46834
+ const fullPath = truncated ? join31(cwd, `magic-context-pi-issue-${timestamp3}-full.md`) : undefined;
46835
+ if (fullPath)
46836
+ writeFileSync10(fullPath, `${rawBodyMarkdown}
46837
+ `);
46838
+ return { path: path6, bodyMarkdown, ...fullPath ? { fullPath } : {}, truncated };
46419
46839
  }
46420
46840
  var init_logs_pi = __esm(() => {
46421
46841
  init_diagnostics_pi();
@@ -46423,8 +46843,8 @@ var init_logs_pi = __esm(() => {
46423
46843
  });
46424
46844
 
46425
46845
  // src/commands/doctor-pi.ts
46426
- import { execFileSync as execFileSync6, spawnSync as spawnSync7 } from "node:child_process";
46427
- import { existsSync as existsSync34, mkdirSync as mkdirSync11, readdirSync as readdirSync6, readFileSync as readFileSync24, rmSync as rmSync4, statSync as statSync15 } from "node:fs";
46846
+ import { execFileSync as execFileSync6, spawnSync as spawnSync8 } from "node:child_process";
46847
+ import { existsSync as existsSync34, mkdirSync as mkdirSync11, readdirSync as readdirSync6, readFileSync as readFileSync25, rmSync as rmSync4, statSync as statSync15 } from "node:fs";
46428
46848
  import { createRequire as createRequire7 } from "node:module";
46429
46849
  import { homedir as homedir19 } from "node:os";
46430
46850
  import { dirname as dirname18, isAbsolute as isAbsolute5, join as join32 } from "node:path";
@@ -46517,7 +46937,7 @@ function summarize(results) {
46517
46937
  function readJsonc2(path6) {
46518
46938
  try {
46519
46939
  return {
46520
- value: import_comment_json14.parse(readFileSync24(path6, "utf-8"))
46940
+ value: import_comment_json14.parse(readFileSync25(path6, "utf-8"))
46521
46941
  };
46522
46942
  } catch (error51) {
46523
46943
  return {
@@ -46674,7 +47094,7 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
46674
47094
  const packageJson = join32(path6, "package.json");
46675
47095
  if (existsSync34(packageJson)) {
46676
47096
  try {
46677
- const pkg = JSON.parse(readFileSync24(packageJson, "utf-8"));
47097
+ const pkg = JSON.parse(readFileSync25(packageJson, "utf-8"));
46678
47098
  const name = typeof pkg.name === "string" ? pkg.name : "";
46679
47099
  const version2 = typeof pkg.version === "string" ? pkg.version : undefined;
46680
47100
  if (name === PACKAGE_NAME2) {
@@ -46901,7 +47321,12 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
46901
47321
  for (const pluginDir of piPluginDirCandidates(packages, options.cwd)) {
46902
47322
  const runtime = checkLocalEmbeddingRuntimeByResolution(pluginDir);
46903
47323
  if (runtime.state === "ok") {
46904
- add2(results, "pass", `Embedding provider: ${loadedConfig.config.embedding.provider} (native runtime present)`);
47324
+ add2(results, "pass", `Embedding provider: ${loadedConfig.config.embedding.provider} (native runtime OK)`);
47325
+ runtimeReported = true;
47326
+ break;
47327
+ }
47328
+ if (runtime.state === "wasm-fallback") {
47329
+ add2(results, "warn", formatLocalEmbeddingRuntimeWasmFallback(runtime));
46905
47330
  runtimeReported = true;
46906
47331
  break;
46907
47332
  }
@@ -46943,7 +47368,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
46943
47368
  if (existsSync34(logPath)) {
46944
47369
  const stat = statSync15(logPath);
46945
47370
  const sizeKb = (stat.size / 1024).toFixed(0);
46946
- const lines = readFileSync24(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
47371
+ const lines = readFileSync25(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
46947
47372
  add2(results, "info", `Log file: ${logPath} (${sizeKb} KB)`);
46948
47373
  const lastLine = lines.at(-1);
46949
47374
  add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
@@ -47021,17 +47446,31 @@ function repair2(plan, prompts) {
47021
47446
  }
47022
47447
  return fixed;
47023
47448
  }
47024
- function ghAvailableAndAuthed(deps) {
47025
- try {
47026
- deps.execFileSync("gh", ["--version"], {
47027
- stdio: ["ignore", "pipe", "ignore"]
47449
+ function runGhCommandWithDeps2(deps, args) {
47450
+ if (args[0] === "issue") {
47451
+ const result = deps.spawnSync("gh", args, {
47452
+ encoding: "utf-8",
47453
+ stdio: ["ignore", "pipe", "pipe"]
47028
47454
  });
47029
- deps.execFileSync("gh", ["auth", "status"], {
47030
- stdio: ["ignore", "pipe", "ignore"]
47455
+ return {
47456
+ status: result.status,
47457
+ stdout: String(result.stdout ?? ""),
47458
+ stderr: String(result.stderr ?? "")
47459
+ };
47460
+ }
47461
+ try {
47462
+ const output = deps.execFileSync("gh", args, {
47463
+ encoding: "utf-8",
47464
+ stdio: ["ignore", "pipe", "pipe"]
47031
47465
  });
47032
- return true;
47033
- } catch {
47034
- return false;
47466
+ return { status: 0, stdout: String(output ?? ""), stderr: "" };
47467
+ } catch (error51) {
47468
+ const result = error51;
47469
+ return {
47470
+ status: typeof result.status === "number" ? result.status : 1,
47471
+ stdout: String(result.stdout ?? ""),
47472
+ stderr: String(result.stderr ?? "")
47473
+ };
47035
47474
  }
47036
47475
  }
47037
47476
  async function runIssueFlow3(options) {
@@ -47069,32 +47508,22 @@ async function runIssueFlow3(options) {
47069
47508
  now: options.deps.now(),
47070
47509
  sessionFilter
47071
47510
  });
47072
- spinner3.stop(`Report written to ${bundled.path}`);
47073
- if (ghAvailableAndAuthed(options.deps)) {
47074
- const shouldSubmit = await options.prompts.confirm("Submit this issue on GitHub now?", false);
47075
- if (shouldSubmit) {
47076
- const result = options.deps.spawnSync("gh", [
47077
- "issue",
47078
- "create",
47079
- "-R",
47080
- "cortexkit/magic-context",
47081
- "--title",
47082
- `[pi] ${title}`,
47083
- "--body-file",
47084
- bundled.path
47085
- ], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
47086
- if (result.status === 0) {
47087
- options.prompts.log.success(String(result.stdout).trim());
47088
- options.prompts.outro("Issue submitted — thanks for the report!");
47089
- return 0;
47090
- }
47091
- options.prompts.log.warn(String(result.stderr).trim() || "gh issue create failed");
47511
+ spinner3.stop(bundled.fullPath ? `Report written to ${bundled.path}; full bundle at ${bundled.fullPath}` : `Report written to ${bundled.path}`);
47512
+ const shouldSubmit = await options.prompts.confirm("Submit this issue on GitHub now?", false);
47513
+ if (shouldSubmit) {
47514
+ const result = submitGithubIssue(`[pi] ${title}`, bundled.path, (args) => runGhCommandWithDeps2(options.deps, args));
47515
+ if (result.ok) {
47516
+ options.prompts.log.success(result.output);
47517
+ if (bundled.fullPath) {
47518
+ options.prompts.log.info(`Full diagnostics bundle available to drag onto the issue: ${bundled.fullPath}`);
47519
+ }
47520
+ options.prompts.outro("Issue submitted — thanks for the report!");
47521
+ return 0;
47092
47522
  }
47093
- } else {
47094
- options.prompts.log.warn("gh CLI is unavailable or not authenticated; printing report for manual issue creation");
47523
+ options.prompts.log.warn(formatGithubIssueFallback(result, bundled.fullPath ?? bundled.path));
47095
47524
  }
47096
47525
  console.log(bundled.bodyMarkdown);
47097
- options.prompts.log.info(`Open https://github.com/cortexkit/magic-context/issues/new and attach ${bundled.path}`);
47526
+ options.prompts.log.info(`Open https://github.com/cortexkit/magic-context/issues/new and drag ${bundled.fullPath ?? bundled.path} into the issue`);
47098
47527
  options.prompts.outro("Issue report ready");
47099
47528
  return 0;
47100
47529
  } catch (error51) {
@@ -47199,6 +47628,7 @@ var init_doctor_pi = __esm(async () => {
47199
47628
  init_config_location_migration();
47200
47629
  init_diagnostics_pi();
47201
47630
  init_embedding_runtime();
47631
+ init_github_issue();
47202
47632
  init_logs_pi();
47203
47633
  init_paths();
47204
47634
  init_pi_helpers();
@@ -47224,7 +47654,7 @@ var init_doctor_pi = __esm(async () => {
47224
47654
  openExistingContextDatabase,
47225
47655
  now: () => new Date,
47226
47656
  execFileSync: execFileSync6,
47227
- spawnSync: spawnSync7
47657
+ spawnSync: spawnSync8
47228
47658
  };
47229
47659
  });
47230
47660
 
@@ -47353,7 +47783,7 @@ async function runClear() {
47353
47783
  outro2("Done.");
47354
47784
  return 0;
47355
47785
  }
47356
- let failed = 0;
47786
+ let failed2 = 0;
47357
47787
  for (const idxStr of picks) {
47358
47788
  const idx = Number.parseInt(idxStr, 10);
47359
47789
  const item = items[idx];
@@ -47369,11 +47799,11 @@ async function runClear() {
47369
47799
  } catch (err) {
47370
47800
  s.stop(`Failed: ${item.path}`);
47371
47801
  log2.error(err.message);
47372
- failed += 1;
47802
+ failed2 += 1;
47373
47803
  }
47374
47804
  }
47375
- outro2(failed === 0 ? "Done." : `Done with ${failed} failure(s).`);
47376
- return failed === 0 ? 0 : 1;
47805
+ outro2(failed2 === 0 ? "Done." : `Done with ${failed2} failure(s).`);
47806
+ return failed2 === 0 ? 0 : 1;
47377
47807
  }
47378
47808
  function formatSize(bytes) {
47379
47809
  if (bytes < 1024)