oh-my-opencode 5.0.0-beta.3 → 5.0.0-beta.30

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 (583) hide show
  1. package/.agents/command/publish.md +44 -16
  2. package/.agents/skills/publish/SKILL.md +44 -16
  3. package/.agents/skills/senpi-qa/SKILL.md +80 -0
  4. package/.agents/skills/senpi-qa/scripts/resolve-evidence-dir.mjs +65 -0
  5. package/.agents/skills/senpi-qa/scripts/resolve-evidence-dir.test.mjs +171 -0
  6. package/.agents/skills/work-with-pr/SKILL.md +37 -23
  7. package/.opencode/command/publish.md +44 -16
  8. package/.opencode/skills/work-with-pr/SKILL.md +37 -23
  9. package/README.ja.md +25 -21
  10. package/README.ko.md +25 -21
  11. package/README.md +38 -23
  12. package/README.ru.md +24 -20
  13. package/README.zh-cn.md +25 -21
  14. package/dist/agents/atlas/agent.d.ts +0 -1
  15. package/dist/agents/sisyphus/grok-4.d.ts +20 -0
  16. package/dist/agents/sisyphus/index.d.ts +2 -0
  17. package/dist/agents/sisyphus-agent-config.d.ts +6 -0
  18. package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
  19. package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +15 -4
  20. package/dist/agents/types.d.ts +2 -2
  21. package/dist/cli/config-manager/parse-opencode-config-file.d.ts +2 -1
  22. package/dist/cli/doctor/checks/system-plugin.d.ts +4 -3
  23. package/dist/cli/fallback-lane-policy.d.ts +1 -0
  24. package/dist/cli/index.js +22572 -20322
  25. package/dist/cli/install-codex/install-codex-test-fixtures.d.ts +1 -1
  26. package/dist/cli/run/on-complete-hook.d.ts +2 -0
  27. package/dist/cli/runtime-commands.d.ts +1 -1
  28. package/dist/cli/worktree-sweep/classify.d.ts +16 -0
  29. package/dist/cli/worktree-sweep/format.d.ts +8 -0
  30. package/dist/cli/worktree-sweep/git.d.ts +19 -0
  31. package/dist/cli/worktree-sweep/index.d.ts +7 -0
  32. package/dist/cli/worktree-sweep/options.d.ts +2 -0
  33. package/dist/cli/worktree-sweep/parse-worktree-list.d.ts +8 -0
  34. package/dist/cli/worktree-sweep/sweep.d.ts +2 -0
  35. package/dist/cli/worktree-sweep/types.d.ts +65 -0
  36. package/dist/cli/worktree-sweep/worktree-sweep.d.ts +2 -0
  37. package/dist/cli-node/index.js +22190 -19917
  38. package/dist/config/schema/commands.d.ts +1 -1
  39. package/dist/config/schema/hooks.d.ts +1 -1
  40. package/dist/config/schema/oh-my-opencode-config.d.ts +4 -1
  41. package/dist/config/schema/ulw-execute.d.ts +5 -0
  42. package/dist/config/validate.d.ts +2 -0
  43. package/dist/create-hooks.d.ts +3 -1
  44. package/dist/features/btw-side/btw-command-draft.d.ts +7 -0
  45. package/dist/features/btw-side/context-injector.d.ts +15 -0
  46. package/dist/features/btw-side/index.d.ts +8 -0
  47. package/dist/features/btw-side/metadata.d.ts +15 -0
  48. package/dist/features/btw-side/parent-context-budget.d.ts +9 -0
  49. package/dist/features/btw-side/server-session-registry.d.ts +8 -0
  50. package/dist/features/btw-side/tui-adoption-cache.d.ts +13 -0
  51. package/dist/features/btw-side/tui-adoption-guard.d.ts +5 -0
  52. package/dist/features/btw-side/tui-controller-types.d.ts +68 -0
  53. package/dist/features/btw-side/tui-controller.d.ts +19 -0
  54. package/dist/features/btw-side/tui-escape-return.d.ts +12 -0
  55. package/dist/features/btw-side/tui-keymap.d.ts +17 -0
  56. package/dist/features/btw-side/tui-parent-validator.d.ts +6 -0
  57. package/dist/features/btw-side/tui-picker-options.d.ts +20 -0
  58. package/dist/features/btw-side/tui-picker.d.ts +9 -0
  59. package/dist/features/btw-side/tui-prompt-queue.d.ts +8 -0
  60. package/dist/features/btw-side/tui-session-bridge.d.ts +11 -0
  61. package/dist/features/btw-side/tui-session-catalog.d.ts +35 -0
  62. package/dist/features/btw-side/tui-side-removal.d.ts +11 -0
  63. package/dist/features/btw-side/tui-side-start.d.ts +9 -0
  64. package/dist/features/btw-side/tui-wiring.d.ts +8 -0
  65. package/dist/features/builtin-commands/templates/ulw-execute.d.ts +1 -0
  66. package/dist/features/builtin-commands/types.d.ts +1 -1
  67. package/dist/features/opengateway-provider/index.d.ts +13 -0
  68. package/dist/features/team-mode/tools/messaging-fallback-wake.d.ts +15 -0
  69. package/dist/hooks/atlas/atlas-hook.d.ts +1 -0
  70. package/dist/hooks/atlas/atlas-lifecycle-store.d.ts +50 -0
  71. package/dist/hooks/atlas/event-handler.d.ts +1 -0
  72. package/dist/hooks/atlas/final-wave-approval-gate.test-support.d.ts +50 -0
  73. package/dist/hooks/atlas/system-reminder-templates.d.ts +0 -1
  74. package/dist/hooks/atlas/tool-execute-before.d.ts +3 -0
  75. package/dist/hooks/atlas/types.d.ts +1 -0
  76. package/dist/hooks/index.d.ts +1 -1
  77. package/dist/hooks/prometheus-md-only/agent-resolution.d.ts +2 -2
  78. package/dist/hooks/runtime-fallback/chat-message-handler.d.ts +2 -0
  79. package/dist/hooks/runtime-fallback/retry-model-payload.d.ts +1 -0
  80. package/dist/hooks/runtime-fallback/runtime-model-settings.d.ts +6 -0
  81. package/dist/hooks/runtime-fallback/session-status-handler.d.ts +1 -1
  82. package/dist/hooks/runtime-fallback/types.d.ts +3 -1
  83. package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
  84. package/dist/hooks/todo-continuation-enforcer/types.d.ts +1 -0
  85. package/dist/hooks/{start-work → ulw-execute}/context-info-builder.d.ts +1 -1
  86. package/dist/hooks/{start-work → ulw-execute}/index.d.ts +1 -1
  87. package/dist/hooks/ulw-execute/ulw-execute-hook.d.ts +23 -0
  88. package/dist/index.js +12573 -6957
  89. package/dist/oh-my-opencode.schema.json +15 -2
  90. package/dist/plugin/chat-message/types.d.ts +3 -3
  91. package/dist/plugin/chat-message/ulw-execute-message.d.ts +5 -0
  92. package/dist/plugin/event-session-lifecycle.d.ts +1 -0
  93. package/dist/plugin/hooks/create-core-hooks.d.ts +2 -1
  94. package/dist/plugin/hooks/create-session-hooks.d.ts +2 -2
  95. package/dist/plugin/hooks/create-transform-hooks.d.ts +2 -0
  96. package/dist/plugin/messages-transform.d.ts +1 -0
  97. package/dist/shared/index.d.ts +2 -0
  98. package/dist/shared/legacy-plugin-warning.d.ts +2 -1
  99. package/dist/shared/normalize-sdk-response.d.ts +1 -0
  100. package/dist/shared/plugin-entry-migrator.d.ts +4 -3
  101. package/dist/shared/plugin-entry-shape.d.ts +6 -0
  102. package/dist/shared/runtime-fallback-retry-marker.d.ts +16 -0
  103. package/dist/shared/shell-env.d.ts +1 -1
  104. package/dist/skills/ast-grep/AGENTS.md +51 -0
  105. package/dist/skills/coding-agent-sessions/AGENTS.md +62 -0
  106. package/dist/skills/coding-agent-sessions/SKILL.md +3 -2
  107. package/dist/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  108. package/dist/skills/coding-agent-sessions/references/senpi.md +4 -4
  109. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  110. package/dist/skills/data-scientist/SKILL.md +99 -239
  111. package/dist/skills/data-scientist/references/execution-surfaces.md +91 -0
  112. package/dist/skills/data-scientist/references/placement.md +74 -0
  113. package/dist/skills/data-scientist/references/polars-lane.md +95 -0
  114. package/dist/skills/data-scientist/references/uv-setup.md +1 -1
  115. package/dist/skills/data-scientist/references/visualization.md +64 -0
  116. package/dist/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  117. package/dist/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  118. package/dist/skills/debugging/SKILL.md +2 -0
  119. package/dist/skills/debugging/references/methodology/00-setup.md +12 -0
  120. package/dist/skills/debugging/references/methodology/02-investigate.md +21 -0
  121. package/dist/skills/debugging/references/runtimes/go.md +15 -1
  122. package/dist/skills/debugging/references/runtimes/native-binary.md +38 -0
  123. package/dist/skills/debugging/references/runtimes/node.md +25 -0
  124. package/dist/skills/debugging/references/runtimes/python.md +13 -0
  125. package/dist/skills/debugging/references/runtimes/rust.md +41 -0
  126. package/dist/skills/debugging/references/scripts/dap.mjs +267 -0
  127. package/dist/skills/debugging/references/scripts/dap.test.ts +86 -0
  128. package/dist/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  129. package/dist/skills/debugging/references/tools/dap.md +103 -0
  130. package/dist/skills/debugging/references/tools/frida.md +193 -0
  131. package/dist/skills/frontend/SKILL.md +11 -7
  132. package/dist/skills/frontend/references/design/_INDEX.md +1 -0
  133. package/dist/skills/frontend/references/design/print-paged-media.md +76 -0
  134. package/dist/skills/frontend/references/design/stylegallery.md +80 -0
  135. package/dist/skills/frontend/references/designpowers/README.md +1 -1
  136. package/dist/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  137. package/dist/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  138. package/dist/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  139. package/dist/skills/frontend/references/designpowers/orchestration.md +1 -1
  140. package/dist/skills/frontend/references/designpowers/routing.md +5 -5
  141. package/dist/skills/review-work/SKILL.md +3 -3
  142. package/dist/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  143. package/dist/skills/ultimate-browsing/SKILL.md +2 -0
  144. package/dist/skills/ultimate-browsing/engine/AGENTS.md +179 -0
  145. package/dist/skills/ultimate-browsing/engine/templates/package.json +1 -1
  146. package/dist/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  147. package/dist/skills/{start-work → ulw-execute}/SKILL.md +9 -8
  148. package/dist/skills/ulw-plan/SKILL.md +6 -6
  149. package/dist/skills/ulw-plan/references/full-workflow.md +31 -7
  150. package/dist/skills/ulw-plan/references/intent-clear.md +2 -1
  151. package/dist/skills/ulw-plan/references/intent-unclear.md +5 -5
  152. package/dist/skills/ulw-research/SKILL.md +4 -2
  153. package/dist/skills/visual-qa/AGENTS.md +58 -0
  154. package/dist/skills/visual-qa/SKILL.md +3 -2
  155. package/dist/tools/delegate-task/builtin-categories.d.ts +1 -0
  156. package/dist/tools/delegate-task/builtin-category-definition.d.ts +1 -0
  157. package/dist/tools/delegate-task/tool-description.d.ts +3 -1
  158. package/dist/tools/delegate-task/types.d.ts +3 -0
  159. package/dist/tui.d.ts +12 -0
  160. package/dist/tui.js +11480 -11512
  161. package/package.json +42 -36
  162. package/packages/git-bash-mcp/dist/cli.js +5 -1
  163. package/packages/git-bash-mcp/package.json +1 -1
  164. package/packages/lsp-core/src/index.ts +1 -0
  165. package/packages/lsp-core/src/lsp/client-diagnostics-concurrency.integration.test.ts +44 -0
  166. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +0 -28
  167. package/packages/lsp-core/src/lsp/client-wrapper-outside-cwd.test.ts +78 -0
  168. package/packages/lsp-core/src/lsp/client-wrapper.test.ts +66 -13
  169. package/packages/lsp-core/src/lsp/client-wrapper.ts +95 -23
  170. package/packages/lsp-core/src/lsp/client.ts +26 -0
  171. package/packages/lsp-core/src/lsp/connection.ts +16 -0
  172. package/packages/lsp-core/src/lsp/constants.ts +1 -0
  173. package/packages/lsp-core/src/lsp/format-document.test.ts +143 -0
  174. package/packages/lsp-core/src/lsp/format-document.ts +90 -0
  175. package/packages/lsp-core/src/lsp/manager-max-clients.test.ts +151 -0
  176. package/packages/lsp-core/src/lsp/manager.ts +34 -1
  177. package/packages/lsp-core/src/lsp/outside-context-workspace.ts +33 -0
  178. package/packages/lsp-core/src/lsp/server-definitions.ts +29 -0
  179. package/packages/lsp-core/src/lsp/server-installation.test.ts +376 -0
  180. package/packages/lsp-core/src/lsp/server-installation.ts +200 -27
  181. package/packages/lsp-core/src/lsp/server-resolution-local-binary.test.ts +170 -0
  182. package/packages/lsp-core/src/lsp/server-resolution.ts +18 -5
  183. package/packages/lsp-core/src/lsp/transport.ts +9 -0
  184. package/packages/lsp-core/src/lsp/types.ts +8 -0
  185. package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +20 -1
  186. package/packages/lsp-core/src/lsp/workspace-markers.ts +1 -0
  187. package/packages/lsp-core/src/request-context.test.ts +29 -0
  188. package/packages/lsp-core/src/request-context.ts +1 -1
  189. package/packages/lsp-core/src/tool-surface.test.ts +13 -1
  190. package/packages/lsp-core/src/tools/definitions.ts +14 -0
  191. package/packages/lsp-core/src/tools/diagnostics.ts +3 -3
  192. package/packages/lsp-core/src/tools/format.test.ts +56 -0
  193. package/packages/lsp-core/src/tools/format.ts +56 -0
  194. package/packages/lsp-core/src/tools/index.ts +1 -0
  195. package/packages/lsp-core/src/tools/navigation.ts +4 -2
  196. package/packages/lsp-core/src/tools/rename.ts +4 -2
  197. package/packages/lsp-core/src/tools/symbols.ts +1 -1
  198. package/packages/lsp-core/src/tools/types.ts +10 -0
  199. package/packages/lsp-daemon/dist/cli.js +645 -296
  200. package/packages/lsp-daemon/dist/client.d.ts +10 -0
  201. package/packages/lsp-daemon/dist/client.js +605 -253
  202. package/packages/lsp-daemon/dist/daemon-client.d.ts +1 -0
  203. package/packages/lsp-daemon/dist/daemon-client.js +3 -0
  204. package/packages/lsp-daemon/dist/ensure-daemon.js +1 -0
  205. package/packages/lsp-daemon/dist/index.js +609 -262
  206. package/packages/lsp-daemon/dist/version-reap.js +1 -1
  207. package/packages/lsp-daemon/package.json +1 -1
  208. package/packages/lsp-tools-mcp/dist/cli.js +564 -217
  209. package/packages/lsp-tools-mcp/dist/lsp/manager.js +115 -92
  210. package/packages/lsp-tools-mcp/dist/mcp.js +566 -219
  211. package/packages/lsp-tools-mcp/dist/request-context.js +12 -13
  212. package/packages/lsp-tools-mcp/dist/tools.js +571 -227
  213. package/packages/omo-codex/THIRD-PARTY-NOTICES.md +4 -4
  214. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +4 -4
  215. package/packages/omo-codex/plugin/AGENTS.md +47 -0
  216. package/packages/omo-codex/plugin/README.md +1 -1
  217. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +34 -33
  218. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  219. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  220. package/packages/omo-codex/plugin/components/bootstrap/src/hook.ts +1 -0
  221. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +293 -116
  222. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +245 -84
  223. package/packages/omo-codex/plugin/components/codegraph/package.json +4 -4
  224. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +1 -0
  225. package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +1 -0
  226. package/packages/omo-codex/plugin/components/comment-checker/AGENTS.md +9 -0
  227. package/packages/omo-codex/plugin/components/comment-checker/biome.json +2 -2
  228. package/packages/omo-codex/plugin/components/comment-checker/dist/cli.js +2 -1
  229. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  230. package/packages/omo-codex/plugin/components/comment-checker/package.json +5 -5
  231. package/packages/omo-codex/plugin/components/comment-checker/src/apply-patch.ts +2 -8
  232. package/packages/omo-codex/plugin/components/comment-checker/src/core.ts +1 -2
  233. package/packages/omo-codex/plugin/components/comment-checker/src/request-extractor.ts +1 -1
  234. package/packages/omo-codex/plugin/components/comment-checker/src/runner.ts +1 -0
  235. package/packages/omo-codex/plugin/components/git-bash/AGENTS.md +1 -1
  236. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  237. package/packages/omo-codex/plugin/components/git-bash/package.json +3 -4
  238. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/biome.json +2 -2
  239. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +1 -5
  240. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +1 -5
  241. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  242. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +5 -5
  243. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +1 -5
  244. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +4 -21
  245. package/packages/omo-codex/plugin/components/lsp/AGENTS.md +30 -15
  246. package/packages/omo-codex/plugin/components/lsp/biome.json +2 -2
  247. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +4 -4
  248. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +596 -267
  249. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +1 -1
  250. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  251. package/packages/omo-codex/plugin/components/lsp/package.json +5 -5
  252. package/packages/omo-codex/plugin/components/lsp/src/cli.ts +1 -1
  253. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +1 -1
  254. package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +1 -5
  255. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +6 -7
  256. package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +1 -2
  257. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +11 -1
  258. package/packages/omo-codex/plugin/components/rules/AGENTS.md +12 -0
  259. package/packages/omo-codex/plugin/components/rules/biome.json +2 -2
  260. package/packages/omo-codex/plugin/components/rules/dist/cli.js +60 -45
  261. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  262. package/packages/omo-codex/plugin/components/rules/package.json +7 -7
  263. package/packages/omo-codex/plugin/components/rules/src/config.ts +1 -2
  264. package/packages/omo-codex/plugin/components/rules/src/persistent-cache.ts +1 -2
  265. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +9 -5
  266. package/packages/omo-codex/plugin/components/rules/src/rules-engine-factory.ts +1 -4
  267. package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +4 -9
  268. package/packages/omo-codex/plugin/components/rules/test/bundled-rules-priority.test.ts +11 -16
  269. package/packages/omo-codex/plugin/components/rules/test/bundled-rules.test.ts +17 -25
  270. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-budget.test.ts +9 -7
  271. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-context.test.ts +0 -6
  272. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-dedup.test.ts +6 -4
  273. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-directive.test.ts +12 -9
  274. package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +28 -37
  275. package/packages/omo-codex/plugin/components/rules/test/dynamic-target-fingerprints.test.ts +1 -2
  276. package/packages/omo-codex/plugin/components/rules/test/engine.test.ts +7 -4
  277. package/packages/omo-codex/plugin/components/rules/test/finder.test.ts +2 -3
  278. package/packages/omo-codex/plugin/components/rules/test/formatter.test.ts +39 -72
  279. package/packages/omo-codex/plugin/components/rules/test/hephaestus-model-variant.test.ts +1 -2
  280. package/packages/omo-codex/plugin/components/rules/test/hook-output.test.ts +2 -3
  281. package/packages/omo-codex/plugin/components/rules/test/matcher.test.ts +2 -3
  282. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +1 -1
  283. package/packages/omo-codex/plugin/components/rules/test/parser.test.ts +1 -2
  284. package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +5 -6
  285. package/packages/omo-codex/plugin/components/rules/test/rules-engine-consumption.test.ts +3 -6
  286. package/packages/omo-codex/plugin/components/rules/test/scanner.test.ts +1 -2
  287. package/packages/omo-codex/plugin/components/rules/test/sources.test.ts +2 -5
  288. package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +2 -17
  289. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  290. package/packages/omo-codex/plugin/components/teammode/package.json +5 -5
  291. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +3 -9
  292. package/packages/omo-codex/plugin/components/telemetry/AGENTS.md +8 -0
  293. package/packages/omo-codex/plugin/components/telemetry/biome.json +2 -2
  294. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +2463 -437
  295. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +2467 -441
  296. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  297. package/packages/omo-codex/plugin/components/telemetry/package.json +5 -5
  298. package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +1 -4
  299. package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -14
  300. package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +1 -1
  301. package/packages/omo-codex/plugin/components/telemetry/test/diagnostics.test.ts +2 -5
  302. package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +5 -0
  303. package/packages/omo-codex/plugin/components/ultrawork/biome.json +2 -2
  304. package/packages/omo-codex/plugin/components/ultrawork/directive.md +13 -1
  305. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  306. package/packages/omo-codex/plugin/components/ultrawork/package.json +5 -5
  307. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +13 -1
  308. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +6 -6
  309. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +31 -7
  310. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -1
  311. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +5 -5
  312. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +9 -1
  313. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +0 -136
  314. package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +0 -2
  315. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/AGENTS.md +5 -4
  316. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/NOTICE +1 -1
  317. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/README.md +5 -5
  318. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/biome.json +2 -2
  319. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/directive.md +6 -6
  320. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/dist/cli.js +12 -12
  321. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +28 -0
  322. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/package.json +12 -12
  323. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/boulder-reader.ts +1 -1
  324. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/cli.ts +1 -1
  325. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/codex-hook.ts +3 -3
  326. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/directive.ts +1 -1
  327. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/index.ts +1 -1
  328. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/boulder-reader.test.ts +3 -3
  329. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/cli.test.ts +1 -4
  330. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/codex-hook.test.ts +8 -22
  331. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +16 -0
  332. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +1 -1
  333. package/packages/omo-codex/plugin/components/ulw-loop/biome.json +2 -2
  334. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +13 -1
  335. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +5 -1
  336. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +2 -1
  337. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +11 -1
  338. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +24 -14
  339. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +1 -1
  340. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +1 -1
  341. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +3 -3
  342. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  343. package/packages/omo-codex/plugin/components/ulw-loop/package.json +5 -5
  344. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +3 -2
  345. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/define-goal.md +108 -0
  346. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -0
  347. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +5 -1
  348. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +13 -1
  349. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +3 -5
  350. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-snapshot.ts +3 -1
  351. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +3 -1
  352. package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +1 -1
  353. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +3 -3
  354. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +0 -1
  355. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +25 -0
  356. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +26 -2
  357. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +2 -2
  358. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-snapshot.test.ts +18 -0
  359. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +0 -3
  360. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -37
  361. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +9 -0
  362. package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +8 -5
  363. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +1 -1
  364. package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +4 -5
  365. package/packages/omo-codex/plugin/components/ulw-loop/vitest.config.ts +1 -0
  366. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  367. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  368. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  369. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  370. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  371. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  372. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  373. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  374. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  375. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  376. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  377. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  378. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  379. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  380. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  381. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  382. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +17 -0
  383. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  384. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json +17 -0
  385. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  386. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  387. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  388. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  389. package/packages/omo-codex/plugin/model-catalog.json +3 -3
  390. package/packages/omo-codex/plugin/package-lock.json +681 -395
  391. package/packages/omo-codex/plugin/package.json +2 -2
  392. package/packages/omo-codex/plugin/scripts/AGENTS.md +40 -0
  393. package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +1 -1
  394. package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +3 -3
  395. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +11 -11
  396. package/packages/omo-codex/plugin/shared/package.json +3 -4
  397. package/packages/omo-codex/plugin/skills/ast-grep/AGENTS.md +51 -0
  398. package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +62 -0
  399. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +3 -2
  400. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  401. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +4 -4
  402. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  403. package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +99 -239
  404. package/packages/omo-codex/plugin/skills/data-scientist/references/execution-surfaces.md +91 -0
  405. package/packages/omo-codex/plugin/skills/data-scientist/references/placement.md +74 -0
  406. package/packages/omo-codex/plugin/skills/data-scientist/references/polars-lane.md +95 -0
  407. package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +1 -1
  408. package/packages/omo-codex/plugin/skills/data-scientist/references/visualization.md +64 -0
  409. package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  410. package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  411. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -0
  412. package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +12 -0
  413. package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +21 -0
  414. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +15 -1
  415. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +38 -0
  416. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +25 -0
  417. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +13 -0
  418. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +41 -0
  419. package/packages/omo-codex/plugin/skills/debugging/references/scripts/dap.mjs +267 -0
  420. package/packages/omo-codex/plugin/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  421. package/packages/omo-codex/plugin/skills/debugging/references/tools/dap.md +103 -0
  422. package/packages/omo-codex/plugin/skills/debugging/references/tools/frida.md +193 -0
  423. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +11 -7
  424. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
  425. package/packages/omo-codex/plugin/skills/frontend/references/design/print-paged-media.md +76 -0
  426. package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +80 -0
  427. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +1 -1
  428. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  429. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  430. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  431. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/orchestration.md +1 -1
  432. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +5 -5
  433. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +4 -4
  434. package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  435. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +2 -0
  436. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +179 -0
  437. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
  438. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  439. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +13 -1
  440. package/packages/omo-codex/plugin/skills/{start-work → ulw-execute}/SKILL.md +12 -11
  441. package/packages/omo-codex/plugin/skills/ulw-execute/agents/openai.yaml +2 -0
  442. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +3 -2
  443. package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +108 -0
  444. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -0
  445. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +6 -6
  446. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +31 -7
  447. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -1
  448. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +5 -5
  449. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +4 -2
  450. package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +58 -0
  451. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +3 -2
  452. package/packages/omo-codex/plugin/test/AGENTS.md +47 -0
  453. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +19 -173
  454. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +8 -28
  455. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -1
  456. package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +1 -1
  457. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +175 -13
  458. package/packages/omo-codex/plugin/test/aggregate.test.mjs +78 -2
  459. package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +19 -33
  460. package/packages/omo-codex/plugin/test/auto-update.test.mjs +2 -2
  461. package/packages/omo-codex/plugin/test/component-bin-names.test.mjs +2 -2
  462. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +1 -1
  463. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
  464. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +4 -4
  465. package/packages/omo-codex/plugin/test/lcx-contribute-bug-fix-template.test.mjs +21 -27
  466. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +8 -8
  467. package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +0 -36
  468. package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +101 -0
  469. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +12 -12
  470. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +1 -119
  471. package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +0 -40
  472. package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +6 -62
  473. package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +3 -36
  474. package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +0 -44
  475. package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +2 -6
  476. package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +0 -3
  477. package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +0 -3
  478. package/packages/omo-codex/scripts/AGENTS.md +36 -0
  479. package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +2 -2
  480. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2637 -549
  481. package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +7 -2
  482. package/packages/shared-skills/skills/ast-grep/AGENTS.md +51 -0
  483. package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +62 -0
  484. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +3 -2
  485. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  486. package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +4 -4
  487. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  488. package/packages/shared-skills/skills/data-scientist/SKILL.md +99 -239
  489. package/packages/shared-skills/skills/data-scientist/references/execution-surfaces.md +91 -0
  490. package/packages/shared-skills/skills/data-scientist/references/placement.md +74 -0
  491. package/packages/shared-skills/skills/data-scientist/references/polars-lane.md +95 -0
  492. package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +1 -1
  493. package/packages/shared-skills/skills/data-scientist/references/visualization.md +64 -0
  494. package/packages/shared-skills/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  495. package/packages/shared-skills/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  496. package/packages/shared-skills/skills/debugging/SKILL.md +2 -0
  497. package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +12 -0
  498. package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +21 -0
  499. package/packages/shared-skills/skills/debugging/references/runtimes/go.md +15 -1
  500. package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +38 -0
  501. package/packages/shared-skills/skills/debugging/references/runtimes/node.md +25 -0
  502. package/packages/shared-skills/skills/debugging/references/runtimes/python.md +13 -0
  503. package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +41 -0
  504. package/packages/shared-skills/skills/debugging/references/scripts/dap.mjs +267 -0
  505. package/packages/shared-skills/skills/debugging/references/scripts/dap.test.ts +86 -0
  506. package/packages/shared-skills/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  507. package/packages/shared-skills/skills/debugging/references/tools/dap.md +103 -0
  508. package/packages/shared-skills/skills/debugging/references/tools/frida.md +193 -0
  509. package/packages/shared-skills/skills/frontend/SKILL.md +11 -7
  510. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
  511. package/packages/shared-skills/skills/frontend/references/design/print-paged-media.md +76 -0
  512. package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +80 -0
  513. package/packages/shared-skills/skills/frontend/references/designpowers/README.md +1 -1
  514. package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  515. package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  516. package/packages/shared-skills/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  517. package/packages/shared-skills/skills/frontend/references/designpowers/orchestration.md +1 -1
  518. package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +5 -5
  519. package/packages/shared-skills/skills/review-work/SKILL.md +3 -3
  520. package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  521. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +2 -0
  522. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +179 -0
  523. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
  524. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  525. package/packages/shared-skills/skills/{start-work → ulw-execute}/SKILL.md +9 -8
  526. package/packages/shared-skills/skills/ulw-plan/SKILL.md +6 -6
  527. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +31 -7
  528. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -1
  529. package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +5 -5
  530. package/packages/shared-skills/skills/ulw-research/SKILL.md +4 -2
  531. package/packages/shared-skills/skills/visual-qa/AGENTS.md +58 -0
  532. package/packages/shared-skills/skills/visual-qa/SKILL.md +3 -2
  533. package/script/qa/web-terminal-visual-qa.mjs +2 -0
  534. package/script/qa/xterm-live-terminal.mjs +18 -2
  535. package/dist/config/schema/start-work.d.ts +0 -5
  536. package/dist/features/builtin-commands/templates/start-work.d.ts +0 -1
  537. package/dist/hooks/start-work/start-work-hook.d.ts +0 -23
  538. package/dist/plugin/chat-message/start-work-message.d.ts +0 -5
  539. package/dist/skills/data-scientist/references/common-scenarios.md +0 -176
  540. package/dist/skills/data-scientist/references/execution-templates.md +0 -197
  541. package/dist/skills/data-scientist/references/integration-patterns.md +0 -153
  542. package/dist/skills/data-scientist/references/performance-benchmarks.md +0 -37
  543. package/dist/tools/call-omo-agent/background-agent-executor.d.ts +0 -5
  544. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +0 -28
  545. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +0 -17
  546. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +0 -17
  547. package/packages/omo-codex/plugin/skills/data-scientist/references/common-scenarios.md +0 -176
  548. package/packages/omo-codex/plugin/skills/data-scientist/references/execution-templates.md +0 -197
  549. package/packages/omo-codex/plugin/skills/data-scientist/references/integration-patterns.md +0 -153
  550. package/packages/omo-codex/plugin/skills/data-scientist/references/performance-benchmarks.md +0 -37
  551. package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +0 -2
  552. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +0 -92
  553. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +0 -314
  554. package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +0 -24
  555. package/packages/shared-skills/skills/data-scientist/references/common-scenarios.md +0 -176
  556. package/packages/shared-skills/skills/data-scientist/references/execution-templates.md +0 -197
  557. package/packages/shared-skills/skills/data-scientist/references/integration-patterns.md +0 -153
  558. package/packages/shared-skills/skills/data-scientist/references/performance-benchmarks.md +0 -37
  559. /package/dist/hooks/{start-work → ulw-execute}/context-info-formatters.d.ts +0 -0
  560. /package/dist/hooks/{start-work → ulw-execute}/explicit-plan-context.d.ts +0 -0
  561. /package/dist/hooks/{start-work → ulw-execute}/notepad-scaffold.d.ts +0 -0
  562. /package/dist/hooks/{start-work → ulw-execute}/parse-user-request.d.ts +0 -0
  563. /package/dist/hooks/{start-work → ulw-execute}/plan-discovery-context.d.ts +0 -0
  564. /package/dist/hooks/{start-work → ulw-execute}/plan-selection.d.ts +0 -0
  565. /package/dist/hooks/{start-work → ulw-execute}/session-plan-affinity.d.ts +0 -0
  566. /package/dist/hooks/{start-work → ulw-execute}/work-initializer.d.ts +0 -0
  567. /package/dist/hooks/{start-work → ulw-execute}/worktree-block.d.ts +0 -0
  568. /package/dist/hooks/{start-work → ulw-execute}/worktree-detector.d.ts +0 -0
  569. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/.gitattributes +0 -0
  570. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/CHANGELOG.md +0 -0
  571. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/LICENSE +0 -0
  572. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/plan-checklist.ts +0 -0
  573. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/types.ts +0 -0
  574. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-completed.json +0 -0
  575. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-mixed-platforms.json +0 -0
  576. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-single-codex-work.json +0 -0
  577. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-all-done.md +0 -0
  578. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-scaffold.md +0 -0
  579. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-nested-checkboxes.md +0 -0
  580. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-unchecked.md +0 -0
  581. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.build.json +0 -0
  582. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.json +0 -0
  583. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/vitest.config.ts +0 -0
@@ -6,6 +6,7 @@ import type { LspClientTimeoutOptions } from "./transport.js";
6
6
  import type {
7
7
  Diagnostic,
8
8
  DocumentSymbol,
9
+ FormattingOptions,
9
10
  Location,
10
11
  LocationLink,
11
12
  PrepareRenameDefaultBehavior,
@@ -13,6 +14,7 @@ import type {
13
14
  Range,
14
15
  ResolvedServer,
15
16
  SymbolInfo,
17
+ TextEdit,
16
18
  WorkspaceEdit,
17
19
  } from "./types.js";
18
20
  import { LspRequestTimeoutError } from "./errors.js";
@@ -133,6 +135,30 @@ export class LspClient extends LspClientConnection {
133
135
  }, options);
134
136
  }
135
137
 
138
+ /**
139
+ * Requests whole-document formatting edits, returning null when the server never advertised the
140
+ * capability so callers can report unavailability instead of surfacing a method-not-found error.
141
+ */
142
+ async formatDocument(
143
+ filePath: string,
144
+ options: FormattingOptions,
145
+ signal?: AbortSignal,
146
+ ): Promise<TextEdit[] | null> {
147
+ if (!this.isDocumentFormattingSupported()) return null;
148
+ const absPath = this.resolveWorkspacePath(filePath);
149
+ await this.openFile(absPath);
150
+ const requestOptions = signal === undefined ? {} : { signal };
151
+ const edits = await this.sendRequest<TextEdit[] | null>(
152
+ "textDocument/formatting",
153
+ {
154
+ textDocument: { uri: pathToFileURL(absPath).href },
155
+ options,
156
+ },
157
+ requestOptions,
158
+ );
159
+ return edits ?? [];
160
+ }
161
+
136
162
  async workspaceSymbols(query: string, signal?: AbortSignal): Promise<SymbolInfo[]> {
137
163
  const options = signal === undefined ? {} : { signal };
138
164
  return this.sendRequest<SymbolInfo[]>("workspace/symbol", { query }, options);
@@ -4,6 +4,7 @@ import { LspClientTransport } from "./transport.js";
4
4
 
5
5
  interface InitializeCapabilities {
6
6
  readonly diagnosticProvider?: unknown;
7
+ readonly documentFormattingProvider?: unknown;
7
8
  }
8
9
 
9
10
  function supportsDiagnosticPull(capabilities: InitializeCapabilities | undefined): boolean {
@@ -11,6 +12,19 @@ function supportsDiagnosticPull(capabilities: InitializeCapabilities | undefined
11
12
  return Object.hasOwn(capabilities, "diagnosticProvider");
12
13
  }
13
14
 
15
+ /**
16
+ * Reads the whole-document formatting capability the server advertised at initialize time.
17
+ *
18
+ * The provider is either a boolean or an options object, and an explicit `false` means the
19
+ * server refuses the request, so both shapes are checked instead of mere key presence.
20
+ */
21
+ function supportsDocumentFormatting(capabilities: InitializeCapabilities | undefined): boolean {
22
+ if (capabilities === undefined) return false;
23
+ const provider = capabilities.documentFormattingProvider;
24
+ if (provider === undefined || provider === null || provider === false) return false;
25
+ return provider === true || typeof provider === "object";
26
+ }
27
+
14
28
  export class LspClientConnection extends LspClientTransport {
15
29
  async initialize(): Promise<void> {
16
30
  const rootUri = pathToFileURL(this.root).href;
@@ -28,6 +42,7 @@ export class LspClientConnection extends LspClientTransport {
28
42
  references: {},
29
43
  documentSymbol: { hierarchicalDocumentSymbolSupport: true },
30
44
  publishDiagnostics: {},
45
+ formatting: { dynamicRegistration: false },
31
46
  rename: {
32
47
  prepareSupport: true,
33
48
  prepareSupportDefaultBehavior: 1,
@@ -71,6 +86,7 @@ export class LspClientConnection extends LspClientTransport {
71
86
  { timeoutMs: this.initializeTimeoutMs },
72
87
  );
73
88
  this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
89
+ this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
74
90
  await this.sendNotification("initialized", {});
75
91
  await this.sendNotification("workspace/didChangeConfiguration", {
76
92
  settings: { json: { validate: { enable: true } } },
@@ -6,6 +6,7 @@ export const DEFAULT_MAX_DIRECTORY_FILES = 50;
6
6
  export const REQUEST_TIMEOUT_MS = 15_000;
7
7
  export const INIT_TIMEOUT_MS = 60_000;
8
8
  export const IDLE_TIMEOUT_MS = 5 * 60_000;
9
+ export const MAX_RESIDENT_CLIENTS = 6;
9
10
  export const REAPER_INTERVAL_MS = 60_000;
10
11
  export const STOP_HARD_KILL_TIMEOUT_MS = 5_000;
11
12
  export const STOP_SIGKILL_GRACE_MS = 1_000;
@@ -0,0 +1,143 @@
1
+ import { mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+
5
+ import { afterEach, describe, expect, it } from "bun:test";
6
+
7
+ import type { LspClient } from "./client.js";
8
+ import { formatDocumentWithClient } from "./format-document.js";
9
+ import type { TextEdit } from "./types.js";
10
+
11
+ const workspaces: string[] = [];
12
+
13
+ afterEach(() => {
14
+ for (const workspace of workspaces.splice(0)) rmSync(workspace, { recursive: true, force: true });
15
+ });
16
+
17
+ function workspaceWith(fileName: string, content: string): { readonly root: string; readonly filePath: string } {
18
+ const root = mkdtempSync(join(tmpdir(), "lsp-format-"));
19
+ workspaces.push(root);
20
+ const filePath = join(root, fileName);
21
+ writeFileSync(filePath, content, "utf-8");
22
+ return { root, filePath };
23
+ }
24
+
25
+ function stubClient(edits: TextEdit[] | null): LspClient {
26
+ return {
27
+ async formatDocument() {
28
+ return edits;
29
+ },
30
+ async openFile() {},
31
+ } as Pick<LspClient, "formatDocument" | "openFile"> as LspClient;
32
+ }
33
+
34
+ describe("formatDocumentWithClient", () => {
35
+ it("#given a server returning text edits #when the document is formatted #then the file is rewritten and line deltas are reported", async () => {
36
+ // given
37
+ const { filePath } = workspaceWith("sample.ts", "const a=1\nconst b =2\nconst c=3\n");
38
+ const edits: TextEdit[] = [
39
+ { range: { start: { line: 0, character: 0 }, end: { line: 1, character: 12 } }, newText: "const a = 1;\nconst b = 2;" },
40
+ ];
41
+
42
+ // when
43
+ const result = await formatDocumentWithClient(stubClient(edits), filePath);
44
+
45
+ // then
46
+ expect(result.status).toBe("formatted");
47
+ expect(readFileSync(filePath, "utf-8")).toBe("const a = 1;\nconst b = 2;\nconst c=3\n");
48
+ expect(result).toMatchObject({ status: "formatted", linesAdded: 2, linesRemoved: 2 });
49
+ });
50
+
51
+ it("#given a server returning an edit that adds lines #when the document is formatted #then the added and removed line counts differ", async () => {
52
+ // given
53
+ const { filePath } = workspaceWith("sample.ts", "const a=1;const b=2\n");
54
+ const edits: TextEdit[] = [
55
+ { range: { start: { line: 0, character: 0 }, end: { line: 0, character: 19 } }, newText: "const a = 1;\nconst b = 2;" },
56
+ ];
57
+
58
+ // when
59
+ const result = await formatDocumentWithClient(stubClient(edits), filePath);
60
+
61
+ // then
62
+ expect(result).toMatchObject({ status: "formatted", linesAdded: 2, linesRemoved: 1 });
63
+ expect(readFileSync(filePath, "utf-8")).toBe("const a = 1;\nconst b = 2;\n");
64
+ });
65
+
66
+ it("#given a server that does not advertise document formatting #when the document is formatted #then the result is unavailable and the file bytes are untouched", async () => {
67
+ // given
68
+ const original = "const a=1\n";
69
+ const { filePath } = workspaceWith("sample.ts", original);
70
+ const before = statSync(filePath);
71
+
72
+ // when
73
+ const result = await formatDocumentWithClient(stubClient(null), filePath);
74
+
75
+ // then
76
+ expect(result).toEqual({ status: "unavailable", reason: "capability_not_advertised" });
77
+ expect(readFileSync(filePath)).toEqual(Buffer.from(original));
78
+ expect(statSync(filePath).mtimeMs).toBe(before.mtimeMs);
79
+ });
80
+
81
+ it("#given a server returning no edits #when the document is formatted #then the result is unchanged and the file bytes are untouched", async () => {
82
+ // given
83
+ const original = "const a = 1;\n";
84
+ const { filePath } = workspaceWith("sample.ts", original);
85
+
86
+ // when
87
+ const result = await formatDocumentWithClient(stubClient([]), filePath);
88
+
89
+ // then
90
+ expect(result).toEqual({ status: "unchanged", linesAdded: 0, linesRemoved: 0 });
91
+ expect(readFileSync(filePath)).toEqual(Buffer.from(original));
92
+ });
93
+
94
+ it("#given edits that reproduce the current bytes #when the document is formatted #then the result is unchanged", async () => {
95
+ // given
96
+ const original = "const a = 1;\n";
97
+ const { filePath } = workspaceWith("sample.ts", original);
98
+ const edits: TextEdit[] = [
99
+ { range: { start: { line: 0, character: 0 }, end: { line: 0, character: 12 } }, newText: "const a = 1;" },
100
+ ];
101
+
102
+ // when
103
+ const result = await formatDocumentWithClient(stubClient(edits), filePath);
104
+
105
+ // then
106
+ expect(result.status).toBe("unchanged");
107
+ expect(readFileSync(filePath, "utf-8")).toBe(original);
108
+ });
109
+
110
+ it("#given the file shrinks after the server computed its edits #when the edits are applied #then the stale edit is rejected instead of corrupting the file", async () => {
111
+ // given
112
+ const { filePath } = workspaceWith("sample.ts", "const a=1\nconst b=2\n");
113
+ const staleEdits: TextEdit[] = [
114
+ { range: { start: { line: 1, character: 0 }, end: { line: 1, character: 9 } }, newText: "const b = 2;" },
115
+ ];
116
+ const racingClient = {
117
+ async formatDocument() {
118
+ writeFileSync(filePath, "short\n", "utf-8");
119
+ return staleEdits;
120
+ },
121
+ async openFile() {},
122
+ } as Pick<LspClient, "formatDocument" | "openFile"> as LspClient;
123
+
124
+ // when / then
125
+ await expect(formatDocumentWithClient(racingClient, filePath)).rejects.toThrow(/outside line/);
126
+ expect(readFileSync(filePath, "utf-8")).toBe("short\n");
127
+ });
128
+
129
+ it("#given a formatted document #when the write completes #then no temporary file is left behind", async () => {
130
+ // given
131
+ const { root, filePath } = workspaceWith("sample.ts", "const a=1\n");
132
+ const edits: TextEdit[] = [
133
+ { range: { start: { line: 0, character: 0 }, end: { line: 0, character: 9 } }, newText: "const a = 1;" },
134
+ ];
135
+
136
+ // when
137
+ await formatDocumentWithClient(stubClient(edits), filePath);
138
+
139
+ // then
140
+ expect(readFileSync(filePath, "utf-8")).toBe("const a = 1;\n");
141
+ expect(() => statSync(join(root, "sample.ts.tmp"))).toThrow();
142
+ });
143
+ });
@@ -0,0 +1,90 @@
1
+ import { readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
+
3
+ import type { LspClient } from "./client.js";
4
+ import type { FormattingOptions, TextEdit } from "./types.js";
5
+ import { normalizeTextEdits } from "./workspace-edit-text.js";
6
+
7
+ export const DEFAULT_FORMATTING_OPTIONS: FormattingOptions = {
8
+ tabSize: 4,
9
+ insertSpaces: false,
10
+ trimTrailingWhitespace: true,
11
+ insertFinalNewline: true,
12
+ trimFinalNewlines: true,
13
+ };
14
+
15
+ export type FormatDocumentResult =
16
+ | { readonly status: "formatted"; readonly linesAdded: number; readonly linesRemoved: number }
17
+ | { readonly status: "unchanged"; readonly linesAdded: 0; readonly linesRemoved: 0 }
18
+ | { readonly status: "unavailable"; readonly reason: "capability_not_advertised" };
19
+
20
+ export interface FormatDocumentOptions {
21
+ readonly formattingOptions?: FormattingOptions;
22
+ readonly signal?: AbortSignal;
23
+ }
24
+
25
+ const UNCHANGED: FormatDocumentResult = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
26
+
27
+ /**
28
+ * Formats one document through the resident language server and commits the result to disk.
29
+ *
30
+ * The server is asked for whole-document edits rather than formatted text, so the edits are
31
+ * validated and applied with the same normalization the workspace-edit path uses. Nothing is
32
+ * written when the server declines the capability or when the edits reproduce the current bytes,
33
+ * which keeps a no-op format from touching file mtimes that downstream tooling watches.
34
+ */
35
+ export async function formatDocumentWithClient(
36
+ client: LspClient,
37
+ filePath: string,
38
+ options: FormatDocumentOptions = {},
39
+ ): Promise<FormatDocumentResult> {
40
+ const edits = await client.formatDocument(
41
+ filePath,
42
+ options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS,
43
+ options.signal,
44
+ );
45
+ if (edits === null) return { status: "unavailable", reason: "capability_not_advertised" };
46
+ if (edits.length === 0) return UNCHANGED;
47
+
48
+ const before = readFileSync(filePath, "utf-8");
49
+ const normalized = normalizeTextEdits(before, edits, 0);
50
+ if (normalized.text === before) return UNCHANGED;
51
+
52
+ writeAtomically(filePath, normalized.text);
53
+ await client.openFile(filePath);
54
+
55
+ return {
56
+ status: "formatted",
57
+ ...lineDelta(normalized.edits),
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Counts the lines each edit removes from the document and adds back in its place.
63
+ *
64
+ * Counting from the edits instead of diffing the whole file keeps the report proportional to what
65
+ * the server actually rewrote, so an unrelated line never shows up as churn.
66
+ */
67
+ function lineDelta(edits: readonly TextEdit[]): { readonly linesAdded: number; readonly linesRemoved: number } {
68
+ let linesAdded = 0;
69
+ let linesRemoved = 0;
70
+ for (const edit of edits) {
71
+ linesRemoved += edit.range.end.line - edit.range.start.line + 1;
72
+ linesAdded += edit.newText.split("\n").length;
73
+ }
74
+ return { linesAdded, linesRemoved };
75
+ }
76
+
77
+ function writeAtomically(filePath: string, content: string): void {
78
+ const tempPath = `${filePath}.omo-format.tmp`;
79
+ writeFileSync(tempPath, content, "utf-8");
80
+ try {
81
+ renameSync(tempPath, filePath);
82
+ } catch (error) {
83
+ try {
84
+ unlinkSync(tempPath);
85
+ } catch {
86
+ // The rename failure is the actionable error; a leftover temp file must not mask it.
87
+ }
88
+ throw error;
89
+ }
90
+ }
@@ -0,0 +1,151 @@
1
+ import { describe, expect, it } from "bun:test";
2
+
3
+ import type { LspClient } from "./client.js";
4
+ import { LspManager } from "./manager.js";
5
+ import type { ResolvedServer } from "./types.js";
6
+
7
+ const SERVER: ResolvedServer = {
8
+ id: "typescript",
9
+ command: ["typescript-language-server", "--stdio"],
10
+ extensions: [".ts"],
11
+ priority: 1,
12
+ };
13
+
14
+ class FakeLspClient {
15
+ alive = true;
16
+ stopCallCount = 0;
17
+
18
+ constructor(readonly root: string) {}
19
+
20
+ async start(): Promise<void> {}
21
+
22
+ async initialize(): Promise<void> {}
23
+
24
+ isAlive(): boolean {
25
+ return this.alive;
26
+ }
27
+
28
+ command(): string[] {
29
+ return [...SERVER.command];
30
+ }
31
+
32
+ async stop(): Promise<void> {
33
+ this.stopCallCount += 1;
34
+ this.alive = false;
35
+ }
36
+ }
37
+
38
+ function managerWithFakes(maxResidentClients: number): {
39
+ readonly manager: LspManager;
40
+ readonly clients: Map<string, FakeLspClient>;
41
+ readonly clock: { value: number };
42
+ } {
43
+ const clients = new Map<string, FakeLspClient>();
44
+ const clock = { value: 1_000 };
45
+ const manager = new LspManager({
46
+ maxResidentClients,
47
+ reaperIntervalMs: 60_000,
48
+ idleTimeoutMs: 60_000_000,
49
+ now: () => clock.value,
50
+ clientFactory: (root) => {
51
+ const client = new FakeLspClient(root);
52
+ clients.set(root, client);
53
+ return client as unknown as LspClient;
54
+ },
55
+ });
56
+ return { manager, clients, clock };
57
+ }
58
+
59
+ describe("LspManager resident client cap", () => {
60
+ it("#given a cap of two idle clients #when a third client is admitted #then the least recently used one is stopped and evicted", async () => {
61
+ // given
62
+ const { manager, clients, clock } = managerWithFakes(2);
63
+ try {
64
+ await manager.getClient("/root-a", SERVER);
65
+ manager.releaseClient("/root-a", SERVER.id);
66
+ clock.value += 10;
67
+ await manager.getClient("/root-b", SERVER);
68
+ manager.releaseClient("/root-b", SERVER.id);
69
+ clock.value += 10;
70
+
71
+ // when
72
+ await manager.getClient("/root-c", SERVER);
73
+ manager.releaseClient("/root-c", SERVER.id);
74
+
75
+ // then
76
+ expect(manager.clientCount()).toBe(2);
77
+ expect(manager.hasClient("/root-a", SERVER.id)).toBe(false);
78
+ expect(manager.hasClient("/root-b", SERVER.id)).toBe(true);
79
+ expect(manager.hasClient("/root-c", SERVER.id)).toBe(true);
80
+ expect(clients.get("/root-a")?.stopCallCount).toBe(1);
81
+ } finally {
82
+ await manager.stopAll();
83
+ }
84
+ });
85
+
86
+ it("#given the least recently used client is mid-request #when a new client is admitted #then the busy client survives and an idle one is evicted", async () => {
87
+ // given
88
+ const { manager, clients, clock } = managerWithFakes(2);
89
+ try {
90
+ await manager.getClient("/root-busy", SERVER);
91
+ clock.value += 10;
92
+ await manager.getClient("/root-idle", SERVER);
93
+ manager.releaseClient("/root-idle", SERVER.id);
94
+ clock.value += 10;
95
+
96
+ // when
97
+ await manager.getClient("/root-new", SERVER);
98
+ manager.releaseClient("/root-new", SERVER.id);
99
+
100
+ // then
101
+ expect(manager.hasClient("/root-busy", SERVER.id)).toBe(true);
102
+ expect(manager.hasClient("/root-idle", SERVER.id)).toBe(false);
103
+ expect(clients.get("/root-busy")?.stopCallCount).toBe(0);
104
+ expect(clients.get("/root-idle")?.stopCallCount).toBe(1);
105
+ } finally {
106
+ manager.releaseClient("/root-busy", SERVER.id);
107
+ await manager.stopAll();
108
+ }
109
+ });
110
+
111
+ it("#given every resident client is busy #when a new client is admitted #then nothing is evicted and the cap is exceeded rather than breaking a live request", async () => {
112
+ // given
113
+ const { manager, clients } = managerWithFakes(1);
114
+ try {
115
+ await manager.getClient("/root-busy", SERVER);
116
+
117
+ // when
118
+ await manager.getClient("/root-second", SERVER);
119
+
120
+ // then
121
+ expect(manager.clientCount()).toBe(2);
122
+ expect(clients.get("/root-busy")?.stopCallCount).toBe(0);
123
+ } finally {
124
+ manager.releaseClient("/root-busy", SERVER.id);
125
+ manager.releaseClient("/root-second", SERVER.id);
126
+ await manager.stopAll();
127
+ }
128
+ });
129
+
130
+ it("#given warmup requests beyond the cap #when a warm client is admitted #then the idle least recently used client is evicted too", async () => {
131
+ // given
132
+ const { manager, clients, clock } = managerWithFakes(1);
133
+ try {
134
+ await manager.getClient("/root-first", SERVER);
135
+ manager.releaseClient("/root-first", SERVER.id);
136
+ clock.value += 10;
137
+
138
+ // when
139
+ manager.warmupClient("/root-warm", SERVER);
140
+ await Promise.resolve();
141
+ await Promise.resolve();
142
+
143
+ // then
144
+ expect(manager.hasClient("/root-first", SERVER.id)).toBe(false);
145
+ expect(clients.get("/root-first")?.stopCallCount).toBe(1);
146
+ expect(manager.hasClient("/root-warm", SERVER.id)).toBe(true);
147
+ } finally {
148
+ await manager.stopAll();
149
+ }
150
+ });
151
+ });
@@ -1,6 +1,6 @@
1
1
  import { reportBestEffortCleanupError } from "./cleanup-errors.js";
2
2
  import { LspClient } from "./client.js";
3
- import { IDLE_TIMEOUT_MS, INIT_TIMEOUT_MS, REAPER_INTERVAL_MS } from "./constants.js";
3
+ import { IDLE_TIMEOUT_MS, INIT_TIMEOUT_MS, MAX_RESIDENT_CLIENTS, REAPER_INTERVAL_MS } from "./constants.js";
4
4
  import { installProcessSignalCleanup } from "./process-signal-cleanup.js";
5
5
  import type { ResolvedServer } from "./types.js";
6
6
 
@@ -28,6 +28,7 @@ export interface ClientSnapshot {
28
28
  export interface LspManagerOptions {
29
29
  idleTimeoutMs?: number;
30
30
  initTimeoutMs?: number;
31
+ maxResidentClients?: number;
31
32
  reaperIntervalMs?: number;
32
33
  clientFactory?: (root: string, server: ResolvedServer) => LspClient;
33
34
  now?: () => number;
@@ -80,6 +81,7 @@ export class LspManager {
80
81
 
81
82
  private readonly idleTimeoutMs: number;
82
83
  private readonly initTimeoutMs: number;
84
+ private readonly maxResidentClients: number;
83
85
  private readonly reaperIntervalMs: number;
84
86
  private readonly clientFactory: (root: string, server: ResolvedServer) => LspClient;
85
87
  private readonly now: () => number;
@@ -87,6 +89,7 @@ export class LspManager {
87
89
  constructor(options: LspManagerOptions = {}) {
88
90
  this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
89
91
  this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
92
+ this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
90
93
  this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
91
94
  this.clientFactory = options.clientFactory ?? ((root, server) => new LspClient(root, server));
92
95
  this.now = options.now ?? (() => Date.now());
@@ -134,6 +137,32 @@ export class LspManager {
134
137
  }
135
138
  }
136
139
 
140
+ /**
141
+ * Frees capacity for one new client by stopping the least recently used idle client.
142
+ *
143
+ * Only clients with no in-flight work are eligible, so a resident server is never torn down
144
+ * underneath a live request; when every resident client is busy the cap is exceeded instead.
145
+ */
146
+ private evictForAdmission(): void {
147
+ while (this.clients.size >= this.maxResidentClients) {
148
+ const victim = this.leastRecentlyUsedIdleClient();
149
+ if (!victim) return;
150
+ this.clients.delete(victim.key);
151
+ void stopClientBestEffort(victim.managed.client);
152
+ }
153
+ }
154
+
155
+ private leastRecentlyUsedIdleClient(): { readonly key: string; readonly managed: ManagedClient } | null {
156
+ let candidate: { readonly key: string; readonly managed: ManagedClient } | null = null;
157
+ for (const [key, managed] of this.clients) {
158
+ if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing) continue;
159
+ if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
160
+ candidate = { key, managed };
161
+ }
162
+ }
163
+ return candidate;
164
+ }
165
+
137
166
  private async tryDeleteIfOrphaned(key: string, managed: ManagedClient): Promise<void> {
138
167
  if (
139
168
  managed.refCount === 0 &&
@@ -197,6 +226,8 @@ export class LspManager {
197
226
  return managed.client;
198
227
  }
199
228
 
229
+ this.evictForAdmission();
230
+
200
231
  const client = this.clientFactory(root, server);
201
232
  const initStartedAt = this.now();
202
233
  const initPromise = (async () => {
@@ -264,6 +295,8 @@ export class LspManager {
264
295
  const key = this.getKey(root, server.id);
265
296
  if (this.clients.has(key)) return;
266
297
 
298
+ this.evictForAdmission();
299
+
267
300
  const client = this.clientFactory(root, server);
268
301
  const initStartedAt = this.now();
269
302
  const initPromise = (async () => {
@@ -0,0 +1,33 @@
1
+ import { existsSync, realpathSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+
4
+ import { WORKSPACE_MARKERS } from "./workspace-markers.js";
5
+
6
+ /** Read-only tools accept out-of-cwd files, so cwd cannot bound this search; the fallback keeps the server scoped to the file's own directory. */
7
+ export function findWorkspaceRootOutsideContext(directory: string): string {
8
+ const marked = nearestMarkedAncestor(directory);
9
+ if (marked !== undefined) return marked;
10
+ return realpathSync(nearestExistingAncestor(directory));
11
+ }
12
+
13
+ function nearestMarkedAncestor(directory: string): string | undefined {
14
+ let current = directory;
15
+ for (;;) {
16
+ if (existsSync(current) && WORKSPACE_MARKERS.some((marker) => existsSync(join(current, marker)))) {
17
+ return realpathSync(current);
18
+ }
19
+ const parent = dirname(current);
20
+ if (parent === current) return undefined;
21
+ current = parent;
22
+ }
23
+ }
24
+
25
+ function nearestExistingAncestor(directory: string): string {
26
+ let current = directory;
27
+ while (!existsSync(current)) {
28
+ const parent = dirname(current);
29
+ if (parent === current) return current;
30
+ current = parent;
31
+ }
32
+ return current;
33
+ }
@@ -49,6 +49,35 @@ export const LSP_INSTALL_HINTS: Record<string, string> = {
49
49
  "Install: dotnet tool install -g roslyn-language-server --prerelease (requires v5.8.0+). See https://github.com/dotnet/razor",
50
50
  };
51
51
 
52
+ /**
53
+ * Repo-local install commands, offered ahead of the global hints in `LSP_INSTALL_HINTS`.
54
+ *
55
+ * A devDependency (or project venv) is resolvable by `resolveServerBinary()` without any
56
+ * global install, and it pins the version the project actually expects. Only servers that
57
+ * are genuinely distributed per-project belong here; toolchain-wide servers (rust-analyzer,
58
+ * gopls, clangd, ...) keep their global hint alone.
59
+ */
60
+ export const LSP_LOCAL_INSTALL_HINTS: Record<string, string> = {
61
+ typescript: "bun add -d typescript-language-server typescript",
62
+ vue: "bun add -d @vue/language-server",
63
+ eslint: "bun add -d vscode-langservers-extracted",
64
+ oxlint: "bun add -d oxlint",
65
+ biome: "bun add -d @biomejs/biome",
66
+ svelte: "bun add -d svelte-language-server",
67
+ astro: "bun add -d @astrojs/language-server",
68
+ bash: "bun add -d bash-language-server",
69
+ "bash-ls": "bun add -d bash-language-server",
70
+ "yaml-ls": "bun add -d yaml-language-server",
71
+ php: "bun add -d intelephense",
72
+ prisma: "bun add -d prisma",
73
+ dockerfile: "bun add -d dockerfile-language-server-nodejs",
74
+ pyright: "uv add --dev pyright",
75
+ basedpyright: "uv add --dev basedpyright",
76
+ ruff: "uv add --dev ruff",
77
+ ty: "uv add --dev ty",
78
+ "ruby-lsp": "bundle add ruby-lsp --group development",
79
+ };
80
+
52
81
  export const BUILTIN_SERVERS: Record<string, Omit<LspServerConfig, "id">> = {
53
82
  typescript: {
54
83
  command: ["typescript-language-server", "--stdio"],