oh-my-opencode 4.18.0 → 4.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +3654 -0
  2. package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +3071 -0
  3. package/.agents/skills/work-with-pr/SKILL.md +16 -37
  4. package/.agents/skills/work-with-pr-workspace/evals/evals.json +3 -3
  5. package/.opencode/skills/work-with-pr/SKILL.md +16 -37
  6. package/.opencode/skills/work-with-pr-workspace/evals/evals.json +3 -3
  7. package/dist/cli/index.js +457 -154
  8. package/dist/cli-node/index.js +457 -154
  9. package/dist/index.js +415 -388
  10. package/package.json +16 -16
  11. package/packages/lsp-core/package.json +4 -0
  12. package/packages/lsp-core/src/index.ts +1 -0
  13. package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
  14. package/packages/lsp-core/src/lsp/cleanup-errors.ts +12 -3
  15. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +261 -0
  16. package/packages/lsp-core/src/lsp/client-wrapper.test.ts +63 -0
  17. package/packages/lsp-core/src/lsp/client-wrapper.ts +35 -5
  18. package/packages/lsp-core/src/lsp/client.ts +262 -80
  19. package/packages/lsp-core/src/lsp/config-loader.ts +5 -17
  20. package/packages/lsp-core/src/lsp/connection.ts +12 -6
  21. package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +104 -0
  22. package/packages/lsp-core/src/lsp/directory-diagnostics.ts +60 -27
  23. package/packages/lsp-core/src/lsp/errors.ts +11 -0
  24. package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
  25. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
  26. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +215 -0
  27. package/packages/lsp-core/src/lsp/formatters.ts +3 -0
  28. package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
  29. package/packages/lsp-core/src/lsp/json-rpc-connection.ts +73 -5
  30. package/packages/lsp-core/src/lsp/server-install-state.ts +3 -6
  31. package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
  32. package/packages/lsp-core/src/lsp/transport.ts +96 -70
  33. package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
  34. package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +214 -0
  35. package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
  36. package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +163 -0
  37. package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
  38. package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +67 -0
  39. package/packages/lsp-core/src/lsp/workspace-document-state.ts +368 -0
  40. package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +113 -0
  41. package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
  42. package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
  43. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
  44. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
  45. package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
  46. package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
  47. package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
  48. package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
  49. package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
  50. package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
  51. package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
  52. package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
  53. package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
  54. package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
  55. package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
  56. package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
  57. package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
  58. package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
  59. package/packages/lsp-core/src/lsp/workspace-edit.ts +49 -200
  60. package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
  61. package/packages/lsp-core/src/mcp.ts +18 -7
  62. package/packages/lsp-core/src/missing-dependency-result.test.ts +105 -0
  63. package/packages/lsp-core/src/missing-dependency-result.ts +57 -0
  64. package/packages/lsp-core/src/post-edit/index.ts +1 -0
  65. package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
  66. package/packages/lsp-core/src/post-edit/orchestration.ts +178 -0
  67. package/packages/lsp-core/src/request-context.test.ts +171 -0
  68. package/packages/lsp-core/src/request-context.ts +222 -9
  69. package/packages/lsp-core/src/tool-surface.test.ts +4 -1
  70. package/packages/lsp-core/src/tools/diagnostics.ts +32 -13
  71. package/packages/lsp-core/src/tools/navigation.ts +12 -12
  72. package/packages/lsp-core/src/tools/rename.ts +10 -15
  73. package/packages/lsp-core/src/tools/symbols.ts +11 -11
  74. package/packages/lsp-core/src/tools/types.ts +2 -1
  75. package/packages/lsp-daemon/dist/cli.js +3114 -747
  76. package/packages/lsp-daemon/dist/client.d.ts +105 -0
  77. package/packages/lsp-daemon/dist/client.js +5851 -0
  78. package/packages/lsp-daemon/dist/daemon-client.d.ts +11 -6
  79. package/packages/lsp-daemon/dist/daemon-client.js +113 -30
  80. package/packages/lsp-daemon/dist/daemon-server.d.ts +1 -0
  81. package/packages/lsp-daemon/dist/daemon-server.js +40 -15
  82. package/packages/lsp-daemon/dist/ensure-daemon.d.ts +8 -7
  83. package/packages/lsp-daemon/dist/ensure-daemon.js +67 -44
  84. package/packages/lsp-daemon/dist/index.d.ts +2 -2
  85. package/packages/lsp-daemon/dist/index.js +2862 -754
  86. package/packages/lsp-daemon/dist/ipc-protocol.d.ts +46 -0
  87. package/packages/lsp-daemon/dist/ipc-protocol.js +187 -0
  88. package/packages/lsp-daemon/dist/lock.js +14 -4
  89. package/packages/lsp-daemon/dist/ownership.d.ts +49 -0
  90. package/packages/lsp-daemon/dist/ownership.js +168 -0
  91. package/packages/lsp-daemon/dist/paths.d.ts +33 -9
  92. package/packages/lsp-daemon/dist/paths.js +72 -33
  93. package/packages/lsp-daemon/dist/proxy.d.ts +3 -0
  94. package/packages/lsp-daemon/dist/proxy.js +54 -3
  95. package/packages/lsp-daemon/dist/request-routing.d.ts +7 -2
  96. package/packages/lsp-daemon/dist/request-routing.js +71 -22
  97. package/packages/lsp-daemon/dist/run-daemon.js +9 -2
  98. package/packages/lsp-daemon/dist/runtime-contract.d.ts +21 -0
  99. package/packages/lsp-daemon/dist/runtime-contract.js +58 -0
  100. package/packages/lsp-daemon/dist/socket-jsonrpc.js +6 -1
  101. package/packages/lsp-daemon/package.json +12 -3
  102. package/packages/lsp-tools-mcp/dist/cli.js +2115 -442
  103. package/packages/lsp-tools-mcp/dist/lsp/manager.js +1741 -148
  104. package/packages/lsp-tools-mcp/dist/mcp.js +2127 -454
  105. package/packages/lsp-tools-mcp/dist/request-context.js +176 -6
  106. package/packages/lsp-tools-mcp/dist/tools.js +2118 -446
  107. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  108. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  109. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  110. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  111. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  112. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  113. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  114. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  115. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  116. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  117. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +55 -0
  118. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +2959 -944
  119. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook-cli.js +0 -4
  120. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.d.ts +5 -2
  121. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +41 -62
  122. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.d.ts +1 -1
  123. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +24 -15
  124. package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.d.ts +3 -7
  125. package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.js +23 -49
  126. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  127. package/packages/omo-codex/plugin/components/lsp/package.json +3 -2
  128. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.mjs +31 -1
  129. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.test.mjs +76 -0
  130. package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.mjs +201 -0
  131. package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.test.mjs +55 -0
  132. package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +0 -4
  133. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +49 -71
  134. package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +26 -15
  135. package/packages/omo-codex/plugin/components/lsp/src/lsp-session-state.ts +26 -64
  136. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +16 -17
  137. package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +30 -4
  138. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +19 -5
  139. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
  140. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +1 -1
  141. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  142. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  143. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +1 -1
  144. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  145. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  146. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  147. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  148. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  149. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  150. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  151. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  152. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  153. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  154. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +1 -1
  155. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +6 -5
  156. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  157. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  158. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  159. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  160. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  161. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  162. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  163. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  164. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  165. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  166. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  170. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  171. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  172. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  173. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  174. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  175. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  176. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  177. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  178. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  179. package/packages/omo-codex/plugin/package-lock.json +26 -14
  180. package/packages/omo-codex/plugin/package.json +1 -1
  181. package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +2 -3
  182. package/packages/omo-codex/plugin/scripts/build-components.mjs +13 -1
  183. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +1 -1
  184. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +1 -1
  185. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +1 -1
  186. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +6 -5
  187. package/packages/omo-codex/plugin/test/aggregate-build.test.mjs +8 -0
  188. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +128 -15
  189. package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +10 -0
  190. package/packages/omo-codex/plugin/test/lsp-prebuild-layouts.test.mjs +2 -0
  191. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
  192. package/packages/omo-codex/scripts/install-dist/install-local.mjs +328 -63
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook session-start",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.18.0) Loading Project Rules",
10
+ "statusMessage": "(OmO 4.18.1) Loading Project Rules",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook session-start"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/telemetry/dist/cli.js\" hook session-start",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.18.0) Recording Session Telemetry",
10
+ "statusMessage": "(OmO 4.18.1) Recording Session Telemetry",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\telemetry\\dist\\cli.js\" hook session-start"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.18.0) Checking Start-Work Continuation",
10
+ "statusMessage": "(OmO 4.18.1) Checking Start-Work Continuation",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\start-work-continuation\\dist\\cli.js\" hook stop"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.18.0) Checking Ulw-Loop Resume",
10
+ "statusMessage": "(OmO 4.18.1) Checking Ulw-Loop Resume",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook stop"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook subagent-stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.18.0) Checking Start-Work Continuation",
10
+ "statusMessage": "(OmO 4.18.1) Checking Start-Work Continuation",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\start-work-continuation\\dist\\cli.js\" hook subagent-stop"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/lazycodex-executor-verify/dist/cli.js\" hook subagent-stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.18.0) Verifying LazyCodex Executor Evidence",
10
+ "statusMessage": "(OmO 4.18.1) Verifying LazyCodex Executor Evidence",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lazycodex-executor-verify\\dist\\cli.js\" hook subagent-stop"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ultrawork/dist/cli.js\" hook user-prompt-submit",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.18.0) Checking Ultrawork Trigger",
10
+ "statusMessage": "(OmO 4.18.1) Checking Ultrawork Trigger",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ultrawork\\dist\\cli.js\" hook user-prompt-submit"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook user-prompt-submit",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.18.0) Checking Ulw-Loop Steering",
10
+ "statusMessage": "(OmO 4.18.1) Checking Ulw-Loop Steering",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook user-prompt-submit"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook user-prompt-submit",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.18.0) Loading Project Rules",
10
+ "statusMessage": "(OmO 4.18.1) Loading Project Rules",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook user-prompt-submit"
12
12
  }
13
13
  ]
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/omo-codex-plugin",
3
- "version": "4.18.0",
3
+ "version": "4.18.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sisyphuslabs/omo-codex-plugin",
9
- "version": "4.18.0",
9
+ "version": "4.18.1",
10
10
  "workspaces": [
11
11
  "components/codegraph",
12
12
  "components/comment-checker",
@@ -32,6 +32,13 @@
32
32
  "@oh-my-opencode/utils": "workspace:*"
33
33
  }
34
34
  },
35
+ "../../lsp-core": {
36
+ "name": "@oh-my-opencode/lsp-core",
37
+ "version": "0.1.0",
38
+ "dependencies": {
39
+ "@oh-my-opencode/mcp-stdio-core": "workspace:*"
40
+ }
41
+ },
35
42
  "../../lsp-daemon": {
36
43
  "name": "@code-yeongyu/lsp-daemon",
37
44
  "version": "0.1.0",
@@ -93,7 +100,7 @@
93
100
  },
94
101
  "components/codegraph": {
95
102
  "name": "@sisyphuslabs/codex-codegraph",
96
- "version": "4.18.0",
103
+ "version": "4.18.1",
97
104
  "bin": {
98
105
  "omo-codegraph": "dist/cli.js"
99
106
  },
@@ -112,7 +119,7 @@
112
119
  },
113
120
  "components/comment-checker": {
114
121
  "name": "@code-yeongyu/codex-comment-checker",
115
- "version": "4.18.0",
122
+ "version": "4.18.1",
116
123
  "license": "MIT",
117
124
  "bin": {
118
125
  "omo-comment-checker": "dist/cli.js"
@@ -133,7 +140,7 @@
133
140
  },
134
141
  "components/git-bash": {
135
142
  "name": "@sisyphuslabs/codex-git-bash-hook",
136
- "version": "4.18.0",
143
+ "version": "4.18.1",
137
144
  "bin": {
138
145
  "omo-git-bash-hook": "dist/cli.js"
139
146
  },
@@ -148,7 +155,7 @@
148
155
  },
149
156
  "components/lazycodex-executor-verify": {
150
157
  "name": "@code-yeongyu/codex-lazycodex-executor-verify",
151
- "version": "4.18.0",
158
+ "version": "4.18.1",
152
159
  "license": "MIT",
153
160
  "bin": {
154
161
  "lazycodex-executor-verify": "dist/cli.js"
@@ -165,10 +172,11 @@
165
172
  },
166
173
  "components/lsp": {
167
174
  "name": "@code-yeongyu/codex-lsp",
168
- "version": "4.18.0",
175
+ "version": "4.18.1",
169
176
  "license": "MIT",
170
177
  "dependencies": {
171
- "@code-yeongyu/lsp-daemon": "file:../../../../lsp-daemon"
178
+ "@code-yeongyu/lsp-daemon": "file:../../../../lsp-daemon",
179
+ "@oh-my-opencode/lsp-core": "file:../../../../lsp-core"
172
180
  },
173
181
  "bin": {
174
182
  "omo-lsp": "dist/cli.js"
@@ -185,7 +193,7 @@
185
193
  },
186
194
  "components/rules": {
187
195
  "name": "@code-yeongyu/codex-rules",
188
- "version": "4.18.0",
196
+ "version": "4.18.1",
189
197
  "license": "MIT",
190
198
  "dependencies": {
191
199
  "picomatch": "^4.0.3"
@@ -207,7 +215,7 @@
207
215
  },
208
216
  "components/start-work-continuation": {
209
217
  "name": "@code-yeongyu/codex-start-work-continuation",
210
- "version": "4.18.0",
218
+ "version": "4.18.1",
211
219
  "license": "MIT",
212
220
  "bin": {
213
221
  "omo-start-work-continuation": "dist/cli.js"
@@ -224,7 +232,7 @@
224
232
  },
225
233
  "components/teammode": {
226
234
  "name": "@sisyphuslabs/codex-teammode",
227
- "version": "4.18.0",
235
+ "version": "4.18.1",
228
236
  "devDependencies": {
229
237
  "@types/node": "^25.9.3",
230
238
  "bun-types": "^1.3.1",
@@ -237,7 +245,7 @@
237
245
  },
238
246
  "components/telemetry": {
239
247
  "name": "@code-yeongyu/codex-telemetry",
240
- "version": "4.18.0",
248
+ "version": "4.18.1",
241
249
  "license": "MIT",
242
250
  "bin": {
243
251
  "omo-telemetry": "dist/cli.js"
@@ -255,7 +263,7 @@
255
263
  },
256
264
  "components/ultrawork": {
257
265
  "name": "@code-yeongyu/codex-ultrawork",
258
- "version": "4.18.0",
266
+ "version": "4.18.1",
259
267
  "license": "MIT",
260
268
  "bin": {
261
269
  "omo-ultrawork": "dist/cli.js"
@@ -273,7 +281,7 @@
273
281
  },
274
282
  "components/ulw-loop": {
275
283
  "name": "@code-yeongyu/codex-ulw-loop",
276
- "version": "4.18.0",
284
+ "version": "4.18.1",
277
285
  "license": "MIT",
278
286
  "bin": {
279
287
  "omo-ulw-loop": "dist/cli.js",
@@ -663,6 +671,10 @@
663
671
  "resolved": "../../comment-checker-core",
664
672
  "link": true
665
673
  },
674
+ "node_modules/@oh-my-opencode/lsp-core": {
675
+ "resolved": "../../lsp-core",
676
+ "link": true
677
+ },
666
678
  "node_modules/@oh-my-opencode/prompts-core": {
667
679
  "resolved": "../../prompts-core",
668
680
  "link": true
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/omo-codex-plugin",
3
- "version": "4.18.0",
3
+ "version": "4.18.1",
4
4
  "description": "Aggregate Codex plugin root for OMO components.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -16,8 +16,7 @@ const runtimes = [
16
16
  {
17
17
  label: "lsp-daemon",
18
18
  packageRoot: join(repoPackagesRoot, "lsp-daemon"),
19
- requiredOutputs: ["dist/cli.js", "dist/index.js", "dist/index.d.ts"],
20
- install: true,
19
+ requiredOutputs: ["dist/cli.js", "dist/client.js", "dist/client.d.ts", "dist/index.js", "dist/index.d.ts"],
21
20
  },
22
21
  {
23
22
  label: "git-bash-mcp",
@@ -42,7 +41,7 @@ function buildRuntime(runtime) {
42
41
  return;
43
42
  }
44
43
 
45
- if (runtime.install === true && !existsSync(join(runtime.packageRoot, "node_modules"))) {
44
+ if (existsSync(join(runtime.packageRoot, "package-lock.json")) && !existsSync(join(runtime.packageRoot, "node_modules"))) {
46
45
  const install = spawnSync("npm", ["ci"], {
47
46
  cwd: runtime.packageRoot,
48
47
  shell: process.platform === "win32",
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from "node:child_process";
3
3
  import { availableParallelism } from "node:os";
4
- import { readdir, readFile, writeFile } from "node:fs/promises";
4
+ import { readdir, readFile, stat, writeFile } from "node:fs/promises";
5
5
  import { builtinModules } from "node:module";
6
6
  import { dirname, join } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
@@ -55,6 +55,7 @@ async function runTasksWithConcurrency(items, limit) {
55
55
 
56
56
  async function buildComponent(task) {
57
57
  await runCaptured(task.buildCommand, task.buildArgs, task.buildCwd, `Building ${task.componentPath}`);
58
+ if (await hasComponentOwnedBundle(task.componentPath)) return;
58
59
  await bundleCli(task.componentPath);
59
60
  }
60
61
 
@@ -84,6 +85,17 @@ async function bundleCli(workspace) {
84
85
  await normalizeBuiltinImports(output);
85
86
  }
86
87
 
88
+ async function hasComponentOwnedBundle(workspace) {
89
+ try {
90
+ const manifest = JSON.parse(await readFile(join(root, workspace, "dist", ".omo-runtime-manifest.json"), "utf8"));
91
+ const cli = await stat(join(root, workspace, "dist", "cli.js"));
92
+ return manifest?.schemaVersion === 1 && cli.isFile() && cli.size > 0;
93
+ } catch (error) {
94
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return false;
95
+ throw error;
96
+ }
97
+ }
98
+
87
99
  // Buffers each child's stdout/stderr and flushes it as one contiguous block so
88
100
  // concurrent builds never interleave, keeping a failing component's output readable.
89
101
  function runCaptured(command, args, cwd, label) {
@@ -132,7 +132,7 @@ const startWorkOriginalCompletion = `When all top-level checkboxes in \`## TODOs
132
132
  const startWorkCodexCompletion = `When all top-level checkboxes in \`## TODOs\` and \`## Final Verification Wave\` are complete:
133
133
 
134
134
  1. Run the plan's final verification commands.
135
- 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge:
135
+ 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge. The gate's pass binds to the commit SHA it reviewed and covers every later checkpoint at that same SHA — never re-run it on an already-passed SHA; re-run only when new commits land:
136
136
  - Invoke the \`review-work\` skill with the final diff, changed files, user goal, constraints, run command, and verification evidence. All five review lanes must return PASS. A timeout, missing deliverable, ack-only child, \`BLOCKED:\`, or inconclusive lane is a gate failure, not approval.
137
137
  - Run a debugging-oriented runtime audit even when the review passes: name at least three plausible failure hypotheses for the changed surface, run the distinguishing checks against the actual artifact, and append the ruled-out or confirmed result to \`.omo/start-work/ledger.jsonl\`.
138
138
  - If any review lane or debugging hypothesis fails, invoke the \`debugging\` skill, confirm root cause with runtime evidence, add the minimal failing test or reproduction, fix it, rerun the affected verification, then rerun the Global Review and Debugging Gate.
@@ -176,7 +176,7 @@ Only after verification passes:
176
176
  When all top-level checkboxes in `## TODOs` and `## Final Verification Wave` are complete:
177
177
 
178
178
  1. Run the plan's final verification commands.
179
- 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge:
179
+ 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge. The gate's pass binds to the commit SHA it reviewed and covers every later checkpoint at that same SHA — never re-run it on an already-passed SHA; re-run only when new commits land:
180
180
  - Invoke the `review-work` skill with the final diff, changed files, user goal, constraints, run command, and verification evidence. All five review lanes must return PASS. A timeout, missing deliverable, ack-only child, `BLOCKED:`, or inconclusive lane is a gate failure, not approval.
181
181
  - Run a debugging-oriented runtime audit even when the review passes: name at least three plausible failure hypotheses for the changed surface, run the distinguishing checks against the actual artifact, and append the ruled-out or confirmed result to `.omo/start-work/ledger.jsonl`.
182
182
  - If any review lane or debugging hypothesis fails, invoke the `debugging` skill, confirm root cause with runtime evidence, add the minimal failing test or reproduction, fix it, rerun the affected verification, then rerun the Global Review and Debugging Gate.
@@ -23,7 +23,7 @@ This skill is intentionally compact. The full workflow lives in `references/full
23
23
  - After any compaction or context loss, re-read brief + goals + ledger FIRST plus `omo ulw-loop status --json`, then resume; never re-plan from scratch.
24
24
  - If `omo ulw-loop create-goals` says the existing aggregate is already complete, start unrelated new work with a fresh `--session-id <new-id>` instead of steering or forcing the completed default state. Use `--force` only to intentionally overwrite completed evidence.
25
25
  - Every success criterion needs observable evidence from a real surface: a channel (terminal/TUI via the xterm.js web terminal, HTTP, browser, computer-use) or, for CLI- or data-shaped criteria, an auxiliary surface (CLI stdout, DB diff, parsed config dump).
26
- - Evidence is bound to its capture commit; a later fix, rebase, or merge makes it stale re-run at the current HEAD and re-record, never relabel or regenerate. Record only after cleanup receipts exist.
26
+ - Evidence is bound to the tree it was captured at (`git rev-parse --short "HEAD^{tree}"`); it goes stale only when tracked content changes — a rebase or amend that keeps the tree identical keeps it valid. When the tree differs, re-run at the current HEAD and re-record, never relabel or regenerate. Record only after cleanup receipts exist.
27
27
  - Delegate code edits, test writes, fixes, and QA execution to right-sized Codex subagents when the workflow requires it.
28
28
  - Every `spawn_agent` message starts with `TASK:`, then names `DELIVERABLE`, `SCOPE`, and `VERIFY`; put role and specialty instructions inside `message`; use `fork_turns: "none"` (v1: `fork_context: false`) unless full history is truly required.
29
29
  - Plan and reviewer agents may run for a long time; spawn them in the background and keep doing independent root work. Between `wait_agent` calls, back off — double the timeout up to ~5 minutes — instead of spinning short cycles.
@@ -165,9 +165,9 @@ Loop per goal. Cap at 5 cycles per goal. Cap identical same-criterion failures a
165
165
  5. EXECUTE-AS-SCENARIO: ACTUALLY run the Manual-QA scenario the criterion named (channel table above). Run it yourself for the orchestrator check; for heavier flows dispatch a dedicated QA execution worker (`lazycodex-worker-medium` by default; `lazycodex-worker-high` when the QA flow itself is hard) whose ONLY job is to drive the channel and write the artifact to the named evidence path. If the scenario FAILS, respawn the implementing worker with the captured failure — do not hand-patch around it.
166
166
  6. CAPTURE: collect the observable artifact path: transcript, stdout, screenshot, assertion, status+body, diff, or parsed dump. No artifact written at the evidence path — not done; record BLOCKED and respawn QA.
167
167
  7. CLEAN (PAIRED, NEVER SKIP): tear down every runtime artifact step 5 spawned BEFORE recording — server PIDs (`kill`, verify `kill -0` fails), `tmux` sessions (`tmux kill-session -t ulw-qa-<criterion>`; confirm `tmux ls`), browser / Playwright contexts (`.close()`), containers (`docker rm -f`), bound ports (`lsof -i :<port>` empty), temp sockets / files / dirs (`rm -rf` the `mktemp` paths), QA-only env vars, AND close every finished worker (v1 `close_agent`; on V2 finished workers end on their own — `interrupt_agent` any still running). Register each teardown as its own todo the moment the QA spawns the resource (scripts, tmux assets, browsers / agent-browser sessions, PIDs, ports) so none is forgotten. Embed a one-line cleanup receipt in the evidence string, e.g. `cleanup: killed 12345; tmux kill-session ulw-qa-foo; rm -rf /tmp/ulw.aB12cD; interrupt_agent w-3`. Missing receipt → record BLOCKED, not PASS.
168
- 8. RECORD one result immediately from the artifact you just wrote — never from memory or a later turn — stamping the capture commit `$(git rev-parse --short HEAD)` into the evidence:
169
- - PASS: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass --evidence "<observable> @<short-sha> | <cleanup receipt>" --json`
170
- - FAIL: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status fail --evidence "<observable> @<short-sha> | <cleanup receipt>" --notes "<diagnosis>" --json`
168
+ 8. RECORD one result immediately from the artifact you just wrote — never from memory or a later turn — stamping the capture tree `$(git rev-parse --short "HEAD^{tree}")` into the evidence:
169
+ - PASS: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass --evidence "<observable> @tree:<short-tree> | <cleanup receipt>" --json`
170
+ - FAIL: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status fail --evidence "<observable> @tree:<short-tree> | <cleanup receipt>" --notes "<diagnosis>" --json`
171
171
  - BLOCKED: `omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status blocked --evidence "<observable>" --notes "<safety/blocker/leftover-state>" --json`
172
172
  9. If actual does not match expected, diagnose, respawn the right-sized worker with the failure context to fix minimally, and rerun the SAME criterion (including a fresh cleanup).
173
173
  10. After 3 same-criterion failures, exit the goal with diagnosis.
@@ -184,9 +184,10 @@ Loop per goal. Cap at 5 cycles per goal. Cap identical same-criterion failures a
184
184
  ## Final Quality Gate
185
185
  Trigger only for the final aggregate goal after every criterion in every goal is `pass`.
186
186
  1. Run targeted verification for changed behavior.
187
- 2. FREEZE first — no more edits or rebases. At the frozen `git rev-parse HEAD`, re-run Manual-QA for any PASS criterion whose stamped commit is not HEAD, so every criterion is proven at HEAD; each artifact exists and is non-empty.
187
+ 2. FREEZE first — no more edits or rebases. At the frozen HEAD, re-run Manual-QA for any PASS criterion whose stamped tree differs from `git rev-parse --short "HEAD^{tree}"`, so every criterion is proven on the frozen tree; each artifact exists and is non-empty.
188
188
  3a. Spawn lazycodex-code-reviewer and lazycodex-qa-executor in parallel (`fork_context: false` on v1; `fork_turns: "none"` on v2) with brief, goals, desired outcome, diff, evidence; wait for BOTH and confirm their report artifacts exist on disk.
189
189
  3b. Only then spawn lazycodex-gate-reviewer with those artifact paths.
190
+ 3c. The gate's approval binds to the frozen tree and covers its three lanes — code quality, hands-on QA, and goal verification. A later rebase or amend that keeps the tree identical keeps the approval; changed content needs fresh review of the delta.
190
191
  4. Treat timeout, missing deliverable, ack-only, `BLOCKED:`, or inconclusive review as a blocker. Any fix restarts the freeze at the new HEAD: re-run ONLY the proofs it invalidated and stamp the fresh output — never regenerate all evidence or relabel stale output to HEAD — re-review the delta at most TWICE; then record-review-blockers (step 5) and surface to the user.
191
192
  5. If review remains blocked, run `omo ulw-loop record-review-blockers --goal-id <id> --title "<...>" --objective "<...>" --evidence "<review findings>" --codex-goal-json <snapshot> --json`.
192
193
  6. If clean, checkpoint final completion:
@@ -224,7 +225,7 @@ Structured prompt directives accepted: `OMO_ULW_LOOP_STEER: { ... }`, `omo.ulw-l
224
225
  ## Constraints
225
226
  1. NEVER call `update_goal` mid-aggregate; only on final story after the quality gate passes.
226
227
  2. NEVER call `create_goal` when `get_goal` shows a different active goal.
227
- 3. Evidence is bound to the commit it was captured at; a later fix, rebase, or merge invalidates it — re-run the QA at the current HEAD and re-record. NEVER mark PASS from memory, and NEVER relabel, pin, refresh, or regenerate prior output to a moved HEAD.
228
+ 3. Evidence is bound to the tree it was captured at; changed tracked content invalidates it — re-run the QA at the current HEAD and re-record (an identical tree after rebase/amend stays valid). NEVER mark PASS from memory, and NEVER relabel, pin, refresh, or regenerate prior output to a moved HEAD.
228
229
  4. NEVER bypass the criteria gate: non-final aggregate completion requires all essential criteria; final aggregate completion requires all criteria across the whole plan.
229
230
  5. Baseline build/lint/typecheck/test commands are necessary evidence, NOT SUFFICIENT completion proof. Criteria coverage with observable evidence is the gate.
230
231
  6. Treat `.omo/ulw-loop/ledger.jsonl` as the durable audit trail; checkpoint after every success or failure.
@@ -36,3 +36,11 @@ test("#given omo-codex package build script #when inspected #then delegates to t
36
36
  // then
37
37
  assert.equal(buildPluginScript, "bun run --cwd plugin build");
38
38
  });
39
+
40
+ test("#given a component-owned runtime manifest #when aggregate component build script is inspected #then it preserves bundled bytes", async () => {
41
+ const buildScript = await readFile(join(root, "scripts", "build-components.mjs"), "utf8");
42
+
43
+ assert.match(buildScript, /hasComponentOwnedBundle/u);
44
+ assert.match(buildScript, /"dist", "\.omo-runtime-manifest\.json"/u);
45
+ assert.match(buildScript, /if \(await hasComponentOwnedBundle\(task\.componentPath\)\) return/u);
46
+ });
@@ -1,5 +1,15 @@
1
1
  import assert from "node:assert/strict";
2
- import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import {
3
+ chmodSync,
4
+ cpSync,
5
+ existsSync,
6
+ mkdirSync,
7
+ mkdtempSync,
8
+ readFileSync,
9
+ readdirSync,
10
+ rmSync,
11
+ writeFileSync,
12
+ } from "node:fs";
3
13
  import { readFile } from "node:fs/promises";
4
14
  import { tmpdir } from "node:os";
5
15
  import { join } from "node:path";
@@ -23,6 +33,7 @@ const HOOK_EVENTS_BY_COMPONENT = {
23
33
  };
24
34
  const MCP_ONLY_COMPONENTS = new Set(["codegraph"]);
25
35
  const HOOK_CLI_TEST_TIMEOUT_MS = 45_000;
36
+ const DAEMON_EXIT_TIMEOUT_MS = 5_000;
26
37
 
27
38
  test("#given required component CLI contracts #when workspaces are inspected #then every contract component is covered", async () => {
28
39
  // given
@@ -125,29 +136,84 @@ test("#given representative component hook payloads #when executed through dist
125
136
  }
126
137
  });
127
138
 
128
- test("#given bundled LSP hook CLI in installed layout #when diagnostics run #then it spawns sibling daemon target", () => {
139
+ test("#given bundled LSP hook CLI in installed layout #when diagnostics run #then it spawns sibling daemon target", async () => {
129
140
  const tempRoot = mkdtempSync(join(tmpdir(), "omo-codex-lsp-installed-"));
130
141
  try {
131
142
  const lspDist = join(tempRoot, "components", "lsp", "dist");
132
143
  const daemonDist = join(tempRoot, "components", "lsp-daemon", "dist");
133
144
  const daemonDir = join(tempRoot, "daemon");
134
- const invocationLog = join(tempRoot, "fake-daemon-invocations.jsonl");
135
145
  mkdirSync(lspDist, { recursive: true });
136
146
  mkdirSync(daemonDist, { recursive: true });
137
147
  mkdirSync(join(tempRoot, "src"), { recursive: true });
138
148
  writeFileSync(join(tempRoot, "package.json"), JSON.stringify({ type: "module" }));
139
149
  writeFileSync(join(lspDist, "cli.js"), readFileSync(componentCliPath("lsp"), "utf8"));
140
- writeFileSync(join(daemonDist, "package.json"), JSON.stringify({ type: "module", version: "0.1.0" }));
141
- writeFakeLspDaemonCli(join(daemonDist, "cli.js"));
142
- const editedFile = join(tempRoot, "src", "broken.c");
143
- writeFileSync(editedFile, "int main(void) { return missing_symbol; }\n");
150
+ cpSync(join(root, "..", "..", "lsp-daemon", "dist"), daemonDist, { recursive: true });
151
+ const editedFile = join(tempRoot, "src", "broken.ts");
152
+ const scenarioPath = join(tempRoot, "scenario.json");
153
+ const eventsPath = join(tempRoot, "lsp-events.jsonl");
154
+ const codexHome = join(tempRoot, "codex-home");
155
+ mkdirSync(codexHome, { recursive: true });
156
+ writeFileSync(editedFile, "const value: string = 1;\n");
157
+ writeFileSync(eventsPath, "");
158
+ writeFileSync(
159
+ scenarioPath,
160
+ JSON.stringify({
161
+ publishDiagnostics: [
162
+ {
163
+ trigger: "didOpen",
164
+ version: 1,
165
+ diagnostics: [
166
+ {
167
+ range: { start: { line: 0, character: 6 }, end: { line: 0, character: 11 } },
168
+ severity: 1,
169
+ code: "fake",
170
+ source: "fake",
171
+ message: "Missing fake symbol.",
172
+ },
173
+ ],
174
+ },
175
+ ],
176
+ diagnosticResponses: [
177
+ {
178
+ report: {
179
+ items: [
180
+ {
181
+ range: { start: { line: 0, character: 6 }, end: { line: 0, character: 11 } },
182
+ severity: 1,
183
+ code: "fake",
184
+ source: "fake",
185
+ message: "Missing fake symbol.",
186
+ },
187
+ ],
188
+ },
189
+ },
190
+ ],
191
+ }),
192
+ );
193
+ writeFileSync(
194
+ join(codexHome, "lsp-client.json"),
195
+ JSON.stringify({
196
+ lsp: {
197
+ typescript: {
198
+ command: [
199
+ process.execPath,
200
+ join(root, "..", "..", "lsp-core", "src", "lsp", "fixtures", "workspace-edit-server.mjs"),
201
+ scenarioPath,
202
+ eventsPath,
203
+ ],
204
+ extensions: [".ts"],
205
+ },
206
+ },
207
+ }),
208
+ );
144
209
 
145
210
  const result = spawnSync(process.execPath, [join(lspDist, "cli.js"), "hook", "post-tool-use"], {
146
211
  cwd: tempRoot,
147
212
  encoding: "utf8",
148
213
  env: hookEnv(tempRoot, {
149
- CODEX_LSP_DAEMON_DIR: daemonDir,
150
- FAKE_LSP_DAEMON_LOG: invocationLog,
214
+ CODEX_HOME: codexHome,
215
+ OMO_LSP_DAEMON_DIR: daemonDir,
216
+ NODE_PATH: "",
151
217
  }),
152
218
  input: JSON.stringify({
153
219
  session_id: "bundled-lsp-hook",
@@ -158,17 +224,17 @@ test("#given bundled LSP hook CLI in installed layout #when diagnostics run #the
158
224
  timeout: HOOK_CLI_TEST_TIMEOUT_MS,
159
225
  });
160
226
 
161
- const daemonInvocations = existsSync(invocationLog) ? readFileSync(invocationLog, "utf8") : "";
162
- const failureContext = `stdout: ${result.stdout}\nstderr: ${result.stderr}\ndaemon log: ${daemonInvocations}`;
227
+ const failureContext = `stdout: ${result.stdout}\nstderr: ${result.stderr}`;
163
228
  assert.equal(result.status, 0, failureContext);
164
229
  assert.equal(result.stderr, "", failureContext);
165
230
  assert.notEqual(result.stdout, "", failureContext);
166
231
  const parsed = JSON.parse(result.stdout);
167
232
  assert.equal(parsed.decision, "block");
168
- assert.match(parsed.reason, /error\[fake\] \(1\) at 1:1: Missing fake symbol\./);
169
- assert.deepEqual(daemonInvocations.trim().split("\n").map(JSON.parse), [["daemon"]]);
170
- assert.equal(existsSync(join(daemonDir, "v0.1.0", "daemon.log")), true);
233
+ assert.match(parsed.reason, /Missing fake symbol\./);
234
+ assert.match(readFileSync(eventsPath, "utf8"), /textDocument\/publishDiagnostics/);
235
+ assert.equal(existsSync(join(daemonDir, `v${JSON.parse(readFileSync(join(daemonDist, "package.json"), "utf8")).version}`, "daemon.log")), true);
171
236
  } finally {
237
+ await stopTestDaemons(join(tempRoot, "daemon"));
172
238
  rmSync(tempRoot, { recursive: true, force: true });
173
239
  }
174
240
  });
@@ -336,7 +402,7 @@ function writeFakeLspDaemonCli(path) {
336
402
  'import { createServer } from "node:net";',
337
403
  "",
338
404
  "appendFileSync(process.env.FAKE_LSP_DAEMON_LOG, `${JSON.stringify(process.argv.slice(2))}\\n`);",
339
- "const baseDir = process.env.CODEX_LSP_DAEMON_DIR;",
405
+ "const baseDir = process.env.OMO_LSP_DAEMON_DIR;",
340
406
  'const versionDirName = readdirSync(baseDir).find((entry) => entry.startsWith("v")) ?? "v0";',
341
407
  "const version = versionDirName.slice(1);",
342
408
  "const dir = join(baseDir, versionDirName);",
@@ -374,6 +440,53 @@ function writeFakeLspDaemonCli(path) {
374
440
  );
375
441
  }
376
442
 
443
+ async function stopTestDaemons(daemonRoot) {
444
+ if (!existsSync(daemonRoot)) return;
445
+ for (const versionDir of readdirSync(daemonRoot)) {
446
+ const pidPath = join(daemonRoot, versionDir, "daemon.pid");
447
+ if (!existsSync(pidPath)) continue;
448
+ const pid = Number(readFileSync(pidPath, "utf8").trim());
449
+ if (!Number.isInteger(pid) || pid <= 0) continue;
450
+ if (process.platform === "win32") {
451
+ const result = spawnSync("taskkill", ["/pid", String(pid), "/f", "/t"], {
452
+ encoding: "utf8",
453
+ windowsHide: true,
454
+ });
455
+ if (result.error) throw result.error;
456
+ if (result.status !== 0 && processIsRunning(pid)) {
457
+ throw new Error(
458
+ `taskkill failed for test daemon ${pid}: exit=${result.status} stderr=${result.stderr.trim()}`,
459
+ );
460
+ }
461
+ } else {
462
+ try {
463
+ process.kill(pid, "SIGTERM");
464
+ } catch (error) {
465
+ if (error instanceof Error && "code" in error && error.code === "ESRCH") continue;
466
+ throw error;
467
+ }
468
+ }
469
+ await waitForProcessExit(pid);
470
+ }
471
+ }
472
+
473
+ async function waitForProcessExit(pid) {
474
+ const deadline = Date.now() + DAEMON_EXIT_TIMEOUT_MS;
475
+ while (processIsRunning(pid)) {
476
+ if (Date.now() >= deadline) throw new Error(`Timed out waiting for test daemon ${pid} to exit`);
477
+ await new Promise((resolve) => setTimeout(resolve, 50));
478
+ }
479
+ }
480
+
481
+ function processIsRunning(pid) {
482
+ try {
483
+ process.kill(pid, 0);
484
+ return true;
485
+ } catch {
486
+ return false;
487
+ }
488
+ }
489
+
377
490
  function hookEnv(tempRoot, extraEnv = {}) {
378
491
  return {
379
492
  ...process.env,
@@ -31,3 +31,13 @@ test("#given aggregate build scripts #when inspected #then npm subprocesses reso
31
31
  assert.match(installTimeBuildScripts, /shell: process\.platform === "win32"/);
32
32
  assert.doesNotMatch(installTimeBuildScripts, /npm\.cmd/);
33
33
  });
34
+
35
+ test("#given bundled MCP runtime builds #when a locked runtime has no node_modules #then npm ci bootstraps it before build", async () => {
36
+ // given
37
+ const buildBundledMcpRuntimesScript = await readFile(join(root, "scripts", "build-bundled-mcp-runtimes.mjs"), "utf8");
38
+
39
+ // then
40
+ assert.match(buildBundledMcpRuntimesScript, /package-lock\.json/);
41
+ assert.match(buildBundledMcpRuntimesScript, /spawnSync\("npm", \["ci"\]/);
42
+ assert.match(buildBundledMcpRuntimesScript, /!existsSync\(join\(runtime\.packageRoot, "node_modules"\)\)/);
43
+ });
@@ -64,6 +64,8 @@ test("#given the installed cache layout #when running build-lsp-daemon #then use
64
64
 
65
65
  await mkdir(join(root, "components", "lsp-daemon", "dist"), { recursive: true });
66
66
  await writeFile(join(root, "components", "lsp-daemon", "dist", "cli.js"), "");
67
+ await writeFile(join(root, "components", "lsp-daemon", "dist", "client.js"), "");
68
+ await writeFile(join(root, "components", "lsp-daemon", "dist", "client.d.ts"), "");
67
69
  await writeFile(join(root, "components", "lsp-daemon", "dist", "index.js"), "");
68
70
  await writeFile(join(root, "components", "lsp-daemon", "dist", "index.d.ts"), "");
69
71
 
@@ -77,7 +77,7 @@ const startWorkOriginalCompletion = `When all top-level checkboxes in \`## TODOs
77
77
  const startWorkCodexCompletion = `When all top-level checkboxes in \`## TODOs\` and \`## Final Verification Wave\` are complete:
78
78
 
79
79
  1. Run the plan's final verification commands.
80
- 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge:
80
+ 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge. The gate's pass binds to the commit SHA it reviewed and covers every later checkpoint at that same SHA — never re-run it on an already-passed SHA; re-run only when new commits land:
81
81
  - Invoke the \`review-work\` skill with the final diff, changed files, user goal, constraints, run command, and verification evidence. All five review lanes must return PASS. A timeout, missing deliverable, ack-only child, \`BLOCKED:\`, or inconclusive lane is a gate failure, not approval.
82
82
  - Run a debugging-oriented runtime audit even when the review passes: name at least three plausible failure hypotheses for the changed surface, run the distinguishing checks against the actual artifact, and append the ruled-out or confirmed result to \`.omo/start-work/ledger.jsonl\`.
83
83
  - If any review lane or debugging hypothesis fails, invoke the \`debugging\` skill, confirm root cause with runtime evidence, add the minimal failing test or reproduction, fix it, rerun the affected verification, then rerun the Global Review and Debugging Gate.