oh-my-opencode 4.19.2 → 4.19.4

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 (241) hide show
  1. package/.agents/command/get-unpublished-changes.md +2 -0
  2. package/.agents/command/omomomo.md +1 -1
  3. package/.agents/command/publish.md +102 -28
  4. package/.agents/skills/get-unpublished-changes/SKILL.md +2 -0
  5. package/.agents/skills/hyperplan/SKILL.md +3 -3
  6. package/.agents/skills/omomomo/SKILL.md +1 -1
  7. package/.agents/skills/publish/SKILL.md +27 -6
  8. package/.opencode/command/get-unpublished-changes.md +2 -0
  9. package/.opencode/command/omomomo.md +1 -1
  10. package/.opencode/command/publish.md +102 -28
  11. package/.opencode/skills/hyperplan/SKILL.md +3 -3
  12. package/THIRD-PARTY-NOTICES.md +7 -7
  13. package/dist/agents/sisyphus-junior/agent.d.ts +1 -1
  14. package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +1 -1
  15. package/dist/cli/config-migrate.d.ts +8 -0
  16. package/dist/cli/doctor/checks/deprecated-reasoning-keys.d.ts +2 -0
  17. package/dist/cli/doctor/checks/legacy-config-leftovers.d.ts +10 -0
  18. package/dist/cli/doctor/checks/model-resolution-config.d.ts +1 -1
  19. package/dist/cli/doctor/checks/tools-lsp.d.ts +1 -1
  20. package/dist/cli/doctor/framework/constants.d.ts +1 -1
  21. package/dist/cli/index.js +95684 -92814
  22. package/dist/cli-node/index.js +95650 -92780
  23. package/dist/config/schema/agent-overrides.d.ts +800 -0
  24. package/dist/config/schema/categories.d.ts +132 -0
  25. package/dist/config/schema/fallback-models.d.ts +50 -0
  26. package/dist/config/schema/oh-my-opencode-config.d.ts +818 -2
  27. package/dist/config/validate.d.ts +2 -1
  28. package/dist/config-migration/deep-diff.d.ts +1 -0
  29. package/dist/config-migration/discovery-paths.d.ts +11 -0
  30. package/dist/config-migration/discovery-roots.d.ts +7 -0
  31. package/dist/config-migration/discovery.d.ts +4 -0
  32. package/dist/config-migration/index.d.ts +10 -0
  33. package/dist/config-migration/legacy-history.d.ts +3 -0
  34. package/dist/config-migration/migration-executor.d.ts +4 -0
  35. package/dist/config-migration/migration-plans.d.ts +15 -0
  36. package/dist/config-migration/reasoning-unification.d.ts +3 -0
  37. package/dist/config-migration/record-values.d.ts +4 -0
  38. package/dist/config-migration/schema-url.d.ts +1 -0
  39. package/dist/config-migration/transform-config-jsonc.d.ts +2 -0
  40. package/dist/config-migration/transform-opencode.d.ts +2 -0
  41. package/dist/config-migration/transform-types.d.ts +24 -0
  42. package/dist/config-migration/types.d.ts +39 -0
  43. package/dist/features/builtin-commands/templates/hyperplan.d.ts +1 -1
  44. package/dist/features/team-mode/tools/lifecycle-test-fixture.d.ts +2 -0
  45. package/dist/hooks/auto-update-checker/constants.d.ts +3 -3
  46. package/dist/hooks/codegraph-bootstrap/command-runner.d.ts +1 -0
  47. package/dist/hooks/model-fallback/next-fallback.d.ts +1 -0
  48. package/dist/hooks/runtime-fallback/constants.d.ts +1 -1
  49. package/dist/index.js +12368 -9788
  50. package/dist/oh-my-opencode.schema.json +1672 -8
  51. package/dist/plugin-config/omo-config-chain.d.ts +14 -0
  52. package/dist/plugin-config/unknown-key-diagnostics.d.ts +5 -0
  53. package/dist/plugin-config.d.ts +2 -2
  54. package/dist/plugin-handlers/prometheus-agent-config-builder.d.ts +1 -0
  55. package/dist/shared/agent-display-names.d.ts +1 -1
  56. package/dist/shared/agent-variant.d.ts +11 -0
  57. package/dist/shared/jsonc-parser.d.ts +1 -1
  58. package/dist/shared/migration.d.ts +5 -1
  59. package/dist/shared/opencode-config-dir-types.d.ts +0 -1
  60. package/dist/shared/plugin-identity.d.ts +6 -8
  61. package/dist/shared/project-discovery-dirs.d.ts +0 -1
  62. package/dist/shared/session-prompt-params-helpers.d.ts +6 -1
  63. package/dist/skills/coding-agent-sessions/SKILL.md +4 -3
  64. package/dist/skills/coding-agent-sessions/references/all-platforms.md +3 -1
  65. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +140 -0
  66. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +3 -0
  67. package/dist/skills/data-scientist/SKILL.md +243 -0
  68. package/dist/skills/data-scientist/references/common-scenarios.md +176 -0
  69. package/dist/skills/data-scientist/references/execution-templates.md +197 -0
  70. package/dist/skills/data-scientist/references/integration-patterns.md +153 -0
  71. package/dist/skills/data-scientist/references/performance-benchmarks.md +37 -0
  72. package/dist/skills/data-scientist/references/uv-setup.md +78 -0
  73. package/dist/skills/data-scientist/scripts/quick-query.py +111 -0
  74. package/dist/skills/data-scientist/scripts/setup-uv.ps1 +53 -0
  75. package/dist/skills/data-scientist/scripts/setup-uv.sh +60 -0
  76. package/dist/skills/debugging/SKILL.md +1 -1
  77. package/dist/skills/frontend/ATTRIBUTION.md +7 -0
  78. package/dist/skills/frontend/SKILL.md +4 -1
  79. package/dist/skills/frontend/references/design/README.md +8 -0
  80. package/dist/skills/frontend/references/design/_INDEX.md +14 -1
  81. package/dist/skills/frontend/references/design/interaction-skill.md +144 -0
  82. package/dist/skills/programming/SKILL.md +1 -2
  83. package/dist/skills/ulw-plan/SKILL.md +1 -1
  84. package/dist/skills/ulw-research/SKILL.md +122 -11
  85. package/dist/startup-migration.d.ts +28 -0
  86. package/dist/testing/create-plugin-module.d.ts +4 -0
  87. package/dist/tools/delegate-task/builtin-categories.d.ts +1 -0
  88. package/dist/tools/delegate-task/builtin-category-definition.d.ts +1 -0
  89. package/dist/tools/delegate-task/constants.d.ts +1 -1
  90. package/dist/tui.js +6040 -5443
  91. package/package.json +13 -13
  92. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +21 -5
  93. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +11 -2
  94. package/packages/omo-codex/THIRD-PARTY-NOTICES.md +2 -2
  95. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  96. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +21 -3
  97. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  98. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  99. package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +11 -5
  100. package/packages/omo-codex/plugin/components/codegraph/NOTICE +1 -1
  101. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +10373 -2570
  102. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +7502 -574
  103. package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
  104. package/packages/omo-codex/plugin/components/codegraph/src/hook-input.ts +33 -0
  105. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +36 -10
  106. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +164 -159
  107. package/packages/omo-codex/plugin/components/codegraph/src/post-tool-use-hook.ts +34 -0
  108. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +20 -2
  109. package/packages/omo-codex/plugin/components/codegraph/src/session-start-command.ts +106 -0
  110. package/packages/omo-codex/plugin/components/codegraph/src/session-start-cooldown.ts +145 -0
  111. package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +21 -0
  112. package/packages/omo-codex/plugin/components/codegraph/src/session-start-lock.ts +139 -0
  113. package/packages/omo-codex/plugin/components/codegraph/src/session-start-outcome.ts +15 -0
  114. package/packages/omo-codex/plugin/components/codegraph/src/session-start-paths.ts +32 -0
  115. package/packages/omo-codex/plugin/components/codegraph/src/session-start-project.ts +109 -0
  116. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker-result.ts +148 -0
  117. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +126 -175
  118. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +4 -4
  119. package/packages/omo-codex/plugin/components/codegraph/test/hook-session-start-guard.test.ts +160 -0
  120. package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +12 -138
  121. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +34 -24
  122. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +3 -3
  123. package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +2 -2
  124. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +5 -5
  125. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +3 -3
  126. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +1 -1
  127. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +45 -0
  128. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +2 -2
  129. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +70 -13
  130. package/packages/omo-codex/plugin/components/codegraph/test/session-start-project.test.ts +58 -0
  131. package/packages/omo-codex/plugin/components/codegraph/test/session-start-state.test.ts +104 -0
  132. package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +4 -2
  133. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts +116 -0
  134. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +58 -57
  135. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  136. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  137. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  138. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  139. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  140. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  141. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  142. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  143. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  144. package/packages/omo-codex/plugin/components/rules/dist/cli.js +32 -15
  145. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  146. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  147. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +1 -1
  148. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  149. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  150. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  151. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  152. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  153. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  154. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  155. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  156. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +1 -1
  157. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  158. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  159. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +17 -0
  160. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  161. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  162. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  163. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  164. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  165. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  166. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  170. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  171. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  172. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  173. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  174. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  175. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  176. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  177. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  178. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  179. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  180. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  181. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  182. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  183. package/packages/omo-codex/plugin/package-lock.json +42 -41
  184. package/packages/omo-codex/plugin/package.json +1 -1
  185. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +6 -0
  186. package/packages/omo-codex/plugin/shared/src/config-loader.ts +165 -16
  187. package/packages/omo-codex/plugin/shared/src/config-migration.ts +162 -0
  188. package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +186 -9
  189. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +4 -3
  190. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +3 -1
  191. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +140 -0
  192. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +3 -0
  193. package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +243 -0
  194. package/packages/omo-codex/plugin/skills/data-scientist/agents/openai.yaml +2 -0
  195. package/packages/omo-codex/plugin/skills/data-scientist/references/common-scenarios.md +176 -0
  196. package/packages/omo-codex/plugin/skills/data-scientist/references/execution-templates.md +197 -0
  197. package/packages/omo-codex/plugin/skills/data-scientist/references/integration-patterns.md +153 -0
  198. package/packages/omo-codex/plugin/skills/data-scientist/references/performance-benchmarks.md +37 -0
  199. package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +78 -0
  200. package/packages/omo-codex/plugin/skills/data-scientist/scripts/quick-query.py +111 -0
  201. package/packages/omo-codex/plugin/skills/data-scientist/scripts/setup-uv.ps1 +53 -0
  202. package/packages/omo-codex/plugin/skills/data-scientist/scripts/setup-uv.sh +60 -0
  203. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +1 -1
  204. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +7 -0
  205. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +4 -1
  206. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +8 -0
  207. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +14 -1
  208. package/packages/omo-codex/plugin/skills/frontend/references/design/interaction-skill.md +144 -0
  209. package/packages/omo-codex/plugin/skills/programming/SKILL.md +1 -2
  210. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +17 -0
  211. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +1 -1
  212. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +121 -11
  213. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +7 -0
  214. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +12 -0
  215. package/packages/omo-codex/scripts/install-dist/install-local.mjs +24 -5
  216. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +4 -3
  217. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +3 -1
  218. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +140 -0
  219. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +3 -0
  220. package/packages/shared-skills/skills/data-scientist/SKILL.md +243 -0
  221. package/packages/shared-skills/skills/data-scientist/references/common-scenarios.md +176 -0
  222. package/packages/shared-skills/skills/data-scientist/references/execution-templates.md +197 -0
  223. package/packages/shared-skills/skills/data-scientist/references/integration-patterns.md +153 -0
  224. package/packages/shared-skills/skills/data-scientist/references/performance-benchmarks.md +37 -0
  225. package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +78 -0
  226. package/packages/shared-skills/skills/data-scientist/scripts/quick-query.py +111 -0
  227. package/packages/shared-skills/skills/data-scientist/scripts/setup-uv.ps1 +53 -0
  228. package/packages/shared-skills/skills/data-scientist/scripts/setup-uv.sh +60 -0
  229. package/packages/shared-skills/skills/debugging/SKILL.md +1 -1
  230. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +7 -0
  231. package/packages/shared-skills/skills/frontend/SKILL.md +4 -1
  232. package/packages/shared-skills/skills/frontend/references/design/README.md +8 -0
  233. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +14 -1
  234. package/packages/shared-skills/skills/frontend/references/design/interaction-skill.md +144 -0
  235. package/packages/shared-skills/skills/programming/SKILL.md +1 -2
  236. package/packages/shared-skills/skills/ulw-plan/SKILL.md +1 -1
  237. package/packages/shared-skills/skills/ulw-research/SKILL.md +122 -11
  238. package/dist/plugin-config/layered-config-loader.d.ts +0 -2
  239. package/dist/plugin-config/single-config-loader.d.ts +0 -4
  240. package/dist/shared/migrate-legacy-config-file.d.ts +0 -1
  241. package/dist/shared/migration/config-migration.d.ts +0 -1
@@ -0,0 +1,160 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join, resolve } from "node:path";
5
+ import { Readable } from "node:stream";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ import {
9
+ executeCodegraphSessionStartHook,
10
+ type CodegraphSessionStartOutcome,
11
+ type WorkerSpawnInvocation,
12
+ } from "../src/hook.ts";
13
+ import { recordSessionStartFailure } from "../src/session-start-cooldown.ts";
14
+
15
+ const pluginRoot = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
16
+
17
+ function createAllowedWorkspace(prefix: string): string {
18
+ return mkdtempSync(join(pluginRoot, `.tmp-${prefix}-`));
19
+ }
20
+
21
+ describe("CodeGraph SessionStart spawn guards", () => {
22
+ it("#given an inconclusive probe timeout #when SessionStart runs #then timeout is not treated as uninitialized", async () => {
23
+ // given
24
+ const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-timeout-home-"));
25
+ const workspace = createAllowedWorkspace("codegraph-timeout-workspace");
26
+ const spawned: WorkerSpawnInvocation[] = [];
27
+ try {
28
+ // when
29
+ const result = await executeCodegraphSessionStartHook({
30
+ ancestorProbe: () => ({ kind: "inconclusive", reason: "status timed out" }),
31
+ config: { codegraph: { enabled: true }, sources: [], warnings: [] },
32
+ cwd: workspace,
33
+ env: { HOME: homeDir },
34
+ spawnWorker: (invocation) => spawned.push(invocation),
35
+ stdin: Readable.from(["{}"]),
36
+ sweepZombies: () => undefined,
37
+ });
38
+
39
+ // then
40
+ expect(result).toEqual({ action: "skipped-inconclusive", exitCode: 0 });
41
+ expect(spawned).toEqual([]);
42
+ } finally {
43
+ rmSync(homeDir, { recursive: true, force: true });
44
+ rmSync(workspace, { recursive: true, force: true });
45
+ }
46
+ });
47
+
48
+ it("#given one hook already owns the project lock #when a second SessionStart runs #then it records skipped-locked without spawning", async () => {
49
+ // given
50
+ const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-dedup-home-"));
51
+ const workspace = createAllowedWorkspace("codegraph-dedup-workspace");
52
+ const outcomes: CodegraphSessionStartOutcome[] = [];
53
+ const spawned: WorkerSpawnInvocation[] = [];
54
+ const options = {
55
+ ancestorProbe: () => ({ kind: "uninitialized" } as const),
56
+ config: { codegraph: { enabled: true }, sources: [], warnings: [] },
57
+ cwd: workspace,
58
+ env: { HOME: homeDir },
59
+ logOutcome: (outcome: CodegraphSessionStartOutcome) => outcomes.push(outcome),
60
+ spawnWorker: (invocation: WorkerSpawnInvocation) => {
61
+ spawned.push(invocation);
62
+ },
63
+ stdin: Readable.from(["{}"]),
64
+ sweepZombies: () => undefined,
65
+ };
66
+ try {
67
+ await executeCodegraphSessionStartHook(options);
68
+
69
+ // when
70
+ const second = await executeCodegraphSessionStartHook({ ...options, stdin: Readable.from(["{}"]) });
71
+
72
+ // then
73
+ expect(second).toEqual({ action: "skipped-locked", exitCode: 0 });
74
+ expect(spawned).toHaveLength(1);
75
+ expect(outcomes).toContainEqual({ action: "skipped-locked", projectRoot: workspace });
76
+ } finally {
77
+ rmSync(homeDir, { recursive: true, force: true });
78
+ rmSync(workspace, { recursive: true, force: true });
79
+ }
80
+ });
81
+
82
+ it("#given a failed worker cooldown #when SessionStart retries before and after expiry #then only the expired retry spawns", async () => {
83
+ // given
84
+ const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-cooldown-hook-home-"));
85
+ const workspace = createAllowedWorkspace("codegraph-cooldown-hook-workspace");
86
+ const outcomes: CodegraphSessionStartOutcome[] = [];
87
+ const spawned: WorkerSpawnInvocation[] = [];
88
+ try {
89
+ recordSessionStartFailure({
90
+ action: "failed",
91
+ baseCooldownMs: 60_000,
92
+ homeDir,
93
+ nowMs: 1_000,
94
+ projectRoot: workspace,
95
+ });
96
+ const baseOptions = {
97
+ ancestorProbe: () => ({ kind: "uninitialized" } as const),
98
+ config: { codegraph: { enabled: true, session_start_cooldown_ms: 60_000 }, sources: [], warnings: [] },
99
+ cwd: workspace,
100
+ env: { HOME: homeDir },
101
+ logOutcome: (outcome: CodegraphSessionStartOutcome) => outcomes.push(outcome),
102
+ spawnWorker: (invocation: WorkerSpawnInvocation) => {
103
+ spawned.push(invocation);
104
+ },
105
+ sweepZombies: () => undefined,
106
+ };
107
+
108
+ // when
109
+ const suppressed = await executeCodegraphSessionStartHook({ ...baseOptions, nowMs: 60_999, stdin: Readable.from(["{}"]) });
110
+ const expired = await executeCodegraphSessionStartHook({ ...baseOptions, nowMs: 61_000, stdin: Readable.from(["{}"]) });
111
+
112
+ // then
113
+ expect(suppressed).toEqual({ action: "skipped-cooldown", exitCode: 0 });
114
+ expect(expired).toEqual({ action: "spawned", exitCode: 0 });
115
+ expect(spawned).toHaveLength(1);
116
+ expect(outcomes).toContainEqual({
117
+ action: "skipped-cooldown",
118
+ cooldownUntil: 61_000,
119
+ failureCount: 1,
120
+ projectRoot: workspace,
121
+ });
122
+ } finally {
123
+ rmSync(homeDir, { recursive: true, force: true });
124
+ rmSync(workspace, { recursive: true, force: true });
125
+ }
126
+ });
127
+
128
+ it("#given an ancestor has a CodeGraph database #when SessionStart runs in a nested project #then it records skipped-nested-root", async () => {
129
+ // given
130
+ const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-nested-home-"));
131
+ const ancestorRoot = createAllowedWorkspace("codegraph-nested-ancestor");
132
+ const workspace = join(ancestorRoot, "apps", "server");
133
+ const outcomes: CodegraphSessionStartOutcome[] = [];
134
+ const spawned: WorkerSpawnInvocation[] = [];
135
+ try {
136
+ mkdirSync(join(ancestorRoot, ".codegraph"), { recursive: true });
137
+ mkdirSync(workspace, { recursive: true });
138
+ writeFileSync(join(ancestorRoot, ".codegraph", "codegraph.db"), "fixture");
139
+
140
+ // when
141
+ const result = await executeCodegraphSessionStartHook({
142
+ config: { codegraph: { enabled: true }, sources: [], warnings: [] },
143
+ cwd: workspace,
144
+ env: { HOME: homeDir },
145
+ logOutcome: (outcome) => outcomes.push(outcome),
146
+ spawnWorker: (invocation) => spawned.push(invocation),
147
+ stdin: Readable.from(["{}"]),
148
+ sweepZombies: () => undefined,
149
+ });
150
+
151
+ // then
152
+ expect(result).toEqual({ action: "skipped-nested-root", exitCode: 0 });
153
+ expect(spawned).toEqual([]);
154
+ expect(outcomes).toContainEqual({ action: "skipped-nested-root", ancestorRoot, projectRoot: workspace });
155
+ } finally {
156
+ rmSync(homeDir, { recursive: true, force: true });
157
+ rmSync(ancestorRoot, { recursive: true, force: true });
158
+ }
159
+ });
160
+ });
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "bun:test";
2
- import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { mkdirSync, mkdtempSync, 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";
@@ -9,108 +9,33 @@ import { executeCodegraphSessionStartHook, type WorkerSpawnInvocation } from "..
9
9
 
10
10
  const pluginRoot = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
11
11
 
12
- // Observed verbatim from a REAL codegraph 1.4.1 binary running `status --json` (exit 0)
13
- // against a project store built by a REAL codegraph 1.0.1 binary
14
- // (see .omo/evidence/codegraph-daemon-process-hygiene/task-2-store-upgrade.txt).
15
- const MIGRATED_1_0_1_STORE_STATUS_JSON = JSON.stringify({
16
- initialized: true,
17
- version: "1.4.1",
18
- projectPath: "/private/tmp/cg-task2/fixture",
19
- indexPath: "/private/tmp/cg-task2/fixture/.codegraph",
20
- lastIndexed: "2026-07-21T04:28:09.593Z",
21
- fileCount: 2,
22
- nodeCount: 5,
23
- edgeCount: 4,
24
- dbSizeBytes: 159744,
25
- backend: "node-sqlite",
26
- journalMode: "wal",
27
- nodesByKind: { file: 2, function: 3 },
28
- languages: ["typescript"],
29
- pendingChanges: { added: 0, modified: 0, removed: 0 },
30
- worktreeMismatch: null,
31
- index: {
32
- builtWithVersion: "1.0.1",
33
- builtWithExtractionVersion: 24,
34
- currentExtractionVersion: 24,
35
- reindexRecommended: false,
36
- state: null,
37
- pendingRefs: 0,
38
- },
39
- });
40
-
41
12
  function createAllowedWorkspace(prefix: string): string {
42
13
  return mkdtempSync(join(pluginRoot, `.tmp-${prefix}-`));
43
14
  }
44
15
 
45
- // On win32 execFile cannot run a #!/bin/sh script, so emit a codegraph.cmd batch file instead;
46
- // resolveCodegraphCommandInvocation wraps .cmd in `cmd.exe /d /s /c`, exactly like the real codegraph.cmd.
47
- function createFakeCodegraphBin(scripts: {
48
- readonly posix: string;
49
- readonly win32: string;
50
- readonly win32Sidecar?: string;
51
- }): { readonly binPath: string; readonly dir: string } {
52
- const dir = mkdtempSync(join(tmpdir(), "omo-codegraph-fake-bin-"));
53
- if (process.platform === "win32") {
54
- const binPath = join(dir, "codegraph.cmd");
55
- writeFileSync(binPath, scripts.win32);
56
- if (scripts.win32Sidecar !== undefined) writeFileSync(join(dir, "hang.cjs"), scripts.win32Sidecar);
57
- return { binPath, dir };
58
- }
59
- const binPath = join(dir, "codegraph");
60
- writeFileSync(binPath, scripts.posix, { mode: 0o755 });
61
- chmodSync(binPath, 0o755);
62
- return { binPath, dir };
63
- }
64
-
65
- // Keep the probe hermetic on POSIX but viable on win32: resolveCodegraphCommandInvocation wraps
66
- // the fake .cmd in `cmd.exe /d /s /c`, and Windows can only resolve cmd.exe when the child env
67
- // carries the real system PATH (System32) plus SystemRoot (both whitelisted in SAFE_AMBIENT_ENV_KEYS).
68
- // A POSIX-only PATH makes the probe spawn fail, so the hook reports not-initialized and spawns.
69
- function probeEnv(homeDir: string, binPath: string): Record<string, string> {
70
- if (process.platform === "win32") {
71
- const env: Record<string, string> = {
72
- HOME: homeDir,
73
- OMO_CODEGRAPH_BIN: binPath,
74
- };
75
- if (process.env["PATH"] !== undefined) env["PATH"] = process.env["PATH"];
76
- if (process.env["SystemRoot"] !== undefined) env["SystemRoot"] = process.env["SystemRoot"];
77
- return env;
78
- }
79
- return { HOME: homeDir, OMO_CODEGRAPH_BIN: binPath, PATH: "/usr/bin:/bin" };
80
- }
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
-
91
- describe("CodeGraph SessionStart hook with a 1.0.1-era project store under the 1.4.1 binary", () => {
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 () => {
16
+ describe("CodeGraph SessionStart hook with a migrated 1.0.1 project store under CodeGraph 1.5.0", () => {
17
+ it("#given the migrated store has an exact database #when SessionStart runs #then it never invokes the CodeGraph CLI", async () => {
93
18
  // given
94
19
  const stdout: string[] = [];
95
20
  const spawned: WorkerSpawnInvocation[] = [];
96
21
  const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-upgrade-home-"));
97
- // The payload is a single JSON line with no cmd metacharacters (% ^ & < > |), so a plain echo is safe.
98
- const fake = createFakeCodegraphBin({
99
- posix: `#!/bin/sh\nprintf '%s\\n' '${MIGRATED_1_0_1_STORE_STATUS_JSON}'\n`,
100
- win32: `@echo off\r\n@echo ${MIGRATED_1_0_1_STORE_STATUS_JSON}\r\n`,
101
- });
102
22
  const workspace = createAllowedWorkspace("codegraph-upgrade-workspace");
103
- mkdirSync(join(workspace, ".codegraph"), { recursive: true });
104
-
105
23
  try {
24
+ mkdirSync(join(workspace, ".codegraph"), { recursive: true });
25
+ writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "migrated-store");
26
+
106
27
  // when
107
28
  const result = await executeCodegraphSessionStartHook({
29
+ ancestorProbe: () => {
30
+ throw new Error("the exact database check must be the complete fast path");
31
+ },
108
32
  config: { codegraph: { enabled: true }, sources: [], warnings: [] },
109
33
  cwd: workspace,
110
- env: probeEnv(homeDir, fake.binPath),
34
+ env: { HOME: homeDir },
111
35
  stdin: Readable.from(["{}"]),
112
36
  stdout: { write: (chunk) => stdout.push(chunk) },
113
37
  spawnWorker: (invocation) => spawned.push(invocation),
38
+ sweepZombies: () => undefined,
114
39
  });
115
40
 
116
41
  // then
@@ -119,58 +44,7 @@ describe("CodeGraph SessionStart hook with a 1.0.1-era project store under the 1
119
44
  expect(stdout.join("")).toBe("");
120
45
  } finally {
121
46
  rmSync(homeDir, { recursive: true, force: true });
122
- rmSync(fake.dir, { recursive: true, force: true });
123
- rmSync(workspace, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
124
- }
125
- });
126
-
127
- it("#given the status probe spawns a hanging descendant #when SessionStart times out #then it exits promptly and reaps the descendant", async () => {
128
- // given
129
- const stdout: string[] = [];
130
- const spawned: WorkerSpawnInvocation[] = [];
131
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-slow-home-"));
132
- const survivorPidPath = join(homeDir, "survivor.pid");
133
- const fake = createFakeCodegraphBin({
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"),
145
- });
146
- const workspace = createAllowedWorkspace("codegraph-slow-probe-workspace");
147
- let descendantPid: number | undefined;
148
-
149
- try {
150
- // when
151
- const startedAt = Date.now();
152
- const result = await executeCodegraphSessionStartHook({
153
- config: { codegraph: { enabled: true }, sources: [], warnings: [] },
154
- cwd: workspace,
155
- env: probeEnv(homeDir, fake.binPath),
156
- stdin: Readable.from(["{}"]),
157
- stdout: { write: (chunk) => stdout.push(chunk) },
158
- spawnWorker: (invocation) => spawned.push(invocation),
159
- });
160
- const elapsedMs = Date.now() - startedAt;
161
- descendantPid = Number.parseInt(readFileSync(survivorPidPath, "utf8").trim(), 10);
162
-
163
- // then
164
- expect(result.exitCode).toBe(0);
165
- expect(result.action).toBe("spawned");
166
- expect(spawned).toHaveLength(1);
167
- expect(elapsedMs).toBeLessThan(15_000);
168
- expect(isProcessAlive(descendantPid)).toBeFalse();
169
- } finally {
170
- if (descendantPid !== undefined && isProcessAlive(descendantPid)) process.kill(descendantPid, "SIGKILL");
171
- rmSync(homeDir, { recursive: true, force: true });
172
- rmSync(fake.dir, { recursive: true, force: true });
173
- rmSync(workspace, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
47
+ rmSync(workspace, { recursive: true, force: true });
174
48
  }
175
49
  });
176
50
  });
@@ -39,8 +39,9 @@ describe("CodeGraph SessionStart hook", () => {
39
39
  env: { HOME: homeDir },
40
40
  stdin: Readable.from(["{}"]),
41
41
  stdout: { write: (chunk) => stdout.push(chunk) },
42
+ ancestorProbe: () => ({ kind: "uninitialized" }),
42
43
  spawnWorker: (invocation) => spawned.push(invocation),
43
- statusProbe: () => Promise.resolve(false),
44
+ sweepZombies: () => undefined,
44
45
  });
45
46
 
46
47
  // then
@@ -114,6 +115,7 @@ describe("CodeGraph SessionStart hook", () => {
114
115
  env: {},
115
116
  stdin: Readable.from(["{}"]),
116
117
  stdout: { write: (chunk) => stdout.push(chunk) },
118
+ sweepZombies: () => undefined,
117
119
  spawnWorker: (invocation) => spawned.push(invocation),
118
120
  });
119
121
 
@@ -132,7 +134,7 @@ describe("CodeGraph SessionStart hook", () => {
132
134
  try {
133
135
  mkdirSync(join(homeDir, ".omo"), { recursive: true });
134
136
  writeFileSync(
135
- join(homeDir, ".omo", "config.jsonc"),
137
+ join(homeDir, ".omo", "omo.jsonc"),
136
138
  '{ "codegraph": { "enabled": true }, "[codex]": { "codegraph": { "enabled": false } } }\n',
137
139
  );
138
140
 
@@ -142,6 +144,7 @@ describe("CodeGraph SessionStart hook", () => {
142
144
  env: { HOME: homeDir },
143
145
  stdin: Readable.from(["{}"]),
144
146
  stdout: { write: (chunk) => stdout.push(chunk) },
147
+ sweepZombies: () => undefined,
145
148
  spawnWorker: (invocation) => spawned.push(invocation),
146
149
  });
147
150
 
@@ -164,8 +167,8 @@ describe("CodeGraph SessionStart hook", () => {
164
167
  try {
165
168
  mkdirSync(join(homeDir, ".omo"), { recursive: true });
166
169
  mkdirSync(join(workspace, ".omo"), { recursive: true });
167
- writeFileSync(join(homeDir, ".omo", "config.jsonc"), '{ "codegraph": { "enabled": true } }\n');
168
- writeFileSync(join(workspace, ".omo", "config.jsonc"), '{ "[codex]": { "codegraph": { "enabled": false } } }\n');
170
+ writeFileSync(join(homeDir, ".omo", "omo.jsonc"), '{ "codegraph": { "enabled": true } }\n');
171
+ writeFileSync(join(workspace, ".omo", "omo.jsonc"), '{ "[codex]": { "codegraph": { "enabled": false } } }\n');
169
172
 
170
173
  // when
171
174
  const result = await executeCodegraphSessionStartHook({
@@ -173,6 +176,7 @@ describe("CodeGraph SessionStart hook", () => {
173
176
  env: { HOME: homeDir },
174
177
  stdin: Readable.from(["{}"]),
175
178
  stdout: { write: (chunk) => stdout.push(chunk) },
179
+ sweepZombies: () => undefined,
176
180
  spawnWorker: (invocation) => spawned.push(invocation),
177
181
  });
178
182
 
@@ -193,13 +197,14 @@ describe("CodeGraph SessionStart hook", () => {
193
197
  const spawned: WorkerSpawnInvocation[] = [];
194
198
  try {
195
199
  mkdirSync(join(homeDir, ".omo"), { recursive: true });
196
- writeFileSync(join(homeDir, ".omo", "config.jsonc"), '{ "codegraph": { "enabled": true } }\n');
200
+ writeFileSync(join(homeDir, ".omo", "omo.jsonc"), '{ "codegraph": { "enabled": true } }\n');
197
201
 
198
202
  // when
199
203
  const result = await executeCodegraphSessionStartHook({
200
204
  env: { CODEX_CODEGRAPH_ENABLED: "0", HOME: homeDir },
201
205
  stdin: Readable.from(["{}"]),
202
206
  stdout: { write: (chunk) => stdout.push(chunk) },
207
+ sweepZombies: () => undefined,
203
208
  spawnWorker: (invocation) => spawned.push(invocation),
204
209
  });
205
210
 
@@ -215,38 +220,33 @@ describe("CodeGraph SessionStart hook", () => {
215
220
  // given
216
221
  const stdout: string[] = [];
217
222
  const spawned: WorkerSpawnInvocation[] = [];
218
- const statusProbeDaemonValues: boolean[] = [];
219
223
  const workspace = createAllowedWorkspace("codegraph-workspace");
224
+ const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-spawn-home-"));
220
225
 
221
226
  try {
222
227
  // when
223
228
  const result = await executeCodegraphSessionStartHook({
229
+ ancestorProbe: () => ({ kind: "uninitialized" }),
224
230
  config: { codegraph: { enabled: true }, sources: [], warnings: [] },
225
231
  cwd: workspace,
226
- env: { HOME: "/tmp/home", KEEP: "1", OPENAI_API_KEY: "sk-test-secret" },
232
+ env: { HOME: homeDir, KEEP: "1", OPENAI_API_KEY: "sk-test-secret" },
227
233
  stdin: Readable.from(["{}"]),
228
234
  stdout: { write: (chunk) => stdout.push(chunk) },
229
- spawnWorker: (invocation) => spawned.push(invocation),
230
- statusProbe: (options) => {
231
- statusProbeDaemonValues.push(options.daemon);
232
- return Promise.resolve(false);
235
+ spawnWorker: (invocation) => {
236
+ spawned.push(invocation);
233
237
  },
238
+ sweepZombies: () => undefined,
234
239
  workerCliPath: "/plugin/components/codegraph/dist/cli.js",
235
240
  });
236
241
 
237
242
  // then
238
243
  expect(result).toEqual({ action: "spawned", exitCode: 0 });
239
- expect(statusProbeDaemonValues).toEqual([true]);
240
- expect(spawned).toEqual([
241
- {
242
- args: ["/plugin/components/codegraph/dist/cli.js", "hook", "session-start-worker"],
243
- command: process.execPath,
244
- env: {
245
- HOME: "/tmp/home",
246
- OMO_CODEGRAPH_SESSION_START_CWD: workspace,
247
- },
248
- },
249
- ]);
244
+ expect(spawned).toHaveLength(1);
245
+ expect(spawned[0]?.args).toEqual(["/plugin/components/codegraph/dist/cli.js", "hook", "session-start-worker"]);
246
+ expect(spawned[0]?.command).toBe(process.execPath);
247
+ expect(spawned[0]?.env["HOME"]).toBe(homeDir);
248
+ expect(spawned[0]?.env["OMO_CODEGRAPH_SESSION_START_CWD"]).toBe(workspace);
249
+ expect(spawned[0]?.env["OMO_CODEGRAPH_SESSION_START_LOCK_TOKEN"]).toMatch(/^[0-9a-f-]{36}$/);
250
250
  expect(spawned[0]?.env["OPENAI_API_KEY"]).toBeUndefined();
251
251
  expect(spawned[0]?.env["KEEP"]).toBeUndefined();
252
252
  expect(JSON.parse(stdout.join(""))).toEqual({
@@ -256,6 +256,7 @@ describe("CodeGraph SessionStart hook", () => {
256
256
  },
257
257
  });
258
258
  } finally {
259
+ rmSync(homeDir, { recursive: true, force: true });
259
260
  rmSync(workspace, { recursive: true, force: true });
260
261
  }
261
262
  });
@@ -265,17 +266,24 @@ describe("CodeGraph SessionStart hook", () => {
265
266
  const stdout: string[] = [];
266
267
  const spawned: WorkerSpawnInvocation[] = [];
267
268
  const workspace = createAllowedWorkspace("codegraph-initialized-workspace");
269
+ const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-initialized-home-"));
268
270
 
269
271
  try {
272
+ mkdirSync(join(workspace, ".codegraph"), { recursive: true });
273
+ writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "fixture");
274
+
270
275
  // when
271
276
  const result = await executeCodegraphSessionStartHook({
277
+ ancestorProbe: () => {
278
+ throw new Error("an initialized exact root must not invoke any fallback probe");
279
+ },
272
280
  config: { codegraph: { enabled: true }, sources: [], warnings: [] },
273
281
  cwd: workspace,
274
- env: { HOME: "/tmp/home", KEEP: "1" },
282
+ env: { HOME: homeDir, KEEP: "1" },
275
283
  stdin: Readable.from(["{}"]),
276
284
  stdout: { write: (chunk) => stdout.push(chunk) },
285
+ sweepZombies: () => undefined,
277
286
  spawnWorker: (invocation) => spawned.push(invocation),
278
- statusProbe: () => Promise.resolve(true),
279
287
  });
280
288
 
281
289
  // then
@@ -283,6 +291,7 @@ describe("CodeGraph SessionStart hook", () => {
283
291
  expect(spawned).toEqual([]);
284
292
  expect(stdout.join("")).toBe("");
285
293
  } finally {
294
+ rmSync(homeDir, { recursive: true, force: true });
286
295
  rmSync(workspace, { recursive: true, force: true });
287
296
  }
288
297
  });
@@ -298,6 +307,7 @@ describe("CodeGraph SessionStart hook", () => {
298
307
  env: {},
299
308
  stdin: Readable.from(["{not-json"]),
300
309
  stdout: { write: (chunk) => stdout.push(chunk) },
310
+ sweepZombies: () => undefined,
301
311
  spawnWorker: (invocation) => spawned.push(invocation),
302
312
  });
303
313
 
@@ -1,6 +1,6 @@
1
1
  import { chmodSync, writeFileSync } from "node:fs";
2
2
 
3
- export const CODEGRAPH_141_DEFAULT_TOOLS: readonly Record<string, unknown>[] = [
3
+ export const CODEGRAPH_150_DEFAULT_TOOLS: readonly Record<string, unknown>[] = [
4
4
  {
5
5
  name: "codegraph_explore",
6
6
  description:
@@ -41,10 +41,10 @@ export function writeFakeNewlineCodegraph(filePath: string): void {
41
41
  "rl.on('line', (line) => {",
42
42
  " const request = JSON.parse(line);",
43
43
  " if (request.method === 'initialize') {",
44
- " process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { capabilities: { tools: { listChanged: false } }, protocolVersion: request.params.protocolVersion, serverInfo: { name: 'codegraph', version: '1.4.1' } } }) + '\\n');",
44
+ " process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { capabilities: { tools: { listChanged: false } }, protocolVersion: request.params.protocolVersion, serverInfo: { name: 'codegraph', version: '1.5.0' } } }) + '\\n');",
45
45
  " }",
46
46
  " if (request.method === 'tools/list') {",
47
- ` process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { tools: ${JSON.stringify(CODEGRAPH_141_DEFAULT_TOOLS)} } }) + '\\n');`,
47
+ ` process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { tools: ${JSON.stringify(CODEGRAPH_150_DEFAULT_TOOLS)} } }) + '\\n');`,
48
48
  " }",
49
49
  "});",
50
50
  ].join("\n"),
@@ -43,7 +43,7 @@ describe("CodeGraph component runtime package metadata", () => {
43
43
  const files = packageJson.files ?? [];
44
44
 
45
45
  // then
46
- expect(optionalDependencies["@colbymchenry/codegraph"]).toBe("1.4.1");
46
+ expect(optionalDependencies["@colbymchenry/codegraph"]).toBe("1.5.0");
47
47
  expect(files).toContain("LICENSE");
48
48
  expect(files).toContain("NODE-RUNTIME-LICENSES.md");
49
49
  expect(files).toContain("NOTICE");
@@ -58,7 +58,7 @@ describe("CodeGraph component runtime package metadata", () => {
58
58
  // given
59
59
  const notice = readFileSync(resolve(componentRoot, "NOTICE"), "utf8");
60
60
 
61
- expect(notice).toContain("@colbymchenry/codegraph@1.0.1");
61
+ expect(notice).toContain("@colbymchenry/codegraph@1.5.0");
62
62
  expect(notice).toContain("MIT license");
63
63
  expect(notice).toContain("Node.js v24.16.0 runtime");
64
64
  expect(notice).toContain("NODE-RUNTIME-LICENSES.md");
@@ -77,19 +77,19 @@ describe("CodeGraph provisioned launcher Node guard", () => {
77
77
  source: provisioned === null ? "path" : "provisioned",
78
78
  };
79
79
  },
80
+ resolveManagedBin: () => binPath,
80
81
  runCommand: (_projectRoot, command, args) => {
81
82
  calls.push({ args, command });
82
- return Promise.resolve({ exitCode: 0, stdout: calls.length === 1 ? '{"initialized":false}' : "", timedOut: false });
83
+ mkdirSync(join(workspace, ".codegraph"), { recursive: true });
84
+ writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "fixture");
85
+ return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
83
86
  },
84
87
  },
85
88
  });
86
89
 
87
90
  // then
88
91
  expect(result).toEqual({ action: "initialized" });
89
- expect(calls).toEqual([
90
- { args: ["status", "--json"], command: binPath },
91
- { args: ["init"], command: binPath },
92
- ]);
92
+ expect(calls).toEqual([{ args: ["init"], command: binPath }]);
93
93
  expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "provisioned", timedOut: false }]);
94
94
  } finally {
95
95
  rmSync(workspace, { recursive: true, force: true });
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
7
7
  import { runCodegraphServe } from "../src/serve.ts";
8
8
  import {
9
9
  arrayProperty,
10
- CODEGRAPH_141_DEFAULT_TOOLS,
10
+ CODEGRAPH_150_DEFAULT_TOOLS,
11
11
  findTool,
12
12
  frameMcpRequest,
13
13
  parseMcpBodies,
@@ -87,14 +87,14 @@ describe("runCodegraphServe MCP protocol bridge", () => {
87
87
  result: {
88
88
  capabilities: { tools: { listChanged: false } },
89
89
  protocolVersion: "2025-06-18",
90
- serverInfo: { name: "codegraph", version: "1.4.1" },
90
+ serverInfo: { name: "codegraph", version: "1.5.0" },
91
91
  },
92
92
  },
93
93
  {
94
94
  id: 2,
95
95
  jsonrpc: "2.0",
96
96
  result: {
97
- tools: CODEGRAPH_141_DEFAULT_TOOLS,
97
+ tools: CODEGRAPH_150_DEFAULT_TOOLS,
98
98
  },
99
99
  },
100
100
  ]);
@@ -48,7 +48,7 @@ describe("runCodegraphServe MCP unavailable facade", () => {
48
48
  result: {
49
49
  capabilities: { tools: { listChanged: false } },
50
50
  protocolVersion: "2025-06-18",
51
- serverInfo: { name: "codegraph", version: "1.4.1" },
51
+ serverInfo: { name: "codegraph", version: "1.5.0" },
52
52
  },
53
53
  });
54
54
  });