oh-my-opencode 4.19.0 → 4.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/.agents/command/omomomo.md +1 -1
  2. package/.agents/skills/omomomo/SKILL.md +1 -1
  3. package/.opencode/command/omomomo.md +1 -1
  4. package/README.ja.md +6 -6
  5. package/README.ko.md +6 -6
  6. package/README.md +6 -6
  7. package/README.ru.md +6 -6
  8. package/README.zh-cn.md +6 -6
  9. package/dist/agents/atlas/agent.d.ts +1 -1
  10. package/dist/agents/gpt-prompt-identity.d.ts +3 -0
  11. package/dist/agents/sisyphus/gpt-5-5.d.ts +1 -1
  12. package/dist/agents/sisyphus/gpt-task-system-guide.d.ts +1 -0
  13. package/dist/agents/sisyphus-junior/gpt-5-5.d.ts +2 -2
  14. package/dist/cli/index.js +148 -94
  15. package/dist/cli-node/index.js +148 -94
  16. package/dist/config/schema/agent-overrides.d.ts +48 -48
  17. package/dist/config/schema/categories.d.ts +6 -6
  18. package/dist/config/schema/codegraph.d.ts +2 -0
  19. package/dist/config/schema/fallback-models.d.ts +5 -5
  20. package/dist/config/schema/oh-my-opencode-config.d.ts +50 -48
  21. package/dist/hooks/codegraph-bootstrap/hook.d.ts +3 -2
  22. package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
  23. package/dist/hooks/start-work/notepad-scaffold.d.ts +10 -0
  24. package/dist/index.js +2612 -1473
  25. package/dist/oh-my-opencode.schema.json +11 -0
  26. package/dist/shared/omo-process-sweep.d.ts +18 -0
  27. package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
  28. package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
  29. package/dist/skills/ulw-plan/SKILL.md +20 -1
  30. package/dist/testing/create-plugin-module.d.ts +1 -0
  31. package/dist/tui.js +66 -56
  32. package/package.json +13 -13
  33. package/packages/git-bash-mcp/dist/cli.js +54 -8
  34. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +60 -0
  35. package/packages/lsp-core/src/lsp/client.ts +14 -1
  36. package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +2 -2
  37. package/packages/lsp-core/src/mcp.ts +9 -0
  38. package/packages/lsp-daemon/dist/cli.js +319 -51
  39. package/packages/lsp-daemon/dist/client.js +136 -48
  40. package/packages/lsp-daemon/dist/daemon-client.d.ts +0 -10
  41. package/packages/lsp-daemon/dist/daemon-client.js +4 -34
  42. package/packages/lsp-daemon/dist/daemon-failure-result.d.ts +3 -0
  43. package/packages/lsp-daemon/dist/daemon-failure-result.js +38 -0
  44. package/packages/lsp-daemon/dist/daemon-request-error.d.ts +14 -0
  45. package/packages/lsp-daemon/dist/daemon-request-error.js +26 -0
  46. package/packages/lsp-daemon/dist/daemon-server.js +5 -1
  47. package/packages/lsp-daemon/dist/index.js +137 -48
  48. package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
  49. package/packages/lsp-daemon/dist/proxy.js +1 -0
  50. package/packages/lsp-daemon/dist/version-reap.d.ts +26 -0
  51. package/packages/lsp-daemon/dist/version-reap.js +182 -0
  52. package/packages/lsp-tools-mcp/dist/cli.js +61 -10
  53. package/packages/lsp-tools-mcp/dist/lsp/manager.js +6 -1
  54. package/packages/lsp-tools-mcp/dist/mcp.js +61 -10
  55. package/packages/lsp-tools-mcp/dist/tools.js +6 -1
  56. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  57. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +64 -8
  58. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  59. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  60. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +22 -2
  61. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +555 -251
  62. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +178 -89
  63. package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
  64. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +3 -1
  65. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +3 -1
  66. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +98 -32
  67. package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +5 -0
  68. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +15 -6
  69. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +6 -2
  70. package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +1 -0
  71. package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +148 -0
  72. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +31 -2
  73. package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +1 -1
  74. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +65 -1
  75. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +3 -7
  76. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +1 -1
  77. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +57 -3
  78. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +41 -0
  79. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +109 -8
  80. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +2 -2
  81. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +43 -0
  82. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  83. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  84. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  85. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  86. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  87. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  88. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  89. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +80 -40
  90. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  91. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  92. package/packages/omo-codex/plugin/components/rules/dist/cli.js +11 -0
  93. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  94. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  95. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +11 -0
  96. package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +60 -0
  97. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  98. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  99. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  100. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  101. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  102. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  103. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +2 -2
  104. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
  105. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
  106. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +1 -1
  107. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +2 -2
  108. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +1 -1
  109. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +1 -1
  110. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  111. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  112. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +20 -1
  113. package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +1 -1
  114. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +42 -0
  115. package/packages/omo-codex/plugin/components/ulw-loop/README.md +6 -4
  116. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.d.ts +21 -0
  117. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +64 -0
  118. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +15 -2
  119. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-arg-parser.js +1 -1
  120. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +2 -1
  121. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +1 -1
  122. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +3 -3
  123. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.d.ts +3 -0
  124. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +85 -0
  125. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +0 -1
  126. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -33
  127. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +998 -593
  128. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +1 -0
  129. package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.d.ts +1 -1
  130. package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.js +2 -0
  131. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +6 -0
  132. package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.d.ts +1 -0
  133. package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.js +3 -0
  134. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +1 -0
  135. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +4 -0
  136. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +1 -0
  137. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +10 -2
  138. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +1 -1
  139. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.d.ts +15 -0
  140. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.js +84 -0
  141. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.d.ts +5 -0
  142. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.js +81 -0
  143. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +7 -59
  144. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +12 -4
  145. package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.d.ts +9 -0
  146. package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.js +122 -0
  147. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  148. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  149. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +8 -6
  150. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +84 -0
  151. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +13 -2
  152. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-arg-parser.ts +1 -1
  153. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +1 -1
  154. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +3 -3
  155. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +49 -0
  156. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +13 -45
  157. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +1 -0
  158. package/packages/omo-codex/plugin/components/ulw-loop/src/constants.ts +2 -0
  159. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +7 -0
  160. package/packages/omo-codex/plugin/components/ulw-loop/src/goal-status.ts +4 -0
  161. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +4 -1
  162. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +20 -2
  163. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +1 -1
  164. package/packages/omo-codex/plugin/components/ulw-loop/src/steering-batch.ts +125 -0
  165. package/packages/omo-codex/plugin/components/ulw-loop/src/steering-mutations.ts +59 -0
  166. package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +6 -58
  167. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +12 -4
  168. package/packages/omo-codex/plugin/components/ulw-loop/src/validation-batch.ts +122 -0
  169. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +76 -0
  170. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint-continuation.test.ts +111 -0
  171. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-batch.test.ts +67 -0
  172. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-validation-batch.test.ts +57 -0
  173. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +1 -0
  174. package/packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts +152 -0
  175. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +29 -0
  176. package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch-checkpoint.test.ts +147 -0
  177. package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch.test.ts +73 -0
  178. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  179. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  180. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  181. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  182. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  183. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  184. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  185. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  186. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  187. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  188. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  189. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +2 -2
  190. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  191. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +2 -2
  192. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  193. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +2 -2
  194. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  195. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  196. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  197. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  198. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  199. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  200. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  201. package/packages/omo-codex/plugin/package-lock.json +41 -41
  202. package/packages/omo-codex/plugin/package.json +1 -1
  203. package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +43 -0
  204. package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
  205. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +8 -6
  206. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +20 -1
  207. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +9 -9
  208. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +26 -0
  209. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +41 -0
  210. package/packages/omo-codex/scripts/install-dist/install-local.mjs +49 -5
  211. package/packages/omo-codex/scripts/install-marketplace-cache.test.mjs +4 -1
  212. package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
  213. package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
  214. package/packages/shared-skills/skills/ulw-plan/SKILL.md +20 -1
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // components/codegraph/src/cli.ts
4
- import { realpathSync as realpathSync6 } from "node:fs";
5
- import { basename as basename5, resolve as resolve7 } from "node:path";
4
+ import { realpathSync as realpathSync7 } from "node:fs";
5
+ import { basename as basename5, resolve as resolve8 } from "node:path";
6
6
  import { stderr as processStderr4 } from "node:process";
7
7
  import { fileURLToPath as fileURLToPath4 } from "node:url";
8
8
 
9
9
  // components/codegraph/src/hook.ts
10
10
  import { execFile as execFile4, spawn } from "node:child_process";
11
11
  import { homedir as homedir13 } from "node:os";
12
- import { join as join13 } from "node:path";
12
+ import { join as join14 } from "node:path";
13
13
  import {
14
14
  cwd as processCwd2,
15
15
  env as processEnv2,
@@ -56,6 +56,7 @@ var SAFE_AMBIENT_ENV_KEYS = new Set([
56
56
  var SAFE_CODEGRAPH_RUNTIME_ENV_KEYS = new Set([
57
57
  "CODEGRAPH_ALLOW_UNSAFE_NODE",
58
58
  "CODEGRAPH_BIN",
59
+ "CODEGRAPH_DAEMON_IDLE_TIMEOUT_MS",
59
60
  "CODEGRAPH_FAKE_LOG",
60
61
  "CODEGRAPH_NO_DAEMON",
61
62
  "CODEGRAPH_NODE_BIN",
@@ -67,7 +68,7 @@ function buildCodegraphEnv(options = {}) {
67
68
  const homeDir = options.homeDir ?? homedir();
68
69
  return {
69
70
  [CODEGRAPH_INSTALL_DIR_ENV]: join(homeDir, ".omo", "codegraph"),
70
- [CODEGRAPH_NO_DAEMON_ENV]: "1",
71
+ ...options.daemon === true ? {} : { [CODEGRAPH_NO_DAEMON_ENV]: "1" },
71
72
  [CODEGRAPH_NO_DOWNLOAD_ENV]: "1",
72
73
  [CODEGRAPH_TELEMETRY_ENV]: "0",
73
74
  [DO_NOT_TRACK_ENV]: "1"
@@ -399,6 +400,9 @@ var ANSI_ESCAPE_PATTERN = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
399
400
  var CODEGRAPH_STATUS_PROJECT_PATTERN = /^.*?\bProject:\s*(.+?)\s*$/im;
400
401
  var CODEGRAPH_STATUS_UNINITIALIZED_PATTERN = /^.*?\bNot initialized\s*$/im;
401
402
  var CODEGRAPH_INIT_HINT_PATTERN = /Run\s+["'`]codegraph init["'`]\s+(?:in that project first|to initialize)\.?/i;
403
+ var CODEGRAPH_PROJECT_NOT_INDEXED_PATTERN = /The project at (.+?) isn't indexed with codegraph\b/i;
404
+ var CODEGRAPH_NO_PROJECT_LOADED_PATTERN = /No CodeGraph project is loaded for this session\./i;
405
+ var CODEGRAPH_NO_PROJECT_SEARCHED_FROM_PATTERN = /^Searched for a \.codegraph\/ directory starting from:\s*(.+?)\s*$/im;
402
406
  function getCodegraphUninitializedProject(input) {
403
407
  const output = textFromUnknown(input.toolOutput);
404
408
  if (!isCodegraphTool(input.toolName))
@@ -439,6 +443,16 @@ function extractProjectPath(output) {
439
443
  const uninitializedProject = uninitializedMatch?.[1]?.trim();
440
444
  if (uninitializedProject && uninitializedProject.length > 0)
441
445
  return uninitializedProject;
446
+ const notIndexedMatch = normalizedOutput.match(CODEGRAPH_PROJECT_NOT_INDEXED_PATTERN);
447
+ const notIndexedProject = notIndexedMatch?.[1]?.trim();
448
+ if (notIndexedProject && notIndexedProject.length > 0)
449
+ return notIndexedProject;
450
+ if (CODEGRAPH_NO_PROJECT_LOADED_PATTERN.test(normalizedOutput)) {
451
+ const searchedFromMatch = normalizedOutput.match(CODEGRAPH_NO_PROJECT_SEARCHED_FROM_PATTERN);
452
+ const searchedFromProject = searchedFromMatch?.[1]?.trim();
453
+ if (searchedFromProject && searchedFromProject.length > 0)
454
+ return searchedFromProject;
455
+ }
442
456
  if (!looksLikeCodegraphUninitializedOutput(normalizedOutput))
443
457
  return null;
444
458
  const statusMatch = normalizedOutput.match(CODEGRAPH_STATUS_PROJECT_PATTERN);
@@ -1597,8 +1611,9 @@ function parseJsoncSafe(content) {
1597
1611
  var HARNESS_IDS = ["codex", "opencode", "omo"];
1598
1612
  var SETTING_HARNESS_SUPPORT = {
1599
1613
  "codegraph.auto_provision": HARNESS_IDS,
1614
+ "codegraph.daemon": ["codex", "opencode"],
1600
1615
  "codegraph.enabled": HARNESS_IDS,
1601
- "codegraph.excluded_roots": ["codex"],
1616
+ "codegraph.excluded_roots": ["codex", "opencode"],
1602
1617
  "codegraph.install_dir": HARNESS_IDS,
1603
1618
  "codegraph.telemetry": HARNESS_IDS,
1604
1619
  "codegraph.watch_debounce_ms": ["opencode", "omo"]
@@ -1615,6 +1630,7 @@ var BUILT_IN_DEFAULTS = {
1615
1630
  var HARNESS_BLOCK_KEYS = HARNESS_IDS.map((harness) => `[${harness}]`);
1616
1631
  var CODEGRAPH_SETTING_KEYS = [
1617
1632
  "auto_provision",
1633
+ "daemon",
1618
1634
  "enabled",
1619
1635
  "excluded_roots",
1620
1636
  "install_dir",
@@ -1688,6 +1704,10 @@ function setCodegraphSetting(config, key, value) {
1688
1704
  if (typeof value === "boolean")
1689
1705
  config.auto_provision = value;
1690
1706
  return;
1707
+ case "daemon":
1708
+ if (typeof value === "boolean")
1709
+ config.daemon = value;
1710
+ return;
1691
1711
  case "enabled":
1692
1712
  if (typeof value === "boolean")
1693
1713
  config.enabled = value;
@@ -2007,77 +2027,131 @@ function isNonFatalCodegraphGcError(error) {
2007
2027
 
2008
2028
  // components/codegraph/src/hook-sweep.ts
2009
2029
  import { fileURLToPath } from "node:url";
2010
- // ../../utils/src/codegraph/process-sweeper.ts
2030
+ // ../../utils/src/process-sweep/sweeper.ts
2011
2031
  import { existsSync as existsSync7, mkdirSync as mkdirSync2, statSync as statSync2, utimesSync, writeFileSync as writeFileSync2 } from "node:fs";
2012
2032
  import { homedir as homedir10 } from "node:os";
2013
- import { dirname as dirname4, join as join10 } from "node:path";
2014
-
2015
- // ../../utils/src/codegraph/process-exec.ts
2016
- import { execFile } from "node:child_process";
2033
+ import { dirname as dirname5, join as join11 } from "node:path";
2017
2034
 
2018
- // ../../utils/src/codegraph/process-match.ts
2019
- import { posix, win32 } from "node:path";
2020
- var SERVE_WRAPPER_SUFFIX = "/components/codegraph/dist/serve.js";
2021
- var UPSTREAM_PACKAGE_SEGMENT = "/@colbymchenry/codegraph/";
2022
- function parsePosixProcessTable(output) {
2023
- const processes = [];
2024
- for (const line of output.split(/\r?\n/)) {
2025
- const match = /^\s*(\d+)\s+(\d+)\s+(.+?)\s*$/.exec(line);
2026
- if (match === null)
2027
- continue;
2028
- const pid = Number(match[1]);
2029
- const ppid = Number(match[2]);
2030
- const command = match[3];
2031
- if (!isValidProcessId(pid) || !Number.isInteger(ppid) || ppid < 0 || command === undefined)
2032
- continue;
2033
- processes.push({ command, pid, ppid });
2035
+ // ../../utils/src/codegraph/daemon-lock.ts
2036
+ import { readFileSync as readFileSync4, realpathSync as realpathSync4 } from "node:fs";
2037
+ import { dirname as dirname4, join as join9, resolve as resolve5 } from "node:path";
2038
+ function parseDaemonLock(raw) {
2039
+ const trimmed = raw.trim();
2040
+ if (trimmed.length === 0)
2041
+ return null;
2042
+ try {
2043
+ const parsed = JSON.parse(trimmed);
2044
+ if (typeof parsed === "object" && parsed !== null && "pid" in parsed) {
2045
+ const pid = parsed.pid;
2046
+ if (typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0) {
2047
+ const record = parsed;
2048
+ return {
2049
+ pid,
2050
+ ...typeof record["socketPath"] === "string" ? { socketPath: record["socketPath"] } : {},
2051
+ ...typeof record["startedAt"] === "number" ? { startedAt: record["startedAt"] } : {},
2052
+ ...typeof record["version"] === "string" ? { version: record["version"] } : {}
2053
+ };
2054
+ }
2055
+ }
2056
+ return null;
2057
+ } catch (error) {
2058
+ if (!(error instanceof SyntaxError))
2059
+ throw error;
2034
2060
  }
2035
- return processes;
2061
+ const legacyPid = Number(trimmed);
2062
+ if (Number.isSafeInteger(legacyPid) && legacyPid > 0)
2063
+ return { pid: legacyPid };
2064
+ return null;
2036
2065
  }
2037
- function parseWindowsProcessTable(output) {
2038
- const parsed = parseJson(output);
2039
- const entries = Array.isArray(parsed) ? parsed : parsed === undefined ? [] : [parsed];
2040
- const processes = [];
2041
- for (const entry of entries) {
2042
- if (!isRecord3(entry))
2066
+ function daemonLockCandidates(projectRoot) {
2067
+ const dirs = new Set;
2068
+ const resolved = resolve5(projectRoot);
2069
+ collectAncestors(resolved, dirs);
2070
+ collectAncestors(realpathIfPossible2(resolved), dirs);
2071
+ return [...dirs].map((dir) => join9(dir, ".codegraph", "daemon.pid"));
2072
+ }
2073
+ function evaluateDaemonStaleness(pid, projectRoot) {
2074
+ let sawLock = false;
2075
+ for (const lockPath of daemonLockCandidates(projectRoot)) {
2076
+ const raw = readLockIfPresent(lockPath);
2077
+ if (raw === undefined)
2043
2078
  continue;
2044
- const pid = numberField(entry, "ProcessId");
2045
- const ppid = numberField(entry, "ParentProcessId");
2046
- const command = stringField(entry, "CommandLine");
2047
- if (pid === undefined || ppid === undefined || command === undefined || command.trim().length === 0)
2048
- continue;
2049
- processes.push({ command, pid, ppid });
2079
+ if (raw === null)
2080
+ return { stale: false, reason: "lock-unreadable" };
2081
+ sawLock = true;
2082
+ const lock = parseDaemonLock(raw);
2083
+ if (lock === null)
2084
+ return { stale: false, reason: "lock-unparseable" };
2085
+ if (lock.pid === pid)
2086
+ return { stale: false, reason: "lock-pid-match" };
2087
+ }
2088
+ return sawLock ? { stale: true, reason: "lock-pid-mismatch" } : { stale: true, reason: "lock-absent" };
2089
+ }
2090
+ function readLockIfPresent(lockPath) {
2091
+ try {
2092
+ return readFileSync4(lockPath, "utf8");
2093
+ } catch (error) {
2094
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
2095
+ return;
2096
+ if (error instanceof Error && "code" in error && error.code === "ENOTDIR")
2097
+ return;
2098
+ return null;
2050
2099
  }
2051
- return processes;
2052
2100
  }
2053
- function selectZombieCodegraphProcesses(processes, options) {
2054
- const platform = options.platform ?? process.platform;
2055
- const livePids = new Set(processes.map((processInfo) => processInfo.pid));
2056
- const roots = normalizeRoots(options.ownedRoots, platform);
2057
- const zombies = [];
2058
- for (const processInfo of processes) {
2059
- const match = matchOwnedCodegraphCommand(processInfo.command, roots, platform);
2060
- if (match === null)
2061
- continue;
2062
- if (!isOrphaned(processInfo, livePids))
2063
- continue;
2064
- zombies.push({ ...processInfo, matchedRoot: match.root, matchKind: match.kind });
2101
+ function collectAncestors(start, output) {
2102
+ let current = start;
2103
+ for (;; ) {
2104
+ output.add(current);
2105
+ const parent = dirname4(current);
2106
+ if (parent === current)
2107
+ return;
2108
+ current = parent;
2065
2109
  }
2066
- return zombies;
2067
2110
  }
2068
- function matchOwnedCodegraphCommand(command, roots, platform) {
2069
- const normalizedCommand = normalizeForComparison2(command, platform);
2070
- for (const root of roots) {
2071
- if (root.length === 0)
2111
+ function realpathIfPossible2(path) {
2112
+ try {
2113
+ return realpathSync4(path);
2114
+ } catch (error) {
2115
+ if (error instanceof Error)
2116
+ return path;
2117
+ throw error;
2118
+ }
2119
+ }
2120
+
2121
+ // ../../utils/src/process-sweep/command-match.ts
2122
+ import { posix, win32 } from "node:path";
2123
+ function splitCommandTokens(command) {
2124
+ const tokens = [];
2125
+ let current = "";
2126
+ let quote = null;
2127
+ let tokenStarted = false;
2128
+ for (const char of command) {
2129
+ if (quote !== null) {
2130
+ if (char === quote) {
2131
+ quote = null;
2132
+ } else {
2133
+ current += char;
2134
+ }
2135
+ continue;
2136
+ }
2137
+ if (char === '"' || char === "'") {
2138
+ quote = char;
2139
+ tokenStarted = true;
2072
2140
  continue;
2073
- const serveWrapper = `${root}${SERVE_WRAPPER_SUFFIX}`;
2074
- if (hasExecutableToken(normalizedCommand, serveWrapper))
2075
- return { kind: "serve-wrapper", root };
2076
- if (upstreamPackagePathIsUnderRoot(normalizedCommand, root)) {
2077
- return { kind: "upstream-codegraph", root };
2078
2141
  }
2142
+ if (/\s/.test(char)) {
2143
+ if (tokenStarted || current.length > 0) {
2144
+ tokens.push(current);
2145
+ current = "";
2146
+ tokenStarted = false;
2147
+ }
2148
+ continue;
2149
+ }
2150
+ current += char;
2079
2151
  }
2080
- return null;
2152
+ if (tokenStarted || current.length > 0)
2153
+ tokens.push(current);
2154
+ return tokens;
2081
2155
  }
2082
2156
  function hasExecutableToken(command, expectedPath) {
2083
2157
  let searchFrom = 0;
@@ -2093,24 +2167,19 @@ function hasExecutableToken(command, expectedPath) {
2093
2167
  }
2094
2168
  }
2095
2169
  function tokenLooksExecutable(command, tokenStart) {
2096
- const prefix = command.slice(0, tokenStart).trimEnd();
2170
+ let prefix = command.slice(0, tokenStart).trimEnd();
2097
2171
  if (prefix.length === 0)
2098
2172
  return true;
2099
- const previousTokenStart = findTokenStart(prefix, prefix.length - 1);
2100
- const previousToken = prefix.slice(previousTokenStart);
2101
- const executableName = previousToken.split("/").at(-1) ?? previousToken;
2102
- return /^node\d*(\.exe)?$/.test(executableName) || /^bun(\.exe)?$/.test(executableName);
2103
- }
2104
- function upstreamPackagePathIsUnderRoot(command, root) {
2105
- let searchFrom = 0;
2106
2173
  for (;; ) {
2107
- const packageIndex = command.indexOf(UPSTREAM_PACKAGE_SEGMENT, searchFrom);
2108
- if (packageIndex < 0)
2174
+ const previousTokenStart = findTokenStart(prefix, prefix.length - 1);
2175
+ const previousToken = prefix.slice(previousTokenStart);
2176
+ if (!previousToken.startsWith("-")) {
2177
+ const executableName = previousToken.split("/").at(-1) ?? previousToken;
2178
+ return /^node\d*(\.exe)?$/i.test(executableName) || /^bun(\.exe)?$/i.test(executableName);
2179
+ }
2180
+ prefix = prefix.slice(0, previousTokenStart).trimEnd();
2181
+ if (prefix.length === 0)
2109
2182
  return false;
2110
- const tokenStart = findTokenStart(command, packageIndex);
2111
- if (command.slice(tokenStart).startsWith(`${root}/`) && tokenLooksExecutable(command, tokenStart))
2112
- return true;
2113
- searchFrom = packageIndex + UPSTREAM_PACKAGE_SEGMENT.length;
2114
2183
  }
2115
2184
  }
2116
2185
  function findTokenStart(command, index) {
@@ -2144,6 +2213,39 @@ function normalizeForComparison2(value, platform) {
2144
2213
  const normalized = value.replaceAll("\\", "/").replace(/\/+$/, "");
2145
2214
  return platform === "win32" ? normalized.toLowerCase() : normalized;
2146
2215
  }
2216
+
2217
+ // ../../utils/src/process-sweep/process-table.ts
2218
+ function parsePosixProcessTable(output) {
2219
+ const processes = [];
2220
+ for (const line of output.split(/\r?\n/)) {
2221
+ const match = /^\s*(\d+)\s+(\d+)\s+(.+?)\s*$/.exec(line);
2222
+ if (match === null)
2223
+ continue;
2224
+ const pid = Number(match[1]);
2225
+ const ppid = Number(match[2]);
2226
+ const command = match[3];
2227
+ if (!isValidProcessId(pid) || !Number.isInteger(ppid) || ppid < 0 || command === undefined)
2228
+ continue;
2229
+ processes.push({ command, pid, ppid });
2230
+ }
2231
+ return processes;
2232
+ }
2233
+ function parseWindowsProcessTable(output) {
2234
+ const parsed = parseJson(output);
2235
+ const entries = Array.isArray(parsed) ? parsed : parsed === undefined ? [] : [parsed];
2236
+ const processes = [];
2237
+ for (const entry of entries) {
2238
+ if (!isRecord3(entry))
2239
+ continue;
2240
+ const pid = numberField(entry, "ProcessId");
2241
+ const ppid = numberField(entry, "ParentProcessId");
2242
+ const command = stringField(entry, "CommandLine");
2243
+ if (pid === undefined || ppid === undefined || command === undefined || command.trim().length === 0)
2244
+ continue;
2245
+ processes.push({ command, pid, ppid });
2246
+ }
2247
+ return processes;
2248
+ }
2147
2249
  function isOrphaned(processInfo, livePids) {
2148
2250
  return processInfo.ppid === 1 || !livePids.has(processInfo.ppid);
2149
2251
  }
@@ -2171,13 +2273,113 @@ function isRecord3(value) {
2171
2273
  return typeof value === "object" && value !== null;
2172
2274
  }
2173
2275
 
2174
- // ../../utils/src/codegraph/process-exec.ts
2175
- function enumerateCodegraphProcesses(platform = process.platform) {
2276
+ // ../../utils/src/process-sweep/codegraph-family.ts
2277
+ var SERVE_WRAPPER_SUFFIX = "/components/codegraph/dist/serve.js";
2278
+ var UPSTREAM_PACKAGE_SEGMENT = "/@colbymchenry/codegraph/";
2279
+ function selectZombieCodegraphProcesses(processes, options) {
2280
+ const platform = options.platform ?? process.platform;
2281
+ const livePids = new Set(processes.map((processInfo) => processInfo.pid));
2282
+ const roots = normalizeRoots(options.ownedRoots, platform);
2283
+ const zombies = [];
2284
+ for (const processInfo of processes) {
2285
+ const daemon = matchDaemonCommand(processInfo.command, roots, platform);
2286
+ if (daemon !== null) {
2287
+ if (!isOrphaned(processInfo, livePids))
2288
+ continue;
2289
+ zombies.push({
2290
+ ...processInfo,
2291
+ daemonProjectRoot: daemon.projectRoot,
2292
+ matchedRoot: daemon.root,
2293
+ matchKind: "upstream-daemon"
2294
+ });
2295
+ continue;
2296
+ }
2297
+ const match = matchOwnedCodegraphCommand(processInfo.command, roots, platform);
2298
+ if (match === null)
2299
+ continue;
2300
+ if (!isOrphaned(processInfo, livePids))
2301
+ continue;
2302
+ zombies.push({ ...processInfo, matchedRoot: match.root, matchKind: match.kind });
2303
+ }
2304
+ return zombies;
2305
+ }
2306
+ var STANDALONE_LAUNCHER_SUFFIXES = ["/bin/codegraph", "/bin/codegraph.exe"];
2307
+ var BUNDLE_SCRIPT_SUFFIX = "/lib/dist/bin/codegraph.js";
2308
+ function matchDaemonCommand(command, roots, platform) {
2309
+ const projectRoot = extractDaemonProjectRoot(splitCommandTokens(command));
2310
+ if (projectRoot === null)
2311
+ return null;
2312
+ const normalizedCommand = normalizeForComparison2(command, platform);
2313
+ for (const root of roots) {
2314
+ if (root.length === 0)
2315
+ continue;
2316
+ if (upstreamPackagePathIsUnderRoot(normalizedCommand, root))
2317
+ return { projectRoot, root };
2318
+ for (const suffix of STANDALONE_LAUNCHER_SUFFIXES) {
2319
+ if (hasExecutableToken(normalizedCommand, `${root}${suffix}`))
2320
+ return { projectRoot, root };
2321
+ }
2322
+ if (hasExecutableToken(normalizedCommand, `${root}${BUNDLE_SCRIPT_SUFFIX}`))
2323
+ return { projectRoot, root };
2324
+ }
2325
+ return null;
2326
+ }
2327
+ function extractDaemonProjectRoot(tokens) {
2328
+ if (!tokens.includes("serve") || !tokens.includes("--mcp"))
2329
+ return null;
2330
+ const pathIndex = tokens.indexOf("--path");
2331
+ if (pathIndex < 0)
2332
+ return null;
2333
+ const value = tokens[pathIndex + 1];
2334
+ if (value === undefined || value.length === 0 || value.startsWith("--"))
2335
+ return null;
2336
+ return value;
2337
+ }
2338
+ function matchOwnedCodegraphCommand(command, roots, platform) {
2339
+ const normalizedCommand = normalizeForComparison2(command, platform);
2340
+ for (const root of roots) {
2341
+ if (root.length === 0)
2342
+ continue;
2343
+ const serveWrapper = `${root}${SERVE_WRAPPER_SUFFIX}`;
2344
+ if (hasExecutableToken(normalizedCommand, serveWrapper))
2345
+ return { kind: "serve-wrapper", root };
2346
+ if (upstreamPackagePathIsUnderRoot(normalizedCommand, root)) {
2347
+ return { kind: "upstream-codegraph", root };
2348
+ }
2349
+ }
2350
+ return null;
2351
+ }
2352
+ function upstreamPackagePathIsUnderRoot(command, root) {
2353
+ let searchFrom = 0;
2354
+ for (;; ) {
2355
+ const packageIndex = command.indexOf(UPSTREAM_PACKAGE_SEGMENT, searchFrom);
2356
+ if (packageIndex < 0)
2357
+ return false;
2358
+ const tokenStart = findTokenStart(command, packageIndex);
2359
+ if (command.slice(tokenStart).startsWith(`${root}/`) && tokenLooksExecutable(command, tokenStart))
2360
+ return true;
2361
+ searchFrom = packageIndex + UPSTREAM_PACKAGE_SEGMENT.length;
2362
+ }
2363
+ }
2364
+
2365
+ // ../../utils/src/process-sweep/exec.ts
2366
+ import { execFile } from "node:child_process";
2367
+ function enumerateProcesses(platform = process.platform) {
2176
2368
  return platform === "win32" ? enumerateWindowsProcesses() : enumeratePosixProcesses();
2177
2369
  }
2178
- function createDefaultCodegraphProcessKiller(platform = process.platform) {
2370
+ function createDefaultProcessKiller(platform = process.platform) {
2179
2371
  return platform === "win32" ? createWindowsKiller() : createPosixKiller();
2180
2372
  }
2373
+ function defaultIsProcessAlive(pid) {
2374
+ try {
2375
+ process.kill(pid, 0);
2376
+ return true;
2377
+ } catch (error) {
2378
+ if (!(error instanceof Error))
2379
+ throw error;
2380
+ return processKillErrorMeansAlive(error);
2381
+ }
2382
+ }
2181
2383
  function enumeratePosixProcesses() {
2182
2384
  return execFileText("ps", ["-eo", "pid=,ppid=,command="]).then(parsePosixProcessTable);
2183
2385
  }
@@ -2191,16 +2393,7 @@ function enumerateWindowsProcesses() {
2191
2393
  }
2192
2394
  function createPosixKiller() {
2193
2395
  return {
2194
- isAlive: (pid) => {
2195
- try {
2196
- process.kill(pid, 0);
2197
- return true;
2198
- } catch (error) {
2199
- if (!(error instanceof Error))
2200
- throw error;
2201
- return processKillErrorMeansAlive(error);
2202
- }
2203
- },
2396
+ isAlive: defaultIsProcessAlive,
2204
2397
  kill: (pid) => {
2205
2398
  process.kill(pid, "SIGKILL");
2206
2399
  return Promise.resolve();
@@ -2213,16 +2406,7 @@ function createPosixKiller() {
2213
2406
  }
2214
2407
  function createWindowsKiller() {
2215
2408
  return {
2216
- isAlive: (pid) => {
2217
- try {
2218
- process.kill(pid, 0);
2219
- return true;
2220
- } catch (error) {
2221
- if (!(error instanceof Error))
2222
- throw error;
2223
- return processKillErrorMeansAlive(error);
2224
- }
2225
- },
2409
+ isAlive: defaultIsProcessAlive,
2226
2410
  kill: (pid) => execFileVoid("taskkill.exe", ["/PID", String(pid), "/T", "/F"]),
2227
2411
  terminate: (pid) => execFileVoid("taskkill.exe", ["/PID", String(pid), "/T"])
2228
2412
  };
@@ -2252,10 +2436,10 @@ function processKillErrorMeansAlive(error) {
2252
2436
  return false;
2253
2437
  }
2254
2438
 
2255
- // ../../utils/src/codegraph/process-roots.ts
2256
- import { existsSync as existsSync6, readdirSync as readdirSync2, realpathSync as realpathSync4 } from "node:fs";
2439
+ // ../../utils/src/process-sweep/roots.ts
2440
+ import { existsSync as existsSync6, readdirSync as readdirSync2, realpathSync as realpathSync5 } from "node:fs";
2257
2441
  import { homedir as homedir9 } from "node:os";
2258
- import { join as join9, resolve as resolve5 } from "node:path";
2442
+ import { join as join10, resolve as resolve6 } from "node:path";
2259
2443
  function discoverCodegraphOwnedRoots(options = {}) {
2260
2444
  const env = options.env ?? process.env;
2261
2445
  const homeDir = options.homeDir ?? env["HOME"] ?? env["USERPROFILE"] ?? homedir9();
@@ -2265,33 +2449,33 @@ function discoverCodegraphOwnedRoots(options = {}) {
2265
2449
  addRoot(roots, options.pluginRoot);
2266
2450
  for (const root of options.extraRoots ?? [])
2267
2451
  addRoot(roots, root);
2268
- for (const root of readCodexPluginCacheRoots(options.codexHome ?? env["CODEX_HOME"] ?? join9(homeDir, ".codex"))) {
2452
+ for (const root of readCodexPluginCacheRoots(options.codexHome ?? env["CODEX_HOME"] ?? join10(homeDir, ".codex"))) {
2269
2453
  addRoot(roots, root);
2270
2454
  }
2271
2455
  return [...roots];
2272
2456
  }
2273
2457
  function readCodexPluginCacheRoots(codexHome) {
2274
- const cacheRoot = join9(codexHome, "plugins", "cache");
2458
+ const cacheRoot = join10(codexHome, "plugins", "cache");
2275
2459
  if (!existsSync6(cacheRoot))
2276
2460
  return [];
2277
2461
  const roots = [];
2278
2462
  for (const publisher of safeReadDir(cacheRoot)) {
2279
2463
  if (!OMO_CODEX_PLUGIN_CACHE_PUBLISHERS.has(publisher))
2280
2464
  continue;
2281
- const omoRoot = join9(cacheRoot, publisher, "omo");
2465
+ const omoRoot = join10(cacheRoot, publisher, "omo");
2282
2466
  if (!existsSync6(omoRoot))
2283
2467
  continue;
2284
2468
  for (const version of safeReadDir(omoRoot))
2285
- roots.push(join9(omoRoot, version));
2469
+ roots.push(join10(omoRoot, version));
2286
2470
  }
2287
2471
  return roots;
2288
2472
  }
2289
2473
  function addRoot(roots, root) {
2290
2474
  if (root === undefined || root.trim().length === 0)
2291
2475
  return;
2292
- const resolved = resolve5(root);
2476
+ const resolved = resolve6(root);
2293
2477
  roots.add(resolved);
2294
- roots.add(realpathIfPossible2(resolved));
2478
+ roots.add(realpathIfPossible3(resolved));
2295
2479
  }
2296
2480
  function safeReadDir(path) {
2297
2481
  try {
@@ -2302,12 +2486,12 @@ function safeReadDir(path) {
2302
2486
  throw error;
2303
2487
  }
2304
2488
  }
2305
- function realpathIfPossible2(path) {
2489
+ function realpathIfPossible3(path) {
2306
2490
  try {
2307
- return realpathSync4(path);
2491
+ return realpathSync5(path);
2308
2492
  } catch (error) {
2309
2493
  if (error instanceof Error)
2310
- return resolve5(path);
2494
+ return resolve6(path);
2311
2495
  throw error;
2312
2496
  }
2313
2497
  }
@@ -2319,70 +2503,109 @@ function isNonFatalFsError(error) {
2319
2503
  }
2320
2504
  var OMO_CODEX_PLUGIN_CACHE_PUBLISHERS = new Set(["sisyphuslabs"]);
2321
2505
 
2322
- // ../../utils/src/codegraph/process-sweeper.ts
2506
+ // ../../utils/src/process-sweep/sweeper.ts
2323
2507
  var DEFAULT_GRACE_MS = 2000;
2324
2508
  var DEFAULT_THROTTLE_MS = 60 * 60 * 1000;
2325
- var SWEEP_STAMP_FILE = "zombie-sweep.stamp";
2326
- async function sweepCodegraphZombies(options = {}) {
2327
- const homeDir = options.homeDir ?? options.env?.["HOME"] ?? options.env?.["USERPROFILE"] ?? homedir10();
2328
- const stampFile = join10(codegraphDataRoot(homeDir), SWEEP_STAMP_FILE);
2509
+ async function runProcessFamilySweep(config, options) {
2329
2510
  const nowMs = options.nowMs ?? Date.now();
2330
2511
  const dryRun = options.dryRun === true;
2331
- const ownedRoots = options.ownedRoots ?? discoverCodegraphOwnedRoots(options);
2332
- if (options.force !== true && isSweepThrottled(stampFile, nowMs, options.throttleMs ?? DEFAULT_THROTTLE_MS)) {
2333
- return emptyResult("throttled", dryRun, ownedRoots, stampFile);
2512
+ if (options.force !== true && isSweepThrottled(config.stampFile, nowMs, options.throttleMs ?? DEFAULT_THROTTLE_MS)) {
2513
+ return { action: "throttled", candidates: [], dryRun, failed: [], killed: [], spared: [], stampFile: config.stampFile };
2334
2514
  }
2335
2515
  try {
2336
- const provider = options.processProvider ?? (() => enumerateCodegraphProcesses(options.platform));
2337
- const candidates = selectZombieCodegraphProcesses(await provider(), {
2338
- ownedRoots,
2339
- ...options.platform === undefined ? {} : { platform: options.platform }
2340
- });
2341
- const result = dryRun ? { failed: [], killed: [] } : await killCandidates(candidates, options.killer ?? createDefaultCodegraphProcessKiller(options.platform), options);
2516
+ const plan = await config.collect();
2517
+ const { failed, killed } = dryRun ? { failed: [], killed: [] } : await killTargets(plan.killList, options.killer ?? createDefaultProcessKiller(options.platform), options, config.familyLabel);
2342
2518
  if (!dryRun)
2343
- writeSweepStamp(stampFile, nowMs);
2344
- return { action: "swept", candidates, dryRun, failed: result.failed, killed: result.killed, ownedRoots, stampFile };
2519
+ writeSweepStamp(config.stampFile, nowMs);
2520
+ return {
2521
+ action: "swept",
2522
+ candidates: plan.candidates,
2523
+ dryRun,
2524
+ failed,
2525
+ killed,
2526
+ spared: plan.spared,
2527
+ stampFile: config.stampFile
2528
+ };
2345
2529
  } catch (error) {
2346
- options.log?.(`CodeGraph zombie sweep skipped: ${error instanceof Error ? error.message : String(error)}`);
2347
- return emptyResult("failed", dryRun, ownedRoots, stampFile);
2530
+ options.log?.(`${config.familyLabel} skipped: ${error instanceof Error ? error.message : String(error)}`);
2531
+ return { action: "failed", candidates: [], dryRun, failed: [], killed: [], spared: [], stampFile: config.stampFile };
2348
2532
  }
2349
2533
  }
2350
- async function killCandidates(candidates, killer, options) {
2534
+ var CODEGRAPH_SWEEP_STAMP_FILE = "zombie-sweep.stamp";
2535
+ async function sweepCodegraphZombies(options = {}) {
2536
+ const homeDir = options.homeDir ?? options.env?.["HOME"] ?? options.env?.["USERPROFILE"] ?? homedir10();
2537
+ const stampFile = join11(codegraphDataRoot(homeDir), CODEGRAPH_SWEEP_STAMP_FILE);
2538
+ const ownedRoots = options.ownedRoots ?? discoverCodegraphOwnedRoots(options);
2539
+ const result = await runProcessFamilySweep({
2540
+ familyLabel: "CodeGraph zombie sweep",
2541
+ stampFile,
2542
+ collect: async () => {
2543
+ const provider = options.processProvider ?? (() => enumerateProcesses(options.platform));
2544
+ const candidates = selectZombieCodegraphProcesses(await provider(), {
2545
+ ownedRoots,
2546
+ ...options.platform === undefined ? {} : { platform: options.platform }
2547
+ });
2548
+ const { killList, spared } = partitionByDaemonStaleness(candidates, options.log);
2549
+ return { candidates, killList, spared };
2550
+ }
2551
+ }, options);
2552
+ return { ...result, ownedRoots };
2553
+ }
2554
+ function partitionByDaemonStaleness(candidates, log) {
2555
+ const killList = [];
2556
+ const spared = [];
2557
+ for (const candidate of candidates) {
2558
+ if (candidate.matchKind !== "upstream-daemon") {
2559
+ killList.push(candidate);
2560
+ continue;
2561
+ }
2562
+ const staleness = evaluateDaemonStaleness(candidate.pid, candidate.daemonProjectRoot ?? candidate.matchedRoot);
2563
+ if (staleness.stale) {
2564
+ log?.(`CodeGraph zombie sweep sweeping stale daemon pid ${candidate.pid} (${staleness.reason})`);
2565
+ killList.push(candidate);
2566
+ continue;
2567
+ }
2568
+ log?.(`CodeGraph zombie sweep spared live daemon pid ${candidate.pid} (${staleness.reason})`);
2569
+ spared.push(candidate);
2570
+ }
2571
+ return { killList, spared };
2572
+ }
2573
+ async function killTargets(targets, killer, options, familyLabel) {
2351
2574
  const failed = [];
2352
2575
  const killed = [];
2353
- for (const candidate of candidates) {
2354
- const terminated = await safelyTerminate(candidate.pid, killer, failed, options.log);
2576
+ for (const target of targets) {
2577
+ const terminated = await safelyTerminate(target.pid, killer, failed, options.log, familyLabel);
2355
2578
  if (!terminated)
2356
2579
  continue;
2357
2580
  await delay(options.graceMs ?? DEFAULT_GRACE_MS);
2358
- if (!await killer.isAlive(candidate.pid)) {
2359
- killed.push(candidate);
2581
+ if (!await killer.isAlive(target.pid)) {
2582
+ killed.push(target);
2360
2583
  continue;
2361
2584
  }
2362
- if (await safelyKill(candidate.pid, killer, failed, options.log))
2363
- killed.push(candidate);
2585
+ if (await safelyKill(target.pid, killer, failed, options.log, familyLabel))
2586
+ killed.push(target);
2364
2587
  }
2365
2588
  return { failed, killed };
2366
2589
  }
2367
- async function safelyTerminate(pid, killer, failed, log) {
2590
+ async function safelyTerminate(pid, killer, failed, log, familyLabel) {
2368
2591
  try {
2369
2592
  await killer.terminate(pid);
2370
2593
  return true;
2371
2594
  } catch (error) {
2372
2595
  const message = error instanceof Error ? error.message : String(error);
2373
2596
  failed.push({ error: message, pid, stage: "terminate" });
2374
- log?.(`CodeGraph zombie sweep failed to terminate pid ${pid}: ${message}`);
2597
+ log?.(`${familyLabel} failed to terminate pid ${pid}: ${message}`);
2375
2598
  return false;
2376
2599
  }
2377
2600
  }
2378
- async function safelyKill(pid, killer, failed, log) {
2601
+ async function safelyKill(pid, killer, failed, log, familyLabel) {
2379
2602
  try {
2380
2603
  await killer.kill(pid);
2381
2604
  return true;
2382
2605
  } catch (error) {
2383
2606
  const message = error instanceof Error ? error.message : String(error);
2384
2607
  failed.push({ error: message, pid, stage: "kill" });
2385
- log?.(`CodeGraph zombie sweep failed to kill pid ${pid}: ${message}`);
2608
+ log?.(`${familyLabel} failed to kill pid ${pid}: ${message}`);
2386
2609
  return false;
2387
2610
  }
2388
2611
  }
@@ -2392,15 +2615,12 @@ function isSweepThrottled(stampFile, nowMs, throttleMs) {
2392
2615
  return nowMs - statSync2(stampFile).mtimeMs < throttleMs;
2393
2616
  }
2394
2617
  function writeSweepStamp(stampFile, nowMs) {
2395
- mkdirSync2(dirname4(stampFile), { recursive: true });
2618
+ mkdirSync2(dirname5(stampFile), { recursive: true });
2396
2619
  writeFileSync2(stampFile, `${new Date(nowMs).toISOString()}
2397
2620
  `);
2398
2621
  const stampDate = new Date(nowMs);
2399
2622
  utimesSync(stampFile, stampDate, stampDate);
2400
2623
  }
2401
- function emptyResult(action, dryRun, ownedRoots, stampFile) {
2402
- return { action, candidates: [], dryRun, failed: [], killed: [], ownedRoots, stampFile };
2403
- }
2404
2624
  function delay(ms) {
2405
2625
  if (ms <= 0)
2406
2626
  return Promise.resolve();
@@ -2428,56 +2648,55 @@ function defaultPluginRoot() {
2428
2648
  import { execFile as execFile3 } from "node:child_process";
2429
2649
  import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync3 } from "node:fs";
2430
2650
  import { homedir as homedir12 } from "node:os";
2431
- import { extname, join as join12 } from "node:path";
2651
+ import { extname, join as join13 } from "node:path";
2432
2652
  import { cwd as processCwd, env as processEnv, execPath as processExecPath, stderr as processStderr } from "node:process";
2433
2653
 
2434
- // ../../utils/src/codegraph/provision.ts
2435
- import { createHash as createHash2, randomUUID } from "node:crypto";
2436
- import { execFile as execFile2 } from "node:child_process";
2437
- import { chmod, mkdir, readdir, readFile, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
2438
- import { existsSync as existsSync8 } from "node:fs";
2439
- import { homedir as homedir11, hostname } from "node:os";
2440
- import { basename as basename3, join as join11 } from "node:path";
2441
- import { promisify } from "node:util";
2442
-
2443
2654
  // ../../utils/src/codegraph/manifest.ts
2655
+ var CODEGRAPH_PINNED_VERSION = "1.4.1";
2444
2656
  var CODEGRAPH_PROVISION_MANIFEST = {
2445
2657
  assets: {
2446
2658
  "darwin-arm64": {
2447
2659
  executableName: "codegraph",
2448
- sha256: "95bb27bf6382b69659e158e0c04d71cc394778951e1317d582be7807e7866908",
2449
- url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-darwin-arm64.tar.gz"
2660
+ sha256: "4a679ae5a5cb9fff900dd59bb786da6a581b7f68f4cf713bdedd137e347d34dc",
2661
+ url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-darwin-arm64.tar.gz"
2450
2662
  },
2451
2663
  "darwin-x64": {
2452
2664
  executableName: "codegraph",
2453
- sha256: "3311cc1d1f0f0ad742709b6a43d8a9187b1ef0af0dd30e0b58008dc673e29478",
2454
- url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-darwin-x64.tar.gz"
2665
+ sha256: "436f96943cfd926ea6d0a8454f18833d21254d5fd9b3d224317b1426132def95",
2666
+ url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-darwin-x64.tar.gz"
2455
2667
  },
2456
2668
  "linux-arm64": {
2457
2669
  executableName: "codegraph",
2458
- sha256: "e16f612bc96c2ebccd04574cbed500c9939147c80666ad6bb024398dff7992ae",
2459
- url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-linux-arm64.tar.gz"
2670
+ sha256: "0d62c5eb2722f8d19d20f7a1bd974445e18d5294cb59be116a0c3d55ce87591f",
2671
+ url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-linux-arm64.tar.gz"
2460
2672
  },
2461
2673
  "linux-x64": {
2462
2674
  executableName: "codegraph",
2463
- sha256: "d45a068f44596a85c7ba7d0ef924eaf7103fbbf3cafbeb668127daff60a52228",
2464
- url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-linux-x64.tar.gz"
2675
+ sha256: "fb585ff5018d6faaa46d282b61f4f689bc7967ed8a1b467a5c556dd7ced9b542",
2676
+ url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-linux-x64.tar.gz"
2465
2677
  },
2466
2678
  "win32-arm64": {
2467
2679
  executableName: "codegraph.cmd",
2468
- sha256: "8d57ced73b24d35f758f2ede2318e80e1d7241987f37a999e3d80edb6fddf961",
2469
- url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-arm64/-/codegraph-win32-arm64-1.0.1.tgz"
2680
+ sha256: "e2a2a28c802a79804c7df203afa50bd461309c6c180ce3f76079fdc7cddc7697",
2681
+ url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-arm64/-/codegraph-win32-arm64-1.4.1.tgz"
2470
2682
  },
2471
2683
  "win32-x64": {
2472
2684
  executableName: "codegraph.cmd",
2473
- sha256: "52607fe73b05e741fd1087da2ceca9d3c8f565e36bf1a7070600bdbdf3931e32",
2474
- url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-x64/-/codegraph-win32-x64-1.0.1.tgz"
2685
+ sha256: "4f08700fda5f4a03ad5b2956135c5788d739a351b3433db2b5820e5d5224c30d",
2686
+ url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-x64/-/codegraph-win32-x64-1.4.1.tgz"
2475
2687
  }
2476
2688
  },
2477
- version: "1.0.1"
2689
+ version: CODEGRAPH_PINNED_VERSION
2478
2690
  };
2479
2691
 
2480
2692
  // ../../utils/src/codegraph/provision.ts
2693
+ import { createHash as createHash2, randomUUID } from "node:crypto";
2694
+ import { execFile as execFile2 } from "node:child_process";
2695
+ import { chmod, mkdir, readdir, readFile, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
2696
+ import { existsSync as existsSync8 } from "node:fs";
2697
+ import { homedir as homedir11, hostname } from "node:os";
2698
+ import { basename as basename3, join as join12 } from "node:path";
2699
+ import { promisify } from "node:util";
2481
2700
  var DEFAULT_LOCK_WAIT_MS = 5000;
2482
2701
  var DEFAULT_LOCK_STALE_MS = 120000;
2483
2702
  var DEFAULT_DOWNLOAD_TIMEOUT_MS = 60000;
@@ -2486,10 +2705,10 @@ function platformKey() {
2486
2705
  return `${process.platform}-${process.arch}`;
2487
2706
  }
2488
2707
  function markerPath(installDir, version) {
2489
- return join11(installDir, ".provisioned", `codegraph-${version}.json`);
2708
+ return join12(installDir, ".provisioned", `codegraph-${version}.json`);
2490
2709
  }
2491
2710
  function defaultInstallDir() {
2492
- return join11(homedir11(), ".omo", "codegraph");
2711
+ return join12(homedir11(), ".omo", "codegraph");
2493
2712
  }
2494
2713
  function sha256(bytes) {
2495
2714
  return createHash2("sha256").update(bytes).digest("hex");
@@ -2509,7 +2728,7 @@ async function removeEmptyDirectory(path) {
2509
2728
  }
2510
2729
  }
2511
2730
  function sleep(ms) {
2512
- return new Promise((resolve6) => setTimeout(resolve6, ms));
2731
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
2513
2732
  }
2514
2733
  async function defaultDownloader(asset, timeoutMs = DEFAULT_DOWNLOAD_TIMEOUT_MS) {
2515
2734
  const response = await fetch(asset.url, { signal: AbortSignal.timeout(timeoutMs) });
@@ -2523,7 +2742,7 @@ function forcedBadChecksumOptions(options) {
2523
2742
  const key = options.platformKey ?? platformKey();
2524
2743
  return {
2525
2744
  downloader: async () => new TextEncoder().encode("checksum mismatch"),
2526
- installDir: options.installDir ?? join11(options.lockDir, "codegraph-force-bad-checksum"),
2745
+ installDir: options.installDir ?? join12(options.lockDir, "codegraph-force-bad-checksum"),
2527
2746
  manifest: {
2528
2747
  assets: {
2529
2748
  [key]: { executableName: process.platform === "win32" ? "codegraph.cmd" : "codegraph", sha256: "0000", url: "memory://bad" }
@@ -2551,7 +2770,7 @@ async function readMarker(path) {
2551
2770
  }
2552
2771
  async function acquireLock(lockPath, waitMs, staleMs) {
2553
2772
  const startedAt = Date.now();
2554
- await mkdir(join11(lockPath, ".."), { recursive: true });
2773
+ await mkdir(join12(lockPath, ".."), { recursive: true });
2555
2774
  while (Date.now() - startedAt <= waitMs) {
2556
2775
  try {
2557
2776
  await mkdir(lockPath);
@@ -2576,14 +2795,14 @@ async function installExtractedBundle(extractDir, installDir, executableName) {
2576
2795
  const roots = await readdir(extractDir);
2577
2796
  if (roots.length !== 1)
2578
2797
  throw new Error(`CodeGraph archive should contain one root directory, found ${roots.length}`);
2579
- const bundleDir = join11(extractDir, roots[0] ?? "");
2798
+ const bundleDir = join12(extractDir, roots[0] ?? "");
2580
2799
  const bundleEntries = await readdir(bundleDir);
2581
2800
  await mkdir(installDir, { recursive: true });
2582
2801
  for (const entry of bundleEntries) {
2583
- await rm(join11(installDir, entry), { force: true, recursive: true });
2584
- await rename(join11(bundleDir, entry), join11(installDir, entry));
2802
+ await rm(join12(installDir, entry), { force: true, recursive: true });
2803
+ await rename(join12(bundleDir, entry), join12(installDir, entry));
2585
2804
  }
2586
- const destination = join11(installDir, "bin", executableName);
2805
+ const destination = join12(installDir, "bin", executableName);
2587
2806
  if (!existsSync8(destination))
2588
2807
  throw new Error(`CodeGraph archive did not contain bin/${executableName}`);
2589
2808
  await chmod(destination, 493);
@@ -2591,9 +2810,9 @@ async function installExtractedBundle(extractDir, installDir, executableName) {
2591
2810
  }
2592
2811
  async function installAsset(layout) {
2593
2812
  const { asset, downloader, installDir, version } = layout;
2594
- const stagingDir = join11(installDir, ".staging", randomUUID());
2595
- const archivePath = join11(stagingDir, basename3(asset.url));
2596
- const extractDir = join11(stagingDir, "extract");
2813
+ const stagingDir = join12(installDir, ".staging", randomUUID());
2814
+ const archivePath = join12(stagingDir, basename3(asset.url));
2815
+ const extractDir = join12(stagingDir, "extract");
2597
2816
  try {
2598
2817
  await mkdir(extractDir, { recursive: true });
2599
2818
  const bytes = await downloader(asset);
@@ -2607,13 +2826,13 @@ async function installAsset(layout) {
2607
2826
  await writeFile(archivePath, bytes);
2608
2827
  await extractTarGz(archivePath, extractDir);
2609
2828
  const destination = await installExtractedBundle(extractDir, installDir, asset.executableName);
2610
- await mkdir(join11(installDir, ".provisioned"), { recursive: true });
2829
+ await mkdir(join12(installDir, ".provisioned"), { recursive: true });
2611
2830
  await writeFile(markerPath(installDir, version), `${JSON.stringify({ binPath: destination, version })}
2612
2831
  `);
2613
2832
  return destination;
2614
2833
  } finally {
2615
2834
  await rm(stagingDir, { force: true, recursive: true });
2616
- await removeEmptyDirectory(join11(installDir, ".staging"));
2835
+ await removeEmptyDirectory(join12(installDir, ".staging"));
2617
2836
  }
2618
2837
  }
2619
2838
  async function ensureCodegraphProvisioned(options) {
@@ -2626,7 +2845,7 @@ async function ensureCodegraphProvisioned(options) {
2626
2845
  const existing = await readMarker(marker);
2627
2846
  if (existing !== null)
2628
2847
  return { binPath: existing, provisioned: true };
2629
- const lockPath = join11(options.lockDir, `codegraph-${hostname()}.lock`);
2848
+ const lockPath = join12(options.lockDir, `codegraph-${hostname()}.lock`);
2630
2849
  const release = await acquireLock(lockPath, options.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS, options.lockStaleMs ?? DEFAULT_LOCK_STALE_MS);
2631
2850
  if (release === null)
2632
2851
  return { error: "timed out waiting for codegraph provisioning lock", provisioned: false };
@@ -2652,7 +2871,7 @@ async function ensureCodegraphProvisioned(options) {
2652
2871
 
2653
2872
  // components/codegraph/src/session-start-worker.ts
2654
2873
  var SESSION_START_CWD_ENV = "OMO_CODEGRAPH_SESSION_START_CWD";
2655
- var CODEGRAPH_VERSION = "1.0.1";
2874
+ var CODEGRAPH_VERSION = CODEGRAPH_PINNED_VERSION;
2656
2875
  var COMMAND_TIMEOUT_MS = 60000;
2657
2876
  var WINDOWS_CMD_EXTENSIONS = new Set([".bat", ".cmd"]);
2658
2877
  var WINDOWS_NODE_SCRIPT_EXTENSIONS = new Set([".cjs", ".js", ".mjs"]);
@@ -2716,15 +2935,15 @@ async function resolveOrProvisionCommand(deps, config, env, homeDir, nodeSupport
2716
2935
  return { kind: "unsupported-node" };
2717
2936
  if (config.auto_provision === false)
2718
2937
  return { error: "codegraph binary unavailable and auto_provision is disabled", kind: "unavailable", source: resolved.source };
2719
- const installDir = trustedInstallDir ?? join12(homeDir, ".omo", "codegraph");
2720
- const provisioned = await deps.ensureProvisioned({ installDir, lockDir: join12(installDir, ".locks"), version: CODEGRAPH_VERSION });
2938
+ const installDir = trustedInstallDir ?? join13(homeDir, ".omo", "codegraph");
2939
+ const provisioned = await deps.ensureProvisioned({ installDir, lockDir: join13(installDir, ".locks"), version: CODEGRAPH_VERSION });
2721
2940
  if (!provisioned.provisioned || provisioned.binPath === undefined) {
2722
2941
  return { error: provisioned.error ?? "provisioning did not produce a binary", kind: "unavailable", source: resolved.source };
2723
2942
  }
2724
2943
  return { kind: "resolved", resolution: { argsPrefix: [], command: provisioned.binPath, exists: true, source: "provisioned" } };
2725
2944
  }
2726
2945
  function codegraphEnvForConfig(config, homeDir) {
2727
- const env = buildCodegraphEnv({ homeDir });
2946
+ const env = buildCodegraphEnv({ daemon: false, homeDir });
2728
2947
  return config.trustedCodegraphInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: config.trustedCodegraphInstallDir };
2729
2948
  }
2730
2949
  function canUseResolvedCommand(resolved, nodeSupport) {
@@ -2785,9 +3004,9 @@ function resolveCodegraphCommandInvocation(command, args, platform = process.pla
2785
3004
  return { args: ["/d", "/s", "/c", command, ...args], command: "cmd.exe" };
2786
3005
  }
2787
3006
  function appendOutcome(homeDir, outcome) {
2788
- const logDir = join12(homeDir, ".omo", "codegraph");
3007
+ const logDir = join13(homeDir, ".omo", "codegraph");
2789
3008
  mkdirSync3(logDir, { recursive: true });
2790
- appendFileSync2(join12(logDir, "session-start.jsonl"), `${JSON.stringify({ ...outcome, timestamp: new Date().toISOString() })}
3009
+ appendFileSync2(join13(logDir, "session-start.jsonl"), `${JSON.stringify({ ...outcome, timestamp: new Date().toISOString() })}
2791
3010
  `);
2792
3011
  }
2793
3012
  function safeLogOutcome(logOutcome, outcome) {
@@ -2804,7 +3023,7 @@ function safeLogOutcome(logOutcome, outcome) {
2804
3023
  function provisionedBinFromInstallDir(installDir) {
2805
3024
  if (installDir === undefined)
2806
3025
  return null;
2807
- const candidate = join12(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
3026
+ const candidate = join13(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
2808
3027
  return existsSync9(candidate) ? candidate : null;
2809
3028
  }
2810
3029
  function resolveExitCode(error) {
@@ -2865,6 +3084,7 @@ async function executeCodegraphSessionStartHook(options = {}) {
2865
3084
  return { action: "skipped-excluded", exitCode: 0 };
2866
3085
  }
2867
3086
  const isInitialized = await (options.statusProbe ?? isCodegraphProjectInitialized)({
3087
+ daemon: config.codegraph?.daemon === true,
2868
3088
  env,
2869
3089
  homeDir,
2870
3090
  projectRoot,
@@ -2895,7 +3115,7 @@ async function isCodegraphProjectInitialized(options) {
2895
3115
  return false;
2896
3116
  const invocation = resolveCodegraphCommandInvocation(resolved.command, [...resolved.argsPrefix, "status", "--json"]);
2897
3117
  const codegraphEnv = {
2898
- ...buildCodegraphEnv({ homeDir: options.homeDir }),
3118
+ ...buildCodegraphEnv({ daemon: options.daemon, homeDir: options.homeDir }),
2899
3119
  ...options.trustedCodegraphInstallDir === undefined ? {} : { CODEGRAPH_INSTALL_DIR: options.trustedCodegraphInstallDir }
2900
3120
  };
2901
3121
  const status = await runStatusProbe(options.projectRoot, invocation.command, invocation.args, buildCodegraphChildEnv({ ambientEnv: options.env, codegraphEnv, runtimeEnv: options.env }));
@@ -2937,7 +3157,7 @@ function codegraphStatusSaysInitialized(stdout) {
2937
3157
  function provisionedBinFromInstallDir2(installDir) {
2938
3158
  if (installDir === undefined)
2939
3159
  return null;
2940
- return join13(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
3160
+ return join14(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
2941
3161
  }
2942
3162
  async function executeCodegraphPostToolUseHook(options = {}) {
2943
3163
  const env = options.env ?? processEnv2;
@@ -3027,9 +3247,9 @@ function defaultWorkerCliPath() {
3027
3247
  }
3028
3248
 
3029
3249
  // components/codegraph/src/serve.ts
3030
- import { existsSync as existsSync10, realpathSync as realpathSync5 } from "node:fs";
3250
+ import { existsSync as existsSync10, realpathSync as realpathSync6 } from "node:fs";
3031
3251
  import { homedir as homedir14 } from "node:os";
3032
- import { basename as basename4, join as join14, resolve as resolve6 } from "node:path";
3252
+ import { basename as basename4, join as join15, resolve as resolve7 } from "node:path";
3033
3253
  import {
3034
3254
  cwd as processCwd3,
3035
3255
  env as processEnv3,
@@ -3090,7 +3310,7 @@ ${body}` : `${body}
3090
3310
  await writeChunk(output, payload);
3091
3311
  }
3092
3312
  function writeChunk(output, chunk) {
3093
- return new Promise((resolve6, reject) => {
3313
+ return new Promise((resolve7, reject) => {
3094
3314
  let settled = false;
3095
3315
  const onError = (error) => {
3096
3316
  if (settled)
@@ -3110,7 +3330,7 @@ function writeChunk(output, chunk) {
3110
3330
  return;
3111
3331
  }
3112
3332
  output.removeListener("error", onError);
3113
- resolve6();
3333
+ resolve7();
3114
3334
  });
3115
3335
  } catch (error) {
3116
3336
  output.removeListener("error", onError);
@@ -3202,16 +3422,35 @@ function bufferFromChunk(chunk) {
3202
3422
 
3203
3423
  // ../../mcp-stdio-core/src/server.ts
3204
3424
  var DEFAULT_IDLE_TIMEOUT_MS = 10 * 60000;
3425
+ var DEFAULT_PARENT_POLL_INTERVAL_MS = 30000;
3205
3426
  var noopLog = () => {};
3427
+ function isProcessAlive(pid) {
3428
+ try {
3429
+ process.kill(pid, 0);
3430
+ return true;
3431
+ } catch (error) {
3432
+ return !hasErrorCode(error, "ESRCH");
3433
+ }
3434
+ }
3206
3435
  async function runJsonRpcStdioServer(config) {
3207
3436
  const log = config.log ?? noopLog;
3208
3437
  const idleTimeoutMs = config.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
3209
- const idleTimer = createIdleTimer(idleTimeoutMs, log, config.onIdleTimeout);
3438
+ let isClosed = false;
3439
+ const idleTimer = createIdleTimer(idleTimeoutMs, log, () => {
3440
+ isClosed = true;
3441
+ config.onIdleTimeout?.();
3442
+ });
3443
+ const watchdog = createParentWatchdog(config.parentWatchdog, (parentPid, pollIntervalMs) => {
3444
+ isClosed = true;
3445
+ log("parent_exit", { parent_pid: parentPid, poll_interval_ms: pollIntervalMs });
3446
+ config.onParentExit?.();
3447
+ config.input.destroy();
3448
+ });
3210
3449
  log("stdio_started", { cwd: process.cwd(), idle_timeout_ms: idleTimeoutMs });
3211
3450
  idleTimer.arm();
3212
3451
  try {
3213
3452
  for await (const message of readStdioJsonRpcMessages(config.input)) {
3214
- if (idleTimer.closed())
3453
+ if (isClosed)
3215
3454
  break;
3216
3455
  idleTimer.arm();
3217
3456
  if (message.kind === "parse_error") {
@@ -3222,8 +3461,12 @@ async function runJsonRpcStdioServer(config) {
3222
3461
  if (!await handleRequest(message, config, log))
3223
3462
  break;
3224
3463
  }
3464
+ } catch (error) {
3465
+ if (!(isClosed && hasErrorCode(error, "ERR_STREAM_PREMATURE_CLOSE")))
3466
+ throw error;
3225
3467
  } finally {
3226
3468
  idleTimer.clear();
3469
+ watchdog.clear();
3227
3470
  log("stdio_stopped");
3228
3471
  }
3229
3472
  }
@@ -3279,9 +3522,33 @@ function isTerminalOutputError(error) {
3279
3522
  return false;
3280
3523
  return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
3281
3524
  }
3282
- function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
3525
+ function hasErrorCode(error, code) {
3526
+ return error instanceof Error && "code" in error && error.code === code;
3527
+ }
3528
+ function createParentWatchdog(config, onDeadParent) {
3529
+ if (config === undefined)
3530
+ return { clear: () => {} };
3531
+ const pollIntervalMs = config.pollIntervalMs ?? DEFAULT_PARENT_POLL_INTERVAL_MS;
3532
+ if (pollIntervalMs <= 0)
3533
+ return { clear: () => {} };
3534
+ const parentPid = config.parentPid ?? process.ppid;
3535
+ const probeAlive = config.probeAlive ?? isProcessAlive;
3536
+ let fired = false;
3537
+ const timer = setInterval(() => {
3538
+ if (fired || probeAlive(parentPid))
3539
+ return;
3540
+ fired = true;
3541
+ onDeadParent(parentPid, pollIntervalMs);
3542
+ }, pollIntervalMs);
3543
+ timer.unref();
3544
+ return {
3545
+ clear: () => {
3546
+ clearInterval(timer);
3547
+ }
3548
+ };
3549
+ }
3550
+ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
3283
3551
  let timer = null;
3284
- let isClosed = false;
3285
3552
  return {
3286
3553
  arm: () => {
3287
3554
  if (timer !== null)
@@ -3289,9 +3556,8 @@ function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
3289
3556
  if (idleTimeoutMs <= 0)
3290
3557
  return;
3291
3558
  timer = setTimeout(() => {
3292
- isClosed = true;
3293
3559
  log("idle_timeout", { idle_timeout_ms: idleTimeoutMs });
3294
- onIdleTimeout?.();
3560
+ onTimeout();
3295
3561
  }, idleTimeoutMs);
3296
3562
  timer.unref();
3297
3563
  },
@@ -3300,8 +3566,7 @@ function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
3300
3566
  return;
3301
3567
  clearTimeout(timer);
3302
3568
  timer = null;
3303
- },
3304
- closed: () => isClosed
3569
+ }
3305
3570
  };
3306
3571
  }
3307
3572
  // components/codegraph/src/serve-invocation.ts
@@ -3334,6 +3599,7 @@ class CodegraphBridgeStdioError extends Error {
3334
3599
  var CODEGRAPH_NODE_DESCRIPTION = "Inspect one named symbol or file. In symbol mode, includeCode=true includes leaf-symbol source when available. Container symbols such as classes, interfaces, structs, enums, modules, and namespaces return structural outlines with member lists by design. For container source, request a specific member symbol or use file mode with symbolsOnly=false plus offset/limit.";
3335
3600
  var CODEGRAPH_NODE_INCLUDE_CODE_DESCRIPTION = "Symbol mode: include leaf-symbol source when available. Container symbols such as classes, interfaces, structs, enums, modules, and namespaces intentionally return structural outlines with members; request a specific member symbol or use file mode with symbolsOnly=false plus offset/limit for source.";
3336
3601
  var CODEGRAPH_CONTAINER_OUTLINE_GUIDANCE = "Container symbols intentionally return structural outlines with members. For source, request a specific member symbol or call codegraph_node in file mode with symbolsOnly=false plus offset/limit around the symbol location.";
3602
+ var SIGKILL_ESCALATION_MS = 2000;
3337
3603
  async function runBridgedCodegraphProcess(command, args, options) {
3338
3604
  const invocation = resolveServeProcessInvocation(command, args);
3339
3605
  const child = spawn2(invocation.command, invocation.args, {
@@ -3359,17 +3625,24 @@ async function runBridgedCodegraphProcess(command, args, options) {
3359
3625
  resolveExit(signal === null ? 0 : 1);
3360
3626
  });
3361
3627
  });
3362
- const clientForwardingDone = forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
3363
- defaultResponseMode = mode;
3364
- });
3365
- const responseForwardingDone = forwardCodegraphToClient(childOutput, options.output, pendingResponses, () => defaultResponseMode);
3366
- const bridgeDone = Promise.all([clientForwardingDone, responseForwardingDone]);
3367
- const childAndResponsesDone = Promise.all([childExit, responseForwardingDone]).then(([exitCode]) => exitCode);
3368
3628
  const destroyChildPipes = () => {
3369
3629
  childInput.destroy();
3370
3630
  childOutput.destroy();
3371
3631
  };
3372
3632
  childExit.then(destroyChildPipes, destroyChildPipes);
3633
+ let parentWatchdogFired = false;
3634
+ const parentWatchdog = createParentWatchdog(options.parentWatchdog, () => {
3635
+ parentWatchdogFired = true;
3636
+ options.input.destroy();
3637
+ destroyChildPipes();
3638
+ terminateCodegraphChild(child);
3639
+ });
3640
+ const clientForwardingDone = forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
3641
+ defaultResponseMode = mode;
3642
+ }, () => parentWatchdogFired);
3643
+ const responseForwardingDone = forwardCodegraphToClient(childOutput, options.output, pendingResponses, () => defaultResponseMode, () => parentWatchdogFired);
3644
+ const bridgeDone = Promise.all([clientForwardingDone, responseForwardingDone]);
3645
+ const childAndResponsesDone = Promise.all([childExit, responseForwardingDone]).then(([exitCode]) => exitCode);
3373
3646
  try {
3374
3647
  return await Promise.race([childAndResponsesDone, bridgeDone.then(() => childExit)]);
3375
3648
  } catch (error) {
@@ -3380,39 +3653,66 @@ async function runBridgedCodegraphProcess(command, args, options) {
3380
3653
  return;
3381
3654
  });
3382
3655
  throw error;
3656
+ } finally {
3657
+ parentWatchdog.clear();
3383
3658
  }
3384
3659
  }
3385
- async function forwardClientToCodegraph(input, childInput, pendingResponses, setDefaultResponseMode) {
3386
- for await (const message of readStdioJsonRpcMessages(input)) {
3387
- if (message.kind === "parse_error") {
3388
- continue;
3389
- }
3390
- const responseMode = message.responseMode;
3391
- setDefaultResponseMode(responseMode);
3392
- const key = responseModeKey(message.payload);
3393
- if (key !== null) {
3394
- pendingResponses.set(key, {
3395
- method: jsonRpcMethod(message.payload),
3396
- responseMode,
3397
- toolName: jsonRpcToolName(message.payload)
3398
- });
3660
+ function terminateCodegraphChild(child) {
3661
+ if (child.exitCode !== null || child.signalCode !== null)
3662
+ return;
3663
+ child.kill("SIGTERM");
3664
+ const escalation = setTimeout(() => {
3665
+ if (child.exitCode === null && child.signalCode === null)
3666
+ child.kill("SIGKILL");
3667
+ }, SIGKILL_ESCALATION_MS);
3668
+ escalation.unref();
3669
+ }
3670
+ function isWatchdogTeardownError(error) {
3671
+ if (!(error instanceof Error) || !("code" in error))
3672
+ return false;
3673
+ return error.code === "ERR_STREAM_PREMATURE_CLOSE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END" || error.code === "EPIPE";
3674
+ }
3675
+ async function forwardClientToCodegraph(input, childInput, pendingResponses, setDefaultResponseMode, tolerateWatchdogClose) {
3676
+ try {
3677
+ for await (const message of readStdioJsonRpcMessages(input)) {
3678
+ if (message.kind === "parse_error") {
3679
+ continue;
3680
+ }
3681
+ const responseMode = message.responseMode;
3682
+ setDefaultResponseMode(responseMode);
3683
+ const key = responseModeKey(message.payload);
3684
+ if (key !== null) {
3685
+ pendingResponses.set(key, {
3686
+ method: jsonRpcMethod(message.payload),
3687
+ responseMode,
3688
+ toolName: jsonRpcToolName(message.payload)
3689
+ });
3690
+ }
3691
+ await writeLine(childInput, JSON.stringify(message.payload));
3399
3692
  }
3400
- await writeLine(childInput, JSON.stringify(message.payload));
3693
+ childInput.end();
3694
+ } catch (error) {
3695
+ if (!(tolerateWatchdogClose() && isWatchdogTeardownError(error)))
3696
+ throw error;
3401
3697
  }
3402
- childInput.end();
3403
3698
  }
3404
- async function forwardCodegraphToClient(childOutput, output, pendingResponses, defaultResponseMode) {
3405
- for await (const message of readStdioJsonRpcMessages(childOutput)) {
3406
- if (message.kind === "parse_error") {
3407
- await writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
3408
- continue;
3699
+ async function forwardCodegraphToClient(childOutput, output, pendingResponses, defaultResponseMode, tolerateWatchdogClose) {
3700
+ try {
3701
+ for await (const message of readStdioJsonRpcMessages(childOutput)) {
3702
+ if (message.kind === "parse_error") {
3703
+ await writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
3704
+ continue;
3705
+ }
3706
+ const key = responseModeKey(message.payload);
3707
+ const pendingResponse = key === null ? undefined : pendingResponses.get(key);
3708
+ const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
3709
+ if (key !== null)
3710
+ pendingResponses.delete(key);
3711
+ await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
3409
3712
  }
3410
- const key = responseModeKey(message.payload);
3411
- const pendingResponse = key === null ? undefined : pendingResponses.get(key);
3412
- const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
3413
- if (key !== null)
3414
- pendingResponses.delete(key);
3415
- await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
3713
+ } catch (error) {
3714
+ if (!(tolerateWatchdogClose() && isWatchdogTeardownError(error)))
3715
+ throw error;
3416
3716
  }
3417
3717
  }
3418
3718
  function responseModeKey(payload) {
@@ -3544,7 +3844,8 @@ async function runUnavailableCodegraphMcpServer(options) {
3544
3844
  serverVersion: options.serverVersion
3545
3845
  },
3546
3846
  input: options.input,
3547
- output: options.output
3847
+ output: options.output,
3848
+ parentWatchdog: options.parentWatchdog ?? {}
3548
3849
  });
3549
3850
  }
3550
3851
  async function handleUnavailableCodegraphMcpRequest(input, options) {
@@ -3588,7 +3889,7 @@ var CODEGRAPH_DISABLED_HINT = `CodeGraph MCP skipped: disabled by OMO SOT config
3588
3889
  `;
3589
3890
  var CODEGRAPH_EXCLUDED_HINT = `CodeGraph MCP skipped: project excluded by OMO CodeGraph policy.
3590
3891
  `;
3591
- var CODEGRAPH_VERSION2 = "1.0.1";
3892
+ var CODEGRAPH_VERSION2 = CODEGRAPH_PINNED_VERSION;
3592
3893
  var PROJECT_CWD_ENV_KEYS = ["OMO_CODEGRAPH_PROJECT_CWD", SESSION_START_CWD_ENV, "PWD"];
3593
3894
  async function runCodegraphServe(options = {}) {
3594
3895
  const env = options.env ?? processEnv3;
@@ -3636,7 +3937,7 @@ async function runCodegraphServe(options = {}) {
3636
3937
  return runUnavailableMcp(buildCodegraphNodeSkipHint(nodeSupport), options);
3637
3938
  }
3638
3939
  const runProcess = options.runProcess ?? runBridgedCodegraphProcess;
3639
- const codegraphEnv = codegraphEnvForConfig2(trustedInstallDir, homeDir, options.buildEnv);
3940
+ const codegraphEnv = codegraphEnvForConfig2(trustedInstallDir, homeDir, codegraphConfig.daemon === true, options.buildEnv);
3640
3941
  const mergedEnv = buildCodegraphChildEnv({ ambientEnv: env, codegraphEnv, runtimeEnv: env });
3641
3942
  return runProcess(resolution.command, [...resolution.argsPrefix, "serve", "--mcp"], {
3642
3943
  cwd: projectCwd,
@@ -3644,7 +3945,8 @@ async function runCodegraphServe(options = {}) {
3644
3945
  input: options.stdin ?? processStdin2,
3645
3946
  output: options.stdout ?? processStdout2,
3646
3947
  stderr: options.stderr ?? processStderr3,
3647
- stdio: "pipe"
3948
+ stdio: "pipe",
3949
+ parentWatchdog: options.parentWatchdog ?? {}
3648
3950
  });
3649
3951
  }
3650
3952
  async function runUnavailableMcp(reason, options) {
@@ -3653,7 +3955,8 @@ async function runUnavailableMcp(reason, options) {
3653
3955
  input: options.stdin ?? processStdin2,
3654
3956
  output: options.stdout ?? processStdout2,
3655
3957
  reason,
3656
- serverVersion: CODEGRAPH_VERSION2
3958
+ serverVersion: CODEGRAPH_VERSION2,
3959
+ parentWatchdog: options.parentWatchdog ?? {}
3657
3960
  });
3658
3961
  return 0;
3659
3962
  }
@@ -3662,10 +3965,10 @@ async function provisionMissingCodegraph(options) {
3662
3965
  return null;
3663
3966
  if (options.config.auto_provision === false)
3664
3967
  return null;
3665
- const installDir = options.trustedInstallDir ?? join14(options.homeDir, ".omo", "codegraph");
3968
+ const installDir = options.trustedInstallDir ?? join15(options.homeDir, ".omo", "codegraph");
3666
3969
  const result = await options.ensureProvisioned({
3667
3970
  installDir,
3668
- lockDir: join14(installDir, ".locks"),
3971
+ lockDir: join15(installDir, ".locks"),
3669
3972
  version: CODEGRAPH_VERSION2
3670
3973
  });
3671
3974
  if (!result.provisioned || result.binPath === undefined)
@@ -3682,8 +3985,8 @@ function shouldSkipResolvedCommand(resolution, commandExists) {
3682
3985
  function looksLikePath2(command) {
3683
3986
  return command.includes("/") || command.includes("\\");
3684
3987
  }
3685
- function codegraphEnvForConfig2(trustedInstallDir, homeDir, buildEnv) {
3686
- const env = { ...buildEnv?.({ homeDir }) ?? buildCodegraphEnv({ homeDir }), [CODEGRAPH_NO_DAEMON_ENV]: "1" };
3988
+ function codegraphEnvForConfig2(trustedInstallDir, homeDir, daemon, buildEnv) {
3989
+ const env = buildEnv?.({ daemon, homeDir }) ?? buildCodegraphEnv({ daemon, homeDir });
3687
3990
  return trustedInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: trustedInstallDir };
3688
3991
  }
3689
3992
  function resolveProjectCwd(env, fallback) {
@@ -3691,16 +3994,16 @@ function resolveProjectCwd(env, fallback) {
3691
3994
  const candidate = env[key]?.trim();
3692
3995
  if (candidate === undefined || candidate.length === 0)
3693
3996
  continue;
3694
- const resolved = resolve6(candidate);
3997
+ const resolved = resolve7(candidate);
3695
3998
  if (existsSync10(resolved))
3696
3999
  return resolved;
3697
4000
  }
3698
- return resolve6(fallback);
4001
+ return resolve7(fallback);
3699
4002
  }
3700
4003
  function provisionedBinFromInstallDir3(installDir) {
3701
4004
  if (installDir === undefined)
3702
4005
  return null;
3703
- const candidate = join14(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
4006
+ const candidate = join15(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
3704
4007
  return existsSync10(candidate) ? candidate : null;
3705
4008
  }
3706
4009
  async function runCodegraphServeCli() {
@@ -3720,7 +4023,7 @@ function isDirectInvocation(argvPath) {
3720
4023
  const moduleName = basename4(modulePath);
3721
4024
  if (moduleName !== "serve.js" && moduleName !== "serve.ts")
3722
4025
  return false;
3723
- return realpathSync5(resolve6(argvPath)) === realpathSync5(modulePath);
4026
+ return realpathSync6(resolve7(argvPath)) === realpathSync6(modulePath);
3724
4027
  }
3725
4028
 
3726
4029
  // components/codegraph/src/sweep-cli.ts
@@ -3767,6 +4070,7 @@ function writeSweepReport(stdout, result) {
3767
4070
  failed: result.failed,
3768
4071
  killed: result.killed.map(formatProcess),
3769
4072
  ownedRoots: result.ownedRoots,
4073
+ spared: result.spared.map(formatProcess),
3770
4074
  stampFile: result.stampFile
3771
4075
  })}
3772
4076
  `);
@@ -3830,7 +4134,7 @@ function isDirectInvocation2(argvPath) {
3830
4134
  const moduleName = basename5(modulePath);
3831
4135
  if (moduleName !== "cli.js" && moduleName !== "cli.ts")
3832
4136
  return false;
3833
- return realpathSync6(resolve7(argvPath)) === realpathSync6(modulePath);
4137
+ return realpathSync7(resolve8(argvPath)) === realpathSync7(modulePath);
3834
4138
  }
3835
4139
  export {
3836
4140
  runCodegraphCli