(directory: string)
| 439 | } |
| 440 | |
| 441 | export function loadPluginConfigDetailed(directory: string): LoadResultDetailed { |
| 442 | const userDetected = detectConfigFile(getUserConfigBasePath()); |
| 443 | const projectDetected = detectConfigFile(getProjectConfigBasePath(directory)); |
| 444 | // Both-harness sources drive the GC-suppression signal; this-harness sources |
| 445 | // (OpenCode) drive the non-destructive read fallback when the base is absent. |
| 446 | const legacySources = resolveLegacyConfigSources(directory); |
| 447 | const harnessLegacy = resolveLegacyConfigSourcesForHarness(directory, "opencode"); |
| 448 | |
| 449 | // When the CortexKit base is absent (migration refused on a differing |
| 450 | // OpenCode/Pi pair, or hasn't run), read THIS harness's own legacy file |
| 451 | // instead of falling to schema defaults that would silently re-enable |
| 452 | // features the user disabled. |
| 453 | const userLegacyFallback = |
| 454 | userDetected.format === "none" |
| 455 | ? resolveLegacyReadFallback(harnessLegacy.user) |
| 456 | : { source: null }; |
| 457 | const projectLegacyFallback = |
| 458 | projectDetected.format === "none" |
| 459 | ? resolveLegacyReadFallback(harnessLegacy.project) |
| 460 | : { source: null }; |
| 461 | |
| 462 | // "Unmigrated" (→ untrusted, GC suppressed) ONLY when the base is absent, |
| 463 | // some legacy config exists, AND we did NOT read this harness's own legacy. |
| 464 | // If we read our own legacy the config is real → trusted. If only the OTHER |
| 465 | // harness's legacy exists we fell to defaults → keep GC suppressed so a |
| 466 | // default-config start can't reap the other harness's embedding vectors. |
| 467 | const legacyUserUnmigrated = |
| 468 | userDetected.format === "none" && |
| 469 | !userLegacyFallback.source && |
| 470 | legacySources.user.some((source) => existsSync(source.path)); |
| 471 | const legacyProjectUnmigrated = |
| 472 | projectDetected.format === "none" && |
| 473 | !projectLegacyFallback.source && |
| 474 | legacySources.project.some((source) => existsSync(source.path)); |
| 475 | |
| 476 | const userLoaded = |
| 477 | userDetected.format !== "none" |
| 478 | ? loadConfigFileDetailed(userDetected.path, "user") |
| 479 | : userLegacyFallback.source |
| 480 | ? loadConfigFileDetailed(userLegacyFallback.source.path, "user") |
| 481 | : null; |
| 482 | const projectLoaded = |
| 483 | projectDetected.format !== "none" |
| 484 | ? loadConfigFileDetailed(projectDetected.path, "project") |
| 485 | : projectLegacyFallback.source |
| 486 | ? loadConfigFileDetailed(projectLegacyFallback.source.path, "project") |
| 487 | : null; |
| 488 | |
| 489 | const allWarnings: string[] = []; |
| 490 | let mergedRaw: Record<string, unknown> = {}; |
| 491 | |
| 492 | if (userLegacyFallback.source) { |
| 493 | allWarnings.push( |
| 494 | `[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.`, |
| 495 | ); |
| 496 | } else if (legacyUserUnmigrated) { |
| 497 | allWarnings.push( |
| 498 | "[user config] legacy Magic Context config exists but the shared CortexKit config is absent; embedding registration is paused until config migration completes.", |
no test coverage detected