oh-my-opencode 4.19.1 → 4.19.2

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 (184) hide show
  1. package/README.ja.md +2 -2
  2. package/README.ko.md +2 -2
  3. package/README.md +2 -2
  4. package/README.ru.md +2 -2
  5. package/README.zh-cn.md +2 -2
  6. package/dist/agents/atlas/agent.d.ts +4 -2
  7. package/dist/agents/explore.d.ts +4 -2
  8. package/dist/agents/hephaestus/agent.d.ts +4 -2
  9. package/dist/agents/librarian.d.ts +4 -2
  10. package/dist/agents/metis.d.ts +4 -2
  11. package/dist/agents/momus.d.ts +3 -2
  12. package/dist/agents/multimodal-looker.d.ts +4 -2
  13. package/dist/agents/oracle.d.ts +4 -2
  14. package/dist/agents/sisyphus/claude-opus-5.d.ts +33 -0
  15. package/dist/agents/sisyphus/index.d.ts +2 -0
  16. package/dist/agents/sisyphus-agent-factory.d.ts +5 -2
  17. package/dist/agents/sisyphus-junior/agent.d.ts +4 -1
  18. package/dist/agents/types.d.ts +2 -2
  19. package/dist/cli/index.js +23454 -19200
  20. package/dist/cli-node/index.js +23454 -19200
  21. package/dist/config/schema/agent-names.d.ts +26 -26
  22. package/dist/config/schema/agent-overrides.d.ts +400 -400
  23. package/dist/config/schema/browser-automation.d.ts +2 -2
  24. package/dist/config/schema/categories.d.ts +36 -36
  25. package/dist/config/schema/commands.d.ts +2 -2
  26. package/dist/config/schema/dynamic-context-pruning.d.ts +1 -1
  27. package/dist/config/schema/experimental.d.ts +1 -1
  28. package/dist/config/schema/fallback-models.d.ts +25 -25
  29. package/dist/config/schema/hooks.d.ts +43 -43
  30. package/dist/config/schema/internal/permission.d.ts +9 -9
  31. package/dist/config/schema/keyword-detector.d.ts +6 -6
  32. package/dist/config/schema/oh-my-opencode-config.d.ts +402 -402
  33. package/dist/config/schema/tmux.d.ts +6 -6
  34. package/dist/create-hooks.d.ts +35 -35
  35. package/dist/features/background-agent/spawner/tmux-callback-invoker.d.ts +11 -0
  36. package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
  37. package/dist/features/claude-tasks/types.d.ts +4 -4
  38. package/dist/features/team-mode/team-runtime/shutdown-helpers.d.ts +1 -1
  39. package/dist/features/team-mode/team-runtime/shutdown-test-fixtures.d.ts +4 -4
  40. package/dist/features/team-mode/tools/lifecycle-test-fixture.d.ts +42 -42
  41. package/dist/features/tmux-subagent/environment-eligibility.d.ts +2 -0
  42. package/dist/features/tmux-subagent/index.d.ts +1 -0
  43. package/dist/features/tmux-subagent/tracked-session-state.d.ts +1 -0
  44. package/dist/features/tui-sidebar/snapshot-schema.d.ts +6 -6
  45. package/dist/help/schema/acp.d.ts +3 -3
  46. package/dist/help/schema/doctor.d.ts +4 -4
  47. package/dist/help/schema/status.d.ts +3 -3
  48. package/dist/hooks/goal/types.d.ts +5 -5
  49. package/dist/hooks/non-interactive-env/constants.d.ts +4 -1
  50. package/dist/hooks/start-work/parse-user-request.d.ts +2 -0
  51. package/dist/hooks/start-work/worktree-block.d.ts +5 -0
  52. package/dist/index.js +25231 -20301
  53. package/dist/mcp/types.d.ts +3 -3
  54. package/dist/oh-my-opencode.schema.json +1 -1
  55. package/dist/plugin/chat-message/loop-commands.d.ts +1 -0
  56. package/dist/plugin/command-execute-before.d.ts +3 -3
  57. package/dist/plugin/hooks/create-core-hooks.d.ts +25 -25
  58. package/dist/shared/tmux/tmux-utils/environment.d.ts +1 -1
  59. package/dist/shared/tmux/tmux-utils.d.ts +1 -1
  60. package/dist/shared/typescript-native-source-parser.d.ts +7 -0
  61. package/dist/skills/coding-agent-sessions/SKILL.md +5 -2
  62. package/dist/skills/coding-agent-sessions/references/all-platforms.md +3 -1
  63. package/dist/skills/coding-agent-sessions/references/senpi.md +15 -5
  64. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
  65. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
  66. package/dist/skills/debugging/SKILL.md +2 -1
  67. package/dist/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
  68. package/dist/skills/programming/SKILL.md +11 -1
  69. package/dist/skills/programming/references/logging.md +6 -1
  70. package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.ts +51 -17
  71. package/dist/skills/start-work/SKILL.md +12 -2
  72. package/dist/skills/ulw-plan/SKILL.md +1 -1
  73. package/dist/skills/ulw-plan/references/full-workflow.md +12 -1
  74. package/dist/skills/ulw-plan/references/intent-clear.md +1 -1
  75. package/dist/tools/task/types.d.ts +10 -10
  76. package/dist/tui.js +23468 -19218
  77. package/package.json +14 -14
  78. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +2 -2
  79. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  80. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +8 -4
  81. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  82. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  83. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +296 -206
  84. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +126 -86
  85. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  86. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +21 -42
  87. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +3 -4
  88. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +12 -23
  89. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +5 -0
  90. package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +33 -5
  91. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +6 -1
  92. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +6 -0
  93. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +1 -0
  94. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +5 -5
  95. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +1 -0
  96. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +24 -13
  97. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +58 -64
  98. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  99. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  100. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  101. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  102. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  103. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  104. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  105. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  106. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  107. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  108. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  109. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +1 -1
  110. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  111. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  112. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  113. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  114. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  115. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  116. package/packages/omo-codex/plugin/components/ultrawork/directive.md +12 -7
  117. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  118. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  119. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +12 -7
  120. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +1 -1
  121. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +12 -1
  122. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +1 -1
  123. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +12 -7
  124. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  125. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  126. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +2 -1
  127. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  128. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  129. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  130. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  131. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  132. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  133. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  134. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  135. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  136. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  137. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  138. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  139. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  140. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  141. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  142. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  143. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  144. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  145. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  146. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  147. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  148. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  149. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  150. package/packages/omo-codex/plugin/package-lock.json +13 -13
  151. package/packages/omo-codex/plugin/package.json +1 -1
  152. package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +10 -9
  153. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +5 -2
  154. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +3 -1
  155. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +15 -5
  156. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
  157. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
  158. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -1
  159. package/packages/omo-codex/plugin/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
  160. package/packages/omo-codex/plugin/skills/programming/SKILL.md +11 -1
  161. package/packages/omo-codex/plugin/skills/programming/references/logging.md +6 -1
  162. package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +51 -17
  163. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +12 -2
  164. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +12 -7
  165. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +2 -1
  166. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +1 -1
  167. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +12 -1
  168. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +1 -1
  169. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +22 -0
  170. package/packages/omo-codex/scripts/install-dist/install-local.mjs +1 -1
  171. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +5 -2
  172. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +3 -1
  173. package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +15 -5
  174. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
  175. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
  176. package/packages/shared-skills/skills/debugging/SKILL.md +2 -1
  177. package/packages/shared-skills/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
  178. package/packages/shared-skills/skills/programming/SKILL.md +11 -1
  179. package/packages/shared-skills/skills/programming/references/logging.md +6 -1
  180. package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +51 -17
  181. package/packages/shared-skills/skills/start-work/SKILL.md +12 -2
  182. package/packages/shared-skills/skills/ulw-plan/SKILL.md +1 -1
  183. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +12 -1
  184. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +1 -1
@@ -1,6 +1,5 @@
1
- import { execFile, spawn } from "node:child_process";
1
+ import { spawn } from "node:child_process";
2
2
  import { homedir } from "node:os";
3
- import { join } from "node:path";
4
3
  import {
5
4
  cwd as processCwd,
6
5
  env as processEnv,
@@ -13,7 +12,9 @@ import { fileURLToPath } from "node:url";
13
12
 
14
13
  import { buildCodegraphChildEnv, buildCodegraphEnv } from "../../../../../utils/src/codegraph/env.ts";
15
14
  import { buildCodegraphInitGuidanceForToolResult } from "../../../../../utils/src/codegraph/guidance.ts";
15
+ import { resolvePinnedCodegraphBin } from "../../../../../utils/src/codegraph/managed-runtime.ts";
16
16
  import { resolveCodegraphCommand } from "../../../../../utils/src/codegraph/resolve.ts";
17
+ import { runProcessWithTreeTimeout } from "../../../../../utils/src/process-tree.ts";
17
18
  import { shouldExcludeCodegraphProject } from "../../../../../utils/src/codegraph/workspace.ts";
18
19
  import { getCodexOmoConfig } from "../../../shared/src/config-loader.ts";
19
20
  import { pruneCodegraphProjectStoresBestEffort } from "./cache-gc.js";
@@ -66,13 +67,6 @@ export async function executeCodegraphSessionStartHook(options: SessionStartHook
66
67
  const projectRoot = resolveProjectRoot(input, options.cwd ?? processCwd());
67
68
  const homeDir = resolveHomeDir(env);
68
69
  const config = options.config ?? getCodexOmoConfig({ cwd: projectRoot, env, homeDir });
69
- pruneCodegraphProjectStoresBestEffort(homeDir, { debugLog: writeDebugLog });
70
- await sweepCodegraphZombiesBestEffort({
71
- env,
72
- homeDir,
73
- ...(config.trustedCodegraphInstallDir === undefined ? {} : { trustedCodegraphInstallDir: config.trustedCodegraphInstallDir }),
74
- log: writeDebugLog,
75
- }, options.sweepZombies);
76
70
 
77
71
  if (config.codegraph?.enabled === false) {
78
72
  return { action: "skipped-disabled", exitCode: 0 };
@@ -86,8 +80,16 @@ export async function executeCodegraphSessionStartHook(options: SessionStartHook
86
80
  return { action: "skipped-excluded", exitCode: 0 };
87
81
  }
88
82
 
83
+ pruneCodegraphProjectStoresBestEffort(homeDir, { debugLog: writeDebugLog });
84
+ await sweepCodegraphZombiesBestEffort({
85
+ env,
86
+ homeDir,
87
+ ...(config.trustedCodegraphInstallDir === undefined ? {} : { trustedCodegraphInstallDir: config.trustedCodegraphInstallDir }),
88
+ log: writeDebugLog,
89
+ }, options.sweepZombies);
90
+
89
91
  const isInitialized = await (options.statusProbe ?? isCodegraphProjectInitialized)({
90
- daemon: config.codegraph?.daemon === true,
92
+ daemon: config.codegraph?.daemon !== false,
91
93
  env,
92
94
  homeDir,
93
95
  projectRoot,
@@ -145,27 +147,14 @@ function runStatusProbe(
145
147
  args: readonly string[],
146
148
  env: Record<string, string>,
147
149
  ): Promise<{ readonly exitCode: number; readonly stdout: string; readonly timedOut: boolean }> {
148
- return new Promise((resolveProbe) => {
149
- execFile(
150
- command,
151
- [...args],
152
- {
153
- cwd: projectRoot,
154
- encoding: "utf8",
155
- env,
156
- maxBuffer: 1024 * 1024,
157
- timeout: STATUS_PROBE_TIMEOUT_MS,
158
- windowsHide: true,
159
- },
160
- (error, stdout) => {
161
- if (error === null) {
162
- resolveProbe({ exitCode: 0, stdout: toOutputText(stdout), timedOut: false });
163
- return;
164
- }
165
- resolveProbe({ exitCode: resolveExitCode(error), stdout: toOutputText(stdout), timedOut: error.killed === true });
166
- },
167
- );
168
- });
150
+ return runProcessWithTreeTimeout({
151
+ args,
152
+ command,
153
+ cwd: projectRoot,
154
+ env,
155
+ maxBuffer: 1024 * 1024,
156
+ timeoutMs: STATUS_PROBE_TIMEOUT_MS,
157
+ }).then(({ exitCode, stdout, timedOut }) => ({ exitCode, stdout, timedOut }));
169
158
  }
170
159
 
171
160
  function codegraphStatusSaysInitialized(stdout: string): boolean {
@@ -180,8 +169,7 @@ function codegraphStatusSaysInitialized(stdout: string): boolean {
180
169
  }
181
170
 
182
171
  function provisionedBinFromInstallDir(installDir: string | undefined): string | null {
183
- if (installDir === undefined) return null;
184
- return join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
172
+ return resolvePinnedCodegraphBin(installDir);
185
173
  }
186
174
 
187
175
  export async function executeCodegraphPostToolUseHook(options: PostToolUseHookOptions = {}): Promise<PostToolUseHookResult> {
@@ -233,15 +221,6 @@ function resolveHomeDir(env: Record<string, string | undefined>): string {
233
221
  return env["HOME"] ?? env["USERPROFILE"] ?? homedir();
234
222
  }
235
223
 
236
- function resolveExitCode(error: Error): number {
237
- if ("code" in error && typeof error.code === "number") return error.code;
238
- return 1;
239
- }
240
-
241
- function toOutputText(value: string | Buffer): string {
242
- return Buffer.isBuffer(value) ? value.toString("utf8") : value;
243
- }
244
-
245
224
  function resolveProjectRoot(input: unknown, fallback: string): string {
246
225
  if (!isRecord(input)) return fallback;
247
226
  const cwd = input["cwd"];
@@ -16,6 +16,7 @@ import {
16
16
  buildCodegraphChildEnv,
17
17
  buildCodegraphEnv,
18
18
  } from "../../../../../utils/src/codegraph/env.ts";
19
+ import { resolvePinnedCodegraphBin } from "../../../../../utils/src/codegraph/managed-runtime.ts";
19
20
  import type { ParentWatchdogConfig } from "../../../../../mcp-stdio-core/src/index.ts";
20
21
  import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
21
22
  import {
@@ -142,7 +143,7 @@ export async function runCodegraphServe(options: RunCodegraphServeOptions = {}):
142
143
  }
143
144
 
144
145
  const runProcess = options.runProcess ?? runBridgedCodegraphProcess;
145
- const codegraphEnv = codegraphEnvForConfig(trustedInstallDir, homeDir, codegraphConfig.daemon === true, options.buildEnv);
146
+ const codegraphEnv = codegraphEnvForConfig(trustedInstallDir, homeDir, codegraphConfig.daemon !== false, options.buildEnv);
146
147
  const mergedEnv = buildCodegraphChildEnv({ ambientEnv: env, codegraphEnv, runtimeEnv: env });
147
148
  return runProcess(resolution.command, [...resolution.argsPrefix, "serve", "--mcp"], {
148
149
  cwd: projectCwd,
@@ -221,9 +222,7 @@ function resolveProjectCwd(env: Record<string, string | undefined>, fallback: st
221
222
  }
222
223
 
223
224
  function provisionedBinFromInstallDir(installDir: string | undefined): string | null {
224
- if (installDir === undefined) return null;
225
- const candidate = join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
226
- return existsSync(candidate) ? candidate : null;
225
+ return resolvePinnedCodegraphBin(installDir);
227
226
  }
228
227
 
229
228
  export async function runCodegraphServeCli(): Promise<void> {
@@ -1,11 +1,11 @@
1
- import { execFile } from "node:child_process";
2
- import { appendFileSync, existsSync, mkdirSync } from "node:fs";
1
+ import { appendFileSync, mkdirSync } from "node:fs";
3
2
  import { homedir } from "node:os";
4
3
  import { extname, join } from "node:path";
5
4
  import { cwd as processCwd, env as processEnv, execPath as processExecPath, stderr as processStderr } from "node:process";
6
5
 
7
6
  import { getCodexOmoConfig } from "../../../shared/src/config-loader.ts";
8
7
  import { buildCodegraphChildEnv, buildCodegraphEnv } from "../../../../../utils/src/codegraph/env.ts";
8
+ import { resolvePinnedCodegraphBin } from "../../../../../utils/src/codegraph/managed-runtime.ts";
9
9
  import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
10
10
  import { evaluateCodegraphNodeSupport, type CodegraphNodeSupport } from "../../../../../utils/src/codegraph/node-support.ts";
11
11
  import { ensureCodegraphProvisioned } from "../../../../../utils/src/codegraph/provision.ts";
@@ -15,6 +15,7 @@ import {
15
15
  type CodegraphCommandResolution,
16
16
  } from "../../../../../utils/src/codegraph/resolve.ts";
17
17
  import { ensureCodegraphGitignored, prepareCodegraphWorkspace } from "../../../../../utils/src/codegraph/workspace.ts";
18
+ import { runProcessWithTreeTimeout } from "../../../../../utils/src/process-tree.ts";
18
19
  import type {
19
20
  CodegraphCommandResult,
20
21
  CodegraphConfig,
@@ -164,15 +165,14 @@ function jsonSaysInitialized(value: unknown): boolean | undefined {
164
165
 
165
166
  async function runCodegraphCommand(projectRoot: string, command: string, args: readonly string[], options: { readonly env: Record<string, string>; readonly timeoutMs: number }): Promise<CodegraphCommandResult> {
166
167
  const invocation = resolveCodegraphCommandInvocation(command, args);
167
- return new Promise((resolvePromise) => {
168
- execFile(invocation.command, [...invocation.args], { cwd: projectRoot, encoding: "utf8", env: buildCodegraphChildEnv({ ambientEnv: processEnv, codegraphEnv: options.env }), maxBuffer: 1024 * 1024, timeout: options.timeoutMs, windowsHide: true }, (error, stdout, stderr) => {
169
- if (error === null) {
170
- resolvePromise({ exitCode: 0, stderr: toOutputText(stderr), stdout: toOutputText(stdout), timedOut: false });
171
- return;
172
- }
173
- resolvePromise({ exitCode: resolveExitCode(error), stderr: toOutputText(stderr), stdout: toOutputText(stdout), timedOut: error.killed === true });
174
- });
175
- });
168
+ return runProcessWithTreeTimeout({
169
+ args: invocation.args,
170
+ command: invocation.command,
171
+ cwd: projectRoot,
172
+ env: buildCodegraphChildEnv({ ambientEnv: processEnv, codegraphEnv: options.env }),
173
+ maxBuffer: 1024 * 1024,
174
+ timeoutMs: options.timeoutMs,
175
+ }).then(({ exitCode, stderr, stdout, timedOut }) => ({ exitCode, stderr, stdout, timedOut }));
176
176
  }
177
177
 
178
178
  export function resolveCodegraphCommandInvocation(
@@ -203,18 +203,7 @@ function safeLogOutcome(logOutcome: (outcome: CodegraphSessionStartOutcome) => v
203
203
  }
204
204
 
205
205
  function provisionedBinFromInstallDir(installDir: string | undefined): string | null {
206
- if (installDir === undefined) return null;
207
- const candidate = join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
208
- return existsSync(candidate) ? candidate : null;
209
- }
210
-
211
- function resolveExitCode(error: Error): number {
212
- if ("code" in error && typeof error.code === "number") return error.code;
213
- return 1;
214
- }
215
-
216
- function toOutputText(value: string | Buffer): string {
217
- return Buffer.isBuffer(value) ? value.toString("utf8") : value;
206
+ return resolvePinnedCodegraphBin(installDir);
218
207
  }
219
208
 
220
209
  function resolveHomeDir(env: Record<string, string | undefined>): string {
@@ -20,6 +20,7 @@ describe("CodeGraph SessionStart exclusion policy", () => {
20
20
  // given
21
21
  const stdout: string[] = [];
22
22
  const spawned: WorkerSpawnInvocation[] = [];
23
+ let sweepCalls = 0;
23
24
  const stateRoot = createAllowedWorkspace("codegraph-omo-state");
24
25
  const workspace = join(stateRoot, ".omo", "ulw-research", "run", "clones", "repo");
25
26
  mkdirSync(workspace, { recursive: true });
@@ -36,10 +37,14 @@ describe("CodeGraph SessionStart exclusion policy", () => {
36
37
  statusProbe: () => {
37
38
  throw new Error("excluded projects must not probe CodeGraph status");
38
39
  },
40
+ sweepZombies: () => {
41
+ sweepCalls += 1;
42
+ },
39
43
  });
40
44
 
41
45
  // then
42
46
  expect(result).toEqual({ action: "skipped-excluded", exitCode: 0 });
47
+ expect(sweepCalls).toBe(0);
43
48
  expect(spawned).toEqual([]);
44
49
  expect(stdout.join("")).toBe("");
45
50
  } finally {
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "bun:test";
2
- import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join, resolve } from "node:path";
5
5
  import { Readable } from "node:stream";
@@ -44,11 +44,16 @@ function createAllowedWorkspace(prefix: string): string {
44
44
 
45
45
  // On win32 execFile cannot run a #!/bin/sh script, so emit a codegraph.cmd batch file instead;
46
46
  // resolveCodegraphCommandInvocation wraps .cmd in `cmd.exe /d /s /c`, exactly like the real codegraph.cmd.
47
- function createFakeCodegraphBin(scripts: { readonly posix: string; readonly win32: string }): { readonly binPath: string; readonly dir: string } {
47
+ function createFakeCodegraphBin(scripts: {
48
+ readonly posix: string;
49
+ readonly win32: string;
50
+ readonly win32Sidecar?: string;
51
+ }): { readonly binPath: string; readonly dir: string } {
48
52
  const dir = mkdtempSync(join(tmpdir(), "omo-codegraph-fake-bin-"));
49
53
  if (process.platform === "win32") {
50
54
  const binPath = join(dir, "codegraph.cmd");
51
55
  writeFileSync(binPath, scripts.win32);
56
+ if (scripts.win32Sidecar !== undefined) writeFileSync(join(dir, "hang.cjs"), scripts.win32Sidecar);
52
57
  return { binPath, dir };
53
58
  }
54
59
  const binPath = join(dir, "codegraph");
@@ -74,6 +79,15 @@ function probeEnv(homeDir: string, binPath: string): Record<string, string> {
74
79
  return { HOME: homeDir, OMO_CODEGRAPH_BIN: binPath, PATH: "/usr/bin:/bin" };
75
80
  }
76
81
 
82
+ function isProcessAlive(pid: number): boolean {
83
+ try {
84
+ process.kill(pid, 0);
85
+ return true;
86
+ } catch {
87
+ return false;
88
+ }
89
+ }
90
+
77
91
  describe("CodeGraph SessionStart hook with a 1.0.1-era project store under the 1.4.1 binary", () => {
78
92
  it("#given a real 1.4.1 status payload for a migrated 1.0.1 store #when SessionStart probes via the default probe #then it stays silent without spawning a re-init worker", async () => {
79
93
  // given
@@ -110,16 +124,27 @@ describe("CodeGraph SessionStart hook with a 1.0.1-era project store under the 1
110
124
  }
111
125
  });
112
126
 
113
- it("#given the status probe hangs past its 2s timeout #when SessionStart fires #then it exits zero promptly and spawns at most one bounded worker", async () => {
127
+ it("#given the status probe spawns a hanging descendant #when SessionStart times out #then it exits promptly and reaps the descendant", async () => {
114
128
  // given
115
129
  const stdout: string[] = [];
116
130
  const spawned: WorkerSpawnInvocation[] = [];
117
131
  const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-slow-home-"));
132
+ const survivorPidPath = join(homeDir, "survivor.pid");
118
133
  const fake = createFakeCodegraphBin({
119
- posix: "#!/bin/sh\nsleep 30\n",
120
- win32: "@echo off\r\nset /p _probe_hang=\r\n",
134
+ posix: "#!/bin/sh\nsleep 30 &\necho \"$!\" > \"$HOME/survivor.pid\"\nwait\n",
135
+ win32: '@echo off\r\nnode "%~dp0hang.cjs"\r\n',
136
+ win32Sidecar: [
137
+ 'const { spawn } = require("node:child_process");',
138
+ 'const { writeFileSync } = require("node:fs");',
139
+ 'const { join } = require("node:path");',
140
+ 'const child = spawn(process.execPath, ["-e", "setInterval(() => {}, 1000)"], { stdio: "ignore" });',
141
+ 'writeFileSync(join(process.env.HOME, "survivor.pid"), String(child.pid));',
142
+ "setInterval(() => {}, 1000);",
143
+ "",
144
+ ].join("\n"),
121
145
  });
122
146
  const workspace = createAllowedWorkspace("codegraph-slow-probe-workspace");
147
+ let descendantPid: number | undefined;
123
148
 
124
149
  try {
125
150
  // when
@@ -133,13 +158,16 @@ describe("CodeGraph SessionStart hook with a 1.0.1-era project store under the 1
133
158
  spawnWorker: (invocation) => spawned.push(invocation),
134
159
  });
135
160
  const elapsedMs = Date.now() - startedAt;
161
+ descendantPid = Number.parseInt(readFileSync(survivorPidPath, "utf8").trim(), 10);
136
162
 
137
163
  // then
138
164
  expect(result.exitCode).toBe(0);
139
165
  expect(result.action).toBe("spawned");
140
166
  expect(spawned).toHaveLength(1);
141
167
  expect(elapsedMs).toBeLessThan(15_000);
168
+ expect(isProcessAlive(descendantPid)).toBeFalse();
142
169
  } finally {
170
+ if (descendantPid !== undefined && isProcessAlive(descendantPid)) process.kill(descendantPid, "SIGKILL");
143
171
  rmSync(homeDir, { recursive: true, force: true });
144
172
  rmSync(fake.dir, { recursive: true, force: true });
145
173
  rmSync(workspace, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
@@ -215,6 +215,7 @@ describe("CodeGraph SessionStart hook", () => {
215
215
  // given
216
216
  const stdout: string[] = [];
217
217
  const spawned: WorkerSpawnInvocation[] = [];
218
+ const statusProbeDaemonValues: boolean[] = [];
218
219
  const workspace = createAllowedWorkspace("codegraph-workspace");
219
220
 
220
221
  try {
@@ -226,12 +227,16 @@ describe("CodeGraph SessionStart hook", () => {
226
227
  stdin: Readable.from(["{}"]),
227
228
  stdout: { write: (chunk) => stdout.push(chunk) },
228
229
  spawnWorker: (invocation) => spawned.push(invocation),
229
- statusProbe: () => Promise.resolve(false),
230
+ statusProbe: (options) => {
231
+ statusProbeDaemonValues.push(options.daemon);
232
+ return Promise.resolve(false);
233
+ },
230
234
  workerCliPath: "/plugin/components/codegraph/dist/cli.js",
231
235
  });
232
236
 
233
237
  // then
234
238
  expect(result).toEqual({ action: "spawned", exitCode: 0 });
239
+ expect(statusProbeDaemonValues).toEqual([true]);
235
240
  expect(spawned).toEqual([
236
241
  {
237
242
  args: ["/plugin/components/codegraph/dist/cli.js", "hook", "session-start-worker"],
@@ -3,6 +3,7 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
 
6
+ import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
6
7
  import { runCodegraphSessionStartWorker } from "../src/hook.ts";
7
8
  import { runCodegraphServe } from "../src/serve.ts";
8
9
 
@@ -41,7 +42,12 @@ describe("CodeGraph provisioned launcher Node guard", () => {
41
42
 
42
43
  try {
43
44
  mkdirSync(join(installDir, "bin"), { recursive: true });
45
+ mkdirSync(join(installDir, ".provisioned"), { recursive: true });
44
46
  writeFileSync(binPath, "");
47
+ writeFileSync(
48
+ join(installDir, ".provisioned", `codegraph-${CODEGRAPH_PINNED_VERSION}.json`),
49
+ `${JSON.stringify({ binPath, version: CODEGRAPH_PINNED_VERSION })}\n`,
50
+ );
45
51
 
46
52
  // when
47
53
  const result = await runCodegraphSessionStartWorker({
@@ -17,6 +17,7 @@ describe("runCodegraphServe MCP unavailable facade", () => {
17
17
  const run = runCodegraphServe({
18
18
  config: { codegraph: { auto_provision: false, enabled: true }, sources: [], warnings: [] },
19
19
  env: { PATH: "/bin" },
20
+ nodeVersion: "22.14.0",
20
21
  buildEnv: () => ({}),
21
22
  resolve: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
22
23
  stderr: { write: (chunk: string) => stderr.push(chunk) },
@@ -4,7 +4,7 @@ import { join } from "node:path";
4
4
  import { runCodegraphServe } from "../src/serve.ts";
5
5
 
6
6
  describe("runCodegraphServe provisioning", () => {
7
- it("#given CodeGraph is unresolved and daemon is off by default #when serving MCP #then provisions CodeGraph before spawning with CODEGRAPH_NO_DAEMON=1", async () => {
7
+ it("#given CodeGraph is unresolved and daemon is omitted #when serving MCP #then provisions CodeGraph with daemon-on", async () => {
8
8
  // given
9
9
  const binPath = join("/tmp/home/.omo/codegraph", "bin", "codegraph");
10
10
  const calls: Array<{
@@ -42,7 +42,6 @@ describe("runCodegraphServe provisioning", () => {
42
42
  command: binPath,
43
43
  env: {
44
44
  CODEGRAPH_INSTALL_DIR: join("/tmp/home", ".omo", "codegraph"),
45
- CODEGRAPH_NO_DAEMON: "1",
46
45
  CODEGRAPH_NO_DOWNLOAD: "1",
47
46
  CODEGRAPH_TELEMETRY: "0",
48
47
  DO_NOT_TRACK: "1",
@@ -52,7 +51,7 @@ describe("runCodegraphServe provisioning", () => {
52
51
  ]);
53
52
  });
54
53
 
55
- it("#given CodeGraph is unresolved and codegraph.daemon=true #when serving MCP #then provisions CodeGraph and omits CODEGRAPH_NO_DAEMON so the daemon may run", async () => {
54
+ it("#given CodeGraph is unresolved and codegraph.daemon=false #when serving MCP #then provisions CodeGraph with daemon-off", async () => {
56
55
  // given
57
56
  const binPath = join("/tmp/home/.omo/codegraph", "bin", "codegraph");
58
57
  const calls: Array<{
@@ -64,7 +63,7 @@ describe("runCodegraphServe provisioning", () => {
64
63
 
65
64
  // when
66
65
  const exitCode = await runCodegraphServe({
67
- config: { codegraph: { daemon: true, enabled: true }, sources: [], warnings: [] },
66
+ config: { codegraph: { daemon: false, enabled: true }, sources: [], warnings: [] },
68
67
  env: { PATH: "/bin" },
69
68
  homeDir: "/tmp/home",
70
69
  nodeVersion: "22.14.0",
@@ -90,6 +89,7 @@ describe("runCodegraphServe provisioning", () => {
90
89
  command: binPath,
91
90
  env: {
92
91
  CODEGRAPH_INSTALL_DIR: join("/tmp/home", ".omo", "codegraph"),
92
+ CODEGRAPH_NO_DAEMON: "1",
93
93
  CODEGRAPH_NO_DOWNLOAD: "1",
94
94
  CODEGRAPH_TELEMETRY: "0",
95
95
  DO_NOT_TRACK: "1",
@@ -97,6 +97,6 @@ describe("runCodegraphServe provisioning", () => {
97
97
  },
98
98
  },
99
99
  ]);
100
- expect(calls[0]?.env["CODEGRAPH_NO_DAEMON"]).toBeUndefined();
100
+ expect(calls[0]?.env["CODEGRAPH_NO_DAEMON"]).toBe("1");
101
101
  });
102
102
  });
@@ -17,6 +17,7 @@ describe("runCodegraphServe unavailable CodeGraph paths", () => {
17
17
  ...closedMcpStdio(),
18
18
  config: { codegraph: { auto_provision: false, enabled: true }, sources: [], warnings: [] },
19
19
  env: { PATH: "/bin" },
20
+ nodeVersion: "22.14.0",
20
21
  buildEnv: () => ({}),
21
22
  resolve: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
22
23
  runProcess: (command: string) => {
@@ -5,6 +5,7 @@ import { dirname, join, resolve } from "node:path";
5
5
  import { Readable, Writable } from "node:stream";
6
6
  import { fileURLToPath } from "node:url";
7
7
 
8
+ import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
8
9
  import { resolveServeProcessInvocation, runCodegraphServe } from "../src/serve.ts";
9
10
 
10
11
  const componentRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
@@ -48,7 +49,6 @@ describe("runCodegraphServe", () => {
48
49
  cwd: resolve(runCwd),
49
50
  env: {
50
51
  CODEGRAPH_INSTALL_DIR: join("/tmp/home", ".omo", "codegraph"),
51
- CODEGRAPH_NO_DAEMON: "1",
52
52
  CODEGRAPH_NO_DOWNLOAD: "1",
53
53
  CODEGRAPH_TELEMETRY: "0",
54
54
  DO_NOT_TRACK: "1",
@@ -61,7 +61,7 @@ describe("runCodegraphServe", () => {
61
61
  expect(calls[0]?.env["OPENAI_API_KEY"]).toBeUndefined();
62
62
  });
63
63
 
64
- it("#given codegraph.daemon=true #when serving MCP #then CODEGRAPH_NO_DAEMON is omitted so the daemon may run", async () => {
64
+ it("#given codegraph.daemon=false #when serving MCP #then CODEGRAPH_NO_DAEMON pins daemon-off", async () => {
65
65
  // given
66
66
  const runCwd = componentRoot;
67
67
  const calls: Array<{
@@ -74,7 +74,7 @@ describe("runCodegraphServe", () => {
74
74
 
75
75
  // when
76
76
  const exitCode = await runCodegraphServe({
77
- config: { codegraph: { daemon: true, enabled: true }, sources: [], warnings: [] },
77
+ config: { codegraph: { daemon: false, enabled: true }, sources: [], warnings: [] },
78
78
  cwd: runCwd,
79
79
  env: { CUSTOM: "drop", HOME: "/tmp/home", OPENAI_API_KEY: "sk-test-secret" },
80
80
  nodeVersion: "22.14.0",
@@ -100,6 +100,7 @@ describe("runCodegraphServe", () => {
100
100
  cwd: resolve(runCwd),
101
101
  env: {
102
102
  CODEGRAPH_INSTALL_DIR: join("/tmp/home", ".omo", "codegraph"),
103
+ CODEGRAPH_NO_DAEMON: "1",
103
104
  CODEGRAPH_NO_DOWNLOAD: "1",
104
105
  CODEGRAPH_TELEMETRY: "0",
105
106
  DO_NOT_TRACK: "1",
@@ -108,7 +109,7 @@ describe("runCodegraphServe", () => {
108
109
  stdio: "pipe",
109
110
  },
110
111
  ]);
111
- expect(calls[0]?.env["CODEGRAPH_NO_DAEMON"]).toBeUndefined();
112
+ expect(calls[0]?.env["CODEGRAPH_NO_DAEMON"]).toBe("1");
112
113
  expect(calls[0]?.env["CUSTOM"]).toBeUndefined();
113
114
  expect(calls[0]?.env["OPENAI_API_KEY"]).toBeUndefined();
114
115
  });
@@ -182,12 +183,12 @@ describe("runCodegraphServe", () => {
182
183
  expect(spawned).toEqual([{ args: ["serve", "--mcp"], command: commandPath }]);
183
184
  });
184
185
 
185
- it("#given Windows Codex SOT install_dir has codegraph.cmd and daemon is off by default #when serving MCP #then it resolves there, exports CODEGRAPH_INSTALL_DIR, and pins CODEGRAPH_NO_DAEMON=1", async () => {
186
- await withProcessPlatform("win32", async () => {
186
+ it("#given Codex SOT install_dir has the pinned launcher and daemon is omitted #when serving MCP #then it defaults daemon-on", async () => {
187
+ await withProcessPlatform(process.platform, async () => {
187
188
  // given
188
189
  const tempRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-serve-install-dir-"));
189
190
  const installDir = join(tempRoot, "custom-codegraph");
190
- const binPath = join(installDir, "bin", "codegraph.cmd");
191
+ const binPath = join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
191
192
  const calls: Array<{
192
193
  readonly args: readonly string[];
193
194
  readonly command: string;
@@ -196,7 +197,12 @@ describe("runCodegraphServe", () => {
196
197
 
197
198
  try {
198
199
  mkdirSync(join(installDir, "bin"), { recursive: true });
200
+ mkdirSync(join(installDir, ".provisioned"), { recursive: true });
199
201
  writeFileSync(binPath, "");
202
+ writeFileSync(
203
+ join(installDir, ".provisioned", `codegraph-${CODEGRAPH_PINNED_VERSION}.json`),
204
+ `${JSON.stringify({ binPath, version: CODEGRAPH_PINNED_VERSION })}\n`,
205
+ );
200
206
 
201
207
  // when
202
208
  const exitCode = await runCodegraphServe({
@@ -223,7 +229,6 @@ describe("runCodegraphServe", () => {
223
229
  command: binPath,
224
230
  env: {
225
231
  CODEGRAPH_INSTALL_DIR: installDir,
226
- CODEGRAPH_NO_DAEMON: "1",
227
232
  CODEGRAPH_NO_DOWNLOAD: "1",
228
233
  CODEGRAPH_TELEMETRY: "0",
229
234
  DO_NOT_TRACK: "1",
@@ -237,12 +242,12 @@ describe("runCodegraphServe", () => {
237
242
  });
238
243
  });
239
244
 
240
- it("#given Windows Codex SOT install_dir with codegraph.daemon=true #when serving MCP #then CODEGRAPH_NO_DAEMON is omitted so the daemon may run", async () => {
241
- await withProcessPlatform("win32", async () => {
245
+ it("#given Codex SOT install_dir with codegraph.daemon=false #when serving MCP #then CODEGRAPH_NO_DAEMON pins daemon-off", async () => {
246
+ await withProcessPlatform(process.platform, async () => {
242
247
  // given
243
248
  const tempRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-serve-install-dir-daemon-"));
244
249
  const installDir = join(tempRoot, "custom-codegraph");
245
- const binPath = join(installDir, "bin", "codegraph.cmd");
250
+ const binPath = join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
246
251
  const calls: Array<{
247
252
  readonly args: readonly string[];
248
253
  readonly command: string;
@@ -251,11 +256,16 @@ describe("runCodegraphServe", () => {
251
256
 
252
257
  try {
253
258
  mkdirSync(join(installDir, "bin"), { recursive: true });
259
+ mkdirSync(join(installDir, ".provisioned"), { recursive: true });
254
260
  writeFileSync(binPath, "");
261
+ writeFileSync(
262
+ join(installDir, ".provisioned", `codegraph-${CODEGRAPH_PINNED_VERSION}.json`),
263
+ `${JSON.stringify({ binPath, version: CODEGRAPH_PINNED_VERSION })}\n`,
264
+ );
255
265
 
256
266
  // when
257
267
  const exitCode = await runCodegraphServe({
258
- config: { codegraph: { daemon: true, enabled: true, install_dir: installDir }, sources: [], trustedCodegraphInstallDir: installDir, warnings: [] },
268
+ config: { codegraph: { daemon: false, enabled: true, install_dir: installDir }, sources: [], trustedCodegraphInstallDir: installDir, warnings: [] },
259
269
  env: { HOME: "/tmp/home" },
260
270
  nodeVersion: "22.14.0",
261
271
  homeDir: "/tmp/home",
@@ -278,6 +288,7 @@ describe("runCodegraphServe", () => {
278
288
  command: binPath,
279
289
  env: {
280
290
  CODEGRAPH_INSTALL_DIR: installDir,
291
+ CODEGRAPH_NO_DAEMON: "1",
281
292
  CODEGRAPH_NO_DOWNLOAD: "1",
282
293
  CODEGRAPH_TELEMETRY: "0",
283
294
  DO_NOT_TRACK: "1",
@@ -285,7 +296,7 @@ describe("runCodegraphServe", () => {
285
296
  },
286
297
  },
287
298
  ]);
288
- expect(calls[0]?.env["CODEGRAPH_NO_DAEMON"]).toBeUndefined();
299
+ expect(calls[0]?.env["CODEGRAPH_NO_DAEMON"]).toBe("1");
289
300
  } finally {
290
301
  rmSync(tempRoot, { recursive: true, force: true });
291
302
  }