oh-my-opencode 4.19.0 → 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 (310) 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 +5 -3
  10. package/dist/agents/explore.d.ts +4 -2
  11. package/dist/agents/gpt-prompt-identity.d.ts +3 -0
  12. package/dist/agents/hephaestus/agent.d.ts +4 -2
  13. package/dist/agents/librarian.d.ts +4 -2
  14. package/dist/agents/metis.d.ts +4 -2
  15. package/dist/agents/momus.d.ts +3 -2
  16. package/dist/agents/multimodal-looker.d.ts +4 -2
  17. package/dist/agents/oracle.d.ts +4 -2
  18. package/dist/agents/sisyphus/claude-opus-5.d.ts +33 -0
  19. package/dist/agents/sisyphus/gpt-5-5.d.ts +1 -1
  20. package/dist/agents/sisyphus/gpt-task-system-guide.d.ts +1 -0
  21. package/dist/agents/sisyphus/index.d.ts +2 -0
  22. package/dist/agents/sisyphus-agent-factory.d.ts +5 -2
  23. package/dist/agents/sisyphus-junior/agent.d.ts +4 -1
  24. package/dist/agents/sisyphus-junior/gpt-5-5.d.ts +2 -2
  25. package/dist/agents/types.d.ts +2 -2
  26. package/dist/cli/index.js +23577 -19269
  27. package/dist/cli-node/index.js +23577 -19269
  28. package/dist/config/schema/agent-names.d.ts +26 -26
  29. package/dist/config/schema/agent-overrides.d.ts +400 -400
  30. package/dist/config/schema/browser-automation.d.ts +2 -2
  31. package/dist/config/schema/categories.d.ts +36 -36
  32. package/dist/config/schema/codegraph.d.ts +2 -0
  33. package/dist/config/schema/commands.d.ts +2 -2
  34. package/dist/config/schema/dynamic-context-pruning.d.ts +1 -1
  35. package/dist/config/schema/experimental.d.ts +1 -1
  36. package/dist/config/schema/fallback-models.d.ts +25 -25
  37. package/dist/config/schema/hooks.d.ts +43 -43
  38. package/dist/config/schema/internal/permission.d.ts +9 -9
  39. package/dist/config/schema/keyword-detector.d.ts +6 -6
  40. package/dist/config/schema/oh-my-opencode-config.d.ts +404 -402
  41. package/dist/config/schema/tmux.d.ts +6 -6
  42. package/dist/create-hooks.d.ts +35 -35
  43. package/dist/features/background-agent/spawner/tmux-callback-invoker.d.ts +11 -0
  44. package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
  45. package/dist/features/claude-tasks/types.d.ts +4 -4
  46. package/dist/features/team-mode/team-runtime/shutdown-helpers.d.ts +1 -1
  47. package/dist/features/team-mode/team-runtime/shutdown-test-fixtures.d.ts +4 -4
  48. package/dist/features/team-mode/tools/lifecycle-test-fixture.d.ts +42 -42
  49. package/dist/features/tmux-subagent/environment-eligibility.d.ts +2 -0
  50. package/dist/features/tmux-subagent/index.d.ts +1 -0
  51. package/dist/features/tmux-subagent/tracked-session-state.d.ts +1 -0
  52. package/dist/features/tui-sidebar/snapshot-schema.d.ts +6 -6
  53. package/dist/help/schema/acp.d.ts +3 -3
  54. package/dist/help/schema/doctor.d.ts +4 -4
  55. package/dist/help/schema/status.d.ts +3 -3
  56. package/dist/hooks/codegraph-bootstrap/hook.d.ts +3 -2
  57. package/dist/hooks/goal/types.d.ts +5 -5
  58. package/dist/hooks/non-interactive-env/constants.d.ts +4 -1
  59. package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
  60. package/dist/hooks/start-work/notepad-scaffold.d.ts +10 -0
  61. package/dist/hooks/start-work/parse-user-request.d.ts +2 -0
  62. package/dist/hooks/start-work/worktree-block.d.ts +5 -0
  63. package/dist/index.js +27370 -21301
  64. package/dist/mcp/types.d.ts +3 -3
  65. package/dist/oh-my-opencode.schema.json +11 -0
  66. package/dist/plugin/chat-message/loop-commands.d.ts +1 -0
  67. package/dist/plugin/command-execute-before.d.ts +3 -3
  68. package/dist/plugin/hooks/create-core-hooks.d.ts +25 -25
  69. package/dist/shared/omo-process-sweep.d.ts +18 -0
  70. package/dist/shared/tmux/tmux-utils/environment.d.ts +1 -1
  71. package/dist/shared/tmux/tmux-utils.d.ts +1 -1
  72. package/dist/shared/typescript-native-source-parser.d.ts +7 -0
  73. package/dist/skills/coding-agent-sessions/SKILL.md +5 -2
  74. package/dist/skills/coding-agent-sessions/references/all-platforms.md +3 -1
  75. package/dist/skills/coding-agent-sessions/references/senpi.md +15 -5
  76. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
  77. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
  78. package/dist/skills/debugging/SKILL.md +2 -1
  79. package/dist/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
  80. package/dist/skills/programming/SKILL.md +11 -1
  81. package/dist/skills/programming/references/logging.md +6 -1
  82. package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
  83. package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.ts +75 -11
  84. package/dist/skills/start-work/SKILL.md +12 -2
  85. package/dist/skills/ulw-plan/SKILL.md +21 -2
  86. package/dist/skills/ulw-plan/references/full-workflow.md +12 -1
  87. package/dist/skills/ulw-plan/references/intent-clear.md +1 -1
  88. package/dist/testing/create-plugin-module.d.ts +1 -0
  89. package/dist/tools/task/types.d.ts +10 -10
  90. package/dist/tui.js +23442 -19182
  91. package/package.json +14 -14
  92. package/packages/git-bash-mcp/dist/cli.js +54 -8
  93. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +62 -2
  94. package/packages/lsp-core/src/lsp/client.ts +14 -1
  95. package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +2 -2
  96. package/packages/lsp-core/src/mcp.ts +9 -0
  97. package/packages/lsp-daemon/dist/cli.js +319 -51
  98. package/packages/lsp-daemon/dist/client.js +136 -48
  99. package/packages/lsp-daemon/dist/daemon-client.d.ts +0 -10
  100. package/packages/lsp-daemon/dist/daemon-client.js +4 -34
  101. package/packages/lsp-daemon/dist/daemon-failure-result.d.ts +3 -0
  102. package/packages/lsp-daemon/dist/daemon-failure-result.js +38 -0
  103. package/packages/lsp-daemon/dist/daemon-request-error.d.ts +14 -0
  104. package/packages/lsp-daemon/dist/daemon-request-error.js +26 -0
  105. package/packages/lsp-daemon/dist/daemon-server.js +5 -1
  106. package/packages/lsp-daemon/dist/index.js +137 -48
  107. package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
  108. package/packages/lsp-daemon/dist/proxy.js +1 -0
  109. package/packages/lsp-daemon/dist/version-reap.d.ts +26 -0
  110. package/packages/lsp-daemon/dist/version-reap.js +182 -0
  111. package/packages/lsp-tools-mcp/dist/cli.js +61 -10
  112. package/packages/lsp-tools-mcp/dist/lsp/manager.js +6 -1
  113. package/packages/lsp-tools-mcp/dist/mcp.js +61 -10
  114. package/packages/lsp-tools-mcp/dist/tools.js +6 -1
  115. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  116. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +72 -12
  117. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  118. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  119. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +22 -2
  120. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +779 -385
  121. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +302 -173
  122. package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
  123. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +3 -1
  124. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +23 -42
  125. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +98 -32
  126. package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +5 -0
  127. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +17 -9
  128. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +18 -25
  129. package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +1 -0
  130. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +5 -0
  131. package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +176 -0
  132. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +6 -1
  133. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +31 -2
  134. package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +1 -1
  135. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +6 -0
  136. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +65 -1
  137. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +3 -7
  138. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +2 -1
  139. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +57 -3
  140. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +42 -0
  141. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +122 -10
  142. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +2 -2
  143. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +101 -64
  144. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  145. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  146. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  147. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  148. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  149. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  150. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  151. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +80 -40
  152. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  153. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  154. package/packages/omo-codex/plugin/components/rules/dist/cli.js +11 -0
  155. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  156. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  157. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +11 -0
  158. package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +60 -0
  159. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +1 -1
  160. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  161. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  162. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  163. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  164. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  165. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  166. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +2 -2
  167. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
  168. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
  169. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +1 -1
  170. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +2 -2
  171. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +1 -1
  172. package/packages/omo-codex/plugin/components/ultrawork/directive.md +12 -7
  173. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +1 -1
  174. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  175. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  176. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +12 -7
  177. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +21 -2
  178. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +12 -1
  179. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +1 -1
  180. package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +1 -1
  181. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +42 -0
  182. package/packages/omo-codex/plugin/components/ulw-loop/README.md +6 -4
  183. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +12 -7
  184. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.d.ts +21 -0
  185. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +64 -0
  186. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +15 -2
  187. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-arg-parser.js +1 -1
  188. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +2 -1
  189. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +1 -1
  190. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +3 -3
  191. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.d.ts +3 -0
  192. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +85 -0
  193. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +0 -1
  194. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -33
  195. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +998 -593
  196. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +1 -0
  197. package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.d.ts +1 -1
  198. package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.js +2 -0
  199. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +6 -0
  200. package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.d.ts +1 -0
  201. package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.js +3 -0
  202. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +1 -0
  203. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +4 -0
  204. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +1 -0
  205. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +10 -2
  206. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +1 -1
  207. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.d.ts +15 -0
  208. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.js +84 -0
  209. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.d.ts +5 -0
  210. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.js +81 -0
  211. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +7 -59
  212. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +12 -4
  213. package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.d.ts +9 -0
  214. package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.js +122 -0
  215. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  216. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  217. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +2 -1
  218. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +8 -6
  219. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +84 -0
  220. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +13 -2
  221. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-arg-parser.ts +1 -1
  222. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +1 -1
  223. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +3 -3
  224. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +49 -0
  225. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +13 -45
  226. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +1 -0
  227. package/packages/omo-codex/plugin/components/ulw-loop/src/constants.ts +2 -0
  228. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +7 -0
  229. package/packages/omo-codex/plugin/components/ulw-loop/src/goal-status.ts +4 -0
  230. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +4 -1
  231. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +20 -2
  232. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +1 -1
  233. package/packages/omo-codex/plugin/components/ulw-loop/src/steering-batch.ts +125 -0
  234. package/packages/omo-codex/plugin/components/ulw-loop/src/steering-mutations.ts +59 -0
  235. package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +6 -58
  236. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +12 -4
  237. package/packages/omo-codex/plugin/components/ulw-loop/src/validation-batch.ts +122 -0
  238. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +76 -0
  239. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint-continuation.test.ts +111 -0
  240. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-batch.test.ts +67 -0
  241. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-validation-batch.test.ts +57 -0
  242. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +1 -0
  243. package/packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts +152 -0
  244. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +29 -0
  245. package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch-checkpoint.test.ts +147 -0
  246. package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch.test.ts +73 -0
  247. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  248. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  249. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  250. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  251. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  252. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  253. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  254. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  255. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  256. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  257. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  258. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +2 -2
  259. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  260. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +2 -2
  261. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  262. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +2 -2
  263. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  264. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  265. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  266. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  267. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  268. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  269. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  270. package/packages/omo-codex/plugin/package-lock.json +41 -41
  271. package/packages/omo-codex/plugin/package.json +1 -1
  272. package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +44 -0
  273. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +5 -2
  274. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +3 -1
  275. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +15 -5
  276. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
  277. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
  278. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -1
  279. package/packages/omo-codex/plugin/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
  280. package/packages/omo-codex/plugin/skills/programming/SKILL.md +11 -1
  281. package/packages/omo-codex/plugin/skills/programming/references/logging.md +6 -1
  282. package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +75 -11
  283. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +12 -2
  284. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +12 -7
  285. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +2 -1
  286. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +8 -6
  287. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +21 -2
  288. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +12 -1
  289. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +1 -1
  290. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +9 -9
  291. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +26 -0
  292. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +41 -0
  293. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +22 -0
  294. package/packages/omo-codex/scripts/install-dist/install-local.mjs +49 -5
  295. package/packages/omo-codex/scripts/install-marketplace-cache.test.mjs +4 -1
  296. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +5 -2
  297. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +3 -1
  298. package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +15 -5
  299. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
  300. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
  301. package/packages/shared-skills/skills/debugging/SKILL.md +2 -1
  302. package/packages/shared-skills/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
  303. package/packages/shared-skills/skills/programming/SKILL.md +11 -1
  304. package/packages/shared-skills/skills/programming/references/logging.md +6 -1
  305. package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
  306. package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +75 -11
  307. package/packages/shared-skills/skills/start-work/SKILL.md +12 -2
  308. package/packages/shared-skills/skills/ulw-plan/SKILL.md +21 -2
  309. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +12 -1
  310. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-codegraph",
3
- "version": "4.19.0",
3
+ "version": "4.19.2",
4
4
  "description": "Codex plugin MCP wrapper for CodeGraph.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -25,7 +25,7 @@
25
25
  "typescript": "^6.0.3"
26
26
  },
27
27
  "optionalDependencies": {
28
- "@colbymchenry/codegraph": "1.0.1"
28
+ "@colbymchenry/codegraph": "1.4.1"
29
29
  },
30
30
  "engines": {
31
31
  "node": ">=20.0.0"
@@ -1,6 +1,7 @@
1
1
  import type { Readable } from "node:stream";
2
2
 
3
3
  import type { CodexOmoConfig as SharedCodexOmoConfig } from "../../../shared/src/config-loader.ts";
4
+ import type { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
4
5
  import type { SweepCodegraphZombiesOptions } from "../../../../../utils/src/codegraph/process-sweep.ts";
5
6
  import type { CodegraphProvisionResult as SharedCodegraphProvisionResult } from "../../../../../utils/src/codegraph/provision.ts";
6
7
  import type {
@@ -58,7 +59,7 @@ export interface CodegraphSessionStartOutcome {
58
59
 
59
60
  export interface CodegraphSessionStartDeps {
60
61
  readonly ensureGitignored: (projectRoot: string) => boolean;
61
- readonly ensureProvisioned: (options: { readonly installDir?: string; readonly lockDir: string; readonly version: "1.0.1" }) => Promise<CodegraphProvisionResult>;
62
+ readonly ensureProvisioned: (options: { readonly installDir?: string; readonly lockDir: string; readonly version: typeof CODEGRAPH_PINNED_VERSION }) => Promise<CodegraphProvisionResult>;
62
63
  readonly prepareWorkspace: (projectRoot: string, options: { readonly homeDir: string }) => CodegraphWorkspacePreparation;
63
64
  readonly resolveCommand: (options?: ResolveCodegraphCommandOptions) => CodegraphCommandResolution;
64
65
  readonly runCommand: (
@@ -76,6 +77,7 @@ export interface SessionStartHookOptions {
76
77
  readonly env?: Record<string, string | undefined>;
77
78
  readonly spawnWorker?: (invocation: WorkerSpawnInvocation) => void;
78
79
  readonly statusProbe?: (options: {
80
+ readonly daemon: boolean;
79
81
  readonly env: Record<string, string | undefined>;
80
82
  readonly homeDir: string;
81
83
  readonly projectRoot: string;
@@ -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,7 +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)({
92
+ daemon: config.codegraph?.daemon !== false,
90
93
  env,
91
94
  homeDir,
92
95
  projectRoot,
@@ -110,6 +113,7 @@ export async function executeCodegraphSessionStartHook(options: SessionStartHook
110
113
  }
111
114
 
112
115
  async function isCodegraphProjectInitialized(options: {
116
+ readonly daemon: boolean;
113
117
  readonly env: Record<string, string | undefined>;
114
118
  readonly homeDir: string;
115
119
  readonly projectRoot: string;
@@ -124,7 +128,7 @@ async function isCodegraphProjectInitialized(options: {
124
128
 
125
129
  const invocation = resolveCodegraphCommandInvocation(resolved.command, [...resolved.argsPrefix, "status", "--json"]);
126
130
  const codegraphEnv = {
127
- ...buildCodegraphEnv({ homeDir: options.homeDir }),
131
+ ...buildCodegraphEnv({ daemon: options.daemon, homeDir: options.homeDir }),
128
132
  ...(options.trustedCodegraphInstallDir === undefined ? {} : { CODEGRAPH_INSTALL_DIR: options.trustedCodegraphInstallDir }),
129
133
  };
130
134
  const status = await runStatusProbe(
@@ -143,27 +147,14 @@ function runStatusProbe(
143
147
  args: readonly string[],
144
148
  env: Record<string, string>,
145
149
  ): Promise<{ readonly exitCode: number; readonly stdout: string; readonly timedOut: boolean }> {
146
- return new Promise((resolveProbe) => {
147
- execFile(
148
- command,
149
- [...args],
150
- {
151
- cwd: projectRoot,
152
- encoding: "utf8",
153
- env,
154
- maxBuffer: 1024 * 1024,
155
- timeout: STATUS_PROBE_TIMEOUT_MS,
156
- windowsHide: true,
157
- },
158
- (error, stdout) => {
159
- if (error === null) {
160
- resolveProbe({ exitCode: 0, stdout: toOutputText(stdout), timedOut: false });
161
- return;
162
- }
163
- resolveProbe({ exitCode: resolveExitCode(error), stdout: toOutputText(stdout), timedOut: error.killed === true });
164
- },
165
- );
166
- });
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 }));
167
158
  }
168
159
 
169
160
  function codegraphStatusSaysInitialized(stdout: string): boolean {
@@ -178,8 +169,7 @@ function codegraphStatusSaysInitialized(stdout: string): boolean {
178
169
  }
179
170
 
180
171
  function provisionedBinFromInstallDir(installDir: string | undefined): string | null {
181
- if (installDir === undefined) return null;
182
- return join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
172
+ return resolvePinnedCodegraphBin(installDir);
183
173
  }
184
174
 
185
175
  export async function executeCodegraphPostToolUseHook(options: PostToolUseHookOptions = {}): Promise<PostToolUseHookResult> {
@@ -231,15 +221,6 @@ function resolveHomeDir(env: Record<string, string | undefined>): string {
231
221
  return env["HOME"] ?? env["USERPROFILE"] ?? homedir();
232
222
  }
233
223
 
234
- function resolveExitCode(error: Error): number {
235
- if ("code" in error && typeof error.code === "number") return error.code;
236
- return 1;
237
- }
238
-
239
- function toOutputText(value: string | Buffer): string {
240
- return Buffer.isBuffer(value) ? value.toString("utf8") : value;
241
- }
242
-
243
224
  function resolveProjectRoot(input: unknown, fallback: string): string {
244
225
  if (!isRecord(input)) return fallback;
245
226
  const cwd = input["cwd"];
@@ -1,7 +1,8 @@
1
- import { spawn } from "node:child_process";
1
+ import { spawn, type ChildProcess } from "node:child_process";
2
2
  import type { Readable, Writable } from "node:stream";
3
3
 
4
4
  import {
5
+ createParentWatchdog,
5
6
  errorResponse,
6
7
  isPlainRecord,
7
8
  jsonRpcId,
@@ -35,6 +36,8 @@ const CODEGRAPH_NODE_INCLUDE_CODE_DESCRIPTION =
35
36
  const CODEGRAPH_CONTAINER_OUTLINE_GUIDANCE =
36
37
  "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.";
37
38
 
39
+ const SIGKILL_ESCALATION_MS = 2_000;
40
+
38
41
  export async function runBridgedCodegraphProcess(
39
42
  command: string,
40
43
  args: readonly string[],
@@ -63,22 +66,45 @@ export async function runBridgedCodegraphProcess(
63
66
  resolveExit(signal === null ? 0 : 1);
64
67
  });
65
68
  });
66
- const clientForwardingDone = forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
67
- defaultResponseMode = mode;
69
+ const destroyChildPipes = (): void => {
70
+ childInput.destroy();
71
+ childOutput.destroy();
72
+ };
73
+ void childExit.then(destroyChildPipes, destroyChildPipes);
74
+ // Parent-liveness watchdog: when the parent dies while holding our stdio
75
+ // open, the client stream never sees EOF, so the only settle path is to
76
+ // drop the client input, close the child pipes, and terminate the child.
77
+ // The bridge then resolves through the normal child-exit path, and the
78
+ // destroyed input releases its read handle so the process can actually
79
+ // exit (same teardown pattern as runJsonRpcStdioServer's own watchdog).
80
+ // In daemon mode the child is the upstream lightweight proxy, so killing
81
+ // it on parent death is correct; the detached daemon is a separate process
82
+ // and is never touched.
83
+ let parentWatchdogFired = false;
84
+ const parentWatchdog = createParentWatchdog(options.parentWatchdog, () => {
85
+ parentWatchdogFired = true;
86
+ options.input.destroy();
87
+ destroyChildPipes();
88
+ terminateCodegraphChild(child);
68
89
  });
90
+ const clientForwardingDone = forwardClientToCodegraph(
91
+ options.input,
92
+ childInput,
93
+ pendingResponses,
94
+ (mode) => {
95
+ defaultResponseMode = mode;
96
+ },
97
+ () => parentWatchdogFired,
98
+ );
69
99
  const responseForwardingDone = forwardCodegraphToClient(
70
100
  childOutput,
71
101
  options.output,
72
102
  pendingResponses,
73
103
  () => defaultResponseMode,
104
+ () => parentWatchdogFired,
74
105
  );
75
106
  const bridgeDone = Promise.all([clientForwardingDone, responseForwardingDone]);
76
107
  const childAndResponsesDone = Promise.all([childExit, responseForwardingDone]).then(([exitCode]) => exitCode);
77
- const destroyChildPipes = (): void => {
78
- childInput.destroy();
79
- childOutput.destroy();
80
- };
81
- void childExit.then(destroyChildPipes, destroyChildPipes);
82
108
  try {
83
109
  return await Promise.race([childAndResponsesDone, bridgeDone.then(() => childExit)]);
84
110
  } catch (error) {
@@ -86,32 +112,64 @@ export async function runBridgedCodegraphProcess(
86
112
  if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
87
113
  await childExit.catch(() => undefined);
88
114
  throw error;
115
+ } finally {
116
+ parentWatchdog.clear();
89
117
  }
90
118
  }
91
119
 
120
+ function terminateCodegraphChild(child: ChildProcess): void {
121
+ if (child.exitCode !== null || child.signalCode !== null) return;
122
+ child.kill("SIGTERM");
123
+ const escalation = setTimeout(() => {
124
+ if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
125
+ }, SIGKILL_ESCALATION_MS);
126
+ escalation.unref();
127
+ }
128
+
129
+ // Stream errors raised by the watchdog's own teardown (input destroy, child
130
+ // pipe destroy) while a forwarder is parked on that stream.
131
+ function isWatchdogTeardownError(error: unknown): boolean {
132
+ if (!(error instanceof Error) || !("code" in error)) return false;
133
+ return (
134
+ error.code === "ERR_STREAM_PREMATURE_CLOSE" ||
135
+ error.code === "ERR_STREAM_DESTROYED" ||
136
+ error.code === "ERR_STREAM_WRITE_AFTER_END" ||
137
+ error.code === "EPIPE"
138
+ );
139
+ }
140
+
92
141
  async function forwardClientToCodegraph(
93
142
  input: Readable,
94
143
  childInput: Writable,
95
144
  pendingResponses: Map<string, PendingClientResponse>,
96
145
  setDefaultResponseMode: (mode: StdioJsonRpcResponseMode) => void,
146
+ tolerateWatchdogClose: () => boolean,
97
147
  ): Promise<void> {
98
- for await (const message of readStdioJsonRpcMessages(input)) {
99
- if (message.kind === "parse_error") {
100
- continue;
101
- }
102
- const responseMode = message.responseMode;
103
- setDefaultResponseMode(responseMode);
104
- const key = responseModeKey(message.payload);
105
- if (key !== null) {
106
- pendingResponses.set(key, {
107
- method: jsonRpcMethod(message.payload),
108
- responseMode,
109
- toolName: jsonRpcToolName(message.payload),
110
- });
148
+ try {
149
+ for await (const message of readStdioJsonRpcMessages(input)) {
150
+ if (message.kind === "parse_error") {
151
+ continue;
152
+ }
153
+ const responseMode = message.responseMode;
154
+ setDefaultResponseMode(responseMode);
155
+ const key = responseModeKey(message.payload);
156
+ if (key !== null) {
157
+ pendingResponses.set(key, {
158
+ method: jsonRpcMethod(message.payload),
159
+ responseMode,
160
+ toolName: jsonRpcToolName(message.payload),
161
+ });
162
+ }
163
+ await writeLine(childInput, JSON.stringify(message.payload));
111
164
  }
112
- await writeLine(childInput, JSON.stringify(message.payload));
165
+ childInput.end();
166
+ } catch (error) {
167
+ // The parent watchdog destroys the client input and child pipes while
168
+ // this forwarder is parked on a read or write; that teardown is
169
+ // self-inflicted, so settle quietly and let the child-exit path report
170
+ // the outcome.
171
+ if (!(tolerateWatchdogClose() && isWatchdogTeardownError(error))) throw error;
113
172
  }
114
- childInput.end();
115
173
  }
116
174
 
117
175
  async function forwardCodegraphToClient(
@@ -119,17 +177,25 @@ async function forwardCodegraphToClient(
119
177
  output: Writable,
120
178
  pendingResponses: Map<string, PendingClientResponse>,
121
179
  defaultResponseMode: () => StdioJsonRpcResponseMode,
180
+ tolerateWatchdogClose: () => boolean,
122
181
  ): Promise<void> {
123
- for await (const message of readStdioJsonRpcMessages(childOutput)) {
124
- if (message.kind === "parse_error") {
125
- await writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
126
- continue;
182
+ try {
183
+ for await (const message of readStdioJsonRpcMessages(childOutput)) {
184
+ if (message.kind === "parse_error") {
185
+ await writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
186
+ continue;
187
+ }
188
+ const key = responseModeKey(message.payload);
189
+ const pendingResponse = key === null ? undefined : pendingResponses.get(key);
190
+ const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
191
+ if (key !== null) pendingResponses.delete(key);
192
+ await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
127
193
  }
128
- const key = responseModeKey(message.payload);
129
- const pendingResponse = key === null ? undefined : pendingResponses.get(key);
130
- const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
131
- if (key !== null) pendingResponses.delete(key);
132
- await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
194
+ } catch (error) {
195
+ // The parent watchdog destroys the child pipes while this forwarder is
196
+ // parked on a read; that close is self-inflicted, so settle quietly and
197
+ // let the child-exit path report the outcome.
198
+ if (!(tolerateWatchdogClose() && isWatchdogTeardownError(error))) throw error;
133
199
  }
134
200
  }
135
201
 
@@ -7,6 +7,7 @@ import {
7
7
  runJsonRpcStdioServer,
8
8
  successResponse,
9
9
  type JsonRpcResponse,
10
+ type ParentWatchdogConfig,
10
11
  } from "../../../../../mcp-stdio-core/src/index.ts";
11
12
 
12
13
  export interface UnavailableCodegraphMcpOptions {
@@ -14,6 +15,9 @@ export interface UnavailableCodegraphMcpOptions {
14
15
  readonly output: Writable;
15
16
  readonly reason: string;
16
17
  readonly serverVersion: string;
18
+ // Test seam: production callers leave this unset so the watchdog uses its
19
+ // defaults (parentPid = process.ppid, 30s poll).
20
+ readonly parentWatchdog?: ParentWatchdogConfig;
17
21
  }
18
22
 
19
23
  interface UnavailableCodegraphMcpHandlerOptions {
@@ -32,6 +36,7 @@ export async function runUnavailableCodegraphMcpServer(
32
36
  },
33
37
  input: options.input,
34
38
  output: options.output,
39
+ parentWatchdog: options.parentWatchdog ?? {},
35
40
  });
36
41
  }
37
42
 
@@ -13,10 +13,12 @@ import type { Readable, Writable } from "node:stream";
13
13
  import { fileURLToPath } from "node:url";
14
14
 
15
15
  import {
16
- CODEGRAPH_NO_DAEMON_ENV,
17
16
  buildCodegraphChildEnv,
18
17
  buildCodegraphEnv,
19
18
  } from "../../../../../utils/src/codegraph/env.ts";
19
+ import { resolvePinnedCodegraphBin } from "../../../../../utils/src/codegraph/managed-runtime.ts";
20
+ import type { ParentWatchdogConfig } from "../../../../../mcp-stdio-core/src/index.ts";
21
+ import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
20
22
  import {
21
23
  buildCodegraphNodeSkipHint,
22
24
  evaluateCodegraphNodeSupport,
@@ -48,6 +50,7 @@ export interface CodegraphServeProcessOptions {
48
50
  readonly output: Writable;
49
51
  readonly stderr: CodegraphServeStderr;
50
52
  readonly stdio: ServeStdio;
53
+ readonly parentWatchdog?: ParentWatchdogConfig;
51
54
  }
52
55
 
53
56
  export type CodegraphServeProcessRunner = (
@@ -64,7 +67,7 @@ export interface CodegraphServeStderr {
64
67
  }
65
68
 
66
69
  export interface RunCodegraphServeOptions {
67
- readonly buildEnv?: (options: { readonly homeDir: string }) => Record<string, string>;
70
+ readonly buildEnv?: (options: { readonly daemon: boolean; readonly homeDir: string }) => Record<string, string>;
68
71
  readonly commandExists?: (filePath: string) => boolean;
69
72
  readonly config?: CodexOmoConfig;
70
73
  readonly cwd?: string;
@@ -77,6 +80,10 @@ export interface RunCodegraphServeOptions {
77
80
  readonly runProcess?: CodegraphServeProcessRunner;
78
81
  readonly stderr?: CodegraphServeStderr;
79
82
  readonly ensureProvisioned?: CodegraphProvisioner;
83
+ // Test seam: production callers leave this unset so the bridge and the
84
+ // unavailable facade use the watchdog defaults (parentPid = process.ppid,
85
+ // 30s poll).
86
+ readonly parentWatchdog?: ParentWatchdogConfig;
80
87
  }
81
88
 
82
89
  const CODEGRAPH_SKIP_HINT =
@@ -84,7 +91,7 @@ const CODEGRAPH_SKIP_HINT =
84
91
  const CODEGRAPH_DISABLED_HINT =
85
92
  "CodeGraph MCP skipped: disabled by OMO SOT config. Set [codex].codegraph.enabled=true to enable it.\n";
86
93
  const CODEGRAPH_EXCLUDED_HINT = "CodeGraph MCP skipped: project excluded by OMO CodeGraph policy.\n";
87
- const CODEGRAPH_VERSION = "1.0.1";
94
+ const CODEGRAPH_VERSION = CODEGRAPH_PINNED_VERSION;
88
95
  const PROJECT_CWD_ENV_KEYS = ["OMO_CODEGRAPH_PROJECT_CWD", SESSION_START_CWD_ENV, "PWD"] as const;
89
96
 
90
97
  export async function runCodegraphServe(options: RunCodegraphServeOptions = {}): Promise<number> {
@@ -136,7 +143,7 @@ export async function runCodegraphServe(options: RunCodegraphServeOptions = {}):
136
143
  }
137
144
 
138
145
  const runProcess = options.runProcess ?? runBridgedCodegraphProcess;
139
- const codegraphEnv = codegraphEnvForConfig(trustedInstallDir, homeDir, options.buildEnv);
146
+ const codegraphEnv = codegraphEnvForConfig(trustedInstallDir, homeDir, codegraphConfig.daemon !== false, options.buildEnv);
140
147
  const mergedEnv = buildCodegraphChildEnv({ ambientEnv: env, codegraphEnv, runtimeEnv: env });
141
148
  return runProcess(resolution.command, [...resolution.argsPrefix, "serve", "--mcp"], {
142
149
  cwd: projectCwd,
@@ -145,6 +152,7 @@ export async function runCodegraphServe(options: RunCodegraphServeOptions = {}):
145
152
  output: options.stdout ?? processStdout,
146
153
  stderr: options.stderr ?? processStderr,
147
154
  stdio: "pipe",
155
+ parentWatchdog: options.parentWatchdog ?? {},
148
156
  });
149
157
  }
150
158
 
@@ -155,6 +163,7 @@ async function runUnavailableMcp(reason: string, options: RunCodegraphServeOptio
155
163
  output: options.stdout ?? processStdout,
156
164
  reason,
157
165
  serverVersion: CODEGRAPH_VERSION,
166
+ parentWatchdog: options.parentWatchdog ?? {},
158
167
  });
159
168
  return 0;
160
169
  }
@@ -195,9 +204,10 @@ function looksLikePath(command: string): boolean {
195
204
  function codegraphEnvForConfig(
196
205
  trustedInstallDir: string | undefined,
197
206
  homeDir: string,
198
- buildEnv: ((options: { readonly homeDir: string }) => Record<string, string>) | undefined,
207
+ daemon: boolean,
208
+ buildEnv: ((options: { readonly daemon: boolean; readonly homeDir: string }) => Record<string, string>) | undefined,
199
209
  ): Record<string, string> {
200
- const env = { ...(buildEnv?.({ homeDir }) ?? buildCodegraphEnv({ homeDir })), [CODEGRAPH_NO_DAEMON_ENV]: "1" };
210
+ const env = buildEnv?.({ daemon, homeDir }) ?? buildCodegraphEnv({ daemon, homeDir });
201
211
  return trustedInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: trustedInstallDir };
202
212
  }
203
213
 
@@ -212,9 +222,7 @@ function resolveProjectCwd(env: Record<string, string | undefined>, fallback: st
212
222
  }
213
223
 
214
224
  function provisionedBinFromInstallDir(installDir: string | undefined): string | null {
215
- if (installDir === undefined) return null;
216
- const candidate = join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
217
- return existsSync(candidate) ? candidate : null;
225
+ return resolvePinnedCodegraphBin(installDir);
218
226
  }
219
227
 
220
228
  export async function runCodegraphServeCli(): Promise<void> {
@@ -1,11 +1,12 @@
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
+ import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
9
10
  import { evaluateCodegraphNodeSupport, type CodegraphNodeSupport } from "../../../../../utils/src/codegraph/node-support.ts";
10
11
  import { ensureCodegraphProvisioned } from "../../../../../utils/src/codegraph/provision.ts";
11
12
  import {
@@ -14,6 +15,7 @@ import {
14
15
  type CodegraphCommandResolution,
15
16
  } from "../../../../../utils/src/codegraph/resolve.ts";
16
17
  import { ensureCodegraphGitignored, prepareCodegraphWorkspace } from "../../../../../utils/src/codegraph/workspace.ts";
18
+ import { runProcessWithTreeTimeout } from "../../../../../utils/src/process-tree.ts";
17
19
  import type {
18
20
  CodegraphCommandResult,
19
21
  CodegraphConfig,
@@ -25,7 +27,7 @@ import type {
25
27
 
26
28
  export const SESSION_START_CWD_ENV = "OMO_CODEGRAPH_SESSION_START_CWD";
27
29
 
28
- const CODEGRAPH_VERSION = "1.0.1";
30
+ const CODEGRAPH_VERSION = CODEGRAPH_PINNED_VERSION;
29
31
  const COMMAND_TIMEOUT_MS = 60_000;
30
32
  const WINDOWS_CMD_EXTENSIONS = new Set([".bat", ".cmd"]);
31
33
  const WINDOWS_NODE_SCRIPT_EXTENSIONS = new Set([".cjs", ".js", ".mjs"]);
@@ -127,7 +129,10 @@ async function resolveOrProvisionCommand(
127
129
  }
128
130
 
129
131
  function codegraphEnvForConfig(config: CodegraphBootstrapConfig, homeDir: string): Record<string, string> {
130
- const env = buildCodegraphEnv({ homeDir });
132
+ // The detached indexing worker must NEVER engage the upstream daemon, even
133
+ // when the user opted into daemon mode for interactive MCP sessions: a
134
+ // daemon-backed init/sync would outlive and race the worker's lifecycle.
135
+ const env = buildCodegraphEnv({ daemon: false, homeDir });
131
136
  return config.trustedCodegraphInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: config.trustedCodegraphInstallDir };
132
137
  }
133
138
 
@@ -160,15 +165,14 @@ function jsonSaysInitialized(value: unknown): boolean | undefined {
160
165
 
161
166
  async function runCodegraphCommand(projectRoot: string, command: string, args: readonly string[], options: { readonly env: Record<string, string>; readonly timeoutMs: number }): Promise<CodegraphCommandResult> {
162
167
  const invocation = resolveCodegraphCommandInvocation(command, args);
163
- return new Promise((resolvePromise) => {
164
- 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) => {
165
- if (error === null) {
166
- resolvePromise({ exitCode: 0, stderr: toOutputText(stderr), stdout: toOutputText(stdout), timedOut: false });
167
- return;
168
- }
169
- resolvePromise({ exitCode: resolveExitCode(error), stderr: toOutputText(stderr), stdout: toOutputText(stdout), timedOut: error.killed === true });
170
- });
171
- });
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 }));
172
176
  }
173
177
 
174
178
  export function resolveCodegraphCommandInvocation(
@@ -199,18 +203,7 @@ function safeLogOutcome(logOutcome: (outcome: CodegraphSessionStartOutcome) => v
199
203
  }
200
204
 
201
205
  function provisionedBinFromInstallDir(installDir: string | undefined): string | null {
202
- if (installDir === undefined) return null;
203
- const candidate = join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
204
- return existsSync(candidate) ? candidate : null;
205
- }
206
-
207
- function resolveExitCode(error: Error): number {
208
- if ("code" in error && typeof error.code === "number") return error.code;
209
- return 1;
210
- }
211
-
212
- function toOutputText(value: string | Buffer): string {
213
- return Buffer.isBuffer(value) ? value.toString("utf8") : value;
206
+ return resolvePinnedCodegraphBin(installDir);
214
207
  }
215
208
 
216
209
  function resolveHomeDir(env: Record<string, string | undefined>): string {
@@ -61,6 +61,7 @@ function writeSweepReport(stdout: HookStdout, result: SweepCodegraphZombiesResul
61
61
  failed: result.failed,
62
62
  killed: result.killed.map(formatProcess),
63
63
  ownedRoots: result.ownedRoots,
64
+ spared: result.spared.map(formatProcess),
64
65
  stampFile: result.stampFile,
65
66
  })}\n`);
66
67
  }
@@ -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 {