(ctx)
| 49 | import { closeQuietly } from "./shared/sqlite-helpers"; |
| 50 | |
| 51 | const server: Plugin = async (ctx) => { |
| 52 | // Move config from the legacy per-harness locations to the shared CortexKit |
| 53 | // location BEFORE loading (hard cutover: the loader reads only CortexKit). |
| 54 | // Idempotent + lock-guarded for Desktop multi-instance; fails open. Warnings |
| 55 | // (conflicts / partial failures) are surfaced via the config-warning path. |
| 56 | const configMigrationWarnings = migrateMagicContextConfigLocations(ctx.directory, { |
| 57 | warn: (m) => log(`[magic-context] ${m}`), |
| 58 | info: (m) => log(`[magic-context] ${m}`), |
| 59 | }); |
| 60 | const pluginConfig = loadPluginConfig(ctx.directory); |
| 61 | if (configMigrationWarnings.length > 0) { |
| 62 | pluginConfig.configWarnings = [ |
| 63 | ...configMigrationWarnings, |
| 64 | ...(pluginConfig.configWarnings ?? []), |
| 65 | ]; |
| 66 | } |
| 67 | // Apply SQLite connection tuning before the first openDatabase() below. |
| 68 | setSqlitePragmaConfig({ |
| 69 | cacheSizeMb: pluginConfig.sqlite.cache_size_mb, |
| 70 | mmapSizeMb: pluginConfig.sqlite.mmap_size_mb, |
| 71 | }); |
| 72 | // Debug data-collection toggle: when on, keep subagent child sessions |
| 73 | // (historian/dreamer/sidekick/migration) instead of deleting on success. |
| 74 | setKeepSubagents(pluginConfig.keep_subagents === true); |
| 75 | const autoUpdateAbort = new AbortController(); |
| 76 | // Abort on process exit via the shared single-listener registry. Registering |
| 77 | // a process.once("exit") here directly would add one listener PER plugin |
| 78 | // instance, and OpenCode Desktop runs many in one process (Node warns past 10). |
| 79 | registerExitAbort(autoUpdateAbort); |
| 80 | |
| 81 | // Surface config validation warnings to user and log |
| 82 | if (pluginConfig.configWarnings?.length) { |
| 83 | for (const w of pluginConfig.configWarnings) { |
| 84 | log(`[magic-context] config warning: ${w}`); |
| 85 | } |
| 86 | // Send warning to user via startup notification (after a short delay so session is ready) |
| 87 | const warningText = [ |
| 88 | "## ⚠️ Magic Context Config Warning", |
| 89 | "", |
| 90 | "Some configuration values are invalid and were replaced with defaults:", |
| 91 | "", |
| 92 | ...pluginConfig.configWarnings.map((w) => `- ${w}`), |
| 93 | "", |
| 94 | "Check your `magic-context.jsonc` to fix these values.", |
| 95 | ].join("\n"); |
| 96 | |
| 97 | setTimeout(async () => { |
| 98 | try { |
| 99 | const { sendIgnoredMessage } = await import( |
| 100 | "./hooks/magic-context/send-session-notification" |
| 101 | ); |
| 102 | // sendIgnoredMessage already handles TUI (toast) vs Desktop (ignored message) |
| 103 | // via isTuiConnected(). We need a session ID — use the first active session. |
| 104 | // SDK types don't expose `session.list()`'s actual response shape (the |
| 105 | // client surface has been through multiple revisions; some versions |
| 106 | // return `{ data: [...] }`, others return the array directly), so we |
| 107 | // probe both shapes defensively at runtime. |
| 108 | type SessionListFn = () => Promise< |
nothing calls this directly
no test coverage detected