oh-my-opencode 4.8.1 → 4.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/dist/agents/prometheus/system-prompt.d.ts +1 -1
  2. package/dist/agents/sisyphus/claude-fable-5.d.ts +19 -0
  3. package/dist/agents/sisyphus/claude-opus-4-7.d.ts +3 -1
  4. package/dist/agents/sisyphus/claude-opus-4-8.d.ts +19 -0
  5. package/dist/agents/sisyphus/index.d.ts +4 -0
  6. package/dist/agents/types.d.ts +2 -2
  7. package/dist/cli/doctor/checks/codex.d.ts +1 -0
  8. package/dist/cli/doctor/checks/dependencies.d.ts +2 -2
  9. package/dist/cli/doctor/checks/tools-gh.d.ts +8 -1
  10. package/dist/cli/doctor/index.d.ts +1 -0
  11. package/dist/cli/doctor/types.d.ts +2 -0
  12. package/dist/cli/index.js +1908 -787
  13. package/dist/cli/install-codex/codex-config-permissions.d.ts +1 -1
  14. package/dist/cli/install-codex/codex-config-plugins.d.ts +1 -0
  15. package/dist/cli/install-codex/codex-config-toml.d.ts +1 -0
  16. package/dist/cli/install-codex/codex-installer-bin-dir.d.ts +8 -0
  17. package/dist/cli/install-codex/install-codex.d.ts +1 -8
  18. package/dist/cli/install-codex/lsp-daemon-reaper.d.ts +5 -0
  19. package/dist/cli/sparkshell-condense.d.ts +10 -0
  20. package/dist/cli/sparkshell-parse.d.ts +3 -0
  21. package/dist/cli/sparkshell-session-context.d.ts +20 -0
  22. package/dist/cli/sparkshell-spark.d.ts +23 -0
  23. package/dist/cli/sparkshell.d.ts +8 -1
  24. package/dist/cli-node/index.js +92564 -0
  25. package/dist/config/schema/agent-names.d.ts +2 -0
  26. package/dist/config/schema/hooks.d.ts +0 -2
  27. package/dist/config/schema/keyword-detector.d.ts +0 -6
  28. package/dist/config/schema/oh-my-opencode-config.d.ts +2 -4
  29. package/dist/create-hooks.d.ts +0 -2
  30. package/dist/features/background-agent/parent-wake-dedupe.d.ts +2 -0
  31. package/dist/features/background-agent/parent-wake-flush-runner.d.ts +2 -0
  32. package/dist/features/background-agent/parent-wake-prompt-dispatch.d.ts +1 -0
  33. package/dist/features/background-agent/parent-wake-session-history.d.ts +4 -0
  34. package/dist/features/background-agent/parent-wake-session-inspector.d.ts +1 -0
  35. package/dist/features/builtin-commands/templates/handoff.d.ts +1 -1
  36. package/dist/features/builtin-skills/index.d.ts +1 -1
  37. package/dist/features/builtin-skills/skills.d.ts +4 -0
  38. package/dist/features/opencode-runtime-skills/source-server.d.ts +16 -1
  39. package/dist/features/opencode-skill-loader/skill-definition-record.d.ts +2 -0
  40. package/dist/features/team-mode/tools/lifecycle-test-fixture.d.ts +2 -0
  41. package/dist/features/team-mode/types.d.ts +1 -0
  42. package/dist/features/tmux-subagent/failed-readiness-cache.d.ts +28 -0
  43. package/dist/features/tmux-subagent/manager.d.ts +1 -9
  44. package/dist/features/tmux-subagent/resolve-server-url.d.ts +3 -0
  45. package/dist/hooks/anthropic-context-window-limit-recovery/executor.d.ts +1 -1
  46. package/dist/hooks/index.d.ts +0 -1
  47. package/dist/hooks/keyword-detector/constants.d.ts +0 -4
  48. package/dist/hooks/keyword-detector/ultrawork/source-detector.d.ts +1 -1
  49. package/dist/index.js +9001 -1795
  50. package/dist/oh-my-opencode.schema.json +2 -4
  51. package/dist/plugin/chat-params.d.ts +1 -8
  52. package/dist/plugin/hooks/create-core-hooks.d.ts +0 -2
  53. package/dist/plugin/hooks/create-session-hooks.d.ts +0 -2
  54. package/dist/plugin/hooks/create-transform-hooks.d.ts +1 -2
  55. package/dist/plugin/messages-transform.d.ts +0 -1
  56. package/dist/shared/model-availability.d.ts +10 -2
  57. package/dist/shared/module-resolution-failure.d.ts +7 -0
  58. package/package.json +25 -18
  59. package/packages/ast-grep-mcp/dist/cli.js +2 -10
  60. package/packages/git-bash-mcp/dist/cli.js +11 -4
  61. package/packages/lsp-daemon/dist/cli.d.ts +2 -0
  62. package/packages/lsp-daemon/dist/cli.js +3711 -0
  63. package/packages/lsp-daemon/dist/daemon-client.d.ts +19 -0
  64. package/packages/lsp-daemon/dist/daemon-client.js +114 -0
  65. package/packages/lsp-daemon/dist/daemon-server.d.ts +12 -0
  66. package/packages/lsp-daemon/dist/daemon-server.js +106 -0
  67. package/packages/lsp-daemon/dist/ensure-daemon.d.ts +21 -0
  68. package/packages/lsp-daemon/dist/ensure-daemon.js +97 -0
  69. package/packages/lsp-daemon/dist/index.d.ts +5 -0
  70. package/packages/lsp-daemon/dist/index.js +3573 -0
  71. package/packages/lsp-daemon/dist/lock.d.ts +7 -0
  72. package/packages/lsp-daemon/dist/lock.js +61 -0
  73. package/packages/lsp-daemon/dist/package.json +6 -0
  74. package/packages/lsp-daemon/dist/paths.d.ts +11 -0
  75. package/packages/lsp-daemon/dist/paths.js +49 -0
  76. package/packages/lsp-daemon/dist/proxy.d.ts +10 -0
  77. package/packages/lsp-daemon/dist/proxy.js +61 -0
  78. package/packages/lsp-daemon/dist/request-routing.d.ts +9 -0
  79. package/packages/lsp-daemon/dist/request-routing.js +44 -0
  80. package/packages/lsp-daemon/dist/run-daemon.d.ts +1 -0
  81. package/packages/lsp-daemon/dist/run-daemon.js +11 -0
  82. package/packages/lsp-daemon/dist/socket-jsonrpc.d.ts +5 -0
  83. package/packages/lsp-daemon/dist/socket-jsonrpc.js +25 -0
  84. package/packages/lsp-daemon/package.json +38 -0
  85. package/packages/lsp-tools-mcp/dist/cli.js +0 -0
  86. package/packages/lsp-tools-mcp/dist/lsp/client-wrapper.js +40 -17
  87. package/packages/lsp-tools-mcp/dist/lsp/client.js +11 -9
  88. package/packages/lsp-tools-mcp/dist/lsp/config-loader.js +5 -5
  89. package/packages/lsp-tools-mcp/dist/lsp/directory-diagnostics.js +5 -3
  90. package/packages/lsp-tools-mcp/dist/lsp/effective-extension.d.ts +1 -0
  91. package/packages/lsp-tools-mcp/dist/lsp/effective-extension.js +8 -0
  92. package/packages/lsp-tools-mcp/dist/lsp/infer-extension.js +3 -2
  93. package/packages/lsp-tools-mcp/dist/lsp/language-mappings.js +1 -0
  94. package/packages/lsp-tools-mcp/dist/lsp/server-definitions.js +12 -0
  95. package/packages/lsp-tools-mcp/dist/lsp/server-install-state.d.ts +12 -0
  96. package/packages/lsp-tools-mcp/dist/lsp/server-install-state.js +51 -0
  97. package/packages/lsp-tools-mcp/dist/lsp/workspace-edit.js +2 -1
  98. package/packages/lsp-tools-mcp/dist/request-context.d.ts +7 -0
  99. package/packages/lsp-tools-mcp/dist/request-context.js +14 -0
  100. package/packages/lsp-tools-mcp/dist/tools.js +44 -1
  101. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +46 -33
  102. package/packages/omo-codex/plugin/.mcp.json +1 -1
  103. package/packages/omo-codex/plugin/components/comment-checker/dist/apply-patch.d.ts +7 -0
  104. package/packages/omo-codex/plugin/components/comment-checker/dist/apply-patch.js +173 -0
  105. package/packages/omo-codex/plugin/components/comment-checker/dist/cli.d.ts +2 -0
  106. package/packages/omo-codex/plugin/components/comment-checker/dist/cli.js +10 -0
  107. package/packages/omo-codex/plugin/components/comment-checker/dist/codex-hook.d.ts +22 -0
  108. package/packages/omo-codex/plugin/components/comment-checker/dist/codex-hook.js +165 -0
  109. package/packages/omo-codex/plugin/components/comment-checker/dist/core-values.d.ts +1 -0
  110. package/packages/omo-codex/plugin/components/comment-checker/dist/core-values.js +1 -0
  111. package/packages/omo-codex/plugin/components/comment-checker/dist/core.d.ts +5 -0
  112. package/packages/omo-codex/plugin/components/comment-checker/dist/core.js +4 -0
  113. package/packages/omo-codex/plugin/components/comment-checker/dist/hook-input.d.ts +6 -0
  114. package/packages/omo-codex/plugin/components/comment-checker/dist/hook-input.js +10 -0
  115. package/packages/omo-codex/plugin/components/comment-checker/dist/record.d.ts +2 -0
  116. package/packages/omo-codex/plugin/components/comment-checker/dist/record.js +11 -0
  117. package/packages/omo-codex/plugin/components/comment-checker/dist/request-extractor.d.ts +3 -0
  118. package/packages/omo-codex/plugin/components/comment-checker/dist/request-extractor.js +104 -0
  119. package/packages/omo-codex/plugin/components/comment-checker/dist/runner.d.ts +26 -0
  120. package/packages/omo-codex/plugin/components/comment-checker/dist/runner.js +144 -0
  121. package/packages/omo-codex/plugin/components/comment-checker/dist/types.d.ts +43 -0
  122. package/packages/omo-codex/plugin/components/comment-checker/dist/types.js +1 -0
  123. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  124. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  125. package/packages/omo-codex/plugin/components/git-bash/dist/cli.d.ts +2 -0
  126. package/packages/omo-codex/plugin/components/git-bash/dist/cli.js +29 -0
  127. package/packages/omo-codex/plugin/components/git-bash/dist/codex-hook.d.ts +28 -0
  128. package/packages/omo-codex/plugin/components/git-bash/dist/codex-hook.js +137 -0
  129. package/packages/omo-codex/plugin/components/git-bash/dist/index.d.ts +1 -0
  130. package/packages/omo-codex/plugin/components/git-bash/dist/index.js +1 -0
  131. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  132. package/packages/omo-codex/plugin/components/git-bash/package.json +5 -2
  133. package/packages/omo-codex/plugin/components/lsp/.mcp.json +1 -1
  134. package/packages/omo-codex/plugin/components/lsp/dist/cli.d.ts +2 -0
  135. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +42 -0
  136. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook-cli.d.ts +2 -0
  137. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook-cli.js +40 -0
  138. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.d.ts +16 -0
  139. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +180 -0
  140. package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.d.ts +12 -0
  141. package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.js +95 -0
  142. package/packages/omo-codex/plugin/components/lsp/dist/mutated-file-paths.d.ts +6 -0
  143. package/packages/omo-codex/plugin/components/lsp/dist/mutated-file-paths.js +79 -0
  144. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  145. package/packages/omo-codex/plugin/components/lsp/package.json +7 -7
  146. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.mjs +68 -0
  147. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-tools.mjs +45 -22
  148. package/packages/omo-codex/plugin/components/lsp/src/cli.ts +1 -1
  149. package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +1 -1
  150. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +6 -2
  151. package/packages/omo-codex/plugin/components/lsp/src/lsp-session-state.ts +4 -0
  152. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +68 -0
  153. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +8 -20
  154. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus.md +69 -96
  155. package/packages/omo-codex/plugin/components/rules/dist/cli.d.ts +2 -0
  156. package/packages/omo-codex/plugin/components/rules/dist/cli.js +118 -0
  157. package/packages/omo-codex/plugin/components/rules/dist/codex-hook-options.d.ts +5 -0
  158. package/packages/omo-codex/plugin/components/rules/dist/codex-hook-options.js +1 -0
  159. package/packages/omo-codex/plugin/components/rules/dist/codex-hook.d.ts +47 -0
  160. package/packages/omo-codex/plugin/components/rules/dist/codex-hook.js +127 -0
  161. package/packages/omo-codex/plugin/components/rules/dist/config.d.ts +2 -0
  162. package/packages/omo-codex/plugin/components/rules/dist/config.js +100 -0
  163. package/packages/omo-codex/plugin/components/rules/dist/context-pressure.d.ts +2 -0
  164. package/packages/omo-codex/plugin/components/rules/dist/context-pressure.js +26 -0
  165. package/packages/omo-codex/plugin/components/rules/dist/debug-log.d.ts +8 -0
  166. package/packages/omo-codex/plugin/components/rules/dist/debug-log.js +36 -0
  167. package/packages/omo-codex/plugin/components/rules/dist/dynamic-target-fingerprints.d.ts +7 -0
  168. package/packages/omo-codex/plugin/components/rules/dist/dynamic-target-fingerprints.js +65 -0
  169. package/packages/omo-codex/plugin/components/rules/dist/event-budget.d.ts +3 -0
  170. package/packages/omo-codex/plugin/components/rules/dist/event-budget.js +14 -0
  171. package/packages/omo-codex/plugin/components/rules/dist/hook-output.d.ts +2 -0
  172. package/packages/omo-codex/plugin/components/rules/dist/hook-output.js +24 -0
  173. package/packages/omo-codex/plugin/components/rules/dist/path-utils.d.ts +4 -0
  174. package/packages/omo-codex/plugin/components/rules/dist/path-utils.js +24 -0
  175. package/packages/omo-codex/plugin/components/rules/dist/persistent-cache.d.ts +13 -0
  176. package/packages/omo-codex/plugin/components/rules/dist/persistent-cache.js +172 -0
  177. package/packages/omo-codex/plugin/components/rules/dist/post-compact-budget.d.ts +6 -0
  178. package/packages/omo-codex/plugin/components/rules/dist/post-compact-budget.js +74 -0
  179. package/packages/omo-codex/plugin/components/rules/dist/post-compact-claim.d.ts +4 -0
  180. package/packages/omo-codex/plugin/components/rules/dist/post-compact-claim.js +6 -0
  181. package/packages/omo-codex/plugin/components/rules/dist/post-compact-directive.d.ts +1 -0
  182. package/packages/omo-codex/plugin/components/rules/dist/post-compact-directive.js +32 -0
  183. package/packages/omo-codex/plugin/components/rules/dist/post-compact-state.d.ts +13 -0
  184. package/packages/omo-codex/plugin/components/rules/dist/post-compact-state.js +29 -0
  185. package/packages/omo-codex/plugin/components/rules/dist/rules/cache.d.ts +9 -0
  186. package/packages/omo-codex/plugin/components/rules/dist/rules/cache.js +51 -0
  187. package/packages/omo-codex/plugin/components/rules/dist/rules/constants.d.ts +70 -0
  188. package/packages/omo-codex/plugin/components/rules/dist/rules/constants.js +101 -0
  189. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-dynamic-cache.d.ts +5 -0
  190. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-dynamic-cache.js +60 -0
  191. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-dynamic-loader.d.ts +6 -0
  192. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-dynamic-loader.js +61 -0
  193. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-loader.d.ts +7 -0
  194. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-loader.js +60 -0
  195. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-paths.d.ts +11 -0
  196. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-paths.js +75 -0
  197. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-static-loader.d.ts +6 -0
  198. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-static-loader.js +29 -0
  199. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-types.d.ts +44 -0
  200. package/packages/omo-codex/plugin/components/rules/dist/rules/engine-types.js +1 -0
  201. package/packages/omo-codex/plugin/components/rules/dist/rules/engine.d.ts +5 -0
  202. package/packages/omo-codex/plugin/components/rules/dist/rules/engine.js +85 -0
  203. package/packages/omo-codex/plugin/components/rules/dist/rules/errors.d.ts +6 -0
  204. package/packages/omo-codex/plugin/components/rules/dist/rules/errors.js +12 -0
  205. package/packages/omo-codex/plugin/components/rules/dist/rules/finder-cache.d.ts +14 -0
  206. package/packages/omo-codex/plugin/components/rules/dist/rules/finder-cache.js +51 -0
  207. package/packages/omo-codex/plugin/components/rules/dist/rules/finder-paths.d.ts +6 -0
  208. package/packages/omo-codex/plugin/components/rules/dist/rules/finder-paths.js +33 -0
  209. package/packages/omo-codex/plugin/components/rules/dist/rules/finder-sources.d.ts +5 -0
  210. package/packages/omo-codex/plugin/components/rules/dist/rules/finder-sources.js +40 -0
  211. package/packages/omo-codex/plugin/components/rules/dist/rules/finder.d.ts +28 -0
  212. package/packages/omo-codex/plugin/components/rules/dist/rules/finder.js +146 -0
  213. package/packages/omo-codex/plugin/components/rules/dist/rules/formatter.d.ts +7 -0
  214. package/packages/omo-codex/plugin/components/rules/dist/rules/formatter.js +112 -0
  215. package/packages/omo-codex/plugin/components/rules/dist/rules/matcher.d.ts +18 -0
  216. package/packages/omo-codex/plugin/components/rules/dist/rules/matcher.js +93 -0
  217. package/packages/omo-codex/plugin/components/rules/dist/rules/ordering.d.ts +3 -0
  218. package/packages/omo-codex/plugin/components/rules/dist/rules/ordering.js +27 -0
  219. package/packages/omo-codex/plugin/components/rules/dist/rules/parser-frontmatter.d.ts +7 -0
  220. package/packages/omo-codex/plugin/components/rules/dist/rules/parser-frontmatter.js +30 -0
  221. package/packages/omo-codex/plugin/components/rules/dist/rules/parser-yaml.d.ts +2 -0
  222. package/packages/omo-codex/plugin/components/rules/dist/rules/parser-yaml.js +237 -0
  223. package/packages/omo-codex/plugin/components/rules/dist/rules/parser.d.ts +3 -0
  224. package/packages/omo-codex/plugin/components/rules/dist/rules/parser.js +31 -0
  225. package/packages/omo-codex/plugin/components/rules/dist/rules/plugin-root.d.ts +1 -0
  226. package/packages/omo-codex/plugin/components/rules/dist/rules/plugin-root.js +48 -0
  227. package/packages/omo-codex/plugin/components/rules/dist/rules/project-root.d.ts +1 -0
  228. package/packages/omo-codex/plugin/components/rules/dist/rules/project-root.js +23 -0
  229. package/packages/omo-codex/plugin/components/rules/dist/rules/scanner.d.ts +14 -0
  230. package/packages/omo-codex/plugin/components/rules/dist/rules/scanner.js +111 -0
  231. package/packages/omo-codex/plugin/components/rules/dist/rules/sources.d.ts +3 -0
  232. package/packages/omo-codex/plugin/components/rules/dist/rules/sources.js +9 -0
  233. package/packages/omo-codex/plugin/components/rules/dist/rules/truncator.d.ts +18 -0
  234. package/packages/omo-codex/plugin/components/rules/dist/rules/truncator.js +59 -0
  235. package/packages/omo-codex/plugin/components/rules/dist/rules/types.d.ts +126 -0
  236. package/packages/omo-codex/plugin/components/rules/dist/rules/types.js +8 -0
  237. package/packages/omo-codex/plugin/components/rules/dist/rules-engine-factory.d.ts +6 -0
  238. package/packages/omo-codex/plugin/components/rules/dist/rules-engine-factory.js +20 -0
  239. package/packages/omo-codex/plugin/components/rules/dist/session-state-lock.d.ts +3 -0
  240. package/packages/omo-codex/plugin/components/rules/dist/session-state-lock.js +41 -0
  241. package/packages/omo-codex/plugin/components/rules/dist/sparkshell-awareness.d.ts +10 -0
  242. package/packages/omo-codex/plugin/components/rules/dist/sparkshell-awareness.js +90 -0
  243. package/packages/omo-codex/plugin/components/rules/dist/static-injection.d.ts +3 -0
  244. package/packages/omo-codex/plugin/components/rules/dist/static-injection.js +128 -0
  245. package/packages/omo-codex/plugin/components/rules/dist/tool-paths.d.ts +6 -0
  246. package/packages/omo-codex/plugin/components/rules/dist/tool-paths.js +168 -0
  247. package/packages/omo-codex/plugin/components/rules/dist/transcript-rule-filter.d.ts +4 -0
  248. package/packages/omo-codex/plugin/components/rules/dist/transcript-rule-filter.js +49 -0
  249. package/packages/omo-codex/plugin/components/rules/dist/transcript-search.d.ts +4 -0
  250. package/packages/omo-codex/plugin/components/rules/dist/transcript-search.js +91 -0
  251. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  252. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  253. package/packages/omo-codex/plugin/components/rules/src/codex-hook.ts +4 -2
  254. package/packages/omo-codex/plugin/components/rules/src/config.ts +13 -0
  255. package/packages/omo-codex/plugin/components/rules/src/event-budget.ts +17 -0
  256. package/packages/omo-codex/plugin/components/rules/src/persistent-cache.ts +4 -1
  257. package/packages/omo-codex/plugin/components/rules/src/post-compact-directive.ts +39 -0
  258. package/packages/omo-codex/plugin/components/rules/src/rules/constants.ts +16 -0
  259. package/packages/omo-codex/plugin/components/rules/src/rules/engine.ts +8 -0
  260. package/packages/omo-codex/plugin/components/rules/src/rules/types.ts +4 -0
  261. package/packages/omo-codex/plugin/components/rules/src/sparkshell-awareness.ts +53 -4
  262. package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +127 -7
  263. package/packages/omo-codex/plugin/components/rules/src/transcript-rule-filter.ts +9 -1
  264. package/packages/omo-codex/plugin/components/rules/test/bundled-rules.test.ts +4 -2
  265. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-budget.test.ts +7 -2
  266. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-context.test.ts +9 -9
  267. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-dedup.test.ts +10 -4
  268. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-directive.test.ts +241 -0
  269. package/packages/omo-codex/plugin/components/rules/test/event-budget.test.ts +168 -0
  270. package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +4 -0
  271. package/packages/omo-codex/plugin/components/rules/test/sparkshell-awareness.test.ts +86 -3
  272. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +15 -15
  273. package/packages/omo-codex/plugin/components/start-work-continuation/dist/boulder-reader.d.ts +16 -0
  274. package/packages/omo-codex/plugin/components/start-work-continuation/dist/boulder-reader.js +146 -0
  275. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.d.ts +2 -0
  276. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +49 -0
  277. package/packages/omo-codex/plugin/components/start-work-continuation/dist/codex-hook.d.ts +2 -0
  278. package/packages/omo-codex/plugin/components/start-work-continuation/dist/codex-hook.js +80 -0
  279. package/packages/omo-codex/plugin/components/start-work-continuation/dist/directive.d.ts +1 -0
  280. package/packages/omo-codex/plugin/components/start-work-continuation/dist/directive.js +2 -0
  281. package/packages/omo-codex/plugin/components/start-work-continuation/dist/index.d.ts +5 -0
  282. package/packages/omo-codex/plugin/components/start-work-continuation/dist/index.js +3 -0
  283. package/packages/omo-codex/plugin/components/start-work-continuation/dist/types.d.ts +20 -0
  284. package/packages/omo-codex/plugin/components/start-work-continuation/dist/types.js +1 -0
  285. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  286. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  287. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +24 -2
  288. package/packages/omo-codex/plugin/components/telemetry/dist/atomic-write.d.ts +1 -0
  289. package/packages/omo-codex/plugin/components/telemetry/dist/atomic-write.js +18 -0
  290. package/packages/omo-codex/plugin/components/telemetry/dist/cli.d.ts +2 -0
  291. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +62 -0
  292. package/packages/omo-codex/plugin/components/telemetry/dist/codex-hook.d.ts +15 -0
  293. package/packages/omo-codex/plugin/components/telemetry/dist/codex-hook.js +42 -0
  294. package/packages/omo-codex/plugin/components/telemetry/dist/data-path.d.ts +10 -0
  295. package/packages/omo-codex/plugin/components/telemetry/dist/data-path.js +35 -0
  296. package/packages/omo-codex/plugin/components/telemetry/dist/diagnostics.d.ts +12 -0
  297. package/packages/omo-codex/plugin/components/telemetry/dist/diagnostics.js +108 -0
  298. package/packages/omo-codex/plugin/components/telemetry/dist/env-flags.d.ts +4 -0
  299. package/packages/omo-codex/plugin/components/telemetry/dist/env-flags.js +31 -0
  300. package/packages/omo-codex/plugin/components/telemetry/dist/posthog-activity-state.d.ts +8 -0
  301. package/packages/omo-codex/plugin/components/telemetry/dist/posthog-activity-state.js +68 -0
  302. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.d.ts +21 -0
  303. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +133 -0
  304. package/packages/omo-codex/plugin/components/telemetry/dist/product-identity.d.ts +8 -0
  305. package/packages/omo-codex/plugin/components/telemetry/dist/product-identity.js +29 -0
  306. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  307. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  308. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +5 -13
  309. package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +61 -185
  310. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +1 -1
  311. package/packages/omo-codex/plugin/components/ultrawork/directive.md +122 -117
  312. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.d.ts +2 -0
  313. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +48 -0
  314. package/packages/omo-codex/plugin/components/ultrawork/dist/codex-hook.d.ts +7 -0
  315. package/packages/omo-codex/plugin/components/ultrawork/dist/codex-hook.js +122 -0
  316. package/packages/omo-codex/plugin/components/ultrawork/dist/directive.d.ts +1 -0
  317. package/packages/omo-codex/plugin/components/ultrawork/dist/directive.js +2 -0
  318. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  319. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  320. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +20 -11
  321. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +17 -11
  322. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +2 -5
  323. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +0 -71
  324. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.d.ts +16 -0
  325. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +200 -0
  326. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-arg-parser.d.ts +17 -0
  327. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-arg-parser.js +97 -0
  328. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.d.ts +4 -0
  329. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +183 -0
  330. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +6 -0
  331. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +55 -0
  332. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.d.ts +12 -0
  333. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +145 -0
  334. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.d.ts +2 -0
  335. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +39 -0
  336. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.d.ts +13 -0
  337. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +100 -0
  338. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.d.ts +26 -0
  339. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +97 -0
  340. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.d.ts +28 -0
  341. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.js +145 -0
  342. package/packages/omo-codex/plugin/components/ulw-loop/dist/command-types.d.ts +34 -0
  343. package/packages/omo-codex/plugin/components/ulw-loop/dist/command-types.js +1 -0
  344. package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.d.ts +16 -0
  345. package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.js +41 -0
  346. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +95 -0
  347. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.js +1 -0
  348. package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence.d.ts +31 -0
  349. package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence.js +119 -0
  350. package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.d.ts +12 -0
  351. package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.js +69 -0
  352. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.d.ts +16 -0
  353. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +59 -0
  354. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +48 -0
  355. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +119 -0
  356. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +8 -0
  357. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +89 -0
  358. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.d.ts +6 -0
  359. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +123 -0
  360. package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.d.ts +16 -0
  361. package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +70 -0
  362. package/packages/omo-codex/plugin/components/ulw-loop/dist/runtime.d.ts +10 -0
  363. package/packages/omo-codex/plugin/components/ulw-loop/dist/runtime.js +13 -0
  364. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-types.d.ts +63 -0
  365. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-types.js +1 -0
  366. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.d.ts +6 -0
  367. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +292 -0
  368. package/packages/omo-codex/plugin/components/ulw-loop/dist/types.d.ts +5 -0
  369. package/packages/omo-codex/plugin/components/ulw-loop/dist/types.js +5 -0
  370. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
  371. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  372. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +14 -14
  373. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +24 -25
  374. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +17 -3
  375. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +2 -1
  376. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +1 -1
  377. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +95 -0
  378. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +0 -96
  379. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +23 -0
  380. package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +46 -0
  381. package/packages/omo-codex/plugin/hooks/hooks.json +16 -16
  382. package/packages/omo-codex/plugin/package-lock.json +10 -9
  383. package/packages/omo-codex/plugin/package.json +27 -26
  384. package/packages/omo-codex/plugin/scripts/auto-update.mjs +64 -15
  385. package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +16 -0
  386. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +82 -18
  387. package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +2 -2
  388. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +23 -11
  389. package/packages/omo-codex/plugin/scripts/sync-version.mjs +94 -0
  390. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +9 -9
  391. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +16 -1
  392. package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +93 -0
  393. package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +11 -0
  394. package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +17 -13
  395. package/packages/omo-codex/plugin/skills/lsp-setup/SKILL.md +139 -0
  396. package/packages/omo-codex/plugin/skills/lsp-setup/references/bash/README.md +60 -0
  397. package/packages/omo-codex/plugin/skills/lsp-setup/references/c-cpp/README.md +61 -0
  398. package/packages/omo-codex/plugin/skills/lsp-setup/references/csharp/README.md +71 -0
  399. package/packages/omo-codex/plugin/skills/lsp-setup/references/dart/README.md +48 -0
  400. package/packages/omo-codex/plugin/skills/lsp-setup/references/elixir/README.md +51 -0
  401. package/packages/omo-codex/plugin/skills/lsp-setup/references/go/README.md +57 -0
  402. package/packages/omo-codex/plugin/skills/lsp-setup/references/haskell/README.md +57 -0
  403. package/packages/omo-codex/plugin/skills/lsp-setup/references/java/README.md +57 -0
  404. package/packages/omo-codex/plugin/skills/lsp-setup/references/julia/README.md +60 -0
  405. package/packages/omo-codex/plugin/skills/lsp-setup/references/kotlin/README.md +59 -0
  406. package/packages/omo-codex/plugin/skills/lsp-setup/references/lua/README.md +66 -0
  407. package/packages/omo-codex/plugin/skills/lsp-setup/references/php/README.md +62 -0
  408. package/packages/omo-codex/plugin/skills/lsp-setup/references/python/README.md +71 -0
  409. package/packages/omo-codex/plugin/skills/lsp-setup/references/ruby/README.md +53 -0
  410. package/packages/omo-codex/plugin/skills/lsp-setup/references/rust/README.md +59 -0
  411. package/packages/omo-codex/plugin/skills/lsp-setup/references/swift/README.md +51 -0
  412. package/packages/omo-codex/plugin/skills/lsp-setup/references/terraform/README.md +62 -0
  413. package/packages/omo-codex/plugin/skills/lsp-setup/references/typescript/README.md +77 -0
  414. package/packages/omo-codex/plugin/skills/lsp-setup/references/yaml/README.md +70 -0
  415. package/packages/omo-codex/plugin/skills/lsp-setup/references/zig/README.md +49 -0
  416. package/packages/omo-codex/plugin/skills/lsp-setup/scripts/detect-lsp.ts +210 -0
  417. package/packages/omo-codex/plugin/skills/lsp-setup/scripts/lsp-server-table.ts +177 -0
  418. package/packages/omo-codex/plugin/skills/lsp-setup/scripts/tsconfig.json +17 -0
  419. package/packages/omo-codex/plugin/skills/lsp-setup/scripts/verify-lsp.ts +147 -0
  420. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +9 -9
  421. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +10 -10
  422. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +20 -22
  423. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +38 -61
  424. package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +135 -677
  425. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +14 -14
  426. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +24 -25
  427. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +20 -11
  428. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +17 -11
  429. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +9 -9
  430. package/packages/omo-codex/plugin/test/aggregate-build.test.mjs +2 -1
  431. package/packages/omo-codex/plugin/test/aggregate-mcp.test.mjs +1 -1
  432. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +5 -5
  433. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +6 -6
  434. package/packages/omo-codex/plugin/test/auto-update-restart-notice.test.mjs +194 -0
  435. package/packages/omo-codex/plugin/test/auto-update.test.mjs +17 -0
  436. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +15 -44
  437. package/packages/omo-codex/plugin/test/lsp-prebuild-layouts.test.mjs +140 -0
  438. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +189 -7
  439. package/packages/omo-codex/plugin/test/start-work-skill.test.mjs +9 -31
  440. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +68 -4
  441. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +119 -0
  442. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +11 -112
  443. package/packages/omo-codex/plugin/test/sync-version.test.mjs +68 -0
  444. package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +126 -0
  445. package/packages/omo-codex/plugin/test/ulw-plan-skill.test.mjs +2 -2
  446. package/packages/omo-codex/scripts/install/bin-dir.mjs +20 -0
  447. package/packages/omo-codex/scripts/install/bin-links.mjs +43 -6
  448. package/packages/omo-codex/scripts/install/cache.mjs +4 -0
  449. package/packages/omo-codex/scripts/install/config.mjs +4 -4
  450. package/packages/omo-codex/scripts/install/delegated-command.mjs +5 -1
  451. package/packages/omo-codex/scripts/install/git-bash-mcp-env.mjs +28 -0
  452. package/packages/omo-codex/scripts/install/git-bash.mjs +12 -4
  453. package/packages/omo-codex/scripts/install/git-bash.test.mjs +39 -4
  454. package/packages/omo-codex/scripts/install/hook-targets.mjs +46 -0
  455. package/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs +12 -2
  456. package/packages/omo-codex/scripts/install/process.mjs +1 -0
  457. package/packages/omo-codex/scripts/install-bin-links.test.mjs +131 -3
  458. package/packages/omo-codex/scripts/install-config-git-bash.test.mjs +91 -0
  459. package/packages/omo-codex/scripts/install-config.test.mjs +50 -44
  460. package/packages/omo-codex/scripts/install-delegated-command.test.mjs +78 -0
  461. package/packages/omo-codex/scripts/install-git-bash-mcp-env.test.mjs +93 -0
  462. package/packages/omo-codex/scripts/install-hook-targets.test.mjs +100 -0
  463. package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +3 -1
  464. package/packages/omo-codex/scripts/install-local.mjs +7 -18
  465. package/packages/omo-codex/scripts/install-local.test.mjs +34 -1
  466. package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +16 -1
  467. package/packages/shared-skills/skills/lcx-doctor/SKILL.md +93 -0
  468. package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +11 -0
  469. package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +17 -13
  470. package/packages/shared-skills/skills/lsp-setup/SKILL.md +139 -0
  471. package/packages/shared-skills/skills/lsp-setup/references/bash/README.md +60 -0
  472. package/packages/shared-skills/skills/lsp-setup/references/c-cpp/README.md +61 -0
  473. package/packages/shared-skills/skills/lsp-setup/references/csharp/README.md +71 -0
  474. package/packages/shared-skills/skills/lsp-setup/references/dart/README.md +48 -0
  475. package/packages/shared-skills/skills/lsp-setup/references/elixir/README.md +51 -0
  476. package/packages/shared-skills/skills/lsp-setup/references/go/README.md +57 -0
  477. package/packages/shared-skills/skills/lsp-setup/references/haskell/README.md +57 -0
  478. package/packages/shared-skills/skills/lsp-setup/references/java/README.md +57 -0
  479. package/packages/shared-skills/skills/lsp-setup/references/julia/README.md +60 -0
  480. package/packages/shared-skills/skills/lsp-setup/references/kotlin/README.md +59 -0
  481. package/packages/shared-skills/skills/lsp-setup/references/lua/README.md +66 -0
  482. package/packages/shared-skills/skills/lsp-setup/references/php/README.md +62 -0
  483. package/packages/shared-skills/skills/lsp-setup/references/python/README.md +71 -0
  484. package/packages/shared-skills/skills/lsp-setup/references/ruby/README.md +53 -0
  485. package/packages/shared-skills/skills/lsp-setup/references/rust/README.md +59 -0
  486. package/packages/shared-skills/skills/lsp-setup/references/swift/README.md +51 -0
  487. package/packages/shared-skills/skills/lsp-setup/references/terraform/README.md +62 -0
  488. package/packages/shared-skills/skills/lsp-setup/references/typescript/README.md +77 -0
  489. package/packages/shared-skills/skills/lsp-setup/references/yaml/README.md +70 -0
  490. package/packages/shared-skills/skills/lsp-setup/references/zig/README.md +49 -0
  491. package/packages/shared-skills/skills/lsp-setup/scripts/detect-lsp.ts +210 -0
  492. package/packages/shared-skills/skills/lsp-setup/scripts/lsp-server-table.ts +177 -0
  493. package/packages/shared-skills/skills/lsp-setup/scripts/tsconfig.json +17 -0
  494. package/packages/shared-skills/skills/lsp-setup/scripts/verify-lsp.ts +147 -0
  495. package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +1 -1
  496. package/packages/shared-skills/skills/review-work/SKILL.md +10 -14
  497. package/packages/shared-skills/skills/start-work/SKILL.md +30 -59
  498. package/packages/shared-skills/skills/ultraresearch/SKILL.md +126 -667
  499. package/dist/hooks/anthropic-effort/hook.d.ts +0 -26
  500. package/dist/hooks/anthropic-effort/index.d.ts +0 -1
  501. package/dist/hooks/keyword-detector/analyze/default.d.ts +0 -12
  502. package/dist/hooks/keyword-detector/analyze/index.d.ts +0 -1
  503. package/dist/hooks/keyword-detector/search/default.d.ts +0 -12
  504. package/dist/hooks/keyword-detector/search/index.d.ts +0 -1
  505. package/dist/hooks/thinking-block-validator/hook.d.ts +0 -12
  506. package/dist/hooks/thinking-block-validator/index.d.ts +0 -1
  507. package/packages/omo-codex/plugin/components/ultrawork/test/directive-contract.test.ts +0 -18
  508. package/packages/omo-codex/plugin/test/global-review-debug-gate.test.mjs +0 -29
  509. package/packages/omo-codex/plugin/test/subagent-guidance.test.mjs +0 -151
@@ -25,7 +25,7 @@ afterEach(() => {
25
25
  });
26
26
 
27
27
  describe("codex rules post-compaction context budget", () => {
28
- it("#given oversized project rules already injected #when static recovery runs after compaction #then it emits no duplicate static injection", async () => {
28
+ it("#given oversized project rules already injected #when static recovery runs after compaction #then it emits a mandatory read directive instead of rule bodies", async () => {
29
29
  // given
30
30
  const { root, pluginData } = makeOversizedProject();
31
31
  const firstOutput = await runSessionStartHook(sessionStartInput(root), {
@@ -50,7 +50,12 @@ describe("codex rules post-compaction context budget", () => {
50
50
  expect(firstContext).toContain("Project rule");
51
51
  expect(firstContext).toContain("[Truncated. Full:");
52
52
  expect(firstContext.length).toBeLessThan(31_000);
53
- expect(output).toBe("");
53
+ const recoveryContext = readAdditionalContext(output);
54
+ expect(recoveryContext).toContain("MUST READ");
55
+ expect(recoveryContext).toContain("NO EXCUSES");
56
+ expect(recoveryContext).toContain(path.join(root, "CONTEXT.md"));
57
+ expect(recoveryContext).not.toContain("Project rule");
58
+ expect(recoveryContext.length).toBeLessThan(2_000);
54
59
  });
55
60
  });
56
61
 
@@ -20,7 +20,7 @@ afterEach(() => {
20
20
  });
21
21
 
22
22
  describe("codex rules compacted context recovery", () => {
23
- it("#given compacted session source after PostCompact #when static rules re-inject #then output uses the compact recovery budget", async () => {
23
+ it("#given compacted session source after PostCompact #when static recovery runs #then output is a mandatory read directive", async () => {
24
24
  // given
25
25
  const { root, pluginData } = makeOversizedProject("compact-source");
26
26
  const transcriptPath = writeCompactedTranscript(root, "summary dropped injected rules");
@@ -37,10 +37,10 @@ describe("codex rules compacted context recovery", () => {
37
37
 
38
38
  // then
39
39
  const postCompactContext = readAdditionalContext(output);
40
- expect(postCompactContext.length).toBeLessThan(5_000);
41
- expect(postCompactContext).toContain("Instructions from:");
40
+ expect(postCompactContext.length).toBeLessThan(2_000);
41
+ expect(postCompactContext).toContain("MUST READ");
42
42
  expect(postCompactContext).toContain("CONTEXT.md");
43
- expect(postCompactContext).toContain("Project rule");
43
+ expect(postCompactContext).not.toContain("Project rule");
44
44
  });
45
45
 
46
46
  it("#given compacted context warning and near-full transcript #when compact source starts twice #then handles compacted context warning once", async () => {
@@ -65,7 +65,7 @@ describe("codex rules compacted context recovery", () => {
65
65
  // then
66
66
  const firstContext = readOptionalAdditionalContext(firstOutput);
67
67
  expect(firstContext.length).toBeLessThan(1_000);
68
- expect(firstContext).toContain("Instructions from:");
68
+ expect(firstContext).toContain("MUST READ");
69
69
  expect(firstContext).toContain("CONTEXT.md");
70
70
  expect(secondOutput).toBe("");
71
71
  });
@@ -88,7 +88,7 @@ describe("codex rules compacted context recovery", () => {
88
88
  // then
89
89
  const context = readOptionalAdditionalContext(output);
90
90
  expect(context.length).toBeLessThan(1_000);
91
- expect(context).toContain("Instructions from:");
91
+ expect(context).toContain("MUST READ");
92
92
  expect(context).toContain("CONTEXT.md");
93
93
  });
94
94
 
@@ -106,7 +106,7 @@ describe("codex rules compacted context recovery", () => {
106
106
  // then
107
107
  const context = readOptionalAdditionalContext(output);
108
108
  expect(context.length).toBeLessThan(1_000);
109
- expect(context).toContain("Instructions from:");
109
+ expect(context).toContain("MUST READ");
110
110
  expect(context).toContain("CONTEXT.md");
111
111
  });
112
112
 
@@ -128,7 +128,7 @@ describe("codex rules compacted context recovery", () => {
128
128
  // then
129
129
  const context = readOptionalAdditionalContext(output);
130
130
  expect(context.length).toBeLessThan(1_000);
131
- expect(context).toContain("Instructions from:");
131
+ expect(context).toContain("MUST READ");
132
132
  expect(context).toContain("CONTEXT.md");
133
133
  });
134
134
 
@@ -157,7 +157,7 @@ describe("codex rules compacted context recovery", () => {
157
157
  const contexts = outputs.map(readOptionalAdditionalContext);
158
158
  expect(contexts.filter((context) => context.length > 0)).toHaveLength(1);
159
159
  expect(contexts.join("").length).toBeLessThan(1_000);
160
- expect(contexts.join("")).toContain("Instructions from:");
160
+ expect(contexts.join("")).toContain("MUST READ");
161
161
  expect(contexts.join("")).toContain("CONTEXT.md");
162
162
  });
163
163
  });
@@ -93,7 +93,7 @@ describe("codex rules PostCompact deduplication", () => {
93
93
  expect(output).toBe("");
94
94
  });
95
95
 
96
- it("#given startup already injected static context #when UserPromptSubmit runs after PostCompact #then it emits no duplicate static context", async () => {
96
+ it("#given startup static context dropped by compaction #when UserPromptSubmit runs after PostCompact #then it emits a mandatory read directive without rule bodies", async () => {
97
97
  // given
98
98
  const { root, pluginData } = makeTempProject();
99
99
  await runSessionStartHook(sessionStartInput(root), {
@@ -113,10 +113,13 @@ describe("codex rules PostCompact deduplication", () => {
113
113
  });
114
114
 
115
115
  // then
116
- expect(output).toBe("");
116
+ const context = readAdditionalContext(output);
117
+ expect(context).toContain("MUST READ");
118
+ expect(context).toContain("CONTEXT.md");
119
+ expect(context).not.toContain("Instructions from:");
117
120
  });
118
121
 
119
- it("#given startup already injected static context #when compact SessionStart runs after PostCompact #then it emits no duplicate static context", async () => {
122
+ it("#given startup static context dropped by compaction #when compact SessionStart runs after PostCompact #then it emits a mandatory read directive without rule bodies", async () => {
120
123
  // given
121
124
  const { root, pluginData } = makeTempProject();
122
125
  await runSessionStartHook(sessionStartInput(root), {
@@ -136,7 +139,10 @@ describe("codex rules PostCompact deduplication", () => {
136
139
  });
137
140
 
138
141
  // then
139
- expect(output).toBe("");
142
+ const context = readAdditionalContext(output);
143
+ expect(context).toContain("MUST READ");
144
+ expect(context).toContain("CONTEXT.md");
145
+ expect(context).not.toContain("Instructions from:");
140
146
  });
141
147
  });
142
148
 
@@ -0,0 +1,241 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import path from "node:path";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+
6
+ import {
7
+ type CodexPostCompactInput,
8
+ type CodexPostToolUseInput,
9
+ type CodexSessionStartInput,
10
+ type CodexUserPromptSubmitInput,
11
+ runPostCompactHook,
12
+ runPostToolUseHook,
13
+ runSessionStartHook,
14
+ runUserPromptSubmitHook,
15
+ } from "../src/codex-hook.js";
16
+
17
+ const tempDirectories: string[] = [];
18
+ const PROJECT_ONLY_ENV = {
19
+ CODEX_RULES_ENABLED_SOURCES: "CONTEXT.md,.omo/rules",
20
+ };
21
+ const SESSION_ID = "session-post-compact-directive";
22
+
23
+ afterEach(() => {
24
+ for (const directory of tempDirectories.splice(0)) {
25
+ rmSync(directory, { recursive: true, force: true });
26
+ }
27
+ });
28
+
29
+ describe("codex rules post-compaction read directive", () => {
30
+ it("#given injected rules dropped by compaction #when UserPromptSubmit recovers #then it lists rule paths in a mandatory read directive instead of bodies", async () => {
31
+ // given
32
+ const { root, pluginData } = makeProject();
33
+ await runSessionStartHook(sessionStartInput(root), { pluginDataRoot: pluginData, env: PROJECT_ONLY_ENV });
34
+ const dynamicOutput = await runPostToolUseHook(postToolUseInput(root, path.join(root, "src", "app.ts")), {
35
+ pluginDataRoot: pluginData,
36
+ env: PROJECT_ONLY_ENV,
37
+ });
38
+ const transcriptPath = writeCompactedTranscript(root, "summary that dropped every injected rule");
39
+ await runPostCompactHook(
40
+ { ...postCompactInput(root), transcript_path: transcriptPath },
41
+ { pluginDataRoot: pluginData },
42
+ );
43
+
44
+ // when
45
+ const output = await runUserPromptSubmitHook(userPromptSubmitInput(root, transcriptPath), {
46
+ pluginDataRoot: pluginData,
47
+ env: PROJECT_ONLY_ENV,
48
+ });
49
+
50
+ // then
51
+ expect(dynamicOutput).toContain("TypeScript rule");
52
+ const context = readAdditionalContext(output);
53
+ expect(context).toContain("MUST READ");
54
+ expect(context).toContain("NO EXCUSES");
55
+ expect(context).toContain("CONTEXT.md");
56
+ expect(context).toContain(".omo/rules/typescript.md");
57
+ expect(context).not.toContain("A".repeat(50));
58
+ expect(context).not.toContain("B".repeat(50));
59
+ expect(context.length).toBeLessThan(2_000);
60
+ });
61
+
62
+ it("#given recovery directive already emitted #when UserPromptSubmit runs again #then it emits nothing", async () => {
63
+ // given
64
+ const { root, pluginData } = makeProject();
65
+ await runSessionStartHook(sessionStartInput(root), { pluginDataRoot: pluginData, env: PROJECT_ONLY_ENV });
66
+ const transcriptPath = writeCompactedTranscript(root, "summary that dropped every injected rule");
67
+ await runPostCompactHook(
68
+ { ...postCompactInput(root), transcript_path: transcriptPath },
69
+ { pluginDataRoot: pluginData },
70
+ );
71
+ await runUserPromptSubmitHook(userPromptSubmitInput(root, transcriptPath), {
72
+ pluginDataRoot: pluginData,
73
+ env: PROJECT_ONLY_ENV,
74
+ });
75
+
76
+ // when
77
+ const secondOutput = await runUserPromptSubmitHook(userPromptSubmitInput(root, transcriptPath), {
78
+ pluginDataRoot: pluginData,
79
+ env: PROJECT_ONLY_ENV,
80
+ });
81
+
82
+ // then
83
+ expect(secondOutput).toBe("");
84
+ });
85
+
86
+ it("#given rules retained in compacted replacement #when UserPromptSubmit recovers #then it emits nothing", async () => {
87
+ // given
88
+ const { root, pluginData } = makeProject();
89
+ const firstOutput = await runSessionStartHook(sessionStartInput(root), {
90
+ pluginDataRoot: pluginData,
91
+ env: PROJECT_ONLY_ENV,
92
+ });
93
+ const transcriptPath = writeCompactedTranscript(root, readAdditionalContext(firstOutput));
94
+ await runPostCompactHook(
95
+ { ...postCompactInput(root), transcript_path: transcriptPath },
96
+ { pluginDataRoot: pluginData },
97
+ );
98
+
99
+ // when
100
+ const output = await runUserPromptSubmitHook(userPromptSubmitInput(root, transcriptPath), {
101
+ pluginDataRoot: pluginData,
102
+ env: PROJECT_ONLY_ENV,
103
+ });
104
+
105
+ // then
106
+ expect(output).toBe("");
107
+ });
108
+
109
+ it("#given bundled hephaestus rule dropped by compaction #when compact SessionStart recovers #then hephaestus body is re-injected in full alongside the directive", async () => {
110
+ // given
111
+ const { root, pluginData } = makeProject();
112
+ const env = { CODEX_RULES_ENABLED_SOURCES: "CONTEXT.md,plugin-bundled" };
113
+ await runSessionStartHook(sessionStartInput(root), { pluginDataRoot: pluginData, env });
114
+ const transcriptPath = writeCompactedTranscript(root, "summary that dropped every injected rule");
115
+ await runPostCompactHook(
116
+ { ...postCompactInput(root), transcript_path: transcriptPath },
117
+ { pluginDataRoot: pluginData },
118
+ );
119
+
120
+ // when
121
+ const output = await runSessionStartHook(compactSessionStartInput(root, transcriptPath), {
122
+ pluginDataRoot: pluginData,
123
+ env,
124
+ });
125
+
126
+ // then
127
+ const context = readAdditionalContext(output);
128
+ expect(context).toContain("You are Hephaestus");
129
+ expect(context).not.toContain("[Truncated. Full:");
130
+ expect(context).toContain("MUST READ");
131
+ expect(context).toContain("CONTEXT.md");
132
+ });
133
+ });
134
+
135
+ function makeProject(): { root: string; pluginData: string } {
136
+ const root = mkdtempSync(path.join(tmpdir(), "codex-rules-directive-project-"));
137
+ const pluginData = mkdtempSync(path.join(tmpdir(), "codex-rules-directive-data-"));
138
+ tempDirectories.push(root, pluginData);
139
+ writeFileSync(path.join(root, "package.json"), JSON.stringify({ name: "fixture" }));
140
+ writeFileSync(path.join(root, "CONTEXT.md"), `Project rule\n${"A".repeat(8_000)}`);
141
+ mkdirSync(path.join(root, ".omo", "rules"), { recursive: true });
142
+ writeFileSync(
143
+ path.join(root, ".omo", "rules", "typescript.md"),
144
+ ["---", 'globs: "**/*.ts"', "---", "", `TypeScript rule\n${"B".repeat(2_000)}`].join("\n"),
145
+ );
146
+ mkdirSync(path.join(root, "src"), { recursive: true });
147
+ writeFileSync(path.join(root, "src", "app.ts"), "export const app = 1;\n");
148
+ return { root, pluginData };
149
+ }
150
+
151
+ function sessionStartInput(root: string): CodexSessionStartInput {
152
+ return {
153
+ session_id: SESSION_ID,
154
+ transcript_path: null,
155
+ cwd: root,
156
+ hook_event_name: "SessionStart",
157
+ model: "gpt-5.5",
158
+ permission_mode: "default",
159
+ source: "startup",
160
+ };
161
+ }
162
+
163
+ function compactSessionStartInput(root: string, transcriptPath: string): CodexSessionStartInput {
164
+ return {
165
+ session_id: SESSION_ID,
166
+ transcript_path: transcriptPath,
167
+ cwd: root,
168
+ hook_event_name: "SessionStart",
169
+ model: "gpt-5.5",
170
+ permission_mode: "default",
171
+ source: "compact",
172
+ };
173
+ }
174
+
175
+ function postCompactInput(root: string): CodexPostCompactInput {
176
+ return {
177
+ session_id: SESSION_ID,
178
+ turn_id: "turn-compact",
179
+ transcript_path: null,
180
+ cwd: root,
181
+ hook_event_name: "PostCompact",
182
+ model: "gpt-5.5",
183
+ trigger: "auto",
184
+ };
185
+ }
186
+
187
+ function userPromptSubmitInput(root: string, transcriptPath: string): CodexUserPromptSubmitInput {
188
+ return {
189
+ session_id: SESSION_ID,
190
+ turn_id: "turn-after-compact",
191
+ transcript_path: transcriptPath,
192
+ cwd: root,
193
+ hook_event_name: "UserPromptSubmit",
194
+ model: "gpt-5.5",
195
+ permission_mode: "default",
196
+ prompt: "continue",
197
+ };
198
+ }
199
+
200
+ function postToolUseInput(root: string, filePath: string): CodexPostToolUseInput {
201
+ return {
202
+ session_id: SESSION_ID,
203
+ turn_id: "turn-tool",
204
+ transcript_path: null,
205
+ cwd: root,
206
+ hook_event_name: "PostToolUse",
207
+ model: "gpt-5.5",
208
+ permission_mode: "default",
209
+ tool_name: "apply_patch",
210
+ tool_input: { path: filePath },
211
+ tool_response: {},
212
+ tool_use_id: "tool-use-1",
213
+ };
214
+ }
215
+
216
+ function writeCompactedTranscript(root: string, retainedText: string): string {
217
+ const transcriptPath = path.join(root, "transcript-compacted.jsonl");
218
+ writeFileSync(
219
+ transcriptPath,
220
+ `${JSON.stringify({
221
+ type: "compacted",
222
+ payload: {
223
+ message: "summary",
224
+ replacement_history: [{ type: "message", role: "user", content: retainedText }],
225
+ },
226
+ })}\n`,
227
+ );
228
+ return transcriptPath;
229
+ }
230
+
231
+ function readAdditionalContext(output: string): string {
232
+ if (output.trim().length === 0) {
233
+ throw new Error("Expected hook output to include additional context.");
234
+ }
235
+ const parsed: unknown = JSON.parse(output);
236
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return "";
237
+ const hookSpecificOutput = (parsed as Record<string, unknown>)["hookSpecificOutput"];
238
+ if (typeof hookSpecificOutput !== "object" || hookSpecificOutput === null) return "";
239
+ const additionalContext = (hookSpecificOutput as Record<string, unknown>)["additionalContext"];
240
+ return typeof additionalContext === "string" ? additionalContext : "";
241
+ }
@@ -0,0 +1,168 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import path from "node:path";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+
6
+ import {
7
+ type CodexPostToolUseInput,
8
+ type CodexSessionStartInput,
9
+ type CodexUserPromptSubmitInput,
10
+ runPostToolUseHook,
11
+ runSessionStartHook,
12
+ runUserPromptSubmitHook,
13
+ } from "../src/codex-hook.js";
14
+
15
+ const tempDirectories: string[] = [];
16
+ const PROJECT_ONLY_ENV = {
17
+ CODEX_RULES_ENABLED_SOURCES: "CONTEXT.md,.omo/rules",
18
+ };
19
+
20
+ afterEach(() => {
21
+ for (const directory of tempDirectories.splice(0)) {
22
+ rmSync(directory, { recursive: true, force: true });
23
+ }
24
+ });
25
+
26
+ describe("codex rules per-event injection budgets", () => {
27
+ it("#given an oversized glob rule #when PostToolUse injects dynamically #then the block is truncated to the dynamic budget", async () => {
28
+ // given
29
+ const { root, pluginData } = makeProject({ dynamicRuleChars: 30_000 });
30
+
31
+ // when
32
+ const output = await runPostToolUseHook(postToolUseInput(root, path.join(root, "src", "app.ts")), {
33
+ pluginDataRoot: pluginData,
34
+ env: PROJECT_ONLY_ENV,
35
+ });
36
+
37
+ // then
38
+ const context = readAdditionalContext(output);
39
+ expect(context).toContain("[Truncated. Full:");
40
+ expect(context.length).toBeLessThan(11_000);
41
+ });
42
+
43
+ it("#given a mid-sized static rule #when SessionStart injects #then the body is not truncated", async () => {
44
+ // given
45
+ const { root, pluginData } = makeProject({ staticRuleChars: 8_000 });
46
+
47
+ // when
48
+ const output = await runSessionStartHook(sessionStartInput(root), {
49
+ pluginDataRoot: pluginData,
50
+ env: PROJECT_ONLY_ENV,
51
+ });
52
+
53
+ // then
54
+ const context = readAdditionalContext(output);
55
+ expect(context).not.toContain("[Truncated. Full:");
56
+ expect(context.length).toBeGreaterThan(8_000);
57
+ });
58
+
59
+ it("#given the same mid-sized static rule #when UserPromptSubmit injects on a fresh session #then the body is truncated to the prompt budget", async () => {
60
+ // given
61
+ const { root, pluginData } = makeProject({ staticRuleChars: 8_000 });
62
+
63
+ // when
64
+ const output = await runUserPromptSubmitHook(userPromptSubmitInput(root), {
65
+ pluginDataRoot: pluginData,
66
+ env: PROJECT_ONLY_ENV,
67
+ });
68
+
69
+ // then
70
+ const context = readAdditionalContext(output);
71
+ expect(context).toContain("[Truncated. Full:");
72
+ expect(context.length).toBeLessThan(7_000);
73
+ });
74
+
75
+ it("#given dynamic budget env overrides #when PostToolUse injects #then the override budget wins", async () => {
76
+ // given
77
+ const { root, pluginData } = makeProject({ dynamicRuleChars: 30_000 });
78
+
79
+ // when
80
+ const output = await runPostToolUseHook(postToolUseInput(root, path.join(root, "src", "app.ts")), {
81
+ pluginDataRoot: pluginData,
82
+ env: {
83
+ ...PROJECT_ONLY_ENV,
84
+ CODEX_RULES_DYNAMIC_MAX_RULE_CHARS: "1000",
85
+ CODEX_RULES_DYNAMIC_MAX_RESULT_CHARS: "1500",
86
+ },
87
+ });
88
+
89
+ // then
90
+ const context = readAdditionalContext(output);
91
+ expect(context).toContain("[Truncated. Full:");
92
+ expect(context.length).toBeLessThan(2_000);
93
+ });
94
+ });
95
+
96
+ function makeProject(sizes: { staticRuleChars?: number; dynamicRuleChars?: number }): {
97
+ root: string;
98
+ pluginData: string;
99
+ } {
100
+ const root = mkdtempSync(path.join(tmpdir(), "codex-rules-event-budget-project-"));
101
+ const pluginData = mkdtempSync(path.join(tmpdir(), "codex-rules-event-budget-data-"));
102
+ tempDirectories.push(root, pluginData);
103
+ writeFileSync(path.join(root, "package.json"), JSON.stringify({ name: "fixture" }));
104
+ writeFileSync(path.join(root, "CONTEXT.md"), `Project rule\n${"A".repeat(sizes.staticRuleChars ?? 100)}`);
105
+ mkdirSync(path.join(root, ".omo", "rules"), { recursive: true });
106
+ writeFileSync(
107
+ path.join(root, ".omo", "rules", "typescript.md"),
108
+ ["---", 'globs: "**/*.ts"', "---", "", `TypeScript rule\n${"B".repeat(sizes.dynamicRuleChars ?? 100)}`].join(
109
+ "\n",
110
+ ),
111
+ );
112
+ mkdirSync(path.join(root, "src"), { recursive: true });
113
+ writeFileSync(path.join(root, "src", "app.ts"), "export const app = 1;\n");
114
+ return { root, pluginData };
115
+ }
116
+
117
+ function sessionStartInput(root: string): CodexSessionStartInput {
118
+ return {
119
+ session_id: `session-budget-${path.basename(root)}`,
120
+ transcript_path: null,
121
+ cwd: root,
122
+ hook_event_name: "SessionStart",
123
+ model: "gpt-5.5",
124
+ permission_mode: "default",
125
+ source: "startup",
126
+ };
127
+ }
128
+
129
+ function userPromptSubmitInput(root: string): CodexUserPromptSubmitInput {
130
+ return {
131
+ session_id: `session-budget-${path.basename(root)}`,
132
+ turn_id: "turn-1",
133
+ transcript_path: null,
134
+ cwd: root,
135
+ hook_event_name: "UserPromptSubmit",
136
+ model: "gpt-5.5",
137
+ permission_mode: "default",
138
+ prompt: "continue",
139
+ };
140
+ }
141
+
142
+ function postToolUseInput(root: string, filePath: string): CodexPostToolUseInput {
143
+ return {
144
+ session_id: `session-budget-${path.basename(root)}`,
145
+ turn_id: "turn-tool",
146
+ transcript_path: null,
147
+ cwd: root,
148
+ hook_event_name: "PostToolUse",
149
+ model: "gpt-5.5",
150
+ permission_mode: "default",
151
+ tool_name: "apply_patch",
152
+ tool_input: { path: filePath },
153
+ tool_response: {},
154
+ tool_use_id: "tool-use-1",
155
+ };
156
+ }
157
+
158
+ function readAdditionalContext(output: string): string {
159
+ if (output.trim().length === 0) {
160
+ throw new Error("Expected hook output to include additional context.");
161
+ }
162
+ const parsed: unknown = JSON.parse(output);
163
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return "";
164
+ const hookSpecificOutput = (parsed as Record<string, unknown>)["hookSpecificOutput"];
165
+ if (typeof hookSpecificOutput !== "object" || hookSpecificOutput === null) return "";
166
+ const additionalContext = (hookSpecificOutput as Record<string, unknown>)["additionalContext"];
167
+ return typeof additionalContext === "string" ? additionalContext : "";
168
+ }
@@ -14,6 +14,10 @@ const CONFIG: PiRulesConfig = {
14
14
  maxResultChars: 50_000,
15
15
  postCompactMaxRuleChars: 12_000,
16
16
  postCompactMaxResultChars: 20_000,
17
+ dynamicMaxRuleChars: 4_000,
18
+ dynamicMaxResultChars: 10_000,
19
+ promptMaxRuleChars: 6_000,
20
+ promptMaxResultChars: 16_000,
17
21
  enabledSources: "auto",
18
22
  };
19
23
 
@@ -1,8 +1,8 @@
1
- import { mkdtempSync, rmSync } from "node:fs";
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
 
5
- import { describe, expect, it } from "vitest";
5
+ import { afterAll, describe, expect, it } from "vitest";
6
6
 
7
7
  import { runSessionStartHook, runUserPromptSubmitHook } from "../src/codex-hook.js";
8
8
  import { formatAdditionalContextOutput } from "../src/hook-output.js";
@@ -45,13 +45,29 @@ function parseHookOutput(value: unknown): HookOutput {
45
45
  };
46
46
  }
47
47
 
48
+ const fixtureRoot = mkdtempSync(join(tmpdir(), "codex-sparkshell-omo-bin-"));
49
+ const omoOnPathDir = join(fixtureRoot, "path-bin");
50
+ const emptyHomeDir = join(fixtureRoot, "empty-home");
51
+ const localBinHomeDir = join(fixtureRoot, "local-bin-home");
52
+ mkdirSync(omoOnPathDir, { recursive: true });
53
+ mkdirSync(emptyHomeDir, { recursive: true });
54
+ mkdirSync(join(localBinHomeDir, ".local", "bin"), { recursive: true });
55
+ writeFileSync(join(omoOnPathDir, "omo"), "#!/bin/sh\n");
56
+ writeFileSync(join(localBinHomeDir, ".local", "bin", "omo"), "#!/bin/sh\n");
57
+
48
58
  describe("Codex Sparkshell awareness", () => {
49
- it("#given active Codex app server env #when SessionStart runs #then emits Sparkshell guidance", async () => {
59
+ afterAll(() => {
60
+ rmSync(fixtureRoot, { recursive: true, force: true });
61
+ });
62
+
63
+ it("#given active Codex app server env with omo on PATH #when SessionStart runs #then emits Sparkshell guidance", async () => {
50
64
  // given
51
65
  const env = {
52
66
  CODEX_INTERNAL_ORIGINATOR_OVERRIDE: "Codex Desktop",
53
67
  CODEX_SHELL: "1",
54
68
  CODEX_RULES_ENABLED_SOURCES: ".omo/rules",
69
+ PATH: omoOnPathDir,
70
+ HOME: emptyHomeDir,
55
71
  };
56
72
 
57
73
  // when
@@ -70,6 +86,11 @@ describe("Codex Sparkshell awareness", () => {
70
86
 
71
87
  // then
72
88
  expect(parseAdditionalContext(output)).toContain("omo sparkshell <command>");
89
+ expect(parseAdditionalContext(output)).toContain("OMO_SPARKSHELL_SESSION_CONTEXT");
90
+ expect(parseAdditionalContext(output)).toContain("OMO_SPARKSHELL_CONDENSE");
91
+ expect(parseAdditionalContext(output)).toContain("OMO_SPARKSHELL_SPARK");
92
+ expect(parseAdditionalContext(output)).toContain("[sparkshell caption]");
93
+ expect(parseAdditionalContext(output)).not.toContain("[REDACTED]");
73
94
  });
74
95
 
75
96
  it("#given inactive env #when SessionStart runs #then emits no Sparkshell guidance", async () => {
@@ -102,6 +123,8 @@ describe("Codex Sparkshell awareness", () => {
102
123
  OMO_SPARKSHELL_APP_SERVER_SOCKET: "/tmp/app-server-control.sock",
103
124
  CODEX_THREAD_ID: "thread-sparkshell-cli",
104
125
  CODEX_RULES_ENABLED_SOURCES: ".omo/rules",
126
+ PATH: omoOnPathDir,
127
+ HOME: emptyHomeDir,
105
128
  };
106
129
 
107
130
  // when
@@ -122,6 +145,64 @@ describe("Codex Sparkshell awareness", () => {
122
145
  expect(parseAdditionalContext(output)).toContain("omo sparkshell <command>");
123
146
  });
124
147
 
148
+ it("#given active Codex app env without a resolvable omo command #when SessionStart runs #then emits no Sparkshell guidance", async () => {
149
+ // given
150
+ const env = {
151
+ CODEX_INTERNAL_ORIGINATOR_OVERRIDE: "Codex Desktop",
152
+ CODEX_SHELL: "1",
153
+ CODEX_RULES_ENABLED_SOURCES: ".omo/rules",
154
+ PATH: join(fixtureRoot, "missing-path-entry"),
155
+ HOME: emptyHomeDir,
156
+ };
157
+
158
+ // when
159
+ const output = await runSessionStartHook(
160
+ {
161
+ session_id: "session-sparkshell-unresolvable",
162
+ transcript_path: null,
163
+ cwd: process.cwd(),
164
+ hook_event_name: "SessionStart",
165
+ model: "gpt-5.5",
166
+ permission_mode: "default",
167
+ source: "startup",
168
+ },
169
+ { env },
170
+ );
171
+
172
+ // then
173
+ expect(output).toBe("");
174
+ });
175
+
176
+ it("#given omo only under HOME/.local/bin #when SessionStart runs #then emits guidance with the absolute omo path", async () => {
177
+ // given
178
+ const env = {
179
+ CODEX_INTERNAL_ORIGINATOR_OVERRIDE: "Codex Desktop",
180
+ CODEX_SHELL: "1",
181
+ CODEX_RULES_ENABLED_SOURCES: ".omo/rules",
182
+ PATH: join(fixtureRoot, "missing-path-entry"),
183
+ HOME: localBinHomeDir,
184
+ };
185
+
186
+ // when
187
+ const output = await runSessionStartHook(
188
+ {
189
+ session_id: "session-sparkshell-local-bin",
190
+ transcript_path: null,
191
+ cwd: process.cwd(),
192
+ hook_event_name: "SessionStart",
193
+ model: "gpt-5.5",
194
+ permission_mode: "default",
195
+ source: "startup",
196
+ },
197
+ { env },
198
+ );
199
+
200
+ // then
201
+ const context = parseAdditionalContext(output);
202
+ expect(context).toContain(`${join(localBinHomeDir, ".local", "bin", "omo")} sparkshell <command>`);
203
+ expect(context).not.toContain("`omo sparkshell <command>`");
204
+ });
205
+
125
206
  it("#given explicit force-on env #when SessionStart runs #then emits Sparkshell guidance", async () => {
126
207
  // given
127
208
  const env = {
@@ -181,6 +262,8 @@ describe("Codex Sparkshell awareness", () => {
181
262
  CODEX_INTERNAL_ORIGINATOR_OVERRIDE: "Codex Desktop",
182
263
  CODEX_SHELL: "1",
183
264
  CODEX_RULES_ENABLED_SOURCES: ".omo/rules",
265
+ PATH: omoOnPathDir,
266
+ HOME: emptyHomeDir,
184
267
  };
185
268
  try {
186
269
  const firstOutput = await runSessionStartHook(