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

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 (639) 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 +22601 -20302
  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 +22219 -19897
  38. package/dist/config/schema/background-task.d.ts +1 -0
  39. package/dist/config/schema/commands.d.ts +1 -1
  40. package/dist/config/schema/hooks.d.ts +1 -1
  41. package/dist/config/schema/oh-my-opencode-config.d.ts +5 -1
  42. package/dist/config/schema/ulw-execute.d.ts +5 -0
  43. package/dist/config/validate.d.ts +2 -0
  44. package/dist/create-hooks.d.ts +3 -1
  45. package/dist/features/background-agent/constants.d.ts +0 -7
  46. package/dist/features/background-agent/manager.d.ts +2 -1
  47. package/dist/features/background-agent/parent-wake-dispatched-tracker.d.ts +0 -1
  48. package/dist/features/background-agent/subagent-spawn-limits.d.ts +8 -0
  49. package/dist/features/btw-side/btw-command-draft.d.ts +7 -0
  50. package/dist/features/btw-side/context-injector.d.ts +15 -0
  51. package/dist/features/btw-side/index.d.ts +8 -0
  52. package/dist/features/btw-side/metadata.d.ts +15 -0
  53. package/dist/features/btw-side/parent-context-budget.d.ts +9 -0
  54. package/dist/features/btw-side/server-session-registry.d.ts +8 -0
  55. package/dist/features/btw-side/tui-adoption-cache.d.ts +13 -0
  56. package/dist/features/btw-side/tui-adoption-guard.d.ts +5 -0
  57. package/dist/features/btw-side/tui-controller-types.d.ts +68 -0
  58. package/dist/features/btw-side/tui-controller.d.ts +19 -0
  59. package/dist/features/btw-side/tui-escape-return.d.ts +12 -0
  60. package/dist/features/btw-side/tui-keymap.d.ts +17 -0
  61. package/dist/features/btw-side/tui-parent-validator.d.ts +6 -0
  62. package/dist/features/btw-side/tui-picker-options.d.ts +20 -0
  63. package/dist/features/btw-side/tui-picker.d.ts +9 -0
  64. package/dist/features/btw-side/tui-prompt-queue.d.ts +8 -0
  65. package/dist/features/btw-side/tui-session-bridge.d.ts +11 -0
  66. package/dist/features/btw-side/tui-session-catalog.d.ts +35 -0
  67. package/dist/features/btw-side/tui-side-removal.d.ts +11 -0
  68. package/dist/features/btw-side/tui-side-start.d.ts +9 -0
  69. package/dist/features/btw-side/tui-wiring.d.ts +8 -0
  70. package/dist/features/builtin-commands/templates/ulw-execute.d.ts +1 -0
  71. package/dist/features/builtin-commands/types.d.ts +1 -1
  72. package/dist/features/opengateway-provider/index.d.ts +13 -0
  73. package/dist/features/task-toast-manager/manager.d.ts +0 -24
  74. package/dist/features/team-mode/tools/messaging-fallback-wake.d.ts +15 -0
  75. package/dist/hooks/anthropic-context-window-limit-recovery/message-storage-directory.d.ts +0 -3
  76. package/dist/hooks/anthropic-context-window-limit-recovery/state.d.ts +1 -0
  77. package/dist/hooks/anthropic-context-window-limit-recovery/storage/empty-messages.d.ts +0 -1
  78. package/dist/hooks/atlas/atlas-hook.d.ts +1 -0
  79. package/dist/hooks/atlas/atlas-lifecycle-store.d.ts +50 -0
  80. package/dist/hooks/atlas/event-handler.d.ts +1 -0
  81. package/dist/hooks/atlas/final-wave-approval-gate.test-support.d.ts +50 -0
  82. package/dist/hooks/atlas/system-reminder-templates.d.ts +0 -1
  83. package/dist/hooks/atlas/tool-execute-before.d.ts +3 -0
  84. package/dist/hooks/atlas/types.d.ts +1 -0
  85. package/dist/hooks/claude-code-hooks/session-hook-state.d.ts +1 -0
  86. package/dist/hooks/claude-code-hooks/stop.d.ts +2 -0
  87. package/dist/hooks/claude-code-hooks/todo.d.ts +0 -1
  88. package/dist/hooks/claude-code-hooks/transcript.d.ts +2 -0
  89. package/dist/hooks/fsync-skip-warning/index.d.ts +4 -0
  90. package/dist/hooks/hashline-edit-diff-enhancer/hook.d.ts +1 -0
  91. package/dist/hooks/hashline-edit-diff-enhancer/pending-captures.d.ts +13 -0
  92. package/dist/hooks/index.d.ts +1 -1
  93. package/dist/hooks/keyword-detector/hook.d.ts +7 -0
  94. package/dist/hooks/keyword-detector/ultrawork/source-detector.d.ts +0 -1
  95. package/dist/hooks/model-fallback/hook.d.ts +1 -1
  96. package/dist/hooks/prometheus-md-only/agent-resolution.d.ts +2 -2
  97. package/dist/hooks/runtime-fallback/chat-message-handler.d.ts +2 -0
  98. package/dist/hooks/runtime-fallback/retry-model-payload.d.ts +1 -0
  99. package/dist/hooks/runtime-fallback/runtime-model-settings.d.ts +6 -0
  100. package/dist/hooks/runtime-fallback/session-status-handler.d.ts +1 -1
  101. package/dist/hooks/runtime-fallback/types.d.ts +3 -1
  102. package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
  103. package/dist/hooks/todo-continuation-enforcer/types.d.ts +1 -0
  104. package/dist/hooks/{start-work → ulw-execute}/context-info-builder.d.ts +1 -1
  105. package/dist/hooks/{start-work → ulw-execute}/index.d.ts +1 -1
  106. package/dist/hooks/ulw-execute/ulw-execute-hook.d.ts +23 -0
  107. package/dist/index.js +12989 -7152
  108. package/dist/oh-my-opencode.schema.json +20 -2
  109. package/dist/plugin/chat-message/types.d.ts +3 -3
  110. package/dist/plugin/chat-message/ulw-execute-message.d.ts +5 -0
  111. package/dist/plugin/event-session-lifecycle.d.ts +1 -0
  112. package/dist/plugin/hooks/create-core-hooks.d.ts +2 -1
  113. package/dist/plugin/hooks/create-session-hooks.d.ts +2 -2
  114. package/dist/plugin/hooks/create-transform-hooks.d.ts +2 -0
  115. package/dist/plugin/messages-transform.d.ts +1 -0
  116. package/dist/plugin-dispose.d.ts +3 -0
  117. package/dist/shared/agent-tool-restrictions.d.ts +0 -1
  118. package/dist/shared/index.d.ts +2 -0
  119. package/dist/shared/legacy-plugin-warning.d.ts +2 -1
  120. package/dist/shared/normalize-sdk-response.d.ts +1 -0
  121. package/dist/shared/plugin-entry-migrator.d.ts +4 -3
  122. package/dist/shared/plugin-entry-shape.d.ts +6 -0
  123. package/dist/shared/runtime-fallback-retry-marker.d.ts +16 -0
  124. package/dist/shared/shell-env.d.ts +1 -1
  125. package/dist/skills/ast-grep/AGENTS.md +51 -0
  126. package/dist/skills/coding-agent-sessions/AGENTS.md +62 -0
  127. package/dist/skills/coding-agent-sessions/SKILL.md +3 -2
  128. package/dist/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  129. package/dist/skills/coding-agent-sessions/references/senpi.md +4 -4
  130. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  131. package/dist/skills/data-scientist/SKILL.md +99 -239
  132. package/dist/skills/data-scientist/references/execution-surfaces.md +91 -0
  133. package/dist/skills/data-scientist/references/placement.md +74 -0
  134. package/dist/skills/data-scientist/references/polars-lane.md +95 -0
  135. package/dist/skills/data-scientist/references/uv-setup.md +1 -1
  136. package/dist/skills/data-scientist/references/visualization.md +64 -0
  137. package/dist/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  138. package/dist/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  139. package/dist/skills/debugging/SKILL.md +2 -0
  140. package/dist/skills/debugging/references/methodology/00-setup.md +12 -0
  141. package/dist/skills/debugging/references/methodology/02-investigate.md +21 -0
  142. package/dist/skills/debugging/references/runtimes/go.md +15 -1
  143. package/dist/skills/debugging/references/runtimes/native-binary.md +38 -0
  144. package/dist/skills/debugging/references/runtimes/node.md +25 -0
  145. package/dist/skills/debugging/references/runtimes/python.md +13 -0
  146. package/dist/skills/debugging/references/runtimes/rust.md +41 -0
  147. package/dist/skills/debugging/references/scripts/dap.mjs +267 -0
  148. package/dist/skills/debugging/references/scripts/dap.test.ts +86 -0
  149. package/dist/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  150. package/dist/skills/debugging/references/tools/dap.md +103 -0
  151. package/dist/skills/debugging/references/tools/frida.md +193 -0
  152. package/dist/skills/frontend/SKILL.md +11 -7
  153. package/dist/skills/frontend/references/design/_INDEX.md +1 -0
  154. package/dist/skills/frontend/references/design/print-paged-media.md +76 -0
  155. package/dist/skills/frontend/references/design/stylegallery.md +80 -0
  156. package/dist/skills/frontend/references/designpowers/README.md +1 -1
  157. package/dist/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  158. package/dist/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  159. package/dist/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  160. package/dist/skills/frontend/references/designpowers/orchestration.md +1 -1
  161. package/dist/skills/frontend/references/designpowers/routing.md +5 -5
  162. package/dist/skills/review-work/SKILL.md +3 -3
  163. package/dist/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  164. package/dist/skills/ultimate-browsing/SKILL.md +2 -0
  165. package/dist/skills/ultimate-browsing/engine/AGENTS.md +179 -0
  166. package/dist/skills/ultimate-browsing/engine/templates/package.json +1 -1
  167. package/dist/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  168. package/dist/skills/{start-work → ulw-execute}/SKILL.md +9 -8
  169. package/dist/skills/ulw-plan/SKILL.md +6 -6
  170. package/dist/skills/ulw-plan/references/full-workflow.md +31 -7
  171. package/dist/skills/ulw-plan/references/intent-clear.md +2 -1
  172. package/dist/skills/ulw-plan/references/intent-unclear.md +5 -5
  173. package/dist/skills/ulw-research/SKILL.md +4 -2
  174. package/dist/skills/visual-qa/AGENTS.md +58 -0
  175. package/dist/skills/visual-qa/SKILL.md +3 -2
  176. package/dist/tools/delegate-task/builtin-categories.d.ts +1 -0
  177. package/dist/tools/delegate-task/builtin-category-definition.d.ts +1 -0
  178. package/dist/tools/delegate-task/sync-session-cleanup.d.ts +3 -0
  179. package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -0
  180. package/dist/tools/delegate-task/tool-description.d.ts +3 -1
  181. package/dist/tools/delegate-task/types.d.ts +4 -0
  182. package/dist/tui.d.ts +12 -0
  183. package/dist/tui.js +11522 -11501
  184. package/package.json +42 -36
  185. package/packages/git-bash-mcp/dist/cli.js +6 -1
  186. package/packages/git-bash-mcp/package.json +1 -1
  187. package/packages/lsp-core/src/index.ts +1 -0
  188. package/packages/lsp-core/src/lsp/client-diagnostics-concurrency.integration.test.ts +44 -0
  189. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +0 -28
  190. package/packages/lsp-core/src/lsp/client-wrapper-outside-cwd.test.ts +78 -0
  191. package/packages/lsp-core/src/lsp/client-wrapper.test.ts +163 -13
  192. package/packages/lsp-core/src/lsp/client-wrapper.ts +110 -23
  193. package/packages/lsp-core/src/lsp/client.ts +26 -0
  194. package/packages/lsp-core/src/lsp/connection.ts +16 -0
  195. package/packages/lsp-core/src/lsp/constants.ts +6 -0
  196. package/packages/lsp-core/src/lsp/errors.ts +15 -0
  197. package/packages/lsp-core/src/lsp/format-document.test.ts +143 -0
  198. package/packages/lsp-core/src/lsp/format-document.ts +90 -0
  199. package/packages/lsp-core/src/lsp/manager-lifecycle.test.ts +262 -0
  200. package/packages/lsp-core/src/lsp/manager-max-clients.test.ts +151 -0
  201. package/packages/lsp-core/src/lsp/manager.ts +138 -12
  202. package/packages/lsp-core/src/lsp/outside-context-workspace.ts +33 -0
  203. package/packages/lsp-core/src/lsp/server-definitions.ts +29 -0
  204. package/packages/lsp-core/src/lsp/server-installation.test.ts +376 -0
  205. package/packages/lsp-core/src/lsp/server-installation.ts +200 -27
  206. package/packages/lsp-core/src/lsp/server-resolution-local-binary.test.ts +170 -0
  207. package/packages/lsp-core/src/lsp/server-resolution.ts +18 -5
  208. package/packages/lsp-core/src/lsp/transport.ts +9 -0
  209. package/packages/lsp-core/src/lsp/types.ts +8 -0
  210. package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +20 -1
  211. package/packages/lsp-core/src/lsp/workspace-markers.ts +18 -0
  212. package/packages/lsp-core/src/mcp.ts +3 -0
  213. package/packages/lsp-core/src/request-context.test.ts +29 -0
  214. package/packages/lsp-core/src/request-context.ts +1 -1
  215. package/packages/lsp-core/src/tool-surface.test.ts +13 -1
  216. package/packages/lsp-core/src/tools/definitions.ts +14 -0
  217. package/packages/lsp-core/src/tools/diagnostics.ts +3 -3
  218. package/packages/lsp-core/src/tools/format.test.ts +56 -0
  219. package/packages/lsp-core/src/tools/format.ts +56 -0
  220. package/packages/lsp-core/src/tools/index.ts +1 -0
  221. package/packages/lsp-core/src/tools/navigation.ts +4 -2
  222. package/packages/lsp-core/src/tools/rename.ts +4 -2
  223. package/packages/lsp-core/src/tools/symbols.ts +1 -1
  224. package/packages/lsp-core/src/tools/types.ts +10 -0
  225. package/packages/lsp-daemon/dist/cli.js +752 -307
  226. package/packages/lsp-daemon/dist/client.d.ts +10 -0
  227. package/packages/lsp-daemon/dist/client.js +712 -264
  228. package/packages/lsp-daemon/dist/daemon-client.d.ts +1 -0
  229. package/packages/lsp-daemon/dist/daemon-client.js +3 -0
  230. package/packages/lsp-daemon/dist/ensure-daemon.js +1 -0
  231. package/packages/lsp-daemon/dist/index.js +716 -273
  232. package/packages/lsp-daemon/dist/proxy.js +3 -0
  233. package/packages/lsp-daemon/dist/version-reap.js +1 -1
  234. package/packages/lsp-daemon/package.json +1 -1
  235. package/packages/lsp-tools-mcp/dist/cli.js +671 -228
  236. package/packages/lsp-tools-mcp/dist/lsp/manager.js +207 -103
  237. package/packages/lsp-tools-mcp/dist/mcp.js +673 -230
  238. package/packages/lsp-tools-mcp/dist/request-context.js +12 -13
  239. package/packages/lsp-tools-mcp/dist/tools.js +677 -238
  240. package/packages/omo-codex/THIRD-PARTY-NOTICES.md +4 -4
  241. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +4 -4
  242. package/packages/omo-codex/plugin/AGENTS.md +47 -0
  243. package/packages/omo-codex/plugin/README.md +1 -1
  244. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +34 -33
  245. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  246. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  247. package/packages/omo-codex/plugin/components/bootstrap/src/hook.ts +1 -0
  248. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +323 -117
  249. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +275 -85
  250. package/packages/omo-codex/plugin/components/codegraph/package.json +4 -4
  251. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +1 -0
  252. package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +12 -0
  253. package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +1 -0
  254. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable-idle.test.ts +47 -0
  255. package/packages/omo-codex/plugin/components/comment-checker/AGENTS.md +9 -0
  256. package/packages/omo-codex/plugin/components/comment-checker/biome.json +2 -2
  257. package/packages/omo-codex/plugin/components/comment-checker/dist/cli.js +2 -1
  258. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  259. package/packages/omo-codex/plugin/components/comment-checker/package.json +5 -5
  260. package/packages/omo-codex/plugin/components/comment-checker/src/apply-patch.ts +2 -8
  261. package/packages/omo-codex/plugin/components/comment-checker/src/core.ts +1 -2
  262. package/packages/omo-codex/plugin/components/comment-checker/src/request-extractor.ts +1 -1
  263. package/packages/omo-codex/plugin/components/comment-checker/src/runner.ts +1 -0
  264. package/packages/omo-codex/plugin/components/git-bash/AGENTS.md +1 -1
  265. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  266. package/packages/omo-codex/plugin/components/git-bash/package.json +3 -4
  267. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/biome.json +2 -2
  268. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +1 -5
  269. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +1 -5
  270. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  271. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +5 -5
  272. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +1 -5
  273. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +4 -21
  274. package/packages/omo-codex/plugin/components/lsp/AGENTS.md +30 -15
  275. package/packages/omo-codex/plugin/components/lsp/biome.json +2 -2
  276. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +4 -4
  277. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +702 -278
  278. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +1 -1
  279. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  280. package/packages/omo-codex/plugin/components/lsp/package.json +5 -5
  281. package/packages/omo-codex/plugin/components/lsp/src/cli.ts +1 -1
  282. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +1 -1
  283. package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +1 -5
  284. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +6 -7
  285. package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +1 -2
  286. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +11 -1
  287. package/packages/omo-codex/plugin/components/rules/AGENTS.md +12 -0
  288. package/packages/omo-codex/plugin/components/rules/biome.json +2 -2
  289. package/packages/omo-codex/plugin/components/rules/dist/cli.js +60 -45
  290. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  291. package/packages/omo-codex/plugin/components/rules/package.json +7 -7
  292. package/packages/omo-codex/plugin/components/rules/src/config.ts +1 -2
  293. package/packages/omo-codex/plugin/components/rules/src/persistent-cache.ts +1 -2
  294. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +9 -5
  295. package/packages/omo-codex/plugin/components/rules/src/rules-engine-factory.ts +1 -4
  296. package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +4 -9
  297. package/packages/omo-codex/plugin/components/rules/test/bundled-rules-priority.test.ts +11 -16
  298. package/packages/omo-codex/plugin/components/rules/test/bundled-rules.test.ts +17 -25
  299. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-budget.test.ts +9 -7
  300. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-context.test.ts +0 -6
  301. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-dedup.test.ts +6 -4
  302. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-directive.test.ts +12 -9
  303. package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +28 -37
  304. package/packages/omo-codex/plugin/components/rules/test/dynamic-target-fingerprints.test.ts +1 -2
  305. package/packages/omo-codex/plugin/components/rules/test/engine.test.ts +7 -4
  306. package/packages/omo-codex/plugin/components/rules/test/finder.test.ts +2 -3
  307. package/packages/omo-codex/plugin/components/rules/test/formatter.test.ts +39 -72
  308. package/packages/omo-codex/plugin/components/rules/test/hephaestus-model-variant.test.ts +1 -2
  309. package/packages/omo-codex/plugin/components/rules/test/hook-output.test.ts +2 -3
  310. package/packages/omo-codex/plugin/components/rules/test/matcher.test.ts +2 -3
  311. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +1 -1
  312. package/packages/omo-codex/plugin/components/rules/test/parser.test.ts +1 -2
  313. package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +5 -6
  314. package/packages/omo-codex/plugin/components/rules/test/rules-engine-consumption.test.ts +3 -6
  315. package/packages/omo-codex/plugin/components/rules/test/scanner.test.ts +1 -2
  316. package/packages/omo-codex/plugin/components/rules/test/sources.test.ts +2 -5
  317. package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +2 -17
  318. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  319. package/packages/omo-codex/plugin/components/teammode/package.json +5 -5
  320. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +3 -9
  321. package/packages/omo-codex/plugin/components/telemetry/AGENTS.md +8 -0
  322. package/packages/omo-codex/plugin/components/telemetry/biome.json +2 -2
  323. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +2463 -437
  324. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +2467 -441
  325. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  326. package/packages/omo-codex/plugin/components/telemetry/package.json +5 -5
  327. package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +1 -4
  328. package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -14
  329. package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +1 -1
  330. package/packages/omo-codex/plugin/components/telemetry/test/diagnostics.test.ts +2 -5
  331. package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +5 -0
  332. package/packages/omo-codex/plugin/components/ultrawork/biome.json +2 -2
  333. package/packages/omo-codex/plugin/components/ultrawork/directive.md +13 -1
  334. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  335. package/packages/omo-codex/plugin/components/ultrawork/package.json +5 -5
  336. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +13 -1
  337. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +6 -6
  338. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +31 -7
  339. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -1
  340. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +5 -5
  341. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +9 -1
  342. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +0 -136
  343. package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +0 -2
  344. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/AGENTS.md +5 -4
  345. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/NOTICE +1 -1
  346. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/README.md +5 -5
  347. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/biome.json +2 -2
  348. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/directive.md +6 -6
  349. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/dist/cli.js +12 -12
  350. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +28 -0
  351. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/package.json +12 -12
  352. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/boulder-reader.ts +1 -1
  353. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/cli.ts +1 -1
  354. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/codex-hook.ts +3 -3
  355. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/directive.ts +1 -1
  356. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/index.ts +1 -1
  357. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/boulder-reader.test.ts +3 -3
  358. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/cli.test.ts +1 -4
  359. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/codex-hook.test.ts +8 -22
  360. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +17 -0
  361. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +1 -1
  362. package/packages/omo-codex/plugin/components/ulw-loop/biome.json +2 -2
  363. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +13 -1
  364. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +2 -0
  365. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +5 -1
  366. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +2 -1
  367. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +11 -1
  368. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +124 -68
  369. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.d.ts +2 -0
  370. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +9 -6
  371. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +1 -1
  372. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +1 -1
  373. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.d.ts +4 -2
  374. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +7 -10
  375. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +3 -2
  376. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +3 -3
  377. package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.d.ts +15 -0
  378. package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.js +50 -0
  379. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  380. package/packages/omo-codex/plugin/components/ulw-loop/package.json +5 -5
  381. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +3 -2
  382. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/define-goal.md +108 -0
  383. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -0
  384. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +2 -0
  385. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +5 -1
  386. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +13 -1
  387. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +3 -5
  388. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +16 -5
  389. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-snapshot.ts +3 -1
  390. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +3 -1
  391. package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +1 -1
  392. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +11 -14
  393. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +3 -2
  394. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +3 -3
  395. package/packages/omo-codex/plugin/components/ulw-loop/src/surface.ts +73 -0
  396. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +0 -1
  397. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-final.test.ts +44 -1
  398. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +25 -0
  399. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +26 -2
  400. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +27 -2
  401. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-snapshot.test.ts +18 -0
  402. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +0 -3
  403. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +7 -3
  404. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -37
  405. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +9 -0
  406. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-roles.test.ts +45 -2
  407. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +20 -0
  408. package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +8 -5
  409. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +1 -1
  410. package/packages/omo-codex/plugin/components/ulw-loop/test/surface.test.ts +74 -0
  411. package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +4 -5
  412. package/packages/omo-codex/plugin/components/ulw-loop/vitest.config.ts +1 -0
  413. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  414. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  415. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  416. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  417. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  418. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  419. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  420. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  421. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  422. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  423. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  424. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  425. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  426. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  427. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  428. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  429. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +17 -0
  430. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  431. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json +17 -0
  432. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  433. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  434. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  435. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  436. package/packages/omo-codex/plugin/model-catalog.json +3 -3
  437. package/packages/omo-codex/plugin/package-lock.json +681 -395
  438. package/packages/omo-codex/plugin/package.json +2 -2
  439. package/packages/omo-codex/plugin/scripts/AGENTS.md +40 -0
  440. package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +1 -1
  441. package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +3 -3
  442. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +11 -11
  443. package/packages/omo-codex/plugin/shared/package.json +3 -4
  444. package/packages/omo-codex/plugin/skills/ast-grep/AGENTS.md +51 -0
  445. package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +62 -0
  446. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +3 -2
  447. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  448. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +4 -4
  449. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  450. package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +99 -239
  451. package/packages/omo-codex/plugin/skills/data-scientist/references/execution-surfaces.md +91 -0
  452. package/packages/omo-codex/plugin/skills/data-scientist/references/placement.md +74 -0
  453. package/packages/omo-codex/plugin/skills/data-scientist/references/polars-lane.md +95 -0
  454. package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +1 -1
  455. package/packages/omo-codex/plugin/skills/data-scientist/references/visualization.md +64 -0
  456. package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  457. package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  458. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -0
  459. package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +12 -0
  460. package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +21 -0
  461. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +15 -1
  462. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +38 -0
  463. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +25 -0
  464. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +13 -0
  465. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +41 -0
  466. package/packages/omo-codex/plugin/skills/debugging/references/scripts/dap.mjs +267 -0
  467. package/packages/omo-codex/plugin/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  468. package/packages/omo-codex/plugin/skills/debugging/references/tools/dap.md +103 -0
  469. package/packages/omo-codex/plugin/skills/debugging/references/tools/frida.md +193 -0
  470. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +11 -7
  471. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
  472. package/packages/omo-codex/plugin/skills/frontend/references/design/print-paged-media.md +76 -0
  473. package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +80 -0
  474. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +1 -1
  475. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  476. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  477. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  478. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/orchestration.md +1 -1
  479. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +5 -5
  480. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +4 -4
  481. package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  482. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +2 -0
  483. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +179 -0
  484. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
  485. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  486. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +13 -1
  487. package/packages/omo-codex/plugin/skills/{start-work → ulw-execute}/SKILL.md +12 -11
  488. package/packages/omo-codex/plugin/skills/ulw-execute/agents/openai.yaml +2 -0
  489. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +3 -2
  490. package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +108 -0
  491. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -0
  492. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +6 -6
  493. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +31 -7
  494. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -1
  495. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +5 -5
  496. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +4 -2
  497. package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +58 -0
  498. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +3 -2
  499. package/packages/omo-codex/plugin/test/AGENTS.md +47 -0
  500. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +19 -173
  501. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +8 -28
  502. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -1
  503. package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +1 -1
  504. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +175 -13
  505. package/packages/omo-codex/plugin/test/aggregate.test.mjs +78 -2
  506. package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +19 -33
  507. package/packages/omo-codex/plugin/test/auto-update.test.mjs +2 -2
  508. package/packages/omo-codex/plugin/test/component-bin-names.test.mjs +2 -2
  509. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +1 -1
  510. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
  511. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +4 -4
  512. package/packages/omo-codex/plugin/test/lcx-contribute-bug-fix-template.test.mjs +21 -27
  513. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +8 -8
  514. package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +0 -36
  515. package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +101 -0
  516. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +12 -12
  517. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +1 -119
  518. package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +0 -40
  519. package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +6 -62
  520. package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +3 -36
  521. package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +0 -44
  522. package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +2 -6
  523. package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +0 -3
  524. package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +0 -3
  525. package/packages/omo-codex/scripts/AGENTS.md +36 -0
  526. package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +2 -2
  527. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2637 -549
  528. package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +7 -2
  529. package/packages/shared-skills/skills/ast-grep/AGENTS.md +51 -0
  530. package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +62 -0
  531. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +3 -2
  532. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  533. package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +4 -4
  534. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  535. package/packages/shared-skills/skills/data-scientist/SKILL.md +99 -239
  536. package/packages/shared-skills/skills/data-scientist/references/execution-surfaces.md +91 -0
  537. package/packages/shared-skills/skills/data-scientist/references/placement.md +74 -0
  538. package/packages/shared-skills/skills/data-scientist/references/polars-lane.md +95 -0
  539. package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +1 -1
  540. package/packages/shared-skills/skills/data-scientist/references/visualization.md +64 -0
  541. package/packages/shared-skills/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  542. package/packages/shared-skills/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  543. package/packages/shared-skills/skills/debugging/SKILL.md +2 -0
  544. package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +12 -0
  545. package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +21 -0
  546. package/packages/shared-skills/skills/debugging/references/runtimes/go.md +15 -1
  547. package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +38 -0
  548. package/packages/shared-skills/skills/debugging/references/runtimes/node.md +25 -0
  549. package/packages/shared-skills/skills/debugging/references/runtimes/python.md +13 -0
  550. package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +41 -0
  551. package/packages/shared-skills/skills/debugging/references/scripts/dap.mjs +267 -0
  552. package/packages/shared-skills/skills/debugging/references/scripts/dap.test.ts +86 -0
  553. package/packages/shared-skills/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  554. package/packages/shared-skills/skills/debugging/references/tools/dap.md +103 -0
  555. package/packages/shared-skills/skills/debugging/references/tools/frida.md +193 -0
  556. package/packages/shared-skills/skills/frontend/SKILL.md +11 -7
  557. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
  558. package/packages/shared-skills/skills/frontend/references/design/print-paged-media.md +76 -0
  559. package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +80 -0
  560. package/packages/shared-skills/skills/frontend/references/designpowers/README.md +1 -1
  561. package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  562. package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  563. package/packages/shared-skills/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  564. package/packages/shared-skills/skills/frontend/references/designpowers/orchestration.md +1 -1
  565. package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +5 -5
  566. package/packages/shared-skills/skills/review-work/SKILL.md +3 -3
  567. package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  568. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +2 -0
  569. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +179 -0
  570. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
  571. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  572. package/packages/shared-skills/skills/{start-work → ulw-execute}/SKILL.md +9 -8
  573. package/packages/shared-skills/skills/ulw-plan/SKILL.md +6 -6
  574. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +31 -7
  575. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -1
  576. package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +5 -5
  577. package/packages/shared-skills/skills/ulw-research/SKILL.md +4 -2
  578. package/packages/shared-skills/skills/visual-qa/AGENTS.md +58 -0
  579. package/packages/shared-skills/skills/visual-qa/SKILL.md +3 -2
  580. package/script/qa/web-terminal-visual-qa.mjs +2 -0
  581. package/script/qa/xterm-live-terminal.mjs +18 -2
  582. package/dist/config/schema/start-work.d.ts +0 -5
  583. package/dist/features/builtin-commands/templates/start-work.d.ts +0 -1
  584. package/dist/hooks/ralph-loop/completion-promise-detector-test-input.d.ts +0 -11
  585. package/dist/hooks/ralph-loop/loop-session-recovery.d.ts +0 -7
  586. package/dist/hooks/start-work/start-work-hook.d.ts +0 -23
  587. package/dist/plugin/chat-message/start-work-message.d.ts +0 -5
  588. package/dist/skills/data-scientist/references/common-scenarios.md +0 -176
  589. package/dist/skills/data-scientist/references/execution-templates.md +0 -197
  590. package/dist/skills/data-scientist/references/integration-patterns.md +0 -153
  591. package/dist/skills/data-scientist/references/performance-benchmarks.md +0 -37
  592. package/dist/tools/call-omo-agent/background-agent-executor.d.ts +0 -5
  593. package/dist/tools/call-omo-agent/message-storage-directory.d.ts +0 -1
  594. package/dist/tools/delegate-task/model-string-parser.d.ts +0 -1
  595. package/packages/lsp-tools-mcp/dist/lsp/cleanup-errors.d.ts +0 -1
  596. package/packages/lsp-tools-mcp/dist/lsp/constants.d.ts +0 -1
  597. package/packages/lsp-tools-mcp/dist/lsp/language-mappings.d.ts +0 -1
  598. package/packages/lsp-tools-mcp/dist/lsp/process-signal-cleanup.d.ts +0 -1
  599. package/packages/lsp-tools-mcp/dist/missing-dependency-result.d.ts +0 -1
  600. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +0 -28
  601. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +0 -17
  602. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +0 -17
  603. package/packages/omo-codex/plugin/skills/data-scientist/references/common-scenarios.md +0 -176
  604. package/packages/omo-codex/plugin/skills/data-scientist/references/execution-templates.md +0 -197
  605. package/packages/omo-codex/plugin/skills/data-scientist/references/integration-patterns.md +0 -153
  606. package/packages/omo-codex/plugin/skills/data-scientist/references/performance-benchmarks.md +0 -37
  607. package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +0 -2
  608. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +0 -92
  609. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +0 -314
  610. package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +0 -24
  611. package/packages/shared-skills/skills/data-scientist/references/common-scenarios.md +0 -176
  612. package/packages/shared-skills/skills/data-scientist/references/execution-templates.md +0 -197
  613. package/packages/shared-skills/skills/data-scientist/references/integration-patterns.md +0 -153
  614. package/packages/shared-skills/skills/data-scientist/references/performance-benchmarks.md +0 -37
  615. /package/dist/hooks/{start-work → ulw-execute}/context-info-formatters.d.ts +0 -0
  616. /package/dist/hooks/{start-work → ulw-execute}/explicit-plan-context.d.ts +0 -0
  617. /package/dist/hooks/{start-work → ulw-execute}/notepad-scaffold.d.ts +0 -0
  618. /package/dist/hooks/{start-work → ulw-execute}/parse-user-request.d.ts +0 -0
  619. /package/dist/hooks/{start-work → ulw-execute}/plan-discovery-context.d.ts +0 -0
  620. /package/dist/hooks/{start-work → ulw-execute}/plan-selection.d.ts +0 -0
  621. /package/dist/hooks/{start-work → ulw-execute}/session-plan-affinity.d.ts +0 -0
  622. /package/dist/hooks/{start-work → ulw-execute}/work-initializer.d.ts +0 -0
  623. /package/dist/hooks/{start-work → ulw-execute}/worktree-block.d.ts +0 -0
  624. /package/dist/hooks/{start-work → ulw-execute}/worktree-detector.d.ts +0 -0
  625. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/.gitattributes +0 -0
  626. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/CHANGELOG.md +0 -0
  627. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/LICENSE +0 -0
  628. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/plan-checklist.ts +0 -0
  629. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/types.ts +0 -0
  630. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-completed.json +0 -0
  631. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-mixed-platforms.json +0 -0
  632. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-single-codex-work.json +0 -0
  633. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-all-done.md +0 -0
  634. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-scaffold.md +0 -0
  635. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-nested-checkboxes.md +0 -0
  636. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-unchecked.md +0 -0
  637. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.build.json +0 -0
  638. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.json +0 -0
  639. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/vitest.config.ts +0 -0
@@ -0,0 +1,262 @@
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
+ /** Simulates a stop that lingers (production stops reach ~21s), which is the behavior under test. */
15
+ const SLOW_STOP_MS = 50;
16
+
17
+ interface RecordingClientOptions {
18
+ readonly stopDelayMs: number;
19
+ readonly initializeError?: Error;
20
+ readonly alive: boolean;
21
+ }
22
+
23
+ class RecordingFakeClient {
24
+ alive: boolean;
25
+ stopCallCount = 0;
26
+
27
+ constructor(
28
+ readonly root: string,
29
+ private readonly log: EventLog,
30
+ private readonly options: RecordingClientOptions,
31
+ ) {
32
+ this.alive = options.alive;
33
+ }
34
+
35
+ async start(): Promise<void> {
36
+ this.log.push(`spawn:${this.root}`);
37
+ }
38
+
39
+ async initialize(): Promise<void> {
40
+ if (this.options.initializeError !== undefined) {
41
+ throw this.options.initializeError;
42
+ }
43
+ }
44
+
45
+ isAlive(): boolean {
46
+ return this.alive;
47
+ }
48
+
49
+ command(): string[] {
50
+ return [...SERVER.command];
51
+ }
52
+
53
+ async stop(): Promise<void> {
54
+ this.stopCallCount += 1;
55
+ this.log.push(`stop-start:${this.root}`);
56
+ await delay(this.options.stopDelayMs);
57
+ this.alive = false;
58
+ this.log.push(`stop-end:${this.root}`);
59
+ }
60
+ }
61
+
62
+ class EventLog {
63
+ readonly entries: string[] = [];
64
+ private waiters: Array<{ readonly event: string; readonly resolve: () => void }> = [];
65
+
66
+ push(event: string): void {
67
+ this.entries.push(event);
68
+ const due = this.waiters.filter((waiter) => waiter.event === event);
69
+ if (due.length === 0) return;
70
+ this.waiters = this.waiters.filter((waiter) => waiter.event !== event);
71
+ for (const waiter of due) waiter.resolve();
72
+ }
73
+
74
+ waitFor(event: string): Promise<void> {
75
+ if (this.entries.includes(event)) return Promise.resolve();
76
+ return new Promise<void>((resolve) => {
77
+ this.waiters.push({ event, resolve });
78
+ });
79
+ }
80
+ }
81
+
82
+ function delay(ms: number): Promise<void> {
83
+ return new Promise((resolve) => setTimeout(resolve, ms));
84
+ }
85
+
86
+ interface HarnessOptions {
87
+ readonly maxResidentClients?: number;
88
+ readonly stopDelayMs?: number;
89
+ /** Leading generations whose initialize() rejects; later generations start cleanly. */
90
+ readonly initializeFailures?: number;
91
+ /** Generations at or above this index report alive; earlier ones emulate a crash-looping server. */
92
+ readonly aliveFromGeneration?: number;
93
+ }
94
+
95
+ function managerHarness(options: HarnessOptions = {}): {
96
+ readonly manager: LspManager;
97
+ readonly clients: RecordingFakeClient[];
98
+ readonly log: EventLog;
99
+ readonly clock: { value: number };
100
+ } {
101
+ const clients: RecordingFakeClient[] = [];
102
+ const log = new EventLog();
103
+ const clock = { value: 1_000 };
104
+ const generations = new Map<string, number>();
105
+ const aliveFrom = options.aliveFromGeneration ?? 1;
106
+ const stopDelayMs = options.stopDelayMs ?? 0;
107
+ const initializeFailures = options.initializeFailures ?? 0;
108
+ const manager = new LspManager({
109
+ maxResidentClients: options.maxResidentClients ?? 6,
110
+ reaperIntervalMs: 60_000,
111
+ idleTimeoutMs: 60_000_000,
112
+ now: () => clock.value,
113
+ clientFactory: (root) => {
114
+ const generation = (generations.get(root) ?? 0) + 1;
115
+ generations.set(root, generation);
116
+ const client = new RecordingFakeClient(root, log, {
117
+ stopDelayMs,
118
+ alive: generation >= aliveFrom,
119
+ ...(generation <= initializeFailures ? { initializeError: new Error("initialize boom") } : {}),
120
+ });
121
+ clients.push(client);
122
+ return client as unknown as LspClient;
123
+ },
124
+ });
125
+ return { manager, clients, log, clock };
126
+ }
127
+
128
+ describe("LspManager pending-stop tombstones", () => {
129
+ it("#given a slow-stopping client evicted at the resident cap #when the evicted root is re-acquired while the stop is pending #then the replacement spawns only after the old client stopped", async () => {
130
+ // given
131
+ const { manager, log } = managerHarness({ maxResidentClients: 1, stopDelayMs: SLOW_STOP_MS });
132
+ try {
133
+ await manager.getClient("/root-a", SERVER);
134
+ manager.releaseClient("/root-a", SERVER.id);
135
+
136
+ // when: admitting root-b synchronously evicts idle root-a (void stop), and root-a is
137
+ // re-acquired in the same window while the evicted client's stop is still pending.
138
+ const rootBPromise = manager.getClient("/root-b", SERVER);
139
+ const rootAPromise = manager.getClient("/root-a", SERVER);
140
+ await Promise.all([rootBPromise, rootAPromise]);
141
+ manager.releaseClient("/root-b", SERVER.id);
142
+ manager.releaseClient("/root-a", SERVER.id);
143
+
144
+ // then
145
+ expect(log.entries.filter((event) => event.endsWith("/root-a"))).toEqual([
146
+ "spawn:/root-a",
147
+ "stop-start:/root-a",
148
+ "stop-end:/root-a",
149
+ "spawn:/root-a",
150
+ ]);
151
+ } finally {
152
+ await manager.stopAll();
153
+ }
154
+ });
155
+
156
+ it("#given an invalidated client whose stop is still pending #when the same root is re-acquired #then the replacement spawns only after the invalidated client stopped", async () => {
157
+ // given
158
+ const { manager, log } = managerHarness({ stopDelayMs: SLOW_STOP_MS });
159
+ try {
160
+ await manager.getClient("/root-a", SERVER);
161
+ manager.releaseClient("/root-a", SERVER.id);
162
+
163
+ // when
164
+ manager.invalidateClient("/root-a", SERVER.id);
165
+ await manager.getClient("/root-a", SERVER);
166
+
167
+ // then
168
+ expect(log.entries).toEqual([
169
+ "spawn:/root-a",
170
+ "stop-start:/root-a",
171
+ "stop-end:/root-a",
172
+ "spawn:/root-a",
173
+ ]);
174
+ } finally {
175
+ await manager.stopAll();
176
+ }
177
+ });
178
+
179
+ it("#given a client whose initialization failed while its stop is pending #when another getClient races the stop #then the replacement spawns only after the failed client stopped", async () => {
180
+ // given
181
+ const { manager, log } = managerHarness({
182
+ stopDelayMs: SLOW_STOP_MS,
183
+ initializeFailures: 1,
184
+ });
185
+ try {
186
+ const failing = manager.getClient("/root-fail", SERVER);
187
+
188
+ // when: the second acquisition starts once the first one's stop is provably in flight.
189
+ await log.waitFor("stop-start:/root-fail");
190
+ const racing = manager.getClient("/root-fail", SERVER);
191
+ await expect(failing).rejects.toThrow("initialize boom");
192
+ await racing;
193
+ manager.releaseClient("/root-fail", SERVER.id);
194
+
195
+ // then
196
+ expect(log.entries).toEqual([
197
+ "spawn:/root-fail",
198
+ "stop-start:/root-fail",
199
+ "stop-end:/root-fail",
200
+ "spawn:/root-fail",
201
+ ]);
202
+ } finally {
203
+ await manager.stopAll();
204
+ }
205
+ });
206
+ });
207
+
208
+ describe("LspManager dead-client respawn budget", () => {
209
+ it("#given a crash-looping client that is dead on every acquisition #when getClient is called repeatedly #then respawn attempts stay within the retry budget", async () => {
210
+ // given
211
+ const { manager, clients } = managerHarness({ aliveFromGeneration: Number.POSITIVE_INFINITY });
212
+ try {
213
+ // when
214
+ for (let attempt = 0; attempt < 8; attempt += 1) {
215
+ await manager
216
+ .getClient("/root-crash", SERVER)
217
+ .then(
218
+ () => manager.releaseClient("/root-crash", SERVER.id),
219
+ () => undefined,
220
+ );
221
+ }
222
+
223
+ // then: one initial generation plus at most two budgeted respawns.
224
+ expect(clients.length).toBeLessThanOrEqual(3);
225
+ } finally {
226
+ await manager.stopAll();
227
+ }
228
+ });
229
+
230
+ it("#given the respawn budget is exhausted #when getClient is called again #then it rejects with a budget error instead of respawning", async () => {
231
+ // given
232
+ const { manager } = managerHarness({ aliveFromGeneration: Number.POSITIVE_INFINITY });
233
+ try {
234
+ await expect(manager.getClient("/root-crash", SERVER)).rejects.toThrow(/respawn budget/);
235
+
236
+ // when / then
237
+ await expect(manager.getClient("/root-crash", SERVER)).rejects.toThrow(/respawn budget/);
238
+ } finally {
239
+ await manager.stopAll();
240
+ }
241
+ });
242
+
243
+ it("#given the budget was exhausted but the cooldown elapsed and the server recovered #when getClient is called #then it spawns again and resets the budget on a healthy generation", async () => {
244
+ // given: generations one and two crash, the third is healthy.
245
+ const { manager, clients, clock } = managerHarness({ aliveFromGeneration: 3 });
246
+ try {
247
+ await expect(manager.getClient("/root-crash", SERVER)).rejects.toThrow(/respawn budget/);
248
+
249
+ // when: cooldown elapses (60s default) and the server stays alive again.
250
+ clock.value += 60_001;
251
+ const recovered = await manager.getClient("/root-crash", SERVER);
252
+ manager.releaseClient("/root-crash", SERVER.id);
253
+
254
+ // then
255
+ expect(clients.length).toBe(3);
256
+ await expect(manager.getClient("/root-crash", SERVER)).resolves.toBe(recovered);
257
+ manager.releaseClient("/root-crash", SERVER.id);
258
+ } finally {
259
+ await manager.stopAll();
260
+ }
261
+ });
262
+ });
@@ -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,14 @@
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 {
4
+ CLIENT_RESPAWN_COOLDOWN_MS,
5
+ CLIENT_RESPAWN_RETRY_LIMIT,
6
+ IDLE_TIMEOUT_MS,
7
+ INIT_TIMEOUT_MS,
8
+ MAX_RESIDENT_CLIENTS,
9
+ REAPER_INTERVAL_MS,
10
+ } from "./constants.js";
11
+ import { LspClientRespawnBudgetExceededError } from "./errors.js";
4
12
  import { installProcessSignalCleanup } from "./process-signal-cleanup.js";
5
13
  import type { ResolvedServer } from "./types.js";
6
14
 
@@ -14,6 +22,11 @@ interface ManagedClient {
14
22
  initializingSince: number | null;
15
23
  }
16
24
 
25
+ interface RespawnBudget {
26
+ deadGenerations: number;
27
+ exhaustedAt: number | null;
28
+ }
29
+
17
30
  export interface ClientSnapshot {
18
31
  root: string;
19
32
  serverId: string;
@@ -28,6 +41,7 @@ export interface ClientSnapshot {
28
41
  export interface LspManagerOptions {
29
42
  idleTimeoutMs?: number;
30
43
  initTimeoutMs?: number;
44
+ maxResidentClients?: number;
31
45
  reaperIntervalMs?: number;
32
46
  clientFactory?: (root: string, server: ResolvedServer) => LspClient;
33
47
  now?: () => number;
@@ -74,12 +88,16 @@ function awaitWithSignal<T>(promise: Promise<T>, signal: AbortSignal | undefined
74
88
 
75
89
  export class LspManager {
76
90
  private readonly clients = new Map<string, ManagedClient>();
91
+ /** In-flight stops per key; getClient awaits these instead of spawning a duplicate client. */
92
+ private readonly pendingStops = new Map<string, Promise<void>>();
93
+ private readonly respawnBudgets = new Map<string, RespawnBudget>();
77
94
  private reaperHandle: NodeJS.Timeout | null = null;
78
95
  private signalDisposer: (() => void) | null = null;
79
96
  private disposed = false;
80
97
 
81
98
  private readonly idleTimeoutMs: number;
82
99
  private readonly initTimeoutMs: number;
100
+ private readonly maxResidentClients: number;
83
101
  private readonly reaperIntervalMs: number;
84
102
  private readonly clientFactory: (root: string, server: ResolvedServer) => LspClient;
85
103
  private readonly now: () => number;
@@ -87,6 +105,7 @@ export class LspManager {
87
105
  constructor(options: LspManagerOptions = {}) {
88
106
  this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
89
107
  this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
108
+ this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
90
109
  this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
91
110
  this.clientFactory = options.clientFactory ?? ((root, server) => new LspClient(root, server));
92
111
  this.now = options.now ?? (() => Date.now());
@@ -109,6 +128,50 @@ export class LspManager {
109
128
  return `${root}::${serverId}`;
110
129
  }
111
130
 
131
+ /**
132
+ * Deletes-then-stops with a tombstone: the pending stop is recorded so a concurrent getClient
133
+ * for the same key awaits it instead of spawning a duplicate client while the old one lingers
134
+ * (production stops reach ~21s). The tombstone removes itself once the stop settles.
135
+ */
136
+ private tombstoneStop(key: string, client: LspClient): Promise<void> {
137
+ const stop = stopClientBestEffort(client);
138
+ this.pendingStops.set(key, stop);
139
+ void stop.finally(() => {
140
+ if (this.pendingStops.get(key) === stop) {
141
+ this.pendingStops.delete(key);
142
+ }
143
+ });
144
+ return stop;
145
+ }
146
+
147
+ private recordDeadGeneration(key: string): void {
148
+ let budget = this.respawnBudgets.get(key);
149
+ if (budget === undefined) {
150
+ budget = { deadGenerations: 0, exhaustedAt: null };
151
+ this.respawnBudgets.set(key, budget);
152
+ }
153
+ budget.deadGenerations += 1;
154
+ }
155
+
156
+ private markHealthyGeneration(key: string): void {
157
+ this.respawnBudgets.delete(key);
158
+ }
159
+
160
+ /** Throws while the respawn budget is spent and the cooldown has not elapsed. */
161
+ private ensureRespawnAllowed(key: string, root: string, serverId: string): void {
162
+ const budget = this.respawnBudgets.get(key);
163
+ if (budget === undefined || budget.deadGenerations < CLIENT_RESPAWN_RETRY_LIMIT) return;
164
+ if (budget.exhaustedAt === null) {
165
+ budget.exhaustedAt = this.now();
166
+ throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
167
+ }
168
+ if (this.now() - budget.exhaustedAt < CLIENT_RESPAWN_COOLDOWN_MS) {
169
+ throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
170
+ }
171
+ budget.deadGenerations = 0;
172
+ budget.exhaustedAt = null;
173
+ }
174
+
112
175
  private reapStale(): void {
113
176
  const t = this.now();
114
177
  for (const [key, managed] of this.clients) {
@@ -117,8 +180,8 @@ export class LspManager {
117
180
  managed.initializingSince !== null &&
118
181
  t - managed.initializingSince > this.initTimeoutMs
119
182
  ) {
120
- void stopClientBestEffort(managed.client);
121
183
  this.clients.delete(key);
184
+ void this.tombstoneStop(key, managed.client);
122
185
  continue;
123
186
  }
124
187
 
@@ -128,12 +191,38 @@ export class LspManager {
128
191
  managed.pendingWaiters === 0 &&
129
192
  t - managed.lastUsedAt > this.idleTimeoutMs
130
193
  ) {
131
- void stopClientBestEffort(managed.client);
132
194
  this.clients.delete(key);
195
+ void this.tombstoneStop(key, managed.client);
133
196
  }
134
197
  }
135
198
  }
136
199
 
200
+ /**
201
+ * Frees capacity for one new client by stopping the least recently used idle client.
202
+ *
203
+ * Only clients with no in-flight work are eligible, so a resident server is never torn down
204
+ * underneath a live request; when every resident client is busy the cap is exceeded instead.
205
+ */
206
+ private evictForAdmission(): void {
207
+ while (this.clients.size >= this.maxResidentClients) {
208
+ const victim = this.leastRecentlyUsedIdleClient();
209
+ if (!victim) return;
210
+ this.clients.delete(victim.key);
211
+ void this.tombstoneStop(victim.key, victim.managed.client);
212
+ }
213
+ }
214
+
215
+ private leastRecentlyUsedIdleClient(): { readonly key: string; readonly managed: ManagedClient } | null {
216
+ let candidate: { readonly key: string; readonly managed: ManagedClient } | null = null;
217
+ for (const [key, managed] of this.clients) {
218
+ if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing) continue;
219
+ if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
220
+ candidate = { key, managed };
221
+ }
222
+ }
223
+ return candidate;
224
+ }
225
+
137
226
  private async tryDeleteIfOrphaned(key: string, managed: ManagedClient): Promise<void> {
138
227
  if (
139
228
  managed.refCount === 0 &&
@@ -142,7 +231,7 @@ export class LspManager {
142
231
  this.clients.get(key) === managed
143
232
  ) {
144
233
  this.clients.delete(key);
145
- await stopClientBestEffort(managed.client);
234
+ await this.tombstoneStop(key, managed.client);
146
235
  }
147
236
  }
148
237
 
@@ -153,6 +242,16 @@ export class LspManager {
153
242
  signal?.throwIfAborted();
154
243
 
155
244
  const key = this.getKey(root, server.id);
245
+ for (;;) {
246
+ const pendingStop = this.pendingStops.get(key);
247
+ if (pendingStop === undefined) break;
248
+ await awaitWithSignal(pendingStop, signal);
249
+ signal?.throwIfAborted();
250
+ }
251
+ if (this.disposed) {
252
+ throw new Error("LspManager has been disposed");
253
+ }
254
+
156
255
  let managed = this.clients.get(key);
157
256
 
158
257
  if (managed) {
@@ -162,8 +261,8 @@ export class LspManager {
162
261
  managed.initializingSince !== null &&
163
262
  t - managed.initializingSince > this.initTimeoutMs
164
263
  ) {
165
- await stopClientBestEffort(managed.client);
166
264
  this.clients.delete(key);
265
+ await this.tombstoneStop(key, managed.client);
167
266
  managed = undefined;
168
267
  }
169
268
  }
@@ -187,16 +286,23 @@ export class LspManager {
187
286
  }
188
287
 
189
288
  if (!managed.client.isAlive()) {
190
- await stopClientBestEffort(managed.client);
191
- this.clients.delete(key);
289
+ this.recordDeadGeneration(key);
290
+ if (this.clients.get(key) === managed) {
291
+ this.clients.delete(key);
292
+ }
293
+ await this.tombstoneStop(key, managed.client);
192
294
  return this.getClient(root, server, signal);
193
295
  }
194
296
 
297
+ this.markHealthyGeneration(key);
195
298
  managed.refCount++;
196
299
  managed.lastUsedAt = this.now();
197
300
  return managed.client;
198
301
  }
199
302
 
303
+ this.evictForAdmission();
304
+ this.ensureRespawnAllowed(key, root, server.id);
305
+
200
306
  const client = this.clientFactory(root, server);
201
307
  const initStartedAt = this.now();
202
308
  const initPromise = (async () => {
@@ -222,7 +328,7 @@ export class LspManager {
222
328
  if (this.clients.get(key) === newManaged) {
223
329
  this.clients.delete(key);
224
330
  }
225
- await stopClientBestEffort(client);
331
+ await this.tombstoneStop(key, client);
226
332
  throw err;
227
333
  }
228
334
 
@@ -236,6 +342,16 @@ export class LspManager {
236
342
  signal.throwIfAborted();
237
343
  }
238
344
 
345
+ if (!client.isAlive()) {
346
+ this.recordDeadGeneration(key);
347
+ if (this.clients.get(key) === newManaged) {
348
+ this.clients.delete(key);
349
+ }
350
+ await this.tombstoneStop(key, client);
351
+ return this.getClient(root, server, signal);
352
+ }
353
+
354
+ this.markHealthyGeneration(key);
239
355
  newManaged.refCount++;
240
356
  newManaged.lastUsedAt = this.now();
241
357
  return client;
@@ -256,13 +372,20 @@ export class LspManager {
256
372
  if (!managed) return;
257
373
  if (client && managed.client !== client) return;
258
374
  this.clients.delete(key);
259
- void stopClientBestEffort(managed.client);
375
+ void this.tombstoneStop(key, managed.client);
260
376
  }
261
377
 
262
378
  warmupClient(root: string, server: ResolvedServer): void {
263
379
  if (this.disposed) return;
264
380
  const key = this.getKey(root, server.id);
265
- if (this.clients.has(key)) return;
381
+ if (this.clients.has(key) || this.pendingStops.has(key)) return;
382
+
383
+ this.evictForAdmission();
384
+ try {
385
+ this.ensureRespawnAllowed(key, root, server.id);
386
+ } catch {
387
+ return;
388
+ }
266
389
 
267
390
  const client = this.clientFactory(root, server);
268
391
  const initStartedAt = this.now();
@@ -293,7 +416,7 @@ export class LspManager {
293
416
  if (this.clients.get(key) === managed) {
294
417
  this.clients.delete(key);
295
418
  }
296
- void stopClientBestEffort(client);
419
+ void this.tombstoneStop(key, client);
297
420
  },
298
421
  );
299
422
  }
@@ -346,8 +469,11 @@ export class LspManager {
346
469
  for (const managed of this.clients.values()) {
347
470
  stopPromises.push(stopClientBestEffort(managed.client));
348
471
  }
472
+ const tombstonedStops = [...this.pendingStops.values()];
349
473
  this.clients.clear();
350
- await Promise.allSettled(stopPromises);
474
+ this.respawnBudgets.clear();
475
+ await Promise.allSettled([...stopPromises, ...tombstonedStops]);
476
+ this.pendingStops.clear();
351
477
  }
352
478
  }
353
479