olakai-cli 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,30 @@
1
1
  import {
2
2
  getCursorHooksPath,
3
+ getGeminiConfigHooksPath,
4
+ getGeminiSettingsPath,
3
5
  getPlugin,
4
6
  getToolScope,
5
7
  installCodexHooksConfig,
8
+ loadAntigravityConfig,
6
9
  loadCodexConfig,
7
10
  loadCursorConfig,
11
+ loadGeminiCliConfig,
8
12
  mergeCursorHooks,
13
+ mergeHooksFile,
14
+ mergeHooksSettings as mergeHooksSettings2,
15
+ readJsonFile as readJsonFile2,
16
+ readJsonFile2 as readJsonFile3,
9
17
  readRegistry,
10
18
  reconcileCurrentWorkspace,
11
19
  runMonitorInstall,
12
20
  upsertEntry,
21
+ writeAntigravityConfig,
13
22
  writeCodexConfig,
14
- writeCursorConfig
15
- } from "./chunk-75YQWZ4Q.js";
23
+ writeCursorConfig,
24
+ writeGeminiCliConfig,
25
+ writeJsonFile as writeJsonFile2,
26
+ writeJsonFile2 as writeJsonFile3
27
+ } from "./chunk-E33XD5CO.js";
16
28
  import {
17
29
  getAgent,
18
30
  listActivity,
@@ -124,10 +136,65 @@ var cursorAdapter = {
124
136
  fs.writeFileSync(hooksPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
125
137
  }
126
138
  };
139
+ var geminiCliAdapter = {
140
+ tool: "gemini-cli",
141
+ displayName: "Gemini CLI",
142
+ configRelLabel: ".olakai/monitor-gemini-cli.json",
143
+ hooksLabel: "~/.gemini/settings.json",
144
+ loadConfig: (root) => loadGeminiCliConfig(root) ?? null,
145
+ writeConfig: (root, config) => {
146
+ writeGeminiCliConfig(root, {
147
+ agentId: config.agentId,
148
+ apiKey: config.apiKey,
149
+ agentName: config.agentName,
150
+ source: config.source,
151
+ createdAt: config.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
152
+ monitoringEndpoint: config.monitoringEndpoint
153
+ });
154
+ },
155
+ repairHooks: (_root, homeDir = os.homedir()) => {
156
+ const settingsPath = getGeminiSettingsPath(homeDir);
157
+ const existing = readJsonFile2(settingsPath) ?? {};
158
+ const merged = {
159
+ ...existing,
160
+ hooks: mergeHooksSettings2(existing.hooks)
161
+ };
162
+ const dir = path.dirname(settingsPath);
163
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
164
+ writeJsonFile2(settingsPath, merged);
165
+ }
166
+ };
167
+ var antigravityAdapter = {
168
+ tool: "antigravity",
169
+ displayName: "Antigravity",
170
+ configRelLabel: ".olakai/monitor-antigravity.json",
171
+ hooksLabel: "~/.gemini/config/hooks.json",
172
+ loadConfig: (root) => loadAntigravityConfig(root) ?? null,
173
+ writeConfig: (root, config) => {
174
+ writeAntigravityConfig(root, {
175
+ agentId: config.agentId,
176
+ apiKey: config.apiKey,
177
+ agentName: config.agentName,
178
+ source: config.source,
179
+ createdAt: config.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
180
+ monitoringEndpoint: config.monitoringEndpoint
181
+ });
182
+ },
183
+ repairHooks: (_root, homeDir = os.homedir()) => {
184
+ const hooksPath = getGeminiConfigHooksPath(homeDir);
185
+ const existing = readJsonFile3(hooksPath) ?? {};
186
+ const merged = mergeHooksFile(existing);
187
+ const dir = path.dirname(hooksPath);
188
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
189
+ writeJsonFile3(hooksPath, merged);
190
+ }
191
+ };
127
192
  var ADAPTERS = {
128
193
  "claude-code": claudeCodeAdapter,
129
194
  codex: codexAdapter,
130
- cursor: cursorAdapter
195
+ cursor: cursorAdapter,
196
+ "gemini-cli": geminiCliAdapter,
197
+ antigravity: antigravityAdapter
131
198
  };
132
199
  function getDoctorToolAdapter(tool) {
133
200
  return ADAPTERS[tool];
@@ -688,4 +755,4 @@ export {
688
755
  exitCodeForStatus,
689
756
  printDoctorResult
690
757
  };
691
- //# sourceMappingURL=chunk-GXKHWBGO.js.map
758
+ //# sourceMappingURL=chunk-B44Y3ZQP.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/monitor/doctor.ts","../src/monitor/doctor-adapters.ts"],"sourcesContent":["/**\n * `olakai monitor doctor [--tool X] [--all] [--fix] [--json]` (OLA-244, S2).\n *\n * The end-to-end health check for local coding-agent monitoring. Where\n * `monitor status` answers \"is this workspace configured?\", `doctor`\n * answers \"is monitoring actually WORKING here, end-to-end?\" — by running\n * an ordered chain of checks per (workspace, tool):\n *\n * 1. registry-entry — is this install recorded in the machine registry?\n * 2. config-valid — does `.olakai/monitor-<tool>.json` parse + carry\n * agentId/apiKey/endpoint?\n * 3. hooks-installed — are the tool's hooks present at the right scope?\n * 4. api-key-valid — does the config's key authenticate?\n * 5. agent-exists — does the configured agent still resolve on the\n * backend?\n * 6. events-flowing — has the agent reported any event in the last 7d?\n *\n * Each check yields a structured `CheckResult` so `--json` can emit the\n * full picture and `--fix` can dispatch the registered repair for each\n * fixable failure. Repairs are idempotent + best-effort; doctor reports\n * what it fixed vs. what still needs a human.\n *\n * V-001 (verified): codex and cursor install their hooks GLOBALLY\n * (`~/.codex/config.toml`, `~/.cursor/hooks.json`), but attribute events\n * via the per-workspace `.olakai/monitor-<tool>.json`. When a global hook\n * fires in a workspace that has no such config, the plugin's `handleHook`\n * walks ancestors via `findConfiguredWorkspace`, finds nothing, and\n * silent-exits — so NO event is reported and the activity is unattributed.\n * doctor encodes this: for global-scope tools, a present hook + missing\n * config is reported as \"hook installed globally but this workspace has no\n * monitor config, so events here are not attributed.\"\n */\nimport * as os from \"node:os\";\nimport {\n getAgent,\n listActivity,\n listMyAgents,\n regenerateAgentApiKey,\n validateMonitoringApiKey,\n} from \"../lib/api.js\";\nimport { getValidToken } from \"../lib/auth.js\";\nimport { getPlugin, type ToolId } from \"./plugin.js\";\nimport { runMonitorInstall } from \"./install.js\";\nimport {\n getToolScope,\n readRegistry,\n reconcileCurrentWorkspace,\n upsertEntry,\n type RegistryEntry,\n type RegistryScope,\n} from \"./registry.js\";\nimport { findConfiguredWorkspace } from \"./paths.js\";\nimport { getDoctorToolAdapter, type DoctorToolConfig } from \"./doctor-adapters.js\";\n\n/** A single diagnostic check outcome. */\nexport type CheckStatus = \"ok\" | \"warn\" | \"fail\";\n\nexport interface CheckResult {\n /** Stable machine id (e.g. \"config-valid\"). */\n id: string;\n /** Human label for the checklist line. */\n label: string;\n status: CheckStatus;\n /** One-line human detail (the \"why\"). */\n detail: string;\n /** Whether `--fix` has a registered repair for this check. */\n fixable: boolean;\n}\n\n/** Per (workspace, tool) diagnostic report. */\nexport interface DoctorTargetReport {\n path: string;\n tool: ToolId;\n scope: RegistryScope;\n agentId?: string;\n checks: CheckResult[];\n /** Worst status across all checks. */\n overall: CheckStatus;\n}\n\nexport interface DoctorReport {\n targets: DoctorTargetReport[];\n /** Worst status across all targets (\"ok\" when there are no targets). */\n overall: CheckStatus;\n}\n\n/** A (workspace, tool) pairing to diagnose. */\nexport interface DoctorTarget {\n path: string;\n tool: ToolId;\n}\n\nconst SEVERITY: Record<CheckStatus, number> = { ok: 0, warn: 1, fail: 2 };\n\nfunction worst(a: CheckStatus, b: CheckStatus): CheckStatus {\n return SEVERITY[a] >= SEVERITY[b] ? a : b;\n}\n\n/** 7-day lookback window (ISO) for the events-flowing probe. */\nfunction sevenDaysAgoIso(now: Date = new Date()): string {\n return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString();\n}\n\n/**\n * Result of running the check chain for one target, plus the resolved\n * config (so `--fix` can re-link without re-loading) and any backend\n * facts (agent presence, last event) the chain discovered.\n */\ninterface ChainOutcome {\n checks: CheckResult[];\n config: DoctorToolConfig | null;\n /** True only when EVERY check is ok — gates `lastVerifiedAt` writes. */\n allGreen: boolean;\n /** ISO timestamp of the most recent event, if events-flowing saw one. */\n lastEventAt?: string;\n}\n\n/**\n * Run the ordered check chain for a single (workspace, tool). Pure of\n * side effects beyond (a) the reconcile adoption in registry-entry and\n * (b) the `lastEventAt`/`lastVerifiedAt` registry write after a green\n * events-flowing probe — both intentional and best-effort.\n *\n * `homeDir` is injectable so tests never touch the real `~/.olakai`.\n */\nexport async function runCheckChain(\n target: DoctorTarget,\n opts: { homeDir?: string; now?: Date } = {},\n): Promise<ChainOutcome> {\n const homeDir = opts.homeDir ?? os.homedir();\n const now = opts.now ?? new Date();\n const tool = target.tool;\n const scope = getToolScope(tool);\n const adapter = getDoctorToolAdapter(tool);\n const checks: CheckResult[] = [];\n\n // 1) registry-entry --------------------------------------------------\n let registry = readRegistry(homeDir);\n let entry = registry.workspaces.find(\n (e) => e.path === target.path && e.tool === tool,\n );\n if (!entry) {\n // Try to adopt from disk (S1 reconcile) before declaring it missing.\n try {\n reconcileCurrentWorkspace(target.path, homeDir);\n } catch {\n // reconcile is best-effort; fall through to the re-read.\n }\n registry = readRegistry(homeDir);\n entry = registry.workspaces.find(\n (e) => e.path === target.path && e.tool === tool,\n );\n }\n if (entry) {\n checks.push({\n id: \"registry-entry\",\n label: \"Registry entry\",\n status: \"ok\",\n detail: `Recorded in the machine registry as \"${entry.agentName}\".`,\n fixable: false,\n });\n } else {\n checks.push({\n id: \"registry-entry\",\n label: \"Registry entry\",\n status: \"warn\",\n detail:\n \"No machine-registry entry for this workspace+tool (and none could be adopted from disk).\",\n fixable: true,\n });\n }\n\n // 2) config-valid ----------------------------------------------------\n const config = adapter.loadConfig(target.path);\n if (config && config.agentId && config.apiKey && config.monitoringEndpoint) {\n checks.push({\n id: \"config-valid\",\n label: \"Config file\",\n status: \"ok\",\n detail: `${adapter.configRelLabel} is present and valid (agent ${config.agentId}).`,\n fixable: false,\n });\n } else if (config) {\n checks.push({\n id: \"config-valid\",\n label: \"Config file\",\n status: \"fail\",\n detail: `${adapter.configRelLabel} is missing required fields (agentId/apiKey/endpoint).`,\n fixable: true,\n });\n } else {\n // V-001 messaging: for a global-scope tool, the absence of a\n // per-workspace config is the exact reason events here are dropped.\n const detail =\n scope === \"global\"\n ? `No ${adapter.configRelLabel} in this workspace. ${adapter.displayName} hooks are global, so any activity here is NOT attributed to an agent until you run 'olakai monitor init --tool ${tool}'.`\n : `No ${adapter.configRelLabel} — this workspace is not configured for monitoring.`;\n checks.push({\n id: \"config-valid\",\n label: \"Config file\",\n status: \"fail\",\n detail,\n fixable: false,\n });\n }\n\n // 3) hooks-installed -------------------------------------------------\n // Reuse the plugin's own status() so we don't re-parse settings files.\n let hooksConfigured = false;\n let hooksStatusError: string | null = null;\n try {\n const status = await getPlugin(tool).status({ projectRoot: target.path });\n hooksConfigured = status.hooksConfigured;\n } catch (err) {\n hooksStatusError = err instanceof Error ? err.message : String(err);\n }\n if (hooksStatusError) {\n checks.push({\n id: \"hooks-installed\",\n label: \"Hooks installed\",\n status: \"warn\",\n detail: `Couldn't determine hook status (${hooksStatusError}).`,\n fixable: true,\n });\n } else if (hooksConfigured) {\n if (scope === \"global\" && !config) {\n // V-001: hook present globally, but no workspace config to attribute to.\n checks.push({\n id: \"hooks-installed\",\n label: \"Hooks installed\",\n status: \"warn\",\n detail: `${adapter.displayName} hooks are installed globally (${adapter.hooksLabel}), but this workspace has no monitor config — events fired here silent-exit unattributed.`,\n fixable: false,\n });\n } else {\n checks.push({\n id: \"hooks-installed\",\n label: \"Hooks installed\",\n status: \"ok\",\n detail:\n scope === \"global\"\n ? `Installed globally at ${adapter.hooksLabel}.`\n : `Installed at ${adapter.hooksLabel}.`,\n fixable: true,\n });\n }\n } else {\n checks.push({\n id: \"hooks-installed\",\n label: \"Hooks installed\",\n status: \"fail\",\n detail: `${adapter.displayName} hooks are not installed (${adapter.hooksLabel}). The tool will not report any activity.`,\n fixable: true,\n });\n }\n\n // The remaining checks need a usable config. When config is absent we\n // can't authenticate, resolve the agent, or probe activity — emit warns\n // that point back at config-valid rather than spurious fails.\n if (!config || !config.agentId || !config.apiKey) {\n checks.push({\n id: \"api-key-valid\",\n label: \"API key valid\",\n status: \"warn\",\n detail: \"Skipped — no usable config to read the API key from.\",\n fixable: true,\n });\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"warn\",\n detail: \"Skipped — no agentId in config to resolve.\",\n fixable: false,\n });\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail: \"Skipped — no agentId in config to probe.\",\n fixable: false,\n });\n return { checks, config, allGreen: false };\n }\n\n // 4) api-key-valid ---------------------------------------------------\n const validation = await validateMonitoringApiKey(\n config.monitoringEndpoint,\n config.apiKey,\n );\n if (validation === null) {\n // null = invalid key OR network failure (the validator soft-fails\n // both to null). We can't distinguish, so this is fixable (re-link)\n // but we phrase it carefully.\n checks.push({\n id: \"api-key-valid\",\n label: \"API key valid\",\n status: \"fail\",\n detail:\n \"The configured API key did not authenticate (rejected, or the monitoring endpoint was unreachable).\",\n fixable: true,\n });\n } else {\n checks.push({\n id: \"api-key-valid\",\n label: \"API key valid\",\n status: \"ok\",\n detail: `Authenticates against ${config.monitoringEndpoint}.`,\n fixable: false,\n });\n }\n\n // 5) agent-exists ----------------------------------------------------\n let agentResolves = false;\n try {\n await getAgent(config.agentId);\n agentResolves = true;\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"ok\",\n detail: `Agent ${config.agentId} resolves on the backend.`,\n fixable: false,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n // 404 maps to \"Agent not found\" in api.ts — treat as a hard fail\n // (recreatable). Permission errors are the common case for the\n // primary self-monitor persona: `GET /api/config/agents/:id`\n // requires ANALYST+, but coding agents are typically provisioned\n // by EMPLOYEE/USER. In that case fall back to the account lens\n // (`listMyAgents`, which is readable by any authenticated user) and\n // accept membership as verification. Any other error (network, 5xx)\n // stays a warn.\n if (/not found/i.test(message)) {\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"fail\",\n detail: `Agent ${config.agentId} no longer exists on the backend (404).`,\n fixable: true,\n });\n } else if (/permission|forbidden|analyst|403/i.test(message)) {\n // Self-owner fallback. If the configured agent is one *I* created,\n // verifying via the account lens is correct and equivalent to a\n // successful `getAgent` for the purposes of this check.\n try {\n const mine = await listMyAgents();\n if (mine.some((a) => a.id === config.agentId)) {\n agentResolves = true;\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"ok\",\n detail: `Agent ${config.agentId} exists on the backend (verified via account lens — you're the creator).`,\n fixable: false,\n });\n } else {\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"warn\",\n detail: `Agent ${config.agentId} isn't in your account-lens listing (run 'olakai agents mine'). The config may be stale or belong to another user.`,\n fixable: false,\n });\n }\n } catch (mineErr) {\n const mineMsg =\n mineErr instanceof Error ? mineErr.message : String(mineErr);\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"warn\",\n detail: `Couldn't verify agent ${config.agentId} (permission denied; account-lens lookup also failed: ${mineMsg}).`,\n fixable: false,\n });\n }\n } else {\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"warn\",\n detail: `Couldn't verify agent ${config.agentId} (${message}).`,\n fixable: false,\n });\n }\n }\n\n // 6) events-flowing --------------------------------------------------\n // V-002 (resolved): the metadata listing is readable by a normal CLI\n // user (ANALYST_READONLY_DEMO+); only `includeContent` needs ADMIN, so\n // we never pass it. A 403 is handled gracefully as a warn (token lacks\n // activity read) rather than a hard fail.\n let lastEventAt: string | undefined;\n if (!agentResolves) {\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail: \"Skipped — agent could not be resolved.\",\n fixable: false,\n });\n } else if (!getValidToken()) {\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail: \"Skipped — not logged in (run 'olakai login' to enable this check).\",\n fixable: false,\n });\n } else {\n try {\n const since = sevenDaysAgoIso(now);\n const activity = await listActivity({\n agentId: config.agentId,\n since,\n limit: 1,\n });\n if (activity.prompts.length > 0) {\n lastEventAt = activity.prompts[0].createdAt;\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"ok\",\n detail: `Most recent event ${lastEventAt} (within the last 7 days).`,\n fixable: false,\n });\n } else {\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail:\n \"No events in the last 7 days. This is expected if the workspace has been idle; if you've been active, check hooks + API key.\",\n fixable: false,\n });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n // Treat any permission/forbidden error as a soft warn so doctor\n // never hard-fails on a token that simply can't read activity.\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail: /403|forbidden|permission/i.test(message)\n ? \"Couldn't verify — your token lacks activity read access.\"\n : `Couldn't probe activity (${message}).`,\n fixable: false,\n });\n }\n }\n\n const allGreen = checks.every((c) => c.status === \"ok\");\n\n // Persist freshness signals to the registry (best-effort). lastEventAt\n // whenever we saw one; lastVerifiedAt only on a fully-green run.\n if (entry && (lastEventAt || allGreen)) {\n try {\n upsertEntry(\n {\n ...entry,\n ...(lastEventAt ? { lastEventAt } : {}),\n ...(allGreen ? { lastVerifiedAt: now.toISOString() } : {}),\n },\n homeDir,\n );\n } catch {\n // Registry is an index, not the source of truth — never fail doctor\n // on a write error.\n }\n }\n\n return { checks, config, allGreen, lastEventAt };\n}\n\n/** Outcome of attempting `--fix` on a single check. */\nexport interface FixResult {\n checkId: string;\n /** Did the repair succeed (fully resolve the failure)? */\n fixed: boolean;\n /** Human detail of what was done or why it still needs a human. */\n detail: string;\n}\n\n/**\n * Run the registered repairs for every fixable failed/warned check in\n * `checks`, in chain order. Idempotent and best-effort. Returns one\n * `FixResult` per repair attempted.\n *\n * `homeDir` is injectable for tests.\n */\nexport async function runFixes(\n target: DoctorTarget,\n outcome: ChainOutcome,\n opts: {\n homeDir?: string;\n interactive?: boolean;\n /** Opt-in to recreating a missing (404) agent. Off by default so\n * `doctor --fix` never silently provisions a duplicate agent on a\n * transient/false 404 — recreation is the job of `monitor repair`\n * or an explicit `--recreate-missing`. */\n recreateMissing?: boolean;\n } = {},\n): Promise<FixResult[]> {\n const homeDir = opts.homeDir ?? os.homedir();\n const tool = target.tool;\n const adapter = getDoctorToolAdapter(tool);\n const results: FixResult[] = [];\n\n // Index checks by id for ordered, gated repair dispatch.\n const byId = new Map<string, CheckResult>();\n for (const c of outcome.checks) byId.set(c.id, c);\n\n const needsFix = (id: string): boolean => {\n const c = byId.get(id);\n return Boolean(c && c.fixable && c.status !== \"ok\");\n };\n\n // -- registry-entry: adopt from disk via reconcile -------------------\n if (needsFix(\"registry-entry\")) {\n try {\n const adopted = reconcileCurrentWorkspace(target.path, homeDir);\n const has = adopted.some((e) => e.tool === tool);\n results.push({\n checkId: \"registry-entry\",\n fixed: has,\n detail: has\n ? \"Adopted the on-disk config into the machine registry.\"\n : \"Nothing to adopt — there's no on-disk config to register. Run 'olakai monitor init'.\",\n });\n } catch (err) {\n results.push({\n checkId: \"registry-entry\",\n fixed: false,\n detail: `Reconcile failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // -- agent-exists (404): recreate the self-monitor agent -------------\n // Recreating PROVISIONS A NEW backend agent and rotates the key, so it\n // is opt-in: `doctor --fix` never silently recreates (a transient or\n // false 404 could otherwise spawn a duplicate agent). Gated behind\n // `--recreate-missing`; `olakai monitor repair` (S3) is the heavier\n // entry point. Done before config/api-key re-link because recreate\n // rewrites the config with a brand-new agent + key, superseding a\n // stale re-link.\n if (needsFix(\"agent-exists\")) {\n if (!opts.recreateMissing) {\n results.push({\n checkId: \"agent-exists\",\n fixed: false,\n detail: `The configured agent no longer exists on the backend. Recreating it provisions a NEW agent — re-run with '--recreate-missing', or use 'olakai monitor repair --tool ${tool}'.`,\n });\n } else {\n try {\n const result = await runMonitorInstall(tool, {\n projectRoot: target.path,\n interactive: opts.interactive ?? false,\n });\n results.push({\n checkId: \"agent-exists\",\n fixed: true,\n detail: `Recreated the self-monitor agent \"${result.agentName}\" (${result.agentId}) and rewrote the config + registry.`,\n });\n // The recreate already wrote a fresh, valid config + key, so the\n // config-valid / api-key-valid repairs below are moot. Mark them\n // resolved-by-recreate to avoid a redundant key rotation.\n byId.delete(\"config-valid\");\n byId.delete(\"api-key-valid\");\n } catch (err) {\n results.push({\n checkId: \"agent-exists\",\n fixed: false,\n detail: `Could not recreate the agent: ${err instanceof Error ? err.message : String(err)}. This needs a human (check 'olakai login' and your role).`,\n });\n }\n }\n }\n\n // -- config-valid / api-key-valid: re-link by rotating the key -------\n // A single rotation fixes both, so coalesce them. We rotate only when\n // we have an agentId to rotate against.\n const relinkNeeded = needsFix(\"config-valid\") || needsFix(\"api-key-valid\");\n if (relinkNeeded) {\n const config = outcome.config;\n if (!config || !config.agentId) {\n results.push({\n checkId: needsFix(\"config-valid\") ? \"config-valid\" : \"api-key-valid\",\n fixed: false,\n detail:\n \"Can't re-link — no agentId in config. Run 'olakai monitor init' to set up this workspace.\",\n });\n } else {\n try {\n const rotated = await regenerateAgentApiKey(config.agentId);\n adapter.writeConfig(target.path, {\n agentId: config.agentId,\n apiKey: rotated.key,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n const detail =\n \"Rotated the agent API key and rewrote the workspace config. Other workspaces using the old key must re-init.\";\n if (needsFix(\"config-valid\")) {\n results.push({ checkId: \"config-valid\", fixed: true, detail });\n }\n if (needsFix(\"api-key-valid\")) {\n results.push({ checkId: \"api-key-valid\", fixed: true, detail });\n }\n } catch (err) {\n const detail = `Key rotation failed: ${err instanceof Error ? err.message : String(err)}.`;\n if (needsFix(\"config-valid\")) {\n results.push({ checkId: \"config-valid\", fixed: false, detail });\n }\n if (needsFix(\"api-key-valid\")) {\n results.push({ checkId: \"api-key-valid\", fixed: false, detail });\n }\n }\n }\n }\n\n // -- hooks-installed: idempotent re-merge via the plugin's merge path -\n if (needsFix(\"hooks-installed\")) {\n try {\n adapter.repairHooks(target.path);\n results.push({\n checkId: \"hooks-installed\",\n fixed: true,\n detail: `Re-merged ${adapter.displayName} hooks (${adapter.hooksLabel}).`,\n });\n } catch (err) {\n results.push({\n checkId: \"hooks-installed\",\n fixed: false,\n detail: `Could not re-merge hooks: ${err instanceof Error ? err.message : String(err)}.`,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Resolve the set of (workspace, tool) targets to diagnose.\n *\n * - `--all`: every registry entry on the machine (after reconciling the\n * current workspace so a freshly-installed cwd is included).\n * - otherwise: the single (resolved current-workspace root, tool). When\n * the cwd isn't inside a configured workspace we still return the cwd\n * itself so doctor can report the \"not configured\" state honestly.\n */\nexport function resolveTargets(\n opts: { all?: boolean; tool?: ToolId; cwd?: string; homeDir?: string },\n): DoctorTarget[] {\n const cwd = opts.cwd ?? process.cwd();\n const homeDir = opts.homeDir ?? os.homedir();\n\n if (opts.all) {\n try {\n reconcileCurrentWorkspace(cwd, homeDir);\n } catch {\n // best-effort\n }\n const registry = readRegistry(homeDir);\n return registry.workspaces.map((e) => ({ path: e.path, tool: e.tool }));\n }\n\n // Single-target mode requires a tool (the command resolves/prompts it\n // before calling here).\n const tool = opts.tool;\n if (!tool) return [];\n\n // Prefer the configured workspace root; fall back to cwd so doctor can\n // report \"not configured\" rather than silently producing no targets.\n const root = findConfiguredWorkspace(cwd, [tool]) ?? cwd;\n return [{ path: root, tool }];\n}\n\n/** Build the structured report for a list of targets (no fixes). */\nexport async function buildReport(\n targets: DoctorTarget[],\n opts: { homeDir?: string; now?: Date } = {},\n): Promise<{ report: DoctorReport; outcomes: Map<string, ChainOutcome> }> {\n const targetReports: DoctorTargetReport[] = [];\n const outcomes = new Map<string, ChainOutcome>();\n let overall: CheckStatus = \"ok\";\n\n for (const target of targets) {\n const outcome = await runCheckChain(target, opts);\n outcomes.set(targetKey(target), outcome);\n const targetOverall = outcome.checks.reduce<CheckStatus>(\n (acc, c) => worst(acc, c.status),\n \"ok\",\n );\n overall = worst(overall, targetOverall);\n\n const entry = findEntry(target, opts.homeDir);\n targetReports.push({\n path: target.path,\n tool: target.tool,\n scope: getToolScope(target.tool),\n agentId: outcome.config?.agentId ?? entry?.agentId,\n checks: outcome.checks,\n overall: targetOverall,\n });\n }\n\n return { report: { targets: targetReports, overall }, outcomes };\n}\n\nexport function targetKey(target: DoctorTarget): string {\n return `${target.path}::${target.tool}`;\n}\n\nfunction findEntry(\n target: DoctorTarget,\n homeDir?: string,\n): RegistryEntry | undefined {\n const registry = readRegistry(homeDir ?? os.homedir());\n return registry.workspaces.find(\n (e) => e.path === target.path && e.tool === target.tool,\n );\n}\n\n// ===========================================================================\n// Human-readable rendering\n// ===========================================================================\n\nconst ICON: Record<CheckStatus, string> = {\n ok: \"✓\", // ✓\n warn: \"⚠\", // ⚠\n fail: \"✗\", // ✗\n};\n\nexport function formatReport(report: DoctorReport): string {\n if (report.targets.length === 0) {\n return \"No monitored workspaces to check. Run 'olakai monitor init --tool <tool>' first.\";\n }\n const lines: string[] = [];\n for (const t of report.targets) {\n lines.push(`${t.tool} — ${t.path} [${t.scope}]`);\n for (const c of t.checks) {\n lines.push(` ${ICON[c.status]} ${c.label}: ${c.detail}`);\n }\n lines.push(\"\");\n }\n const summary =\n report.overall === \"ok\"\n ? \"All checks passed.\"\n : report.overall === \"warn\"\n ? \"Some checks need attention (warnings). Run with --fix to repair fixable issues.\"\n : \"Some checks failed. Run with --fix to repair fixable issues.\";\n lines.push(summary);\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function formatFixResults(\n target: DoctorTarget,\n fixes: FixResult[],\n): string {\n if (fixes.length === 0) {\n return `${target.tool} — ${target.path}: nothing to fix.`;\n }\n const lines: string[] = [`${target.tool} — ${target.path}:`];\n for (const f of fixes) {\n lines.push(` ${f.fixed ? ICON.ok : ICON.fail} ${f.checkId}: ${f.detail}`);\n }\n return lines.join(\"\\n\");\n}\n\n// ===========================================================================\n// Command entry point\n// ===========================================================================\n\nexport interface DoctorCommandOptions {\n tool?: ToolId;\n all?: boolean;\n fix?: boolean;\n json?: boolean;\n /** Opt-in to recreating a missing (404) agent during `--fix`. */\n recreateMissing?: boolean;\n /** Test seams. */\n cwd?: string;\n homeDir?: string;\n now?: Date;\n interactive?: boolean;\n}\n\nexport interface DoctorJsonResult {\n report: DoctorReport;\n fixes?: Array<{\n path: string;\n tool: ToolId;\n results: FixResult[];\n }>;\n}\n\n/**\n * Pure orchestrator: resolve targets, build the report, optionally run\n * fixes (and re-check after), and return the JSON-shaped result plus the\n * worst overall status. The Commander action wraps this with console\n * output + exit-code mapping.\n */\nexport async function runDoctor(\n options: DoctorCommandOptions,\n): Promise<DoctorJsonResult> {\n const targets = resolveTargets({\n all: options.all,\n tool: options.tool,\n cwd: options.cwd,\n homeDir: options.homeDir,\n });\n\n const { report, outcomes } = await buildReport(targets, {\n homeDir: options.homeDir,\n now: options.now,\n });\n\n if (!options.fix) {\n return { report };\n }\n\n const fixes: NonNullable<DoctorJsonResult[\"fixes\"]> = [];\n for (const target of targets) {\n const outcome = outcomes.get(targetKey(target));\n if (!outcome) continue;\n const results = await runFixes(target, outcome, {\n homeDir: options.homeDir,\n interactive: options.interactive,\n recreateMissing: options.recreateMissing,\n });\n if (results.length > 0) {\n fixes.push({ path: target.path, tool: target.tool, results });\n }\n }\n\n // Re-check after fixes so the returned report reflects the new state.\n const { report: afterReport } = await buildReport(targets, {\n homeDir: options.homeDir,\n now: options.now,\n });\n\n return { report: afterReport, fixes };\n}\n\n/** Map a report's worst status to a process exit code. */\nexport function exitCodeForStatus(status: CheckStatus): number {\n // Warnings are non-fatal (idle workspaces are normal); only hard\n // failures map to a non-zero exit so scripts can gate on real breakage.\n return status === \"fail\" ? 1 : 0;\n}\n\n/**\n * Render `runDoctor`'s result to the console. Separated from `runDoctor`\n * so the orchestration stays testable without capturing stdout.\n */\nexport function printDoctorResult(\n result: DoctorJsonResult,\n json: boolean,\n): void {\n if (json) {\n const payload: DoctorJsonResult = { report: result.report };\n if (result.fixes) payload.fixes = result.fixes;\n console.log(JSON.stringify(payload, null, 2));\n return;\n }\n\n console.log(formatReport(result.report));\n\n if (result.fixes && result.fixes.length > 0) {\n console.log(\"\");\n console.log(\"Repairs:\");\n for (const f of result.fixes) {\n console.log(formatFixResults({ path: f.path, tool: f.tool }, f.results));\n }\n }\n}\n\n// Re-export the adapter type surface so tests importing from doctor.ts\n// have everything in one place.\nexport type { DoctorToolConfig } from \"./doctor-adapters.js\";\n","/**\n * Per-tool adapters for `monitor doctor` (OLA-244, S2).\n *\n * `doctor.ts` is intentionally tool-agnostic: it runs the same check\n * chain for every tool and dispatches repairs through this adapter table.\n * Each adapter wraps the tool's EXISTING config load/write helpers and\n * its idempotent hook-merge path so doctor never re-implements (and never\n * drifts from) the install code.\n *\n * Why a separate module from the plugin contract: the `ToolMonitorPlugin`\n * interface (plugin.ts) exposes install/uninstall/status/handleHook but\n * NOT a config reader/writer or a hooks-only repair — those are internal\n * to each plugin's `config.ts`/`install.ts`. Rather than widen the plugin\n * contract for one consumer, doctor pulls the specific helpers it needs\n * here. If a future tool is added, its adapter is registered below.\n */\nimport {\n loadClaudeCodeConfig,\n writeClaudeCodeConfig,\n getClaudeCodeConfigPath,\n} from \"./plugins/claude-code/config.js\";\nimport {\n getSettingsPath,\n mergeHooksSettings,\n readJsonFile,\n writeJsonFile,\n type ClaudeSettings,\n} from \"./plugins/claude-code/settings.js\";\nimport {\n loadCodexConfig,\n writeCodexConfig,\n getCodexConfigPath,\n} from \"./plugins/codex/config.js\";\nimport { installCodexHooksConfig } from \"./plugins/codex/install.js\";\nimport {\n loadCursorConfig,\n writeCursorConfig,\n getCursorConfigPath,\n} from \"./plugins/cursor/config.js\";\nimport { getCursorHooksPath } from \"./plugins/cursor/paths.js\";\nimport {\n mergeCursorHooks,\n type CursorHooksConfig,\n} from \"./plugins/cursor/hooks-config.js\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ToolId } from \"./plugin.js\";\n\n/**\n * The shared on-disk per-tool config shape. All three plugins persist\n * exactly these fields (see each plugin's `config.ts`).\n */\nexport interface DoctorToolConfig {\n agentId: string;\n apiKey: string;\n agentName: string;\n source: string;\n createdAt?: string;\n monitoringEndpoint: string;\n}\n\nexport interface DoctorToolAdapter {\n tool: ToolId;\n displayName: string;\n /** Short label for the config file in human messages. */\n configRelLabel: string;\n /** Short label for the hooks surface in human messages. */\n hooksLabel: string;\n /** Load + parse the per-tool config; null when absent/corrupt. */\n loadConfig(projectRoot: string): DoctorToolConfig | null;\n /** Overwrite the per-tool config with a fresh, valid record. */\n writeConfig(projectRoot: string, config: DoctorToolConfig): void;\n /**\n * Idempotently re-merge this tool's hooks at the correct scope. Reuses\n * the same merge path the installer uses, so a repeat call is a no-op\n * when the hooks are already present.\n */\n repairHooks(projectRoot: string, homeDir?: string): void;\n}\n\nconst claudeCodeAdapter: DoctorToolAdapter = {\n tool: \"claude-code\",\n displayName: \"Claude Code\",\n configRelLabel: \".olakai/monitor-claude-code.json\",\n hooksLabel: \".claude/settings.json\",\n loadConfig: (root) => {\n const c = loadClaudeCodeConfig(root, () => {});\n return c ?? null;\n },\n writeConfig: (root, config) => {\n writeClaudeCodeConfig(root, {\n agentId: config.agentId,\n apiKey: config.apiKey,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n },\n repairHooks: (root) => {\n // Mirror installClaudeCode's hook-merge: read settings.json, merge in\n // the Olakai hook entries (idempotent), write back. Does NOT touch\n // the agent/config — hooks repair is independent of provisioning.\n const settingsPath = getSettingsPath(root);\n const existing = readJsonFile<ClaudeSettings>(settingsPath) ?? {};\n const merged: ClaudeSettings = {\n ...existing,\n hooks: mergeHooksSettings(existing.hooks),\n };\n writeJsonFile(settingsPath, merged);\n },\n};\n\nconst codexAdapter: DoctorToolAdapter = {\n tool: \"codex\",\n displayName: \"OpenAI Codex CLI\",\n configRelLabel: \".olakai/monitor-codex.json\",\n hooksLabel: \"~/.codex/config.toml\",\n loadConfig: (root) => loadCodexConfig(root) ?? null,\n writeConfig: (root, config) => {\n writeCodexConfig(root, {\n agentId: config.agentId,\n apiKey: config.apiKey,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n },\n repairHooks: () => {\n // Codex hooks live globally; installCodexHooksConfig() is the same\n // idempotent read-merge-write the installer uses.\n installCodexHooksConfig();\n },\n};\n\nconst cursorAdapter: DoctorToolAdapter = {\n tool: \"cursor\",\n displayName: \"Cursor\",\n configRelLabel: \".olakai/monitor-cursor.json\",\n hooksLabel: \"~/.cursor/hooks.json\",\n loadConfig: (root) => loadCursorConfig(root) ?? null,\n writeConfig: (root, config) => {\n writeCursorConfig(root, {\n agentId: config.agentId,\n apiKey: config.apiKey,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n },\n repairHooks: (_root, homeDir = os.homedir()) => {\n // Cursor hooks live globally at ~/.cursor/hooks.json. Re-merge using\n // the same pure helper the installer uses (idempotent).\n const hooksPath = getCursorHooksPath(homeDir);\n let existing: CursorHooksConfig | null = null;\n try {\n if (fs.existsSync(hooksPath)) {\n existing = JSON.parse(\n fs.readFileSync(hooksPath, \"utf-8\"),\n ) as CursorHooksConfig;\n }\n } catch {\n existing = null;\n }\n const merged = mergeCursorHooks(existing);\n const dir = path.dirname(hooksPath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(hooksPath, JSON.stringify(merged, null, 2) + \"\\n\", \"utf-8\");\n },\n};\n\nconst ADAPTERS: Record<ToolId, DoctorToolAdapter> = {\n \"claude-code\": claudeCodeAdapter,\n codex: codexAdapter,\n cursor: cursorAdapter,\n};\n\nexport function getDoctorToolAdapter(tool: ToolId): DoctorToolAdapter {\n return ADAPTERS[tool];\n}\n\n// Re-export config-path resolvers so callers needing the absolute path\n// (not just the short label) have them without reaching into plugins.\nexport {\n getClaudeCodeConfigPath,\n getCodexConfigPath,\n getCursorConfigPath,\n};\n"],"mappings":"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","names":["os"]}
1
+ {"version":3,"sources":["../src/monitor/doctor.ts","../src/monitor/doctor-adapters.ts"],"sourcesContent":["/**\n * `olakai monitor doctor [--tool X] [--all] [--fix] [--json]` (OLA-244, S2).\n *\n * The end-to-end health check for local coding-agent monitoring. Where\n * `monitor status` answers \"is this workspace configured?\", `doctor`\n * answers \"is monitoring actually WORKING here, end-to-end?\" — by running\n * an ordered chain of checks per (workspace, tool):\n *\n * 1. registry-entry — is this install recorded in the machine registry?\n * 2. config-valid — does `.olakai/monitor-<tool>.json` parse + carry\n * agentId/apiKey/endpoint?\n * 3. hooks-installed — are the tool's hooks present at the right scope?\n * 4. api-key-valid — does the config's key authenticate?\n * 5. agent-exists — does the configured agent still resolve on the\n * backend?\n * 6. events-flowing — has the agent reported any event in the last 7d?\n *\n * Each check yields a structured `CheckResult` so `--json` can emit the\n * full picture and `--fix` can dispatch the registered repair for each\n * fixable failure. Repairs are idempotent + best-effort; doctor reports\n * what it fixed vs. what still needs a human.\n *\n * V-001 (verified): codex and cursor install their hooks GLOBALLY\n * (`~/.codex/config.toml`, `~/.cursor/hooks.json`), but attribute events\n * via the per-workspace `.olakai/monitor-<tool>.json`. When a global hook\n * fires in a workspace that has no such config, the plugin's `handleHook`\n * walks ancestors via `findConfiguredWorkspace`, finds nothing, and\n * silent-exits — so NO event is reported and the activity is unattributed.\n * doctor encodes this: for global-scope tools, a present hook + missing\n * config is reported as \"hook installed globally but this workspace has no\n * monitor config, so events here are not attributed.\"\n */\nimport * as os from \"node:os\";\nimport {\n getAgent,\n listActivity,\n listMyAgents,\n regenerateAgentApiKey,\n validateMonitoringApiKey,\n} from \"../lib/api.js\";\nimport { getValidToken } from \"../lib/auth.js\";\nimport { getPlugin, type ToolId } from \"./plugin.js\";\nimport { runMonitorInstall } from \"./install.js\";\nimport {\n getToolScope,\n readRegistry,\n reconcileCurrentWorkspace,\n upsertEntry,\n type RegistryEntry,\n type RegistryScope,\n} from \"./registry.js\";\nimport { findConfiguredWorkspace } from \"./paths.js\";\nimport { getDoctorToolAdapter, type DoctorToolConfig } from \"./doctor-adapters.js\";\n\n/** A single diagnostic check outcome. */\nexport type CheckStatus = \"ok\" | \"warn\" | \"fail\";\n\nexport interface CheckResult {\n /** Stable machine id (e.g. \"config-valid\"). */\n id: string;\n /** Human label for the checklist line. */\n label: string;\n status: CheckStatus;\n /** One-line human detail (the \"why\"). */\n detail: string;\n /** Whether `--fix` has a registered repair for this check. */\n fixable: boolean;\n}\n\n/** Per (workspace, tool) diagnostic report. */\nexport interface DoctorTargetReport {\n path: string;\n tool: ToolId;\n scope: RegistryScope;\n agentId?: string;\n checks: CheckResult[];\n /** Worst status across all checks. */\n overall: CheckStatus;\n}\n\nexport interface DoctorReport {\n targets: DoctorTargetReport[];\n /** Worst status across all targets (\"ok\" when there are no targets). */\n overall: CheckStatus;\n}\n\n/** A (workspace, tool) pairing to diagnose. */\nexport interface DoctorTarget {\n path: string;\n tool: ToolId;\n}\n\nconst SEVERITY: Record<CheckStatus, number> = { ok: 0, warn: 1, fail: 2 };\n\nfunction worst(a: CheckStatus, b: CheckStatus): CheckStatus {\n return SEVERITY[a] >= SEVERITY[b] ? a : b;\n}\n\n/** 7-day lookback window (ISO) for the events-flowing probe. */\nfunction sevenDaysAgoIso(now: Date = new Date()): string {\n return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString();\n}\n\n/**\n * Result of running the check chain for one target, plus the resolved\n * config (so `--fix` can re-link without re-loading) and any backend\n * facts (agent presence, last event) the chain discovered.\n */\ninterface ChainOutcome {\n checks: CheckResult[];\n config: DoctorToolConfig | null;\n /** True only when EVERY check is ok — gates `lastVerifiedAt` writes. */\n allGreen: boolean;\n /** ISO timestamp of the most recent event, if events-flowing saw one. */\n lastEventAt?: string;\n}\n\n/**\n * Run the ordered check chain for a single (workspace, tool). Pure of\n * side effects beyond (a) the reconcile adoption in registry-entry and\n * (b) the `lastEventAt`/`lastVerifiedAt` registry write after a green\n * events-flowing probe — both intentional and best-effort.\n *\n * `homeDir` is injectable so tests never touch the real `~/.olakai`.\n */\nexport async function runCheckChain(\n target: DoctorTarget,\n opts: { homeDir?: string; now?: Date } = {},\n): Promise<ChainOutcome> {\n const homeDir = opts.homeDir ?? os.homedir();\n const now = opts.now ?? new Date();\n const tool = target.tool;\n const scope = getToolScope(tool);\n const adapter = getDoctorToolAdapter(tool);\n const checks: CheckResult[] = [];\n\n // 1) registry-entry --------------------------------------------------\n let registry = readRegistry(homeDir);\n let entry = registry.workspaces.find(\n (e) => e.path === target.path && e.tool === tool,\n );\n if (!entry) {\n // Try to adopt from disk (S1 reconcile) before declaring it missing.\n try {\n reconcileCurrentWorkspace(target.path, homeDir);\n } catch {\n // reconcile is best-effort; fall through to the re-read.\n }\n registry = readRegistry(homeDir);\n entry = registry.workspaces.find(\n (e) => e.path === target.path && e.tool === tool,\n );\n }\n if (entry) {\n checks.push({\n id: \"registry-entry\",\n label: \"Registry entry\",\n status: \"ok\",\n detail: `Recorded in the machine registry as \"${entry.agentName}\".`,\n fixable: false,\n });\n } else {\n checks.push({\n id: \"registry-entry\",\n label: \"Registry entry\",\n status: \"warn\",\n detail:\n \"No machine-registry entry for this workspace+tool (and none could be adopted from disk).\",\n fixable: true,\n });\n }\n\n // 2) config-valid ----------------------------------------------------\n const config = adapter.loadConfig(target.path);\n if (config && config.agentId && config.apiKey && config.monitoringEndpoint) {\n checks.push({\n id: \"config-valid\",\n label: \"Config file\",\n status: \"ok\",\n detail: `${adapter.configRelLabel} is present and valid (agent ${config.agentId}).`,\n fixable: false,\n });\n } else if (config) {\n checks.push({\n id: \"config-valid\",\n label: \"Config file\",\n status: \"fail\",\n detail: `${adapter.configRelLabel} is missing required fields (agentId/apiKey/endpoint).`,\n fixable: true,\n });\n } else {\n // V-001 messaging: for a global-scope tool, the absence of a\n // per-workspace config is the exact reason events here are dropped.\n const detail =\n scope === \"global\"\n ? `No ${adapter.configRelLabel} in this workspace. ${adapter.displayName} hooks are global, so any activity here is NOT attributed to an agent until you run 'olakai monitor init --tool ${tool}'.`\n : `No ${adapter.configRelLabel} — this workspace is not configured for monitoring.`;\n checks.push({\n id: \"config-valid\",\n label: \"Config file\",\n status: \"fail\",\n detail,\n fixable: false,\n });\n }\n\n // 3) hooks-installed -------------------------------------------------\n // Reuse the plugin's own status() so we don't re-parse settings files.\n let hooksConfigured = false;\n let hooksStatusError: string | null = null;\n try {\n const status = await getPlugin(tool).status({ projectRoot: target.path });\n hooksConfigured = status.hooksConfigured;\n } catch (err) {\n hooksStatusError = err instanceof Error ? err.message : String(err);\n }\n if (hooksStatusError) {\n checks.push({\n id: \"hooks-installed\",\n label: \"Hooks installed\",\n status: \"warn\",\n detail: `Couldn't determine hook status (${hooksStatusError}).`,\n fixable: true,\n });\n } else if (hooksConfigured) {\n if (scope === \"global\" && !config) {\n // V-001: hook present globally, but no workspace config to attribute to.\n checks.push({\n id: \"hooks-installed\",\n label: \"Hooks installed\",\n status: \"warn\",\n detail: `${adapter.displayName} hooks are installed globally (${adapter.hooksLabel}), but this workspace has no monitor config — events fired here silent-exit unattributed.`,\n fixable: false,\n });\n } else {\n checks.push({\n id: \"hooks-installed\",\n label: \"Hooks installed\",\n status: \"ok\",\n detail:\n scope === \"global\"\n ? `Installed globally at ${adapter.hooksLabel}.`\n : `Installed at ${adapter.hooksLabel}.`,\n fixable: true,\n });\n }\n } else {\n checks.push({\n id: \"hooks-installed\",\n label: \"Hooks installed\",\n status: \"fail\",\n detail: `${adapter.displayName} hooks are not installed (${adapter.hooksLabel}). The tool will not report any activity.`,\n fixable: true,\n });\n }\n\n // The remaining checks need a usable config. When config is absent we\n // can't authenticate, resolve the agent, or probe activity — emit warns\n // that point back at config-valid rather than spurious fails.\n if (!config || !config.agentId || !config.apiKey) {\n checks.push({\n id: \"api-key-valid\",\n label: \"API key valid\",\n status: \"warn\",\n detail: \"Skipped — no usable config to read the API key from.\",\n fixable: true,\n });\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"warn\",\n detail: \"Skipped — no agentId in config to resolve.\",\n fixable: false,\n });\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail: \"Skipped — no agentId in config to probe.\",\n fixable: false,\n });\n return { checks, config, allGreen: false };\n }\n\n // 4) api-key-valid ---------------------------------------------------\n const validation = await validateMonitoringApiKey(\n config.monitoringEndpoint,\n config.apiKey,\n );\n if (validation === null) {\n // null = invalid key OR network failure (the validator soft-fails\n // both to null). We can't distinguish, so this is fixable (re-link)\n // but we phrase it carefully.\n checks.push({\n id: \"api-key-valid\",\n label: \"API key valid\",\n status: \"fail\",\n detail:\n \"The configured API key did not authenticate (rejected, or the monitoring endpoint was unreachable).\",\n fixable: true,\n });\n } else {\n checks.push({\n id: \"api-key-valid\",\n label: \"API key valid\",\n status: \"ok\",\n detail: `Authenticates against ${config.monitoringEndpoint}.`,\n fixable: false,\n });\n }\n\n // 5) agent-exists ----------------------------------------------------\n let agentResolves = false;\n try {\n await getAgent(config.agentId);\n agentResolves = true;\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"ok\",\n detail: `Agent ${config.agentId} resolves on the backend.`,\n fixable: false,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n // 404 maps to \"Agent not found\" in api.ts — treat as a hard fail\n // (recreatable). Permission errors are the common case for the\n // primary self-monitor persona: `GET /api/config/agents/:id`\n // requires ANALYST+, but coding agents are typically provisioned\n // by EMPLOYEE/USER. In that case fall back to the account lens\n // (`listMyAgents`, which is readable by any authenticated user) and\n // accept membership as verification. Any other error (network, 5xx)\n // stays a warn.\n if (/not found/i.test(message)) {\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"fail\",\n detail: `Agent ${config.agentId} no longer exists on the backend (404).`,\n fixable: true,\n });\n } else if (/permission|forbidden|analyst|403/i.test(message)) {\n // Self-owner fallback. If the configured agent is one *I* created,\n // verifying via the account lens is correct and equivalent to a\n // successful `getAgent` for the purposes of this check.\n try {\n const mine = await listMyAgents();\n if (mine.some((a) => a.id === config.agentId)) {\n agentResolves = true;\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"ok\",\n detail: `Agent ${config.agentId} exists on the backend (verified via account lens — you're the creator).`,\n fixable: false,\n });\n } else {\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"warn\",\n detail: `Agent ${config.agentId} isn't in your account-lens listing (run 'olakai agents mine'). The config may be stale or belong to another user.`,\n fixable: false,\n });\n }\n } catch (mineErr) {\n const mineMsg =\n mineErr instanceof Error ? mineErr.message : String(mineErr);\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"warn\",\n detail: `Couldn't verify agent ${config.agentId} (permission denied; account-lens lookup also failed: ${mineMsg}).`,\n fixable: false,\n });\n }\n } else {\n checks.push({\n id: \"agent-exists\",\n label: \"Agent exists\",\n status: \"warn\",\n detail: `Couldn't verify agent ${config.agentId} (${message}).`,\n fixable: false,\n });\n }\n }\n\n // 6) events-flowing --------------------------------------------------\n // V-002 (resolved): the metadata listing is readable by a normal CLI\n // user (ANALYST_READONLY_DEMO+); only `includeContent` needs ADMIN, so\n // we never pass it. A 403 is handled gracefully as a warn (token lacks\n // activity read) rather than a hard fail.\n let lastEventAt: string | undefined;\n if (!agentResolves) {\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail: \"Skipped — agent could not be resolved.\",\n fixable: false,\n });\n } else if (!getValidToken()) {\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail: \"Skipped — not logged in (run 'olakai login' to enable this check).\",\n fixable: false,\n });\n } else {\n try {\n const since = sevenDaysAgoIso(now);\n const activity = await listActivity({\n agentId: config.agentId,\n since,\n limit: 1,\n });\n if (activity.prompts.length > 0) {\n lastEventAt = activity.prompts[0].createdAt;\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"ok\",\n detail: `Most recent event ${lastEventAt} (within the last 7 days).`,\n fixable: false,\n });\n } else {\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail:\n \"No events in the last 7 days. This is expected if the workspace has been idle; if you've been active, check hooks + API key.\",\n fixable: false,\n });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n // Treat any permission/forbidden error as a soft warn so doctor\n // never hard-fails on a token that simply can't read activity.\n checks.push({\n id: \"events-flowing\",\n label: \"Events flowing\",\n status: \"warn\",\n detail: /403|forbidden|permission/i.test(message)\n ? \"Couldn't verify — your token lacks activity read access.\"\n : `Couldn't probe activity (${message}).`,\n fixable: false,\n });\n }\n }\n\n const allGreen = checks.every((c) => c.status === \"ok\");\n\n // Persist freshness signals to the registry (best-effort). lastEventAt\n // whenever we saw one; lastVerifiedAt only on a fully-green run.\n if (entry && (lastEventAt || allGreen)) {\n try {\n upsertEntry(\n {\n ...entry,\n ...(lastEventAt ? { lastEventAt } : {}),\n ...(allGreen ? { lastVerifiedAt: now.toISOString() } : {}),\n },\n homeDir,\n );\n } catch {\n // Registry is an index, not the source of truth — never fail doctor\n // on a write error.\n }\n }\n\n return { checks, config, allGreen, lastEventAt };\n}\n\n/** Outcome of attempting `--fix` on a single check. */\nexport interface FixResult {\n checkId: string;\n /** Did the repair succeed (fully resolve the failure)? */\n fixed: boolean;\n /** Human detail of what was done or why it still needs a human. */\n detail: string;\n}\n\n/**\n * Run the registered repairs for every fixable failed/warned check in\n * `checks`, in chain order. Idempotent and best-effort. Returns one\n * `FixResult` per repair attempted.\n *\n * `homeDir` is injectable for tests.\n */\nexport async function runFixes(\n target: DoctorTarget,\n outcome: ChainOutcome,\n opts: {\n homeDir?: string;\n interactive?: boolean;\n /** Opt-in to recreating a missing (404) agent. Off by default so\n * `doctor --fix` never silently provisions a duplicate agent on a\n * transient/false 404 — recreation is the job of `monitor repair`\n * or an explicit `--recreate-missing`. */\n recreateMissing?: boolean;\n } = {},\n): Promise<FixResult[]> {\n const homeDir = opts.homeDir ?? os.homedir();\n const tool = target.tool;\n const adapter = getDoctorToolAdapter(tool);\n const results: FixResult[] = [];\n\n // Index checks by id for ordered, gated repair dispatch.\n const byId = new Map<string, CheckResult>();\n for (const c of outcome.checks) byId.set(c.id, c);\n\n const needsFix = (id: string): boolean => {\n const c = byId.get(id);\n return Boolean(c && c.fixable && c.status !== \"ok\");\n };\n\n // -- registry-entry: adopt from disk via reconcile -------------------\n if (needsFix(\"registry-entry\")) {\n try {\n const adopted = reconcileCurrentWorkspace(target.path, homeDir);\n const has = adopted.some((e) => e.tool === tool);\n results.push({\n checkId: \"registry-entry\",\n fixed: has,\n detail: has\n ? \"Adopted the on-disk config into the machine registry.\"\n : \"Nothing to adopt — there's no on-disk config to register. Run 'olakai monitor init'.\",\n });\n } catch (err) {\n results.push({\n checkId: \"registry-entry\",\n fixed: false,\n detail: `Reconcile failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n // -- agent-exists (404): recreate the self-monitor agent -------------\n // Recreating PROVISIONS A NEW backend agent and rotates the key, so it\n // is opt-in: `doctor --fix` never silently recreates (a transient or\n // false 404 could otherwise spawn a duplicate agent). Gated behind\n // `--recreate-missing`; `olakai monitor repair` (S3) is the heavier\n // entry point. Done before config/api-key re-link because recreate\n // rewrites the config with a brand-new agent + key, superseding a\n // stale re-link.\n if (needsFix(\"agent-exists\")) {\n if (!opts.recreateMissing) {\n results.push({\n checkId: \"agent-exists\",\n fixed: false,\n detail: `The configured agent no longer exists on the backend. Recreating it provisions a NEW agent — re-run with '--recreate-missing', or use 'olakai monitor repair --tool ${tool}'.`,\n });\n } else {\n try {\n const result = await runMonitorInstall(tool, {\n projectRoot: target.path,\n interactive: opts.interactive ?? false,\n });\n results.push({\n checkId: \"agent-exists\",\n fixed: true,\n detail: `Recreated the self-monitor agent \"${result.agentName}\" (${result.agentId}) and rewrote the config + registry.`,\n });\n // The recreate already wrote a fresh, valid config + key, so the\n // config-valid / api-key-valid repairs below are moot. Mark them\n // resolved-by-recreate to avoid a redundant key rotation.\n byId.delete(\"config-valid\");\n byId.delete(\"api-key-valid\");\n } catch (err) {\n results.push({\n checkId: \"agent-exists\",\n fixed: false,\n detail: `Could not recreate the agent: ${err instanceof Error ? err.message : String(err)}. This needs a human (check 'olakai login' and your role).`,\n });\n }\n }\n }\n\n // -- config-valid / api-key-valid: re-link by rotating the key -------\n // A single rotation fixes both, so coalesce them. We rotate only when\n // we have an agentId to rotate against.\n const relinkNeeded = needsFix(\"config-valid\") || needsFix(\"api-key-valid\");\n if (relinkNeeded) {\n const config = outcome.config;\n if (!config || !config.agentId) {\n results.push({\n checkId: needsFix(\"config-valid\") ? \"config-valid\" : \"api-key-valid\",\n fixed: false,\n detail:\n \"Can't re-link — no agentId in config. Run 'olakai monitor init' to set up this workspace.\",\n });\n } else {\n try {\n const rotated = await regenerateAgentApiKey(config.agentId);\n adapter.writeConfig(target.path, {\n agentId: config.agentId,\n apiKey: rotated.key,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n const detail =\n \"Rotated the agent API key and rewrote the workspace config. Other workspaces using the old key must re-init.\";\n if (needsFix(\"config-valid\")) {\n results.push({ checkId: \"config-valid\", fixed: true, detail });\n }\n if (needsFix(\"api-key-valid\")) {\n results.push({ checkId: \"api-key-valid\", fixed: true, detail });\n }\n } catch (err) {\n const detail = `Key rotation failed: ${err instanceof Error ? err.message : String(err)}.`;\n if (needsFix(\"config-valid\")) {\n results.push({ checkId: \"config-valid\", fixed: false, detail });\n }\n if (needsFix(\"api-key-valid\")) {\n results.push({ checkId: \"api-key-valid\", fixed: false, detail });\n }\n }\n }\n }\n\n // -- hooks-installed: idempotent re-merge via the plugin's merge path -\n if (needsFix(\"hooks-installed\")) {\n try {\n adapter.repairHooks(target.path);\n results.push({\n checkId: \"hooks-installed\",\n fixed: true,\n detail: `Re-merged ${adapter.displayName} hooks (${adapter.hooksLabel}).`,\n });\n } catch (err) {\n results.push({\n checkId: \"hooks-installed\",\n fixed: false,\n detail: `Could not re-merge hooks: ${err instanceof Error ? err.message : String(err)}.`,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Resolve the set of (workspace, tool) targets to diagnose.\n *\n * - `--all`: every registry entry on the machine (after reconciling the\n * current workspace so a freshly-installed cwd is included).\n * - otherwise: the single (resolved current-workspace root, tool). When\n * the cwd isn't inside a configured workspace we still return the cwd\n * itself so doctor can report the \"not configured\" state honestly.\n */\nexport function resolveTargets(\n opts: { all?: boolean; tool?: ToolId; cwd?: string; homeDir?: string },\n): DoctorTarget[] {\n const cwd = opts.cwd ?? process.cwd();\n const homeDir = opts.homeDir ?? os.homedir();\n\n if (opts.all) {\n try {\n reconcileCurrentWorkspace(cwd, homeDir);\n } catch {\n // best-effort\n }\n const registry = readRegistry(homeDir);\n return registry.workspaces.map((e) => ({ path: e.path, tool: e.tool }));\n }\n\n // Single-target mode requires a tool (the command resolves/prompts it\n // before calling here).\n const tool = opts.tool;\n if (!tool) return [];\n\n // Prefer the configured workspace root; fall back to cwd so doctor can\n // report \"not configured\" rather than silently producing no targets.\n const root = findConfiguredWorkspace(cwd, [tool]) ?? cwd;\n return [{ path: root, tool }];\n}\n\n/** Build the structured report for a list of targets (no fixes). */\nexport async function buildReport(\n targets: DoctorTarget[],\n opts: { homeDir?: string; now?: Date } = {},\n): Promise<{ report: DoctorReport; outcomes: Map<string, ChainOutcome> }> {\n const targetReports: DoctorTargetReport[] = [];\n const outcomes = new Map<string, ChainOutcome>();\n let overall: CheckStatus = \"ok\";\n\n for (const target of targets) {\n const outcome = await runCheckChain(target, opts);\n outcomes.set(targetKey(target), outcome);\n const targetOverall = outcome.checks.reduce<CheckStatus>(\n (acc, c) => worst(acc, c.status),\n \"ok\",\n );\n overall = worst(overall, targetOverall);\n\n const entry = findEntry(target, opts.homeDir);\n targetReports.push({\n path: target.path,\n tool: target.tool,\n scope: getToolScope(target.tool),\n agentId: outcome.config?.agentId ?? entry?.agentId,\n checks: outcome.checks,\n overall: targetOverall,\n });\n }\n\n return { report: { targets: targetReports, overall }, outcomes };\n}\n\nexport function targetKey(target: DoctorTarget): string {\n return `${target.path}::${target.tool}`;\n}\n\nfunction findEntry(\n target: DoctorTarget,\n homeDir?: string,\n): RegistryEntry | undefined {\n const registry = readRegistry(homeDir ?? os.homedir());\n return registry.workspaces.find(\n (e) => e.path === target.path && e.tool === target.tool,\n );\n}\n\n// ===========================================================================\n// Human-readable rendering\n// ===========================================================================\n\nconst ICON: Record<CheckStatus, string> = {\n ok: \"✓\", // ✓\n warn: \"⚠\", // ⚠\n fail: \"✗\", // ✗\n};\n\nexport function formatReport(report: DoctorReport): string {\n if (report.targets.length === 0) {\n return \"No monitored workspaces to check. Run 'olakai monitor init --tool <tool>' first.\";\n }\n const lines: string[] = [];\n for (const t of report.targets) {\n lines.push(`${t.tool} — ${t.path} [${t.scope}]`);\n for (const c of t.checks) {\n lines.push(` ${ICON[c.status]} ${c.label}: ${c.detail}`);\n }\n lines.push(\"\");\n }\n const summary =\n report.overall === \"ok\"\n ? \"All checks passed.\"\n : report.overall === \"warn\"\n ? \"Some checks need attention (warnings). Run with --fix to repair fixable issues.\"\n : \"Some checks failed. Run with --fix to repair fixable issues.\";\n lines.push(summary);\n return lines.join(\"\\n\").trimEnd();\n}\n\nexport function formatFixResults(\n target: DoctorTarget,\n fixes: FixResult[],\n): string {\n if (fixes.length === 0) {\n return `${target.tool} — ${target.path}: nothing to fix.`;\n }\n const lines: string[] = [`${target.tool} — ${target.path}:`];\n for (const f of fixes) {\n lines.push(` ${f.fixed ? ICON.ok : ICON.fail} ${f.checkId}: ${f.detail}`);\n }\n return lines.join(\"\\n\");\n}\n\n// ===========================================================================\n// Command entry point\n// ===========================================================================\n\nexport interface DoctorCommandOptions {\n tool?: ToolId;\n all?: boolean;\n fix?: boolean;\n json?: boolean;\n /** Opt-in to recreating a missing (404) agent during `--fix`. */\n recreateMissing?: boolean;\n /** Test seams. */\n cwd?: string;\n homeDir?: string;\n now?: Date;\n interactive?: boolean;\n}\n\nexport interface DoctorJsonResult {\n report: DoctorReport;\n fixes?: Array<{\n path: string;\n tool: ToolId;\n results: FixResult[];\n }>;\n}\n\n/**\n * Pure orchestrator: resolve targets, build the report, optionally run\n * fixes (and re-check after), and return the JSON-shaped result plus the\n * worst overall status. The Commander action wraps this with console\n * output + exit-code mapping.\n */\nexport async function runDoctor(\n options: DoctorCommandOptions,\n): Promise<DoctorJsonResult> {\n const targets = resolveTargets({\n all: options.all,\n tool: options.tool,\n cwd: options.cwd,\n homeDir: options.homeDir,\n });\n\n const { report, outcomes } = await buildReport(targets, {\n homeDir: options.homeDir,\n now: options.now,\n });\n\n if (!options.fix) {\n return { report };\n }\n\n const fixes: NonNullable<DoctorJsonResult[\"fixes\"]> = [];\n for (const target of targets) {\n const outcome = outcomes.get(targetKey(target));\n if (!outcome) continue;\n const results = await runFixes(target, outcome, {\n homeDir: options.homeDir,\n interactive: options.interactive,\n recreateMissing: options.recreateMissing,\n });\n if (results.length > 0) {\n fixes.push({ path: target.path, tool: target.tool, results });\n }\n }\n\n // Re-check after fixes so the returned report reflects the new state.\n const { report: afterReport } = await buildReport(targets, {\n homeDir: options.homeDir,\n now: options.now,\n });\n\n return { report: afterReport, fixes };\n}\n\n/** Map a report's worst status to a process exit code. */\nexport function exitCodeForStatus(status: CheckStatus): number {\n // Warnings are non-fatal (idle workspaces are normal); only hard\n // failures map to a non-zero exit so scripts can gate on real breakage.\n return status === \"fail\" ? 1 : 0;\n}\n\n/**\n * Render `runDoctor`'s result to the console. Separated from `runDoctor`\n * so the orchestration stays testable without capturing stdout.\n */\nexport function printDoctorResult(\n result: DoctorJsonResult,\n json: boolean,\n): void {\n if (json) {\n const payload: DoctorJsonResult = { report: result.report };\n if (result.fixes) payload.fixes = result.fixes;\n console.log(JSON.stringify(payload, null, 2));\n return;\n }\n\n console.log(formatReport(result.report));\n\n if (result.fixes && result.fixes.length > 0) {\n console.log(\"\");\n console.log(\"Repairs:\");\n for (const f of result.fixes) {\n console.log(formatFixResults({ path: f.path, tool: f.tool }, f.results));\n }\n }\n}\n\n// Re-export the adapter type surface so tests importing from doctor.ts\n// have everything in one place.\nexport type { DoctorToolConfig } from \"./doctor-adapters.js\";\n","/**\n * Per-tool adapters for `monitor doctor` (OLA-244, S2).\n *\n * `doctor.ts` is intentionally tool-agnostic: it runs the same check\n * chain for every tool and dispatches repairs through this adapter table.\n * Each adapter wraps the tool's EXISTING config load/write helpers and\n * its idempotent hook-merge path so doctor never re-implements (and never\n * drifts from) the install code.\n *\n * Why a separate module from the plugin contract: the `ToolMonitorPlugin`\n * interface (plugin.ts) exposes install/uninstall/status/handleHook but\n * NOT a config reader/writer or a hooks-only repair — those are internal\n * to each plugin's `config.ts`/`install.ts`. Rather than widen the plugin\n * contract for one consumer, doctor pulls the specific helpers it needs\n * here. If a future tool is added, its adapter is registered below.\n */\nimport {\n loadClaudeCodeConfig,\n writeClaudeCodeConfig,\n getClaudeCodeConfigPath,\n} from \"./plugins/claude-code/config.js\";\nimport {\n getSettingsPath,\n mergeHooksSettings,\n readJsonFile,\n writeJsonFile,\n type ClaudeSettings,\n} from \"./plugins/claude-code/settings.js\";\nimport {\n loadCodexConfig,\n writeCodexConfig,\n getCodexConfigPath,\n} from \"./plugins/codex/config.js\";\nimport { installCodexHooksConfig } from \"./plugins/codex/install.js\";\nimport {\n loadCursorConfig,\n writeCursorConfig,\n getCursorConfigPath,\n} from \"./plugins/cursor/config.js\";\nimport { getCursorHooksPath } from \"./plugins/cursor/paths.js\";\nimport {\n mergeCursorHooks,\n type CursorHooksConfig,\n} from \"./plugins/cursor/hooks-config.js\";\nimport {\n loadGeminiCliConfig,\n writeGeminiCliConfig,\n getGeminiCliConfigPath,\n} from \"./plugins/gemini-cli/config.js\";\nimport { getGeminiSettingsPath } from \"./plugins/gemini-cli/paths.js\";\nimport {\n mergeHooksSettings as mergeGeminiHooksSettings,\n readJsonFile as readGeminiJsonFile,\n writeJsonFile as writeGeminiJsonFile,\n type GeminiSettings,\n} from \"./plugins/gemini-cli/settings.js\";\nimport {\n loadAntigravityConfig,\n writeAntigravityConfig,\n getAntigravityConfigPath,\n} from \"./plugins/antigravity/config.js\";\nimport { getGeminiConfigHooksPath } from \"./plugins/antigravity/paths.js\";\nimport {\n mergeHooksFile as mergeAntigravityHooksFile,\n readJsonFile as readAntigravityJsonFile,\n writeJsonFile as writeAntigravityJsonFile,\n type AntigravityHooksFile,\n} from \"./plugins/antigravity/settings.js\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ToolId } from \"./plugin.js\";\n\n/**\n * The shared on-disk per-tool config shape. All three plugins persist\n * exactly these fields (see each plugin's `config.ts`).\n */\nexport interface DoctorToolConfig {\n agentId: string;\n apiKey: string;\n agentName: string;\n source: string;\n createdAt?: string;\n monitoringEndpoint: string;\n}\n\nexport interface DoctorToolAdapter {\n tool: ToolId;\n displayName: string;\n /** Short label for the config file in human messages. */\n configRelLabel: string;\n /** Short label for the hooks surface in human messages. */\n hooksLabel: string;\n /** Load + parse the per-tool config; null when absent/corrupt. */\n loadConfig(projectRoot: string): DoctorToolConfig | null;\n /** Overwrite the per-tool config with a fresh, valid record. */\n writeConfig(projectRoot: string, config: DoctorToolConfig): void;\n /**\n * Idempotently re-merge this tool's hooks at the correct scope. Reuses\n * the same merge path the installer uses, so a repeat call is a no-op\n * when the hooks are already present.\n */\n repairHooks(projectRoot: string, homeDir?: string): void;\n}\n\nconst claudeCodeAdapter: DoctorToolAdapter = {\n tool: \"claude-code\",\n displayName: \"Claude Code\",\n configRelLabel: \".olakai/monitor-claude-code.json\",\n hooksLabel: \".claude/settings.json\",\n loadConfig: (root) => {\n const c = loadClaudeCodeConfig(root, () => {});\n return c ?? null;\n },\n writeConfig: (root, config) => {\n writeClaudeCodeConfig(root, {\n agentId: config.agentId,\n apiKey: config.apiKey,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n },\n repairHooks: (root) => {\n // Mirror installClaudeCode's hook-merge: read settings.json, merge in\n // the Olakai hook entries (idempotent), write back. Does NOT touch\n // the agent/config — hooks repair is independent of provisioning.\n const settingsPath = getSettingsPath(root);\n const existing = readJsonFile<ClaudeSettings>(settingsPath) ?? {};\n const merged: ClaudeSettings = {\n ...existing,\n hooks: mergeHooksSettings(existing.hooks),\n };\n writeJsonFile(settingsPath, merged);\n },\n};\n\nconst codexAdapter: DoctorToolAdapter = {\n tool: \"codex\",\n displayName: \"OpenAI Codex CLI\",\n configRelLabel: \".olakai/monitor-codex.json\",\n hooksLabel: \"~/.codex/config.toml\",\n loadConfig: (root) => loadCodexConfig(root) ?? null,\n writeConfig: (root, config) => {\n writeCodexConfig(root, {\n agentId: config.agentId,\n apiKey: config.apiKey,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n },\n repairHooks: () => {\n // Codex hooks live globally; installCodexHooksConfig() is the same\n // idempotent read-merge-write the installer uses.\n installCodexHooksConfig();\n },\n};\n\nconst cursorAdapter: DoctorToolAdapter = {\n tool: \"cursor\",\n displayName: \"Cursor\",\n configRelLabel: \".olakai/monitor-cursor.json\",\n hooksLabel: \"~/.cursor/hooks.json\",\n loadConfig: (root) => loadCursorConfig(root) ?? null,\n writeConfig: (root, config) => {\n writeCursorConfig(root, {\n agentId: config.agentId,\n apiKey: config.apiKey,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n },\n repairHooks: (_root, homeDir = os.homedir()) => {\n // Cursor hooks live globally at ~/.cursor/hooks.json. Re-merge using\n // the same pure helper the installer uses (idempotent).\n const hooksPath = getCursorHooksPath(homeDir);\n let existing: CursorHooksConfig | null = null;\n try {\n if (fs.existsSync(hooksPath)) {\n existing = JSON.parse(\n fs.readFileSync(hooksPath, \"utf-8\"),\n ) as CursorHooksConfig;\n }\n } catch {\n existing = null;\n }\n const merged = mergeCursorHooks(existing);\n const dir = path.dirname(hooksPath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(hooksPath, JSON.stringify(merged, null, 2) + \"\\n\", \"utf-8\");\n },\n};\n\nconst geminiCliAdapter: DoctorToolAdapter = {\n tool: \"gemini-cli\",\n displayName: \"Gemini CLI\",\n configRelLabel: \".olakai/monitor-gemini-cli.json\",\n hooksLabel: \"~/.gemini/settings.json\",\n loadConfig: (root) => loadGeminiCliConfig(root) ?? null,\n writeConfig: (root, config) => {\n writeGeminiCliConfig(root, {\n agentId: config.agentId,\n apiKey: config.apiKey,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n },\n repairHooks: (_root, homeDir = os.homedir()) => {\n // Gemini CLI hooks live globally at ~/.gemini/settings.json. Re-merge\n // using the same pure helper the installer uses (idempotent).\n const settingsPath = getGeminiSettingsPath(homeDir);\n const existing = readGeminiJsonFile<GeminiSettings>(settingsPath) ?? {};\n const merged: GeminiSettings = {\n ...existing,\n hooks: mergeGeminiHooksSettings(existing.hooks),\n };\n const dir = path.dirname(settingsPath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n writeGeminiJsonFile(settingsPath, merged);\n },\n};\n\nconst antigravityAdapter: DoctorToolAdapter = {\n tool: \"antigravity\",\n displayName: \"Antigravity\",\n configRelLabel: \".olakai/monitor-antigravity.json\",\n hooksLabel: \"~/.gemini/config/hooks.json\",\n loadConfig: (root) => loadAntigravityConfig(root) ?? null,\n writeConfig: (root, config) => {\n writeAntigravityConfig(root, {\n agentId: config.agentId,\n apiKey: config.apiKey,\n agentName: config.agentName,\n source: config.source,\n createdAt: config.createdAt ?? new Date().toISOString(),\n monitoringEndpoint: config.monitoringEndpoint,\n });\n },\n repairHooks: (_root, homeDir = os.homedir()) => {\n // Antigravity hooks live globally at ~/.gemini/config/hooks.json.\n // Re-merge using the same pure helper the installer uses (idempotent).\n const hooksPath = getGeminiConfigHooksPath(homeDir);\n const existing =\n readAntigravityJsonFile<AntigravityHooksFile>(hooksPath) ?? {};\n const merged = mergeAntigravityHooksFile(existing);\n const dir = path.dirname(hooksPath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n writeAntigravityJsonFile(hooksPath, merged);\n },\n};\n\nconst ADAPTERS: Record<ToolId, DoctorToolAdapter> = {\n \"claude-code\": claudeCodeAdapter,\n codex: codexAdapter,\n cursor: cursorAdapter,\n \"gemini-cli\": geminiCliAdapter,\n antigravity: antigravityAdapter,\n};\n\nexport function getDoctorToolAdapter(tool: ToolId): DoctorToolAdapter {\n return ADAPTERS[tool];\n}\n\n// Re-export config-path resolvers so callers needing the absolute path\n// (not just the short label) have them without reaching into plugins.\nexport {\n getClaudeCodeConfigPath,\n getCodexConfigPath,\n getCursorConfigPath,\n getGeminiCliConfigPath,\n getAntigravityConfigPath,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,YAAYA,SAAQ;;;ACoCpB,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB,YAAY,UAAU;AAmCtB,IAAM,oBAAuC;AAAA,EAC3C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,YAAY,CAAC,SAAS;AACpB,UAAM,IAAI,qBAAqB,MAAM,MAAM;AAAA,IAAC,CAAC;AAC7C,WAAO,KAAK;AAAA,EACd;AAAA,EACA,aAAa,CAAC,MAAM,WAAW;AAC7B,0BAAsB,MAAM;AAAA,MAC1B,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO;AAAA,MAClB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtD,oBAAoB,OAAO;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EACA,aAAa,CAAC,SAAS;AAIrB,UAAM,eAAe,gBAAgB,IAAI;AACzC,UAAM,WAAW,aAA6B,YAAY,KAAK,CAAC;AAChE,UAAM,SAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,OAAO,mBAAmB,SAAS,KAAK;AAAA,IAC1C;AACA,kBAAc,cAAc,MAAM;AAAA,EACpC;AACF;AAEA,IAAM,eAAkC;AAAA,EACtC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,YAAY,CAAC,SAAS,gBAAgB,IAAI,KAAK;AAAA,EAC/C,aAAa,CAAC,MAAM,WAAW;AAC7B,qBAAiB,MAAM;AAAA,MACrB,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO;AAAA,MAClB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtD,oBAAoB,OAAO;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EACA,aAAa,MAAM;AAGjB,4BAAwB;AAAA,EAC1B;AACF;AAEA,IAAM,gBAAmC;AAAA,EACvC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,YAAY,CAAC,SAAS,iBAAiB,IAAI,KAAK;AAAA,EAChD,aAAa,CAAC,MAAM,WAAW;AAC7B,sBAAkB,MAAM;AAAA,MACtB,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO;AAAA,MAClB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtD,oBAAoB,OAAO;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EACA,aAAa,CAAC,OAAO,UAAa,WAAQ,MAAM;AAG9C,UAAM,YAAY,mBAAmB,OAAO;AAC5C,QAAI,WAAqC;AACzC,QAAI;AACF,UAAO,cAAW,SAAS,GAAG;AAC5B,mBAAW,KAAK;AAAA,UACX,gBAAa,WAAW,OAAO;AAAA,QACpC;AAAA,MACF;AAAA,IACF,QAAQ;AACN,iBAAW;AAAA,IACb;AACA,UAAM,SAAS,iBAAiB,QAAQ;AACxC,UAAM,MAAW,aAAQ,SAAS;AAClC,QAAI,CAAI,cAAW,GAAG,EAAG,CAAG,aAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAC9D,IAAG,iBAAc,WAAW,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,OAAO;AAAA,EAC7E;AACF;AAEA,IAAM,mBAAsC;AAAA,EAC1C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,YAAY,CAAC,SAAS,oBAAoB,IAAI,KAAK;AAAA,EACnD,aAAa,CAAC,MAAM,WAAW;AAC7B,yBAAqB,MAAM;AAAA,MACzB,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO;AAAA,MAClB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtD,oBAAoB,OAAO;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EACA,aAAa,CAAC,OAAO,UAAa,WAAQ,MAAM;AAG9C,UAAM,eAAe,sBAAsB,OAAO;AAClD,UAAM,WAAWC,cAAmC,YAAY,KAAK,CAAC;AACtE,UAAM,SAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,OAAOC,oBAAyB,SAAS,KAAK;AAAA,IAChD;AACA,UAAM,MAAW,aAAQ,YAAY;AACrC,QAAI,CAAI,cAAW,GAAG,EAAG,CAAG,aAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAC9D,IAAAC,eAAoB,cAAc,MAAM;AAAA,EAC1C;AACF;AAEA,IAAM,qBAAwC;AAAA,EAC5C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,YAAY,CAAC,SAAS,sBAAsB,IAAI,KAAK;AAAA,EACrD,aAAa,CAAC,MAAM,WAAW;AAC7B,2BAAuB,MAAM;AAAA,MAC3B,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO;AAAA,MAClB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtD,oBAAoB,OAAO;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EACA,aAAa,CAAC,OAAO,UAAa,WAAQ,MAAM;AAG9C,UAAM,YAAY,yBAAyB,OAAO;AAClD,UAAM,WACJF,cAA8C,SAAS,KAAK,CAAC;AAC/D,UAAM,SAAS,eAA0B,QAAQ;AACjD,UAAM,MAAW,aAAQ,SAAS;AAClC,QAAI,CAAI,cAAW,GAAG,EAAG,CAAG,aAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAC9D,IAAAE,eAAyB,WAAW,MAAM;AAAA,EAC5C;AACF;AAEA,IAAM,WAA8C;AAAA,EAClD,eAAe;AAAA,EACf,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,aAAa;AACf;AAEO,SAAS,qBAAqB,MAAiC;AACpE,SAAO,SAAS,IAAI;AACtB;;;ADhLA,IAAM,WAAwC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAAE;AAExE,SAAS,MAAM,GAAgB,GAA6B;AAC1D,SAAO,SAAS,CAAC,KAAK,SAAS,CAAC,IAAI,IAAI;AAC1C;AAGA,SAAS,gBAAgB,MAAY,oBAAI,KAAK,GAAW;AACvD,SAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI,EAAE,YAAY;AACvE;AAwBA,eAAsB,cACpB,QACA,OAAyC,CAAC,GACnB;AACvB,QAAM,UAAU,KAAK,WAAc,YAAQ;AAC3C,QAAM,MAAM,KAAK,OAAO,oBAAI,KAAK;AACjC,QAAM,OAAO,OAAO;AACpB,QAAM,QAAQ,aAAa,IAAI;AAC/B,QAAM,UAAU,qBAAqB,IAAI;AACzC,QAAM,SAAwB,CAAC;AAG/B,MAAI,WAAW,aAAa,OAAO;AACnC,MAAI,QAAQ,SAAS,WAAW;AAAA,IAC9B,CAAC,MAAM,EAAE,SAAS,OAAO,QAAQ,EAAE,SAAS;AAAA,EAC9C;AACA,MAAI,CAAC,OAAO;AAEV,QAAI;AACF,gCAA0B,OAAO,MAAM,OAAO;AAAA,IAChD,QAAQ;AAAA,IAER;AACA,eAAW,aAAa,OAAO;AAC/B,YAAQ,SAAS,WAAW;AAAA,MAC1B,CAAC,MAAM,EAAE,SAAS,OAAO,QAAQ,EAAE,SAAS;AAAA,IAC9C;AAAA,EACF;AACA,MAAI,OAAO;AACT,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ,wCAAwC,MAAM,SAAS;AAAA,MAC/D,SAAS;AAAA,IACX,CAAC;AAAA,EACH,OAAO;AACL,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QACE;AAAA,MACF,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAGA,QAAM,SAAS,QAAQ,WAAW,OAAO,IAAI;AAC7C,MAAI,UAAU,OAAO,WAAW,OAAO,UAAU,OAAO,oBAAoB;AAC1E,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ,GAAG,QAAQ,cAAc,gCAAgC,OAAO,OAAO;AAAA,MAC/E,SAAS;AAAA,IACX,CAAC;AAAA,EACH,WAAW,QAAQ;AACjB,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ,GAAG,QAAQ,cAAc;AAAA,MACjC,SAAS;AAAA,IACX,CAAC;AAAA,EACH,OAAO;AAGL,UAAM,SACJ,UAAU,WACN,MAAM,QAAQ,cAAc,uBAAuB,QAAQ,WAAW,mHAAmH,IAAI,OAC7L,MAAM,QAAQ,cAAc;AAClC,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAIA,MAAI,kBAAkB;AACtB,MAAI,mBAAkC;AACtC,MAAI;AACF,UAAM,SAAS,MAAM,UAAU,IAAI,EAAE,OAAO,EAAE,aAAa,OAAO,KAAK,CAAC;AACxE,sBAAkB,OAAO;AAAA,EAC3B,SAAS,KAAK;AACZ,uBAAmB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,EACpE;AACA,MAAI,kBAAkB;AACpB,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ,mCAAmC,gBAAgB;AAAA,MAC3D,SAAS;AAAA,IACX,CAAC;AAAA,EACH,WAAW,iBAAiB;AAC1B,QAAI,UAAU,YAAY,CAAC,QAAQ;AAEjC,aAAO,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ,GAAG,QAAQ,WAAW,kCAAkC,QAAQ,UAAU;AAAA,QAClF,SAAS;AAAA,MACX,CAAC;AAAA,IACH,OAAO;AACL,aAAO,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QACE,UAAU,WACN,yBAAyB,QAAQ,UAAU,MAC3C,gBAAgB,QAAQ,UAAU;AAAA,QACxC,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF,OAAO;AACL,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ,GAAG,QAAQ,WAAW,6BAA6B,QAAQ,UAAU;AAAA,MAC7E,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAKA,MAAI,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,QAAQ;AAChD,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AACD,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AACD,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AACD,WAAO,EAAE,QAAQ,QAAQ,UAAU,MAAM;AAAA,EAC3C;AAGA,QAAM,aAAa,MAAM;AAAA,IACvB,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AACA,MAAI,eAAe,MAAM;AAIvB,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QACE;AAAA,MACF,SAAS;AAAA,IACX,CAAC;AAAA,EACH,OAAO;AACL,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ,yBAAyB,OAAO,kBAAkB;AAAA,MAC1D,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAGA,MAAI,gBAAgB;AACpB,MAAI;AACF,UAAM,SAAS,OAAO,OAAO;AAC7B,oBAAgB;AAChB,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ,SAAS,OAAO,OAAO;AAAA,MAC/B,SAAS;AAAA,IACX,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAS/D,QAAI,aAAa,KAAK,OAAO,GAAG;AAC9B,aAAO,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ,SAAS,OAAO,OAAO;AAAA,QAC/B,SAAS;AAAA,MACX,CAAC;AAAA,IACH,WAAW,oCAAoC,KAAK,OAAO,GAAG;AAI5D,UAAI;AACF,cAAM,OAAO,MAAM,aAAa;AAChC,YAAI,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,OAAO,GAAG;AAC7C,0BAAgB;AAChB,iBAAO,KAAK;AAAA,YACV,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,QAAQ;AAAA,YACR,QAAQ,SAAS,OAAO,OAAO;AAAA,YAC/B,SAAS;AAAA,UACX,CAAC;AAAA,QACH,OAAO;AACL,iBAAO,KAAK;AAAA,YACV,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,QAAQ;AAAA,YACR,QAAQ,SAAS,OAAO,OAAO;AAAA,YAC/B,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAAA,MACF,SAAS,SAAS;AAChB,cAAM,UACJ,mBAAmB,QAAQ,QAAQ,UAAU,OAAO,OAAO;AAC7D,eAAO,KAAK;AAAA,UACV,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,QAAQ,yBAAyB,OAAO,OAAO,yDAAyD,OAAO;AAAA,UAC/G,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,aAAO,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ,yBAAyB,OAAO,OAAO,KAAK,OAAO;AAAA,QAC3D,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAOA,MAAI;AACJ,MAAI,CAAC,eAAe;AAClB,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH,WAAW,CAAC,cAAc,GAAG;AAC3B,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH,OAAO;AACL,QAAI;AACF,YAAM,QAAQ,gBAAgB,GAAG;AACjC,YAAM,WAAW,MAAM,aAAa;AAAA,QAClC,SAAS,OAAO;AAAA,QAChB;AAAA,QACA,OAAO;AAAA,MACT,CAAC;AACD,UAAI,SAAS,QAAQ,SAAS,GAAG;AAC/B,sBAAc,SAAS,QAAQ,CAAC,EAAE;AAClC,eAAO,KAAK;AAAA,UACV,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,QAAQ,qBAAqB,WAAW;AAAA,UACxC,SAAS;AAAA,QACX,CAAC;AAAA,MACH,OAAO;AACL,eAAO,KAAK;AAAA,UACV,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,QACE;AAAA,UACF,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAG/D,aAAO,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ,4BAA4B,KAAK,OAAO,IAC5C,kEACA,4BAA4B,OAAO;AAAA,QACvC,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,WAAW,OAAO,MAAM,CAAC,MAAM,EAAE,WAAW,IAAI;AAItD,MAAI,UAAU,eAAe,WAAW;AACtC,QAAI;AACF;AAAA,QACE;AAAA,UACE,GAAG;AAAA,UACH,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,UACrC,GAAI,WAAW,EAAE,gBAAgB,IAAI,YAAY,EAAE,IAAI,CAAC;AAAA,QAC1D;AAAA,QACA;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAGR;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,QAAQ,UAAU,YAAY;AACjD;AAkBA,eAAsB,SACpB,QACA,SACA,OAQI,CAAC,GACiB;AACtB,QAAM,UAAU,KAAK,WAAc,YAAQ;AAC3C,QAAM,OAAO,OAAO;AACpB,QAAM,UAAU,qBAAqB,IAAI;AACzC,QAAM,UAAuB,CAAC;AAG9B,QAAM,OAAO,oBAAI,IAAyB;AAC1C,aAAW,KAAK,QAAQ,OAAQ,MAAK,IAAI,EAAE,IAAI,CAAC;AAEhD,QAAM,WAAW,CAAC,OAAwB;AACxC,UAAM,IAAI,KAAK,IAAI,EAAE;AACrB,WAAO,QAAQ,KAAK,EAAE,WAAW,EAAE,WAAW,IAAI;AAAA,EACpD;AAGA,MAAI,SAAS,gBAAgB,GAAG;AAC9B,QAAI;AACF,YAAM,UAAU,0BAA0B,OAAO,MAAM,OAAO;AAC9D,YAAM,MAAM,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC/C,cAAQ,KAAK;AAAA,QACX,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ,MACJ,0DACA;AAAA,MACN,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,KAAK;AAAA,QACX,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ,qBAAqB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC/E,CAAC;AAAA,IACH;AAAA,EACF;AAUA,MAAI,SAAS,cAAc,GAAG;AAC5B,QAAI,CAAC,KAAK,iBAAiB;AACzB,cAAQ,KAAK;AAAA,QACX,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ,4KAAuK,IAAI;AAAA,MACrL,CAAC;AAAA,IACH,OAAO;AACL,UAAI;AACF,cAAM,SAAS,MAAM,kBAAkB,MAAM;AAAA,UAC3C,aAAa,OAAO;AAAA,UACpB,aAAa,KAAK,eAAe;AAAA,QACnC,CAAC;AACD,gBAAQ,KAAK;AAAA,UACX,SAAS;AAAA,UACT,OAAO;AAAA,UACP,QAAQ,qCAAqC,OAAO,SAAS,MAAM,OAAO,OAAO;AAAA,QACnF,CAAC;AAID,aAAK,OAAO,cAAc;AAC1B,aAAK,OAAO,eAAe;AAAA,MAC7B,SAAS,KAAK;AACZ,gBAAQ,KAAK;AAAA,UACX,SAAS;AAAA,UACT,OAAO;AAAA,UACP,QAAQ,iCAAiC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAC3F,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAKA,QAAM,eAAe,SAAS,cAAc,KAAK,SAAS,eAAe;AACzE,MAAI,cAAc;AAChB,UAAM,SAAS,QAAQ;AACvB,QAAI,CAAC,UAAU,CAAC,OAAO,SAAS;AAC9B,cAAQ,KAAK;AAAA,QACX,SAAS,SAAS,cAAc,IAAI,iBAAiB;AAAA,QACrD,OAAO;AAAA,QACP,QACE;AAAA,MACJ,CAAC;AAAA,IACH,OAAO;AACL,UAAI;AACF,cAAM,UAAU,MAAM,sBAAsB,OAAO,OAAO;AAC1D,gBAAQ,YAAY,OAAO,MAAM;AAAA,UAC/B,SAAS,OAAO;AAAA,UAChB,QAAQ,QAAQ;AAAA,UAChB,WAAW,OAAO;AAAA,UAClB,QAAQ,OAAO;AAAA,UACf,WAAW,OAAO,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,UACtD,oBAAoB,OAAO;AAAA,QAC7B,CAAC;AACD,cAAM,SACJ;AACF,YAAI,SAAS,cAAc,GAAG;AAC5B,kBAAQ,KAAK,EAAE,SAAS,gBAAgB,OAAO,MAAM,OAAO,CAAC;AAAA,QAC/D;AACA,YAAI,SAAS,eAAe,GAAG;AAC7B,kBAAQ,KAAK,EAAE,SAAS,iBAAiB,OAAO,MAAM,OAAO,CAAC;AAAA,QAChE;AAAA,MACF,SAAS,KAAK;AACZ,cAAM,SAAS,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AACvF,YAAI,SAAS,cAAc,GAAG;AAC5B,kBAAQ,KAAK,EAAE,SAAS,gBAAgB,OAAO,OAAO,OAAO,CAAC;AAAA,QAChE;AACA,YAAI,SAAS,eAAe,GAAG;AAC7B,kBAAQ,KAAK,EAAE,SAAS,iBAAiB,OAAO,OAAO,OAAO,CAAC;AAAA,QACjE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,iBAAiB,GAAG;AAC/B,QAAI;AACF,cAAQ,YAAY,OAAO,IAAI;AAC/B,cAAQ,KAAK;AAAA,QACX,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ,aAAa,QAAQ,WAAW,WAAW,QAAQ,UAAU;AAAA,MACvE,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,KAAK;AAAA,QACX,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ,6BAA6B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACvF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAWO,SAAS,eACd,MACgB;AAChB,QAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;AACpC,QAAM,UAAU,KAAK,WAAc,YAAQ;AAE3C,MAAI,KAAK,KAAK;AACZ,QAAI;AACF,gCAA0B,KAAK,OAAO;AAAA,IACxC,QAAQ;AAAA,IAER;AACA,UAAM,WAAW,aAAa,OAAO;AACrC,WAAO,SAAS,WAAW,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,EACxE;AAIA,QAAM,OAAO,KAAK;AAClB,MAAI,CAAC,KAAM,QAAO,CAAC;AAInB,QAAM,OAAO,wBAAwB,KAAK,CAAC,IAAI,CAAC,KAAK;AACrD,SAAO,CAAC,EAAE,MAAM,MAAM,KAAK,CAAC;AAC9B;AAGA,eAAsB,YACpB,SACA,OAAyC,CAAC,GAC8B;AACxE,QAAM,gBAAsC,CAAC;AAC7C,QAAM,WAAW,oBAAI,IAA0B;AAC/C,MAAI,UAAuB;AAE3B,aAAW,UAAU,SAAS;AAC5B,UAAM,UAAU,MAAM,cAAc,QAAQ,IAAI;AAChD,aAAS,IAAI,UAAU,MAAM,GAAG,OAAO;AACvC,UAAM,gBAAgB,QAAQ,OAAO;AAAA,MACnC,CAAC,KAAK,MAAM,MAAM,KAAK,EAAE,MAAM;AAAA,MAC/B;AAAA,IACF;AACA,cAAU,MAAM,SAAS,aAAa;AAEtC,UAAM,QAAQ,UAAU,QAAQ,KAAK,OAAO;AAC5C,kBAAc,KAAK;AAAA,MACjB,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,OAAO,aAAa,OAAO,IAAI;AAAA,MAC/B,SAAS,QAAQ,QAAQ,WAAW,OAAO;AAAA,MAC3C,QAAQ,QAAQ;AAAA,MAChB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,QAAQ,EAAE,SAAS,eAAe,QAAQ,GAAG,SAAS;AACjE;AAEO,SAAS,UAAU,QAA8B;AACtD,SAAO,GAAG,OAAO,IAAI,KAAK,OAAO,IAAI;AACvC;AAEA,SAAS,UACP,QACA,SAC2B;AAC3B,QAAM,WAAW,aAAa,WAAc,YAAQ,CAAC;AACrD,SAAO,SAAS,WAAW;AAAA,IACzB,CAAC,MAAM,EAAE,SAAS,OAAO,QAAQ,EAAE,SAAS,OAAO;AAAA,EACrD;AACF;AAMA,IAAM,OAAoC;AAAA,EACxC,IAAI;AAAA;AAAA,EACJ,MAAM;AAAA;AAAA,EACN,MAAM;AAAA;AACR;AAEO,SAAS,aAAa,QAA8B;AACzD,MAAI,OAAO,QAAQ,WAAW,GAAG;AAC/B,WAAO;AAAA,EACT;AACA,QAAM,QAAkB,CAAC;AACzB,aAAW,KAAK,OAAO,SAAS;AAC9B,UAAM,KAAK,GAAG,EAAE,IAAI,WAAM,EAAE,IAAI,KAAK,EAAE,KAAK,GAAG;AAC/C,eAAW,KAAK,EAAE,QAAQ;AACxB,YAAM,KAAK,KAAK,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,MAAM,EAAE;AAAA,IAC1D;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AACA,QAAM,UACJ,OAAO,YAAY,OACf,uBACA,OAAO,YAAY,SACjB,oFACA;AACR,QAAM,KAAK,OAAO;AAClB,SAAO,MAAM,KAAK,IAAI,EAAE,QAAQ;AAClC;AAEO,SAAS,iBACd,QACA,OACQ;AACR,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,GAAG,OAAO,IAAI,WAAM,OAAO,IAAI;AAAA,EACxC;AACA,QAAM,QAAkB,CAAC,GAAG,OAAO,IAAI,WAAM,OAAO,IAAI,GAAG;AAC3D,aAAW,KAAK,OAAO;AACrB,UAAM,KAAK,KAAK,EAAE,QAAQ,KAAK,KAAK,KAAK,IAAI,IAAI,EAAE,OAAO,KAAK,EAAE,MAAM,EAAE;AAAA,EAC3E;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAmCA,eAAsB,UACpB,SAC2B;AAC3B,QAAM,UAAU,eAAe;AAAA,IAC7B,KAAK,QAAQ;AAAA,IACb,MAAM,QAAQ;AAAA,IACd,KAAK,QAAQ;AAAA,IACb,SAAS,QAAQ;AAAA,EACnB,CAAC;AAED,QAAM,EAAE,QAAQ,SAAS,IAAI,MAAM,YAAY,SAAS;AAAA,IACtD,SAAS,QAAQ;AAAA,IACjB,KAAK,QAAQ;AAAA,EACf,CAAC;AAED,MAAI,CAAC,QAAQ,KAAK;AAChB,WAAO,EAAE,OAAO;AAAA,EAClB;AAEA,QAAM,QAAgD,CAAC;AACvD,aAAW,UAAU,SAAS;AAC5B,UAAM,UAAU,SAAS,IAAI,UAAU,MAAM,CAAC;AAC9C,QAAI,CAAC,QAAS;AACd,UAAM,UAAU,MAAM,SAAS,QAAQ,SAAS;AAAA,MAC9C,SAAS,QAAQ;AAAA,MACjB,aAAa,QAAQ;AAAA,MACrB,iBAAiB,QAAQ;AAAA,IAC3B,CAAC;AACD,QAAI,QAAQ,SAAS,GAAG;AACtB,YAAM,KAAK,EAAE,MAAM,OAAO,MAAM,MAAM,OAAO,MAAM,QAAQ,CAAC;AAAA,IAC9D;AAAA,EACF;AAGA,QAAM,EAAE,QAAQ,YAAY,IAAI,MAAM,YAAY,SAAS;AAAA,IACzD,SAAS,QAAQ;AAAA,IACjB,KAAK,QAAQ;AAAA,EACf,CAAC;AAED,SAAO,EAAE,QAAQ,aAAa,MAAM;AACtC;AAGO,SAAS,kBAAkB,QAA6B;AAG7D,SAAO,WAAW,SAAS,IAAI;AACjC;AAMO,SAAS,kBACd,QACA,MACM;AACN,MAAI,MAAM;AACR,UAAM,UAA4B,EAAE,QAAQ,OAAO,OAAO;AAC1D,QAAI,OAAO,MAAO,SAAQ,QAAQ,OAAO;AACzC,YAAQ,IAAI,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAC5C;AAAA,EACF;AAEA,UAAQ,IAAI,aAAa,OAAO,MAAM,CAAC;AAEvC,MAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AAC3C,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,UAAU;AACtB,eAAW,KAAK,OAAO,OAAO;AAC5B,cAAQ,IAAI,iBAAiB,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,GAAG,EAAE,OAAO,CAAC;AAAA,IACzE;AAAA,EACF;AACF;","names":["os","readJsonFile","mergeHooksSettings","writeJsonFile"]}