oh-my-opencode 4.5.1 → 4.6.0

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 (668) hide show
  1. package/.agents/skills/opencode-qa/SKILL.md +194 -0
  2. package/.agents/skills/opencode-qa/references/cli-commands.md +188 -0
  3. package/.agents/skills/opencode-qa/references/db-investigation.md +197 -0
  4. package/.agents/skills/opencode-qa/references/events-hooks.md +110 -0
  5. package/.agents/skills/opencode-qa/references/sdk.md +96 -0
  6. package/.agents/skills/opencode-qa/references/server-api.md +200 -0
  7. package/.agents/skills/opencode-qa/references/testing-harness.md +218 -0
  8. package/.agents/skills/opencode-qa/references/tui-tmux.md +52 -0
  9. package/.agents/skills/opencode-qa/scripts/db-session-by-id.sh +53 -0
  10. package/.agents/skills/opencode-qa/scripts/db-session-by-name.sh +57 -0
  11. package/.agents/skills/opencode-qa/scripts/db-session-by-text.sh +158 -0
  12. package/.agents/skills/opencode-qa/scripts/export-roundtrip.sh +57 -0
  13. package/.agents/skills/opencode-qa/scripts/lib/common.sh +216 -0
  14. package/.agents/skills/opencode-qa/scripts/server-smoke.sh +64 -0
  15. package/.agents/skills/opencode-qa/scripts/sse-hook-probe.sh +106 -0
  16. package/.agents/skills/opencode-qa/scripts/tui-smoke.sh +89 -0
  17. package/README.ja.md +43 -18
  18. package/README.ko.md +43 -18
  19. package/README.md +92 -24
  20. package/README.ru.md +43 -18
  21. package/README.zh-cn.md +55 -24
  22. package/bin/oh-my-opencode.js +49 -3
  23. package/bin/oh-my-opencode.test.ts +202 -0
  24. package/bin/platform.d.ts +7 -1
  25. package/bin/platform.js +23 -4
  26. package/bin/platform.test.ts +97 -10
  27. package/dist/cli/cleanup-command.d.ts +4 -0
  28. package/dist/cli/cleanup.d.ts +11 -0
  29. package/dist/cli/cli-program.d.ts +19 -0
  30. package/dist/cli/index.js +30085 -26385
  31. package/dist/cli/install-codex/codex-cache-bundled-mcps.d.ts +5 -0
  32. package/dist/cli/install-codex/codex-cache-command-shim.d.ts +1 -0
  33. package/dist/cli/install-codex/codex-cache-legacy-bins.d.ts +3 -0
  34. package/dist/cli/install-codex/codex-cache-local-dependencies.d.ts +1 -0
  35. package/dist/cli/install-codex/codex-cache-paths.d.ts +2 -0
  36. package/dist/cli/install-codex/codex-cache.d.ts +32 -0
  37. package/dist/cli/install-codex/codex-cleanup-config.d.ts +6 -0
  38. package/dist/cli/install-codex/codex-cleanup.d.ts +21 -0
  39. package/dist/cli/install-codex/codex-config-mcp.d.ts +1 -0
  40. package/dist/cli/install-codex/codex-config-permissions.d.ts +1 -0
  41. package/dist/cli/install-codex/codex-config-reasoning.d.ts +1 -0
  42. package/dist/cli/install-codex/codex-config-toml.d.ts +12 -0
  43. package/dist/cli/install-codex/codex-hook-trust.d.ts +6 -0
  44. package/dist/cli/install-codex/codex-installation-detection.d.ts +36 -0
  45. package/dist/cli/install-codex/codex-marketplace-snapshot.d.ts +15 -0
  46. package/dist/cli/install-codex/codex-marketplace.d.ts +9 -0
  47. package/dist/cli/install-codex/codex-multi-agent-v2-config.d.ts +1 -0
  48. package/dist/cli/install-codex/codex-package-layout.d.ts +1 -0
  49. package/dist/cli/install-codex/codex-process.d.ts +2 -0
  50. package/dist/cli/install-codex/codex-project-local-cleanup-best-effort.d.ts +7 -0
  51. package/dist/cli/install-codex/codex-project-local-cleanup.d.ts +35 -0
  52. package/dist/cli/install-codex/git-bash.d.ts +35 -0
  53. package/dist/cli/install-codex/index.d.ts +11 -0
  54. package/dist/cli/install-codex/install-codex.d.ts +17 -0
  55. package/dist/cli/install-codex/link-cached-plugin-agents.d.ts +12 -0
  56. package/dist/cli/install-codex/toml-section-editor.d.ts +11 -0
  57. package/dist/cli/install-codex/types.d.ts +76 -0
  58. package/dist/cli/run/event-state.d.ts +1 -0
  59. package/dist/cli/run/poll-for-completion.d.ts +1 -0
  60. package/dist/cli/run/prompt-start.d.ts +7 -0
  61. package/dist/cli/star-request.d.ts +11 -0
  62. package/dist/cli/tui-install-prompts.d.ts +3 -2
  63. package/dist/cli/types.d.ts +8 -0
  64. package/dist/config/schema/agent-names.d.ts +4 -1
  65. package/dist/config/schema/commands.d.ts +1 -2
  66. package/dist/config/schema/hooks.d.ts +0 -1
  67. package/dist/config/schema/oh-my-opencode-config.d.ts +5 -3
  68. package/dist/create-hooks.d.ts +0 -1
  69. package/dist/create-managers.d.ts +1 -0
  70. package/dist/features/background-agent/parent-wake-message-activity.d.ts +23 -0
  71. package/dist/features/background-agent/parent-wake-notifier.d.ts +0 -1
  72. package/dist/features/boulder-state/storage.d.ts +1 -1
  73. package/dist/features/builtin-commands/templates/refactor.d.ts +1 -1
  74. package/dist/features/builtin-commands/templates/remove-ai-slops.d.ts +2 -2
  75. package/dist/features/builtin-commands/types.d.ts +1 -1
  76. package/dist/features/builtin-skills/skill-file-loader.d.ts +4 -0
  77. package/dist/features/builtin-skills/skills/debugging.d.ts +2 -0
  78. package/dist/features/builtin-skills/skills/index.d.ts +5 -1
  79. package/dist/features/builtin-skills/skills/init-deep.d.ts +2 -0
  80. package/dist/features/builtin-skills/skills/remove-ai-slops.d.ts +2 -0
  81. package/dist/features/builtin-skills/skills/security-research.d.ts +2 -0
  82. package/dist/features/builtin-skills/skills/security-review.d.ts +2 -0
  83. package/dist/features/opencode-runtime-skills/index.d.ts +2 -0
  84. package/dist/features/opencode-runtime-skills/runtime-skill-config.d.ts +17 -0
  85. package/dist/features/opencode-runtime-skills/skill-markdown.d.ts +7 -0
  86. package/dist/features/opencode-runtime-skills/source-server.d.ts +8 -0
  87. package/dist/hooks/claude-code-hooks/hook-text.d.ts +2 -0
  88. package/dist/hooks/index.d.ts +0 -1
  89. package/dist/hooks/session-recovery/storage/latest-assistant-message.d.ts +5 -0
  90. package/dist/hooks/session-recovery/storage/thinking-prepend.d.ts +3 -0
  91. package/dist/hooks/thinking-block-validator/hook.d.ts +0 -18
  92. package/dist/hooks/todo-continuation-enforcer/pending-question-detection.d.ts +4 -0
  93. package/dist/index.js +1949 -1913
  94. package/dist/oh-my-opencode.schema.json +4 -2
  95. package/dist/plugin/hooks/create-core-hooks.d.ts +0 -1
  96. package/dist/plugin/hooks/create-session-hooks.d.ts +1 -2
  97. package/dist/plugin/messages-transform.d.ts +8 -1
  98. package/dist/plugin/user-abort-interrupted-recovery-guard.d.ts +6 -0
  99. package/dist/plugin-handlers/config-handler.d.ts +2 -1
  100. package/dist/shared/external-plugin-detector.d.ts +8 -0
  101. package/dist/shared/prompt-async-gate/message-inspection-error.d.ts +1 -0
  102. package/dist/shared/prompt-async-gate/pending-tool-turn.d.ts +1 -0
  103. package/dist/shared/prompt-async-gate/prompt-message-state.d.ts +8 -0
  104. package/dist/shared/prompt-async-gate/recent-dispatches.d.ts +14 -0
  105. package/dist/shared/prompt-async-gate/semantic-dedupe.d.ts +7 -0
  106. package/dist/shared/prompt-async-gate/session-idle-dispatch.d.ts +1 -0
  107. package/dist/shared/prompt-async-gate/timing.d.ts +1 -0
  108. package/dist/shared/prompt-async-gate/types.d.ts +2 -0
  109. package/dist/shared/prompt-async-gate.d.ts +1 -1
  110. package/dist/shared/prompt-timeout-context.d.ts +2 -0
  111. package/dist/testing/create-plugin-module.d.ts +5 -1
  112. package/dist/tools/delegate-task/sync-prompt-sender.d.ts +2 -2
  113. package/package.json +38 -18
  114. package/packages/ast-grep-mcp/dist/cli.js +245 -40
  115. package/packages/git-bash-mcp/dist/cli.js +367 -0
  116. package/packages/lsp-tools-mcp/dist/cli.js +1 -1
  117. package/packages/omo-codex/marketplace.json +17 -0
  118. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +35 -0
  119. package/packages/omo-codex/plugin/.mcp.json +25 -0
  120. package/packages/omo-codex/plugin/README.md +13 -0
  121. package/packages/omo-codex/plugin/components/comment-checker/.gitattributes +13 -0
  122. package/packages/omo-codex/plugin/components/comment-checker/.github/CODEOWNERS +12 -0
  123. package/packages/omo-codex/plugin/components/comment-checker/.github/ISSUE_TEMPLATE/bug.yml +40 -0
  124. package/packages/omo-codex/plugin/components/comment-checker/.github/ISSUE_TEMPLATE/feature.yml +27 -0
  125. package/packages/omo-codex/plugin/components/comment-checker/.github/branch-ruleset.json +45 -0
  126. package/packages/omo-codex/plugin/components/comment-checker/.github/dependabot.yml +16 -0
  127. package/packages/omo-codex/plugin/components/comment-checker/.github/pull_request_template.md +19 -0
  128. package/packages/omo-codex/plugin/components/comment-checker/.github/workflows/ci.yml +47 -0
  129. package/packages/omo-codex/plugin/components/comment-checker/.github/workflows/publish.yml +51 -0
  130. package/packages/omo-codex/plugin/components/comment-checker/AGENTS.md +35 -0
  131. package/packages/omo-codex/plugin/components/comment-checker/CHANGELOG.md +33 -0
  132. package/packages/omo-codex/plugin/components/comment-checker/LICENSE +21 -0
  133. package/packages/omo-codex/plugin/components/comment-checker/NOTICE +6 -0
  134. package/packages/omo-codex/plugin/components/comment-checker/README.md +87 -0
  135. package/packages/omo-codex/plugin/components/comment-checker/biome.json +48 -0
  136. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +17 -0
  137. package/packages/omo-codex/plugin/components/comment-checker/package.json +57 -0
  138. package/packages/omo-codex/plugin/components/comment-checker/skills/comment-checker/SKILL.md +16 -0
  139. package/packages/omo-codex/plugin/components/comment-checker/src/cli.ts +12 -0
  140. package/packages/omo-codex/plugin/components/comment-checker/src/codex-hook.ts +205 -0
  141. package/packages/omo-codex/plugin/components/comment-checker/src/core.ts +361 -0
  142. package/packages/omo-codex/plugin/components/comment-checker/src/runner.ts +195 -0
  143. package/packages/omo-codex/plugin/components/comment-checker/test/codex-hook-newline.test.ts +52 -0
  144. package/packages/omo-codex/plugin/components/comment-checker/test/codex-hook.test.ts +368 -0
  145. package/packages/omo-codex/plugin/components/comment-checker/test/fixtures/post-tool-use.json +15 -0
  146. package/packages/omo-codex/plugin/components/comment-checker/test/package-smoke.test.ts +93 -0
  147. package/packages/omo-codex/plugin/components/comment-checker/test/runner.test.ts +66 -0
  148. package/packages/omo-codex/plugin/components/comment-checker/tsconfig.build.json +12 -0
  149. package/packages/omo-codex/plugin/components/comment-checker/tsconfig.json +27 -0
  150. package/packages/omo-codex/plugin/components/comment-checker/vitest.config.ts +9 -0
  151. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +29 -0
  152. package/packages/omo-codex/plugin/components/git-bash/package.json +23 -0
  153. package/packages/omo-codex/plugin/components/git-bash/src/cli.ts +33 -0
  154. package/packages/omo-codex/plugin/components/git-bash/src/codex-hook.ts +180 -0
  155. package/packages/omo-codex/plugin/components/git-bash/src/index.ts +10 -0
  156. package/packages/omo-codex/plugin/components/git-bash/test/codex-hook.test.ts +195 -0
  157. package/packages/omo-codex/plugin/components/git-bash/tsconfig.build.json +13 -0
  158. package/packages/omo-codex/plugin/components/git-bash/tsconfig.json +25 -0
  159. package/packages/omo-codex/plugin/components/lsp/.gitattributes +13 -0
  160. package/packages/omo-codex/plugin/components/lsp/.github/CODEOWNERS +1 -0
  161. package/packages/omo-codex/plugin/components/lsp/.github/ISSUE_TEMPLATE/bug.yml +26 -0
  162. package/packages/omo-codex/plugin/components/lsp/.github/ISSUE_TEMPLATE/feature.yml +19 -0
  163. package/packages/omo-codex/plugin/components/lsp/.github/branch-ruleset.json +45 -0
  164. package/packages/omo-codex/plugin/components/lsp/.github/dependabot.yml +11 -0
  165. package/packages/omo-codex/plugin/components/lsp/.github/pull_request_template.md +11 -0
  166. package/packages/omo-codex/plugin/components/lsp/.github/workflows/ci.yml +56 -0
  167. package/packages/omo-codex/plugin/components/lsp/.github/workflows/publish.yml +60 -0
  168. package/packages/omo-codex/plugin/components/lsp/.mcp.json +9 -0
  169. package/packages/omo-codex/plugin/components/lsp/AGENTS.md +25 -0
  170. package/packages/omo-codex/plugin/components/lsp/CHANGELOG.md +25 -0
  171. package/packages/omo-codex/plugin/components/lsp/LICENSE +21 -0
  172. package/packages/omo-codex/plugin/components/lsp/NOTICE +3 -0
  173. package/packages/omo-codex/plugin/components/lsp/README.md +148 -0
  174. package/packages/omo-codex/plugin/components/lsp/biome.json +48 -0
  175. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +17 -0
  176. package/packages/omo-codex/plugin/components/lsp/package.json +64 -0
  177. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-tools.mjs +46 -0
  178. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-tools.test.mjs +104 -0
  179. package/packages/omo-codex/plugin/components/lsp/scripts/clean-dist.mjs +5 -0
  180. package/packages/omo-codex/plugin/components/lsp/scripts/test.mjs +8 -0
  181. package/packages/omo-codex/plugin/components/lsp/skills/lsp/SKILL.md +35 -0
  182. package/packages/omo-codex/plugin/components/lsp/src/cli.ts +44 -0
  183. package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +33 -0
  184. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +277 -0
  185. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-cli.test.ts +28 -0
  186. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-errors.test.ts +55 -0
  187. package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +358 -0
  188. package/packages/omo-codex/plugin/components/lsp/test/fixtures/broken.py +1 -0
  189. package/packages/omo-codex/plugin/components/lsp/test/fixtures/post-tool-use.json +15 -0
  190. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +155 -0
  191. package/packages/omo-codex/plugin/components/lsp/tsconfig.build.json +12 -0
  192. package/packages/omo-codex/plugin/components/lsp/tsconfig.json +27 -0
  193. package/packages/omo-codex/plugin/components/lsp/vitest.config.ts +9 -0
  194. package/packages/omo-codex/plugin/components/rules/.codex-plugin/plugin.json +3 -0
  195. package/packages/omo-codex/plugin/components/rules/.gitattributes +13 -0
  196. package/packages/omo-codex/plugin/components/rules/.github/CODEOWNERS +12 -0
  197. package/packages/omo-codex/plugin/components/rules/.github/ISSUE_TEMPLATE/bug.yml +49 -0
  198. package/packages/omo-codex/plugin/components/rules/.github/ISSUE_TEMPLATE/feature.yml +27 -0
  199. package/packages/omo-codex/plugin/components/rules/.github/branch-ruleset.json +45 -0
  200. package/packages/omo-codex/plugin/components/rules/.github/dependabot.yml +16 -0
  201. package/packages/omo-codex/plugin/components/rules/.github/pull_request_template.md +20 -0
  202. package/packages/omo-codex/plugin/components/rules/.github/workflows/ci.yml +47 -0
  203. package/packages/omo-codex/plugin/components/rules/.github/workflows/publish.yml +51 -0
  204. package/packages/omo-codex/plugin/components/rules/AGENTS.md +34 -0
  205. package/packages/omo-codex/plugin/components/rules/CHANGELOG.md +19 -0
  206. package/packages/omo-codex/plugin/components/rules/LICENSE +21 -0
  207. package/packages/omo-codex/plugin/components/rules/NOTICE +15 -0
  208. package/packages/omo-codex/plugin/components/rules/README.md +124 -0
  209. package/packages/omo-codex/plugin/components/rules/biome.json +48 -0
  210. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus.md +209 -0
  211. package/packages/omo-codex/plugin/components/rules/bundled-rules/windows-git-bash.md +10 -0
  212. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +54 -0
  213. package/packages/omo-codex/plugin/components/rules/package.json +62 -0
  214. package/packages/omo-codex/plugin/components/rules/scripts/bench-codex-rules.mjs +268 -0
  215. package/packages/omo-codex/plugin/components/rules/skills/rules/SKILL.md +34 -0
  216. package/packages/omo-codex/plugin/components/rules/src/cli.ts +143 -0
  217. package/packages/omo-codex/plugin/components/rules/src/codex-hook-options.ts +4 -0
  218. package/packages/omo-codex/plugin/components/rules/src/codex-hook.ts +238 -0
  219. package/packages/omo-codex/plugin/components/rules/src/config.ts +107 -0
  220. package/packages/omo-codex/plugin/components/rules/src/context-pressure.ts +26 -0
  221. package/packages/omo-codex/plugin/components/rules/src/debug-log.ts +65 -0
  222. package/packages/omo-codex/plugin/components/rules/src/dynamic-target-fingerprints.ts +98 -0
  223. package/packages/omo-codex/plugin/components/rules/src/hook-output.ts +19 -0
  224. package/packages/omo-codex/plugin/components/rules/src/path-utils.ts +29 -0
  225. package/packages/omo-codex/plugin/components/rules/src/persistent-cache.ts +234 -0
  226. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +104 -0
  227. package/packages/omo-codex/plugin/components/rules/src/post-compact-claim.ts +13 -0
  228. package/packages/omo-codex/plugin/components/rules/src/post-compact-state.ts +45 -0
  229. package/packages/omo-codex/plugin/components/rules/src/rules/cache.ts +64 -0
  230. package/packages/omo-codex/plugin/components/rules/src/rules/constants.ts +115 -0
  231. package/packages/omo-codex/plugin/components/rules/src/rules/engine.ts +535 -0
  232. package/packages/omo-codex/plugin/components/rules/src/rules/errors.ts +13 -0
  233. package/packages/omo-codex/plugin/components/rules/src/rules/finder-cache.ts +73 -0
  234. package/packages/omo-codex/plugin/components/rules/src/rules/finder-paths.ts +47 -0
  235. package/packages/omo-codex/plugin/components/rules/src/rules/finder-sources.ts +50 -0
  236. package/packages/omo-codex/plugin/components/rules/src/rules/finder.ts +207 -0
  237. package/packages/omo-codex/plugin/components/rules/src/rules/formatter.ts +123 -0
  238. package/packages/omo-codex/plugin/components/rules/src/rules/matcher.ts +142 -0
  239. package/packages/omo-codex/plugin/components/rules/src/rules/ordering.ts +33 -0
  240. package/packages/omo-codex/plugin/components/rules/src/rules/parser.ts +326 -0
  241. package/packages/omo-codex/plugin/components/rules/src/rules/plugin-root.ts +55 -0
  242. package/packages/omo-codex/plugin/components/rules/src/rules/project-root.ts +30 -0
  243. package/packages/omo-codex/plugin/components/rules/src/rules/scanner.ts +162 -0
  244. package/packages/omo-codex/plugin/components/rules/src/rules/truncator.ts +67 -0
  245. package/packages/omo-codex/plugin/components/rules/src/rules/types.ts +141 -0
  246. package/packages/omo-codex/plugin/components/rules/src/rules-engine-factory.ts +24 -0
  247. package/packages/omo-codex/plugin/components/rules/src/session-state-lock.ts +47 -0
  248. package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +56 -0
  249. package/packages/omo-codex/plugin/components/rules/src/tool-paths.ts +192 -0
  250. package/packages/omo-codex/plugin/components/rules/src/transcript-rule-filter.ts +44 -0
  251. package/packages/omo-codex/plugin/components/rules/src/transcript-search.ts +108 -0
  252. package/packages/omo-codex/plugin/components/rules/test/bundled-rules-priority.test.ts +107 -0
  253. package/packages/omo-codex/plugin/components/rules/test/bundled-rules.test.ts +268 -0
  254. package/packages/omo-codex/plugin/components/rules/test/codex-hook-context-pressure.test.ts +243 -0
  255. package/packages/omo-codex/plugin/components/rules/test/codex-hook-performance.test.ts +99 -0
  256. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-budget.test.ts +132 -0
  257. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-context.test.ts +156 -0
  258. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-dedup.test.ts +299 -0
  259. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-lock.test.ts +46 -0
  260. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-process.test.ts +83 -0
  261. package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +667 -0
  262. package/packages/omo-codex/plugin/components/rules/test/engine.test.ts +192 -0
  263. package/packages/omo-codex/plugin/components/rules/test/finder.test.ts +102 -0
  264. package/packages/omo-codex/plugin/components/rules/test/formatter.test.ts +168 -0
  265. package/packages/omo-codex/plugin/components/rules/test/hook-output.test.ts +42 -0
  266. package/packages/omo-codex/plugin/components/rules/test/matcher.test.ts +206 -0
  267. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +153 -0
  268. package/packages/omo-codex/plugin/components/rules/test/persistent-cache.test.ts +63 -0
  269. package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +172 -0
  270. package/packages/omo-codex/plugin/components/rules/test/post-compact-test-fixture.ts +196 -0
  271. package/packages/omo-codex/plugin/components/rules/test/scanner.test.ts +63 -0
  272. package/packages/omo-codex/plugin/components/rules/test/tool-paths.test.ts +198 -0
  273. package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +97 -0
  274. package/packages/omo-codex/plugin/components/rules/tsconfig.build.json +12 -0
  275. package/packages/omo-codex/plugin/components/rules/tsconfig.json +27 -0
  276. package/packages/omo-codex/plugin/components/rules/vitest.config.ts +8 -0
  277. package/packages/omo-codex/plugin/components/start-work-continuation/.gitattributes +13 -0
  278. package/packages/omo-codex/plugin/components/start-work-continuation/AGENTS.md +43 -0
  279. package/packages/omo-codex/plugin/components/start-work-continuation/CHANGELOG.md +5 -0
  280. package/packages/omo-codex/plugin/components/start-work-continuation/LICENSE +21 -0
  281. package/packages/omo-codex/plugin/components/start-work-continuation/NOTICE +5 -0
  282. package/packages/omo-codex/plugin/components/start-work-continuation/README.md +55 -0
  283. package/packages/omo-codex/plugin/components/start-work-continuation/biome.json +48 -0
  284. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +52 -0
  285. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +28 -0
  286. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +53 -0
  287. package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +167 -0
  288. package/packages/omo-codex/plugin/components/start-work-continuation/src/cli.ts +52 -0
  289. package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +66 -0
  290. package/packages/omo-codex/plugin/components/start-work-continuation/src/directive.ts +6 -0
  291. package/packages/omo-codex/plugin/components/start-work-continuation/src/index.ts +5 -0
  292. package/packages/omo-codex/plugin/components/start-work-continuation/src/types.ts +23 -0
  293. package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +63 -0
  294. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +124 -0
  295. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +182 -0
  296. package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/boulder-completed.json +19 -0
  297. package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/boulder-mixed-platforms.json +27 -0
  298. package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/boulder-single-codex-work.json +19 -0
  299. package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-all-done.md +5 -0
  300. package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-with-nested-checkboxes.md +11 -0
  301. package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-with-unchecked.md +6 -0
  302. package/packages/omo-codex/plugin/components/start-work-continuation/tsconfig.build.json +12 -0
  303. package/packages/omo-codex/plugin/components/start-work-continuation/tsconfig.json +27 -0
  304. package/packages/omo-codex/plugin/components/start-work-continuation/vitest.config.ts +10 -0
  305. package/packages/omo-codex/plugin/components/telemetry/AGENTS.md +37 -0
  306. package/packages/omo-codex/plugin/components/telemetry/README.md +102 -0
  307. package/packages/omo-codex/plugin/components/telemetry/biome.json +48 -0
  308. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +16 -0
  309. package/packages/omo-codex/plugin/components/telemetry/package.json +56 -0
  310. package/packages/omo-codex/plugin/components/telemetry/src/atomic-write.ts +22 -0
  311. package/packages/omo-codex/plugin/components/telemetry/src/cli.ts +69 -0
  312. package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +49 -0
  313. package/packages/omo-codex/plugin/components/telemetry/src/data-path.ts +45 -0
  314. package/packages/omo-codex/plugin/components/telemetry/src/env-flags.ts +43 -0
  315. package/packages/omo-codex/plugin/components/telemetry/src/posthog-activity-state.ts +81 -0
  316. package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +165 -0
  317. package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +35 -0
  318. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +270 -0
  319. package/packages/omo-codex/plugin/components/telemetry/tsconfig.build.json +12 -0
  320. package/packages/omo-codex/plugin/components/telemetry/tsconfig.json +27 -0
  321. package/packages/omo-codex/plugin/components/telemetry/vitest.config.ts +8 -0
  322. package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +41 -0
  323. package/packages/omo-codex/plugin/components/ultrawork/CHANGELOG.md +25 -0
  324. package/packages/omo-codex/plugin/components/ultrawork/LICENSE +21 -0
  325. package/packages/omo-codex/plugin/components/ultrawork/NOTICE +5 -0
  326. package/packages/omo-codex/plugin/components/ultrawork/README.md +60 -0
  327. package/packages/omo-codex/plugin/components/ultrawork/agents/codex-ultrawork-reviewer.toml +18 -0
  328. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +82 -0
  329. package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +222 -0
  330. package/packages/omo-codex/plugin/components/ultrawork/agents/metis.toml +65 -0
  331. package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +69 -0
  332. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +164 -0
  333. package/packages/omo-codex/plugin/components/ultrawork/biome.json +48 -0
  334. package/packages/omo-codex/plugin/components/ultrawork/directive.md +290 -0
  335. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +16 -0
  336. package/packages/omo-codex/plugin/components/ultrawork/package.json +54 -0
  337. package/packages/omo-codex/plugin/components/ultrawork/src/cli.ts +50 -0
  338. package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +84 -0
  339. package/packages/omo-codex/plugin/components/ultrawork/src/directive.ts +3 -0
  340. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +275 -0
  341. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +103 -0
  342. package/packages/omo-codex/plugin/components/ultrawork/tsconfig.build.json +12 -0
  343. package/packages/omo-codex/plugin/components/ultrawork/tsconfig.json +27 -0
  344. package/packages/omo-codex/plugin/components/ulw-loop/.gitattributes +13 -0
  345. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +48 -0
  346. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +7 -0
  347. package/packages/omo-codex/plugin/components/ulw-loop/LICENSE +21 -0
  348. package/packages/omo-codex/plugin/components/ulw-loop/NOTICE +6 -0
  349. package/packages/omo-codex/plugin/components/ulw-loop/README.md +74 -0
  350. package/packages/omo-codex/plugin/components/ulw-loop/biome.json +48 -0
  351. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +29 -0
  352. package/packages/omo-codex/plugin/components/ulw-loop/package.json +55 -0
  353. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/.gitkeep +0 -0
  354. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +44 -0
  355. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/agents/openai.yaml +6 -0
  356. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +230 -0
  357. package/packages/omo-codex/plugin/components/ulw-loop/src/.gitkeep +0 -0
  358. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +155 -0
  359. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-arg-parser.ts +95 -0
  360. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +156 -0
  361. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +63 -0
  362. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +94 -0
  363. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +40 -0
  364. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +129 -0
  365. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-snapshot.ts +139 -0
  366. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +177 -0
  367. package/packages/omo-codex/plugin/components/ulw-loop/src/evidence.ts +122 -0
  368. package/packages/omo-codex/plugin/components/ulw-loop/src/goal-status.ts +88 -0
  369. package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +73 -0
  370. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +113 -0
  371. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +124 -0
  372. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +102 -0
  373. package/packages/omo-codex/plugin/components/ulw-loop/src/review-blockers.ts +81 -0
  374. package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +270 -0
  375. package/packages/omo-codex/plugin/components/ulw-loop/src/types.ts +277 -0
  376. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint.test.ts +213 -0
  377. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-commands.test.ts +375 -0
  378. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-helpers.test.ts +250 -0
  379. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering.test.ts +407 -0
  380. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +169 -0
  381. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-snapshot.test.ts +156 -0
  382. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +275 -0
  383. package/packages/omo-codex/plugin/components/ulw-loop/test/evidence-criteria-gate.test.ts +100 -0
  384. package/packages/omo-codex/plugin/components/ulw-loop/test/evidence.test.ts +263 -0
  385. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/.gitkeep +0 -0
  386. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/codex-goal-snapshot.json +1 -0
  387. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/sample-brief.md +5 -0
  388. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/sample-plan.json +108 -0
  389. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/sample-quality-gate.json +18 -0
  390. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/steering-proposal.json +8 -0
  391. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/user-prompt-submit.json +10 -0
  392. package/packages/omo-codex/plugin/components/ulw-loop/test/goal-status.test.ts +327 -0
  393. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +261 -0
  394. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +62 -0
  395. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-crud.test.ts +256 -0
  396. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io.test.ts +239 -0
  397. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +203 -0
  398. package/packages/omo-codex/plugin/components/ulw-loop/test/review-blockers.test.ts +180 -0
  399. package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +353 -0
  400. package/packages/omo-codex/plugin/components/ulw-loop/test/types.test.ts +79 -0
  401. package/packages/omo-codex/plugin/components/ulw-loop/tsconfig.build.json +12 -0
  402. package/packages/omo-codex/plugin/components/ulw-loop/tsconfig.json +27 -0
  403. package/packages/omo-codex/plugin/components/ulw-loop/vitest.config.ts +10 -0
  404. package/packages/omo-codex/plugin/hooks/hooks.json +160 -0
  405. package/packages/omo-codex/plugin/package-lock.json +1769 -0
  406. package/packages/omo-codex/plugin/package.json +28 -0
  407. package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +65 -0
  408. package/packages/omo-codex/plugin/scripts/build-components.mjs +24 -0
  409. package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +46 -0
  410. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +87 -0
  411. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +75 -0
  412. package/packages/omo-codex/plugin/skills/comment-checker/SKILL.md +16 -0
  413. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +116 -0
  414. package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +108 -0
  415. package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +130 -0
  416. package/packages/omo-codex/plugin/skills/debugging/references/methodology/04-oracle-triple.md +136 -0
  417. package/packages/omo-codex/plugin/skills/debugging/references/methodology/05-escalate.md +69 -0
  418. package/packages/omo-codex/plugin/skills/debugging/references/methodology/06-fix.md +116 -0
  419. package/packages/omo-codex/plugin/skills/debugging/references/methodology/08-qa.md +94 -0
  420. package/packages/omo-codex/plugin/skills/debugging/references/methodology/09-cleanup.md +164 -0
  421. package/packages/omo-codex/plugin/skills/debugging/references/methodology/partial-runtime-evidence.md +229 -0
  422. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
  423. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +252 -0
  424. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +484 -0
  425. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +260 -0
  426. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +248 -0
  427. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +234 -0
  428. package/packages/omo-codex/plugin/skills/debugging/references/tools/ghidra.md +212 -0
  429. package/packages/omo-codex/plugin/skills/debugging/references/tools/playwright-cli.md +194 -0
  430. package/packages/omo-codex/plugin/skills/debugging/references/tools/pwndbg.md +263 -0
  431. package/packages/omo-codex/plugin/skills/debugging/references/tools/pwntools.md +265 -0
  432. package/packages/omo-codex/plugin/skills/frontend-ui-ux/SKILL.md +77 -0
  433. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +325 -0
  434. package/packages/omo-codex/plugin/skills/lsp/SKILL.md +35 -0
  435. package/packages/omo-codex/plugin/skills/programming/SKILL.md +463 -0
  436. package/packages/omo-codex/plugin/skills/programming/references/go/README.md +90 -0
  437. package/packages/omo-codex/plugin/skills/programming/references/go/backend-stack.md +641 -0
  438. package/packages/omo-codex/plugin/skills/programming/references/go/bootstrap.md +328 -0
  439. package/packages/omo-codex/plugin/skills/programming/references/go/bubbletea-v2.md +360 -0
  440. package/packages/omo-codex/plugin/skills/programming/references/go/cobra-stack.md +468 -0
  441. package/packages/omo-codex/plugin/skills/programming/references/go/concurrency.md +362 -0
  442. package/packages/omo-codex/plugin/skills/programming/references/go/data-modeling.md +329 -0
  443. package/packages/omo-codex/plugin/skills/programming/references/go/error-handling.md +359 -0
  444. package/packages/omo-codex/plugin/skills/programming/references/go/golangci-strict.md +236 -0
  445. package/packages/omo-codex/plugin/skills/programming/references/go/grpc-connect.md +375 -0
  446. package/packages/omo-codex/plugin/skills/programming/references/go/libraries.md +337 -0
  447. package/packages/omo-codex/plugin/skills/programming/references/go/one-liners.md +202 -0
  448. package/packages/omo-codex/plugin/skills/programming/references/go/sqlc-pgx.md +471 -0
  449. package/packages/omo-codex/plugin/skills/programming/references/go/testing.md +467 -0
  450. package/packages/omo-codex/plugin/skills/programming/references/go/type-patterns.md +298 -0
  451. package/packages/omo-codex/plugin/skills/programming/references/python/README.md +314 -0
  452. package/packages/omo-codex/plugin/skills/programming/references/python/async-anyio.md +442 -0
  453. package/packages/omo-codex/plugin/skills/programming/references/python/data-modeling.md +233 -0
  454. package/packages/omo-codex/plugin/skills/programming/references/python/data-processing.md +133 -0
  455. package/packages/omo-codex/plugin/skills/programming/references/python/error-handling.md +218 -0
  456. package/packages/omo-codex/plugin/skills/programming/references/python/fastapi-stack.md +316 -0
  457. package/packages/omo-codex/plugin/skills/programming/references/python/httpx2-optimization.md +360 -0
  458. package/packages/omo-codex/plugin/skills/programming/references/python/libraries.md +307 -0
  459. package/packages/omo-codex/plugin/skills/programming/references/python/one-liners.md +268 -0
  460. package/packages/omo-codex/plugin/skills/programming/references/python/orjson-stack.md +378 -0
  461. package/packages/omo-codex/plugin/skills/programming/references/python/pydantic-ai.md +285 -0
  462. package/packages/omo-codex/plugin/skills/programming/references/python/pyproject-strict.md +232 -0
  463. package/packages/omo-codex/plugin/skills/programming/references/python/textual-tui.md +201 -0
  464. package/packages/omo-codex/plugin/skills/programming/references/python/type-patterns.md +176 -0
  465. package/packages/omo-codex/plugin/skills/programming/references/rust/README.md +317 -0
  466. package/packages/omo-codex/plugin/skills/programming/references/rust/async-tokio.md +299 -0
  467. package/packages/omo-codex/plugin/skills/programming/references/rust/axum-stack.md +467 -0
  468. package/packages/omo-codex/plugin/skills/programming/references/rust/cargo-strict.md +317 -0
  469. package/packages/omo-codex/plugin/skills/programming/references/rust/clap-stack.md +409 -0
  470. package/packages/omo-codex/plugin/skills/programming/references/rust/concurrency.md +375 -0
  471. package/packages/omo-codex/plugin/skills/programming/references/rust/libraries.md +439 -0
  472. package/packages/omo-codex/plugin/skills/programming/references/rust/one-liners.md +291 -0
  473. package/packages/omo-codex/plugin/skills/programming/references/rust/proptest-insta.md +429 -0
  474. package/packages/omo-codex/plugin/skills/programming/references/rust/type-state.md +354 -0
  475. package/packages/omo-codex/plugin/skills/programming/references/rust/unsafe-discipline.md +250 -0
  476. package/packages/omo-codex/plugin/skills/programming/references/rust/zero-cost-safety.md +527 -0
  477. package/packages/omo-codex/plugin/skills/programming/references/rust-ub/README.md +289 -0
  478. package/packages/omo-codex/plugin/skills/programming/references/rust-ub/miri-sanitizers-loom.md +411 -0
  479. package/packages/omo-codex/plugin/skills/programming/references/rust-ub/ub-taxonomy.md +269 -0
  480. package/packages/omo-codex/plugin/skills/programming/references/typescript/README.md +195 -0
  481. package/packages/omo-codex/plugin/skills/programming/references/typescript/backend-hono.md +672 -0
  482. package/packages/omo-codex/plugin/skills/programming/references/typescript/bootstrap.md +199 -0
  483. package/packages/omo-codex/plugin/skills/programming/references/typescript/data-modeling.md +202 -0
  484. package/packages/omo-codex/plugin/skills/programming/references/typescript/error-handling.md +169 -0
  485. package/packages/omo-codex/plugin/skills/programming/references/typescript/tsconfig-strict.md +152 -0
  486. package/packages/omo-codex/plugin/skills/programming/references/typescript/type-patterns.md +196 -0
  487. package/packages/omo-codex/plugin/skills/programming/scripts/go/check-no-excuse-rules.sh +173 -0
  488. package/packages/omo-codex/plugin/skills/programming/scripts/go/new-project.py +138 -0
  489. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/.editorconfig +13 -0
  490. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/.golangci.yml +95 -0
  491. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/AGENTS.md.tmpl +24 -0
  492. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/README.md.tmpl +12 -0
  493. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/Taskfile.yml +40 -0
  494. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/ci.yml +37 -0
  495. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/config.go +24 -0
  496. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/gitignore +15 -0
  497. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/main.go.tmpl +22 -0
  498. package/packages/omo-codex/plugin/skills/programming/scripts/go/templates/run.go +15 -0
  499. package/packages/omo-codex/plugin/skills/programming/scripts/python/check-no-excuse-rules.py +687 -0
  500. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-project.py +172 -0
  501. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-script.py +116 -0
  502. package/packages/omo-codex/plugin/skills/programming/scripts/rust/check-no-excuse-rules.py +296 -0
  503. package/packages/omo-codex/plugin/skills/programming/scripts/rust/check-no-excuse-rules.sh +158 -0
  504. package/packages/omo-codex/plugin/skills/programming/scripts/rust/new-project.py +175 -0
  505. package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +282 -0
  506. package/packages/omo-codex/plugin/skills/programming/scripts/typescript/new-project.ts +177 -0
  507. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +779 -0
  508. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +333 -0
  509. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +574 -0
  510. package/packages/omo-codex/plugin/skills/rules/SKILL.md +34 -0
  511. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +149 -0
  512. package/packages/omo-codex/plugin/skills/ulw-loop/.gitkeep +0 -0
  513. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +44 -0
  514. package/packages/omo-codex/plugin/skills/ulw-loop/agents/openai.yaml +6 -0
  515. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +230 -0
  516. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +399 -0
  517. package/packages/omo-codex/plugin/test/aggregate.test.mjs +345 -0
  518. package/packages/omo-codex/plugin/test/component-bin-names.test.mjs +66 -0
  519. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +195 -0
  520. package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +34 -0
  521. package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +21 -0
  522. package/packages/omo-codex/plugin/test/node-install-surface.test.mjs +48 -0
  523. package/packages/omo-codex/plugin/test/subagent-guidance.test.mjs +76 -0
  524. package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +66 -0
  525. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +229 -0
  526. package/packages/omo-codex/scripts/install/agents.mjs +84 -0
  527. package/packages/omo-codex/scripts/install/cache.mjs +247 -0
  528. package/packages/omo-codex/scripts/install/cli-args.mjs +112 -0
  529. package/packages/omo-codex/scripts/install/command-shim.mjs +1 -0
  530. package/packages/omo-codex/scripts/install/config.mjs +264 -0
  531. package/packages/omo-codex/scripts/install/delegated-command.mjs +25 -0
  532. package/packages/omo-codex/scripts/install/git-bash.mjs +99 -0
  533. package/packages/omo-codex/scripts/install/git-bash.test.mjs +174 -0
  534. package/packages/omo-codex/scripts/install/hook-trust.mjs +84 -0
  535. package/packages/omo-codex/scripts/install/legacy-bins.mjs +57 -0
  536. package/packages/omo-codex/scripts/install/marketplace.mjs +104 -0
  537. package/packages/omo-codex/scripts/install/mcp-runtime-cache.mjs +81 -0
  538. package/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs +38 -0
  539. package/packages/omo-codex/scripts/install/permissions.d.mts +1 -0
  540. package/packages/omo-codex/scripts/install/permissions.mjs +26 -0
  541. package/packages/omo-codex/scripts/install/process.mjs +19 -0
  542. package/packages/omo-codex/scripts/install/project-local-cleanup.mjs +229 -0
  543. package/packages/omo-codex/scripts/install/reasoning-config.mjs +14 -0
  544. package/packages/omo-codex/scripts/install/snapshot.mjs +54 -0
  545. package/packages/omo-codex/scripts/install/source-package-build.mjs +20 -0
  546. package/packages/omo-codex/scripts/install/toml-editor.mjs +64 -0
  547. package/packages/omo-codex/scripts/install/utils.mjs +15 -0
  548. package/packages/omo-codex/scripts/install-agent-links.test.mjs +104 -0
  549. package/packages/omo-codex/scripts/install-bin-links.test.mjs +123 -0
  550. package/packages/omo-codex/scripts/install-cache-copy.test.mjs +30 -0
  551. package/packages/omo-codex/scripts/install-cli-args.test.mjs +146 -0
  552. package/packages/omo-codex/scripts/install-config-autonomous.test.mjs +48 -0
  553. package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +62 -0
  554. package/packages/omo-codex/scripts/install-config.test.mjs +324 -0
  555. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +129 -0
  556. package/packages/omo-codex/scripts/install-local-git-bash-preflight.test.mjs +145 -0
  557. package/packages/omo-codex/scripts/install-local.mjs +275 -0
  558. package/packages/omo-codex/scripts/install-local.test.mjs +394 -0
  559. package/packages/omo-codex/scripts/install-mcp-runtime.test.mjs +233 -0
  560. package/packages/omo-codex/scripts/install-packaged-local.test.mjs +67 -0
  561. package/packages/omo-codex/scripts/install-project-local-cleanup.test.mjs +277 -0
  562. package/packages/omo-codex/scripts/install-test-fixtures.mjs +58 -0
  563. package/packages/omo-codex/scripts/sync-telemetry-component.mjs +115 -0
  564. package/packages/omo-codex/scripts/sync-telemetry-component.test.mjs +94 -0
  565. package/packages/shared-skills/index.mjs +5 -0
  566. package/packages/shared-skills/package.json +14 -0
  567. package/packages/shared-skills/skills/debugging/SKILL.md +116 -0
  568. package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +108 -0
  569. package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +130 -0
  570. package/packages/shared-skills/skills/debugging/references/methodology/04-oracle-triple.md +136 -0
  571. package/packages/shared-skills/skills/debugging/references/methodology/05-escalate.md +69 -0
  572. package/packages/shared-skills/skills/debugging/references/methodology/06-fix.md +116 -0
  573. package/packages/shared-skills/skills/debugging/references/methodology/08-qa.md +94 -0
  574. package/packages/shared-skills/skills/debugging/references/methodology/09-cleanup.md +164 -0
  575. package/packages/shared-skills/skills/debugging/references/methodology/partial-runtime-evidence.md +229 -0
  576. package/packages/shared-skills/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
  577. package/packages/shared-skills/skills/debugging/references/runtimes/go.md +252 -0
  578. package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +484 -0
  579. package/packages/shared-skills/skills/debugging/references/runtimes/node.md +260 -0
  580. package/packages/shared-skills/skills/debugging/references/runtimes/python.md +248 -0
  581. package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +234 -0
  582. package/packages/shared-skills/skills/debugging/references/tools/ghidra.md +212 -0
  583. package/packages/shared-skills/skills/debugging/references/tools/playwright-cli.md +194 -0
  584. package/packages/shared-skills/skills/debugging/references/tools/pwndbg.md +263 -0
  585. package/packages/shared-skills/skills/debugging/references/tools/pwntools.md +265 -0
  586. package/packages/shared-skills/skills/frontend-ui-ux/SKILL.md +77 -0
  587. package/packages/shared-skills/skills/init-deep/SKILL.md +309 -0
  588. package/packages/shared-skills/skills/programming/SKILL.md +463 -0
  589. package/packages/shared-skills/skills/programming/references/go/README.md +90 -0
  590. package/packages/shared-skills/skills/programming/references/go/backend-stack.md +641 -0
  591. package/packages/shared-skills/skills/programming/references/go/bootstrap.md +328 -0
  592. package/packages/shared-skills/skills/programming/references/go/bubbletea-v2.md +360 -0
  593. package/packages/shared-skills/skills/programming/references/go/cobra-stack.md +468 -0
  594. package/packages/shared-skills/skills/programming/references/go/concurrency.md +362 -0
  595. package/packages/shared-skills/skills/programming/references/go/data-modeling.md +329 -0
  596. package/packages/shared-skills/skills/programming/references/go/error-handling.md +359 -0
  597. package/packages/shared-skills/skills/programming/references/go/golangci-strict.md +236 -0
  598. package/packages/shared-skills/skills/programming/references/go/grpc-connect.md +375 -0
  599. package/packages/shared-skills/skills/programming/references/go/libraries.md +337 -0
  600. package/packages/shared-skills/skills/programming/references/go/one-liners.md +202 -0
  601. package/packages/shared-skills/skills/programming/references/go/sqlc-pgx.md +471 -0
  602. package/packages/shared-skills/skills/programming/references/go/testing.md +467 -0
  603. package/packages/shared-skills/skills/programming/references/go/type-patterns.md +298 -0
  604. package/packages/shared-skills/skills/programming/references/python/README.md +314 -0
  605. package/packages/shared-skills/skills/programming/references/python/async-anyio.md +442 -0
  606. package/packages/shared-skills/skills/programming/references/python/data-modeling.md +233 -0
  607. package/packages/shared-skills/skills/programming/references/python/data-processing.md +133 -0
  608. package/packages/shared-skills/skills/programming/references/python/error-handling.md +218 -0
  609. package/packages/shared-skills/skills/programming/references/python/fastapi-stack.md +316 -0
  610. package/packages/shared-skills/skills/programming/references/python/httpx2-optimization.md +360 -0
  611. package/packages/shared-skills/skills/programming/references/python/libraries.md +307 -0
  612. package/packages/shared-skills/skills/programming/references/python/one-liners.md +268 -0
  613. package/packages/shared-skills/skills/programming/references/python/orjson-stack.md +378 -0
  614. package/packages/shared-skills/skills/programming/references/python/pydantic-ai.md +285 -0
  615. package/packages/shared-skills/skills/programming/references/python/pyproject-strict.md +232 -0
  616. package/packages/shared-skills/skills/programming/references/python/textual-tui.md +201 -0
  617. package/packages/shared-skills/skills/programming/references/python/type-patterns.md +176 -0
  618. package/packages/shared-skills/skills/programming/references/rust/README.md +317 -0
  619. package/packages/shared-skills/skills/programming/references/rust/async-tokio.md +299 -0
  620. package/packages/shared-skills/skills/programming/references/rust/axum-stack.md +467 -0
  621. package/packages/shared-skills/skills/programming/references/rust/cargo-strict.md +317 -0
  622. package/packages/shared-skills/skills/programming/references/rust/clap-stack.md +409 -0
  623. package/packages/shared-skills/skills/programming/references/rust/concurrency.md +375 -0
  624. package/packages/shared-skills/skills/programming/references/rust/libraries.md +439 -0
  625. package/packages/shared-skills/skills/programming/references/rust/one-liners.md +291 -0
  626. package/packages/shared-skills/skills/programming/references/rust/proptest-insta.md +429 -0
  627. package/packages/shared-skills/skills/programming/references/rust/type-state.md +354 -0
  628. package/packages/shared-skills/skills/programming/references/rust/unsafe-discipline.md +250 -0
  629. package/packages/shared-skills/skills/programming/references/rust/zero-cost-safety.md +527 -0
  630. package/packages/shared-skills/skills/programming/references/rust-ub/README.md +289 -0
  631. package/packages/shared-skills/skills/programming/references/rust-ub/miri-sanitizers-loom.md +411 -0
  632. package/packages/shared-skills/skills/programming/references/rust-ub/ub-taxonomy.md +269 -0
  633. package/packages/shared-skills/skills/programming/references/typescript/README.md +195 -0
  634. package/packages/shared-skills/skills/programming/references/typescript/backend-hono.md +672 -0
  635. package/packages/shared-skills/skills/programming/references/typescript/bootstrap.md +199 -0
  636. package/packages/shared-skills/skills/programming/references/typescript/data-modeling.md +202 -0
  637. package/packages/shared-skills/skills/programming/references/typescript/error-handling.md +169 -0
  638. package/packages/shared-skills/skills/programming/references/typescript/tsconfig-strict.md +152 -0
  639. package/packages/shared-skills/skills/programming/references/typescript/type-patterns.md +196 -0
  640. package/packages/shared-skills/skills/programming/scripts/go/check-no-excuse-rules.sh +173 -0
  641. package/packages/shared-skills/skills/programming/scripts/go/new-project.py +138 -0
  642. package/packages/shared-skills/skills/programming/scripts/go/templates/.editorconfig +13 -0
  643. package/packages/shared-skills/skills/programming/scripts/go/templates/.golangci.yml +95 -0
  644. package/packages/shared-skills/skills/programming/scripts/go/templates/AGENTS.md.tmpl +24 -0
  645. package/packages/shared-skills/skills/programming/scripts/go/templates/README.md.tmpl +12 -0
  646. package/packages/shared-skills/skills/programming/scripts/go/templates/Taskfile.yml +40 -0
  647. package/packages/shared-skills/skills/programming/scripts/go/templates/ci.yml +37 -0
  648. package/packages/shared-skills/skills/programming/scripts/go/templates/config.go +24 -0
  649. package/packages/shared-skills/skills/programming/scripts/go/templates/gitignore +15 -0
  650. package/packages/shared-skills/skills/programming/scripts/go/templates/main.go.tmpl +22 -0
  651. package/packages/shared-skills/skills/programming/scripts/go/templates/run.go +15 -0
  652. package/packages/shared-skills/skills/programming/scripts/python/check-no-excuse-rules.py +687 -0
  653. package/packages/shared-skills/skills/programming/scripts/python/new-project.py +172 -0
  654. package/packages/shared-skills/skills/programming/scripts/python/new-script.py +116 -0
  655. package/packages/shared-skills/skills/programming/scripts/rust/check-no-excuse-rules.py +296 -0
  656. package/packages/shared-skills/skills/programming/scripts/rust/check-no-excuse-rules.sh +158 -0
  657. package/packages/shared-skills/skills/programming/scripts/rust/new-project.py +175 -0
  658. package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +282 -0
  659. package/packages/shared-skills/skills/programming/scripts/typescript/new-project.ts +177 -0
  660. package/packages/shared-skills/skills/refactor/SKILL.md +763 -0
  661. package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +317 -0
  662. package/packages/shared-skills/skills/review-work/SKILL.md +574 -0
  663. package/packages/shared-skills/skills/start-work/SKILL.md +149 -0
  664. package/packages/shared-skills/skills/ulw-plan/SKILL.md +383 -0
  665. package/postinstall.mjs +6 -2
  666. package/dist/features/builtin-commands/templates/init-deep.d.ts +0 -1
  667. package/dist/features/builtin-skills/skills/ai-slop-remover.d.ts +0 -2
  668. package/dist/hooks/context-window-monitor.d.ts +0 -19
@@ -0,0 +1,124 @@
1
+ import { appendFile, mkdir, readFile, rename, writeFile } from "node:fs/promises";
2
+
3
+ import { aggregateCodexObjectiveForScope } from "./goal-status.js";
4
+ import {
5
+ repoRelative,
6
+ type UlwLoopScope,
7
+ ulwLoopDir,
8
+ ulwLoopGoalsPath,
9
+ ulwLoopLedgerPath,
10
+ ulwLoopRelativeDir,
11
+ } from "./paths.js";
12
+ import type { UlwLoopLedgerEntry, UlwLoopPlan } from "./types.js";
13
+ import { iso, ULW_LOOP_DIR, ULW_LOOP_GOALS, ULW_LOOP_LEDGER, UlwLoopError } from "./types.js";
14
+
15
+ const LEGACY_OBJECTIVE_PREFIX = `Complete all ulw-loop stories in ${ULW_LOOP_DIR}/${ULW_LOOP_GOALS}: `;
16
+ const LEGACY_OBJECTIVE = `Complete all ulw-loop stories listed in ${ULW_LOOP_DIR}/${ULW_LOOP_GOALS}. Use ${ULW_LOOP_DIR}/${ULW_LOOP_LEDGER} as the durable audit trail.`;
17
+ const locks = new Map<string, Promise<unknown>>();
18
+
19
+ function hasCode(error: unknown, code: string): boolean {
20
+ return error instanceof Error && "code" in error && error.code === code;
21
+ }
22
+
23
+ function isLegacyEnumeratedAggregateObjective(objective: string | undefined): objective is string {
24
+ return objective === LEGACY_OBJECTIVE || Boolean(objective?.startsWith(LEGACY_OBJECTIVE_PREFIX));
25
+ }
26
+
27
+ function isSteeringKind(value: unknown): value is UlwLoopLedgerEntry["kind"] {
28
+ return value === "steering_accepted" || value === "steering_rejected" || value === "criteria_revised";
29
+ }
30
+
31
+ export async function withUlwLoopMutationLock<T>(repoRoot: string, fn: () => Promise<T>): Promise<T>;
32
+ export async function withUlwLoopMutationLock<T>(
33
+ repoRoot: string,
34
+ scope: UlwLoopScope | undefined,
35
+ fn: () => Promise<T>,
36
+ ): Promise<T>;
37
+ export async function withUlwLoopMutationLock<T>(
38
+ repoRoot: string,
39
+ scopeOrFn: UlwLoopScope | (() => Promise<T>) | undefined,
40
+ maybeFn?: () => Promise<T>,
41
+ ): Promise<T> {
42
+ const scope = typeof scopeOrFn === "function" ? undefined : scopeOrFn;
43
+ const fn = typeof scopeOrFn === "function" ? scopeOrFn : maybeFn;
44
+ if (fn === undefined) throw new UlwLoopError("Missing ulw-loop mutation body.", "ULW_LOOP_LOCK_BODY_MISSING");
45
+ const lockKey = `${repoRoot}\0${ulwLoopRelativeDir(scope)}`;
46
+ const prior = locks.get(lockKey) ?? Promise.resolve();
47
+ const run = prior.then(fn, fn);
48
+ locks.set(
49
+ lockKey,
50
+ run.catch(() => undefined),
51
+ );
52
+ return run;
53
+ }
54
+
55
+ export async function readUlwLoopPlan(repoRoot: string, scope?: UlwLoopScope): Promise<UlwLoopPlan> {
56
+ const path = ulwLoopGoalsPath(repoRoot, scope);
57
+ let raw: string;
58
+ try {
59
+ raw = await readFile(path, "utf8");
60
+ } catch (error) {
61
+ if (!hasCode(error, "ENOENT")) throw error;
62
+ throw new UlwLoopError(
63
+ `No ulw-loop plan found at ${repoRelative(path, repoRoot)}. Run \`omo ulw-loop create-goals ...\` first.`,
64
+ "ULW_LOOP_PLAN_MISSING",
65
+ { cause: error },
66
+ );
67
+ }
68
+ const parsed: UlwLoopPlan = JSON.parse(raw);
69
+ if (parsed.version !== 1 || !Array.isArray(parsed.goals)) {
70
+ throw new UlwLoopError(`Invalid ulw-loop plan at ${repoRelative(path, repoRoot)}.`, "ULW_LOOP_PLAN_INVALID");
71
+ }
72
+ const previousObjective = parsed.codexObjective;
73
+ if (
74
+ (parsed.codexGoalMode ?? "per_story") === "aggregate" &&
75
+ isLegacyEnumeratedAggregateObjective(previousObjective)
76
+ ) {
77
+ const now = iso();
78
+ parsed.codexObjective = aggregateCodexObjectiveForScope(scope);
79
+ parsed.codexObjectiveAliases = [...new Set([...(parsed.codexObjectiveAliases ?? []), previousObjective])];
80
+ parsed.updatedAt = now;
81
+ await writePlan(repoRoot, parsed, scope);
82
+ await appendLedger(
83
+ repoRoot,
84
+ {
85
+ at: now,
86
+ kind: "aggregate_objective_migrated",
87
+ message: "Migrated legacy enumerated aggregate Codex objective to the stable pointer objective.",
88
+ before: { codexObjective: previousObjective },
89
+ after: { codexObjective: parsed.codexObjective },
90
+ },
91
+ scope,
92
+ );
93
+ }
94
+ return parsed;
95
+ }
96
+
97
+ export async function writePlan(repoRoot: string, plan: UlwLoopPlan, scope?: UlwLoopScope): Promise<void> {
98
+ await mkdir(ulwLoopDir(repoRoot, scope), { recursive: true });
99
+ const path = ulwLoopGoalsPath(repoRoot, scope);
100
+ const tmpPath = `${path}.${process.pid}.${Date.now()}.tmp`;
101
+ await writeFile(tmpPath, `${JSON.stringify(plan, null, 2)}\n`, "utf8");
102
+ await rename(tmpPath, path);
103
+ }
104
+
105
+ export async function appendLedger(repoRoot: string, entry: UlwLoopLedgerEntry, scope?: UlwLoopScope): Promise<void> {
106
+ await mkdir(ulwLoopDir(repoRoot, scope), { recursive: true });
107
+ await appendFile(ulwLoopLedgerPath(repoRoot, scope), `${JSON.stringify(entry)}\n`, "utf8");
108
+ }
109
+
110
+ export async function readSteeringLedgerEntries(repoRoot: string, scope?: UlwLoopScope): Promise<UlwLoopLedgerEntry[]> {
111
+ let raw: string;
112
+ try {
113
+ raw = await readFile(ulwLoopLedgerPath(repoRoot, scope), "utf8");
114
+ } catch (error) {
115
+ if (hasCode(error, "ENOENT")) return [];
116
+ throw error;
117
+ }
118
+ const entries: UlwLoopLedgerEntry[] = [];
119
+ for (const line of raw.split(/\r?\n/).filter(Boolean)) {
120
+ const entry: UlwLoopLedgerEntry = JSON.parse(line);
121
+ if (isSteeringKind(entry.kind)) entries.push(entry);
122
+ }
123
+ return entries;
124
+ }
@@ -0,0 +1,102 @@
1
+ import type { UlwLoopItem, UlwLoopPlan, UlwLoopQualityGate } from "./types.js";
2
+ import { UlwLoopError } from "./types.js";
3
+
4
+ const BLOCKER_FIELD_KEYS = "blocker blockerSignature blockerEvidence blockerOccurrences blockedAt".split(" ");
5
+ const URL_PATTERN = /https?:\/\/\S+/g;
6
+ const PUNCTUATION_PATTERN = /[`"'()[\]{}:,;]/g;
7
+ const WHITESPACE_PATTERN = /\s+/g;
8
+ const AUTH_PATTERN = /\b(auth\w*|credential\w*|token|permission\w*|scope\w*|access|unauthorized|forbidden|401|403)\b/;
9
+ const MISSING_PATTERN =
10
+ /\b(unset|missing|required|requires|without|omit\w*|not set|not available|no read packages|read packages)\b/;
11
+ const GHCR_PATTERN =
12
+ /\b(ghcr|github container registry|read packages|imagepullsecret|package api|anonymous|container image)\b/;
13
+ const GHCR_401_PATTERN = /\b(401|unauthorized|anonymous pull|authentication required)\b/;
14
+ const GHCR_403_PATTERN = /\b(403|forbidden|read packages|package api)\b/;
15
+
16
+ function invalid(message: string, field: string): never {
17
+ throw new UlwLoopError(message, "ULW_LOOP_QUALITY_GATE_INVALID", { details: { field } });
18
+ }
19
+
20
+ function isRecord(value: unknown): value is Record<string, unknown> {
21
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22
+ }
23
+
24
+ function section(value: unknown, field: string): Record<string, unknown> {
25
+ return isRecord(value) ? value : invalid(`Final quality gate is missing ${field} evidence.`, field);
26
+ }
27
+
28
+ function nonEmptyString(value: unknown, field: string): string {
29
+ return typeof value === "string" && value.trim() !== ""
30
+ ? value
31
+ : invalid(`Final quality gate requires non-empty ${field}.`, field);
32
+ }
33
+
34
+ function numberField(value: unknown, field: string): number {
35
+ return typeof value === "number" && Number.isFinite(value)
36
+ ? value
37
+ : invalid(`Final quality gate requires numeric ${field}.`, field);
38
+ }
39
+
40
+ function stringArray(value: unknown, field: string): string[] {
41
+ if (!Array.isArray(value) || value.length === 0) return invalid(`Final quality gate requires ${field}.`, field);
42
+ return value.map((item) => nonEmptyString(item, field));
43
+ }
44
+
45
+ export function validateQualityGate(input: unknown): UlwLoopQualityGate {
46
+ const gate = section(input, "qualityGate");
47
+ const cleaner = section(gate["aiSlopCleaner"], "aiSlopCleaner");
48
+ const verification = section(gate["verification"], "verification");
49
+ const review = section(gate["codeReview"], "codeReview");
50
+ const coverage = section(gate["criteriaCoverage"], "criteriaCoverage");
51
+ if (cleaner["status"] !== "passed") invalid("aiSlopCleaner.status must be passed.", "aiSlopCleaner.status");
52
+ if (verification["status"] !== "passed") invalid("verification.status must be passed.", "verification.status");
53
+ if (review["recommendation"] !== "APPROVE") invalid("recommendation must be APPROVE.", "codeReview.recommendation");
54
+ if (review["architectStatus"] !== "CLEAR") invalid("architectStatus must be CLEAR.", "codeReview.architectStatus");
55
+ const totalCriteria = numberField(coverage["totalCriteria"], "criteriaCoverage.totalCriteria");
56
+ const passCount = numberField(coverage["passCount"], "criteriaCoverage.passCount");
57
+ if (passCount < totalCriteria)
58
+ invalid("criteriaCoverage.passCount must cover totalCriteria.", "criteriaCoverage.passCount");
59
+ const commands = stringArray(verification["commands"], "verification.commands");
60
+ const covered = stringArray(coverage["adversarialClassesCovered"], "criteriaCoverage.adversarialClassesCovered");
61
+ const cleanerEvidence = nonEmptyString(cleaner["evidence"], "aiSlopCleaner.evidence");
62
+ const verificationEvidence = nonEmptyString(verification["evidence"], "verification.evidence");
63
+ const reviewEvidence = nonEmptyString(review["evidence"], "codeReview.evidence");
64
+ const result: UlwLoopQualityGate = {
65
+ aiSlopCleaner: { status: "passed", evidence: cleanerEvidence },
66
+ verification: { status: "passed", commands, evidence: verificationEvidence },
67
+ codeReview: { recommendation: "APPROVE", architectStatus: "CLEAR", evidence: reviewEvidence },
68
+ };
69
+ Object.assign(result, { criteriaCoverage: { totalCriteria, passCount, adversarialClassesCovered: covered } });
70
+ return result;
71
+ }
72
+
73
+ export function normalizeBlockerEvidence(evidence: string): string {
74
+ const withoutUrls = evidence.toLowerCase().replace(URL_PATTERN, " ");
75
+ const withoutPunctuation = withoutUrls.replace(PUNCTUATION_PATTERN, " ");
76
+ return withoutPunctuation.replace(WHITESPACE_PATTERN, " ").trim();
77
+ }
78
+
79
+ export function classifyExternalAuthorizationBlocker(evidence: string): string | null {
80
+ const normalized = normalizeBlockerEvidence(evidence);
81
+ if (!normalized || !AUTH_PATTERN.test(normalized) || !MISSING_PATTERN.test(normalized)) return null;
82
+ if (!GHCR_PATTERN.test(normalized)) return "EXTERNAL_AUTHORIZATION_REQUIRED";
83
+ const status401 = GHCR_401_PATTERN.test(normalized) ? "HTTP_401_ANONYMOUS" : null;
84
+ const status403 = GHCR_403_PATTERN.test(normalized) ? "HTTP_403_NO_READ_PACKAGES" : null;
85
+ const status = [status401, status403].filter((part): part is string => part !== null).join("+");
86
+ return `GHCR_PULL_ACCESS:${status || "AUTHORIZATION_REQUIRED"}:GHCR_VISIBILITY_OR_CREDENTIAL_REQUIRED`;
87
+ }
88
+
89
+ function nestedBlockerSignature(goal: UlwLoopItem): string | null {
90
+ const blocker = Reflect.get(goal, "blocker");
91
+ const signature = isRecord(blocker) ? blocker["signature"] : null;
92
+ return typeof signature === "string" ? signature : null;
93
+ }
94
+
95
+ export function sameBlockerOccurrences(plan: UlwLoopPlan, signature: string): number {
96
+ return plan.goals.filter((goal) => goal.blockerSignature === signature || nestedBlockerSignature(goal) === signature)
97
+ .length;
98
+ }
99
+
100
+ export function clearGoalBlockerFields(goal: UlwLoopItem): void {
101
+ for (const key of BLOCKER_FIELD_KEYS) Reflect.deleteProperty(goal, key);
102
+ }
@@ -0,0 +1,81 @@
1
+ // biome-ignore-all format: compact port must stay within the requested pure LOC budget.
2
+
3
+ import { readCodexGoalSnapshotInput, reconcileCodexGoalSnapshot } from "./codex-goal-snapshot.js";
4
+ import { codexGoalMode, compatibleCodexObjectives, expectedCodexObjective, isFinalRunCompletionCandidate } from "./goal-status.js";
5
+ import type { UlwLoopScope } from "./paths.js";
6
+ import { seedDefaultSuccessCriteria } from "./plan-crud.js";
7
+ import { appendLedger, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
8
+ import type { UlwLoopItem, UlwLoopLedgerEntry, UlwLoopPlan } from "./types.js";
9
+ import { iso, UlwLoopError } from "./types.js";
10
+
11
+ export interface RecordFinalReviewBlockersArgs { readonly goalId: string; readonly title: string; readonly objective: string; readonly evidence: string; readonly codexGoalJson: string }
12
+ export interface RecordFinalReviewBlockersResult { readonly plan: UlwLoopPlan; readonly blockedGoal: UlwLoopItem; readonly newGoal: UlwLoopItem; readonly ledgerEntries: UlwLoopLedgerEntry[] }
13
+
14
+ const BLOCKER_FIELDS = "blockedReason blockerSignature blockerOccurrenceCount requiredExternalDecision nonRetriable failedAt failureReason completedAt blocker blockerEvidence blockerOccurrences blockedAt".split(" ");
15
+
16
+ function ulwLoopError(message: string, code: string): never {
17
+ throw new UlwLoopError(message, code);
18
+ }
19
+
20
+ function nextGoalId(plan: UlwLoopPlan): string {
21
+ const max = plan.goals.reduce((current, goal) => {
22
+ const digits = /^G(\d+)/u.exec(goal.id)?.[1];
23
+ return digits === undefined ? current : Math.max(current, Number(digits));
24
+ }, 0);
25
+ return `G${String(max + 1).padStart(3, "0")}`;
26
+ }
27
+
28
+ function appendBlockerGoal(plan: UlwLoopPlan, args: RecordFinalReviewBlockersArgs, now: string): UlwLoopItem {
29
+ const index = plan.goals.length;
30
+ const goal: UlwLoopItem = {
31
+ id: nextGoalId(plan),
32
+ title: args.title,
33
+ objective: args.objective,
34
+ status: "pending",
35
+ successCriteria: seedDefaultSuccessCriteria(index, args.objective),
36
+ attempt: 0,
37
+ createdAt: now,
38
+ updatedAt: now,
39
+ };
40
+ plan.goals.push(goal);
41
+ return goal;
42
+ }
43
+
44
+ export async function recordFinalReviewBlockers(
45
+ repoRoot: string,
46
+ args: RecordFinalReviewBlockersArgs,
47
+ scope?: UlwLoopScope,
48
+ ): Promise<RecordFinalReviewBlockersResult> {
49
+ return withUlwLoopMutationLock(repoRoot, scope, async () => {
50
+ const plan = await readUlwLoopPlan(repoRoot, scope);
51
+ const goal = plan.goals.find((candidate) => candidate.id === args.goalId);
52
+ if (goal === undefined) ulwLoopError(`Unknown ulw-loop id: ${args.goalId}`, "ulw_loop_goal_not_found");
53
+ if (goal.status !== "in_progress") ulwLoopError(`${goal.id} is ${goal.status}.`, "ulw_loop_goal_not_in_progress");
54
+ if (!isFinalRunCompletionCandidate(plan, goal)) ulwLoopError(`${goal.id} is not final.`, "ulw_loop_not_final_story");
55
+
56
+ const snapshot = await readCodexGoalSnapshotInput(args.codexGoalJson, repoRoot);
57
+ const aggregate = codexGoalMode(plan) === "aggregate";
58
+ const reconciliation = reconcileCodexGoalSnapshot(snapshot, { expectedObjective: expectedCodexObjective(plan, goal), ...(aggregate ? { acceptedObjectives: compatibleCodexObjectives(plan) } : {}), allowedStatuses: ["active"], requireSnapshot: true, requireComplete: false });
59
+ if (!reconciliation.ok) ulwLoopError(reconciliation.errors.join(" "), "ulw_loop_codex_snapshot_mismatch");
60
+
61
+ const now = iso();
62
+ for (const field of BLOCKER_FIELDS) Reflect.deleteProperty(goal, field);
63
+ goal.status = "review_blocked";
64
+ goal.reviewBlockedAt = now;
65
+ goal.evidence = args.evidence;
66
+ goal.updatedAt = now;
67
+ if (plan.activeGoalId === goal.id) delete plan.activeGoalId;
68
+ const newGoal = appendBlockerGoal(plan, args, now);
69
+ plan.updatedAt = now;
70
+
71
+ const codexGoal = reconciliation.snapshot.raw;
72
+ const blockedEntry: UlwLoopLedgerEntry = { at: now, kind: "goal_review_blocked", goalId: goal.id, status: goal.status, evidence: args.evidence, codexGoal };
73
+ const addedEntry: UlwLoopLedgerEntry = { at: now, kind: "goal_added", goalId: newGoal.id, status: newGoal.status, evidence: args.evidence, message: newGoal.title };
74
+ const summaryEntry: UlwLoopLedgerEntry = { at: now, kind: "goal_review_blocked", goalId: goal.id, status: goal.status, evidence: args.evidence, codexGoal, message: `Review blockers recorded; appended ${newGoal.id}.` };
75
+ Reflect.set(summaryEntry, "kind", "blocker_recorded");
76
+ const ledgerEntries = [blockedEntry, addedEntry, summaryEntry];
77
+ await writePlan(repoRoot, plan, scope);
78
+ for (const entry of ledgerEntries) await appendLedger(repoRoot, entry, scope);
79
+ return { plan, blockedGoal: goal, newGoal, ledgerEntries };
80
+ });
81
+ }
@@ -0,0 +1,270 @@
1
+ // biome-ignore-all format: compact steering module must stay below the 240 pure-LOC budget
2
+ import { isUlwLoopDone } from "./goal-status.js";
3
+ import type { UlwLoopScope } from "./paths.js";
4
+ import { seedDefaultSuccessCriteria } from "./plan-crud.js";
5
+ import { appendLedger, readSteeringLedgerEntries, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
6
+ import type {
7
+ SteerUlwLoopResult,
8
+ UlwLoopItem,
9
+ UlwLoopLedgerEntry,
10
+ UlwLoopPlan,
11
+ UlwLoopSteeringAudit,
12
+ UlwLoopSteeringChildGoal,
13
+ UlwLoopSteeringMutationKind,
14
+ UlwLoopSteeringProposal,
15
+ UlwLoopSteeringSource,
16
+ UlwLoopSuccessCriterionUserModel,
17
+ } from "./types.js";
18
+ import { iso, ULW_LOOP_STEERING_MUTATION_KINDS, ULW_LOOP_SUCCESS_CRITERION_USER_MODELS } from "./types.js";
19
+
20
+ const SOURCES = ["user_prompt_submit", "finding", "cli"] as const satisfies readonly UlwLoopSteeringSource[];
21
+ const PROTECTED = new Set(["aggregateCompletion", "codexObjective", "codexObjectiveAliases", "originalConstraints", "qualityGate", "status", "completedAt", "completionStatus"]);
22
+ const isObject = (value: unknown): value is object => typeof value === "object" && value !== null; const isPlain = (value: unknown): value is object => isObject(value) && !Array.isArray(value);
23
+ const read = (value: object, key: string): unknown => Object.entries(value).find(([name]) => name === key)?.[1];
24
+ const isText = (value: unknown): value is string => typeof value === "string" && value.trim().length > 0;
25
+ const text = (value: object, key: string): string | undefined => {
26
+ const candidate = read(value, key);
27
+ return isText(candidate) ? candidate.trim() : undefined;
28
+ };
29
+ const isKind = (value: unknown): value is UlwLoopSteeringMutationKind => typeof value === "string" && ULW_LOOP_STEERING_MUTATION_KINDS.some((kind) => kind === value);
30
+ const isSource = (value: unknown): value is UlwLoopSteeringSource => typeof value === "string" && SOURCES.some((source) => source === value);
31
+ const isModel = (value: unknown): value is UlwLoopSuccessCriterionUserModel => typeof value === "string" && ULW_LOOP_SUCCESS_CRITERION_USER_MODELS.some((model) => model === value);
32
+ const texts = (value: object, key: string): string[] => {
33
+ const candidate = read(value, key);
34
+ return Array.isArray(candidate) && candidate.every((item) => typeof item === "string") ? candidate : [];
35
+ };
36
+
37
+ function targets(proposal: object): string[] {
38
+ const many = texts(proposal, "targetGoalIds");
39
+ const one = text(proposal, "targetGoalId") ?? text(proposal, "goalId");
40
+ return many.length > 0 ? many : one === undefined ? [] : [one];
41
+ }
42
+
43
+ const after = (proposal: object): object | undefined => {
44
+ const candidate = read(proposal, "after");
45
+ return isPlain(candidate) ? candidate : undefined;
46
+ };
47
+ const revised = (proposal: object, direct: string, nested: string): string | undefined => text(proposal, direct) ?? text(after(proposal) ?? proposal, nested);
48
+
49
+ function child(value: unknown): UlwLoopSteeringChildGoal | null {
50
+ if (!isPlain(value)) return null;
51
+ const title = text(value, "title");
52
+ const objective = text(value, "objective");
53
+ if (title === undefined || objective === undefined) return null;
54
+ return { title, objective };
55
+ }
56
+
57
+ function childValues(proposal: object): unknown[] {
58
+ const direct = read(proposal, "childGoals");
59
+ if (Array.isArray(direct) && direct.length > 0) return direct;
60
+ const nested = after(proposal);
61
+ const fromAfter = nested === undefined ? undefined : read(nested, "children");
62
+ return Array.isArray(fromAfter) ? fromAfter : [];
63
+ }
64
+
65
+ const children = (proposal: object): UlwLoopSteeringChildGoal[] => childValues(proposal).map(child).filter((item): item is UlwLoopSteeringChildGoal => item !== null);
66
+ const pendingOrder = (proposal: object): string[] => {
67
+ const direct = texts(proposal, "pendingOrder");
68
+ return direct.length > 0 ? direct : texts(after(proposal) ?? proposal, "pendingGoalIds");
69
+ };
70
+
71
+ function hasProtected(value: unknown): boolean {
72
+ if (!isObject(value)) return false;
73
+ for (const [key, childValue] of Object.entries(value)) if (PROTECTED.has(key) || key.toLowerCase().includes("complete") || hasProtected(childValue)) return true;
74
+ return false;
75
+ }
76
+
77
+ function allText(value: unknown): string {
78
+ if (typeof value === "string") return value;
79
+ return isObject(value) ? Object.values(value).map(allText).filter(Boolean).join("\n") : "";
80
+ }
81
+
82
+ function weakens(value: unknown): boolean {
83
+ const valueText = allText(value).toLowerCase();
84
+ return /\b(skip|bypass|weaken|remove|omit|auto[-\s]?complete|mark complete|complete faster)\b/.test(valueText) && /\b(test|tests|verification|review|quality gate|complete|completion)\b/.test(valueText);
85
+ }
86
+
87
+ function auditFor(proposal: unknown, reasons: string[]): UlwLoopSteeringAudit {
88
+ const object = isPlain(proposal) ? proposal : undefined;
89
+ const kindRaw = object === undefined ? undefined : read(object, "kind");
90
+ const sourceRaw = object === undefined ? undefined : read(object, "source");
91
+ const evidence = object === undefined ? "" : (text(object, "evidence") ?? "");
92
+ const rationale = object === undefined ? "" : (text(object, "rationale") ?? "");
93
+ const audit: UlwLoopSteeringAudit = { kind: isKind(kindRaw) ? kindRaw : "annotate_ledger", source: isSource(sourceRaw) ? sourceRaw : "cli", targetGoalIds: object === undefined ? [] : targets(object), evidence, rationale, invariant: { accepted: reasons.length === 0, structuralInvariantAccepted: reasons.length === 0, evidenceBackedNecessity: evidence.length > 0 && rationale.length > 0, noEasierCompletion: !weakens(proposal), rejectedReasons: reasons, reasons } };
94
+ if (object === undefined) return audit;
95
+ const criterionId = text(object, "criterionId");
96
+ const directiveText = text(object, "directiveText");
97
+ const promptSignature = text(object, "promptSignature");
98
+ const idempotencyKey = text(object, "idempotencyKey");
99
+ if (criterionId !== undefined) audit.criterionId = criterionId;
100
+ if (directiveText !== undefined) audit.directiveText = directiveText;
101
+ if (promptSignature !== undefined) audit.promptSignature = promptSignature;
102
+ if (idempotencyKey !== undefined) audit.idempotencyKey = idempotencyKey;
103
+ return audit;
104
+ }
105
+
106
+ export function validateUlwLoopSteeringProposal(plan: UlwLoopPlan, proposal: unknown): UlwLoopSteeringAudit {
107
+ const reasons: string[] = [];
108
+ if (!isPlain(proposal)) reasons.push("proposal must be an object");
109
+ const object = isPlain(proposal) ? proposal : {};
110
+ const kind = read(object, "kind");
111
+ if (!isKind(kind)) reasons.push(`invalid kind: ${String(kind)}`);
112
+ if (!isSource(read(object, "source"))) reasons.push(`invalid source: ${String(read(object, "source"))}`);
113
+ if (text(object, "evidence") === undefined) reasons.push("missing evidence");
114
+ if (text(object, "rationale") === undefined) reasons.push("missing rationale");
115
+ if (hasProtected(proposal)) reasons.push("protected payload");
116
+ if (weakens(proposal)) reasons.push("weakened completion");
117
+ if (isUlwLoopDone(plan)) reasons.push("plan already complete");
118
+ if (isKind(kind)) validateKind(plan, object, kind, reasons);
119
+ return auditFor(proposal, reasons);
120
+ }
121
+
122
+ function goal(plan: UlwLoopPlan, id: string | undefined): UlwLoopItem | undefined {
123
+ return id === undefined ? undefined : plan.goals.find((item) => item.id === id);
124
+ }
125
+
126
+ function validateKind(plan: UlwLoopPlan, proposal: object, kind: UlwLoopSteeringMutationKind, reasons: string[]): void {
127
+ const target = goal(plan, targets(proposal)[0]);
128
+ if (kind === "add_subgoal" && (text(proposal, "title") === undefined || text(proposal, "objective") === undefined)) reasons.push("add_subgoal requires title/objective");
129
+ if ((kind === "split_subgoal" || kind === "revise_pending_wording" || kind === "mark_blocked_superseded") && target === undefined) reasons.push(`${kind} requires target`);
130
+ if ((kind === "split_subgoal" || kind === "revise_pending_wording") && target !== undefined && target.status !== "pending") reasons.push(`${kind} requires pending target`);
131
+ const rawChildren = childValues(proposal);
132
+ if (kind === "split_subgoal" && rawChildren.length === 0) reasons.push("split_subgoal requires children");
133
+ if ((kind === "split_subgoal" || kind === "mark_blocked_superseded") && rawChildren.some((item) => child(item) === null)) reasons.push(`${kind} children require title/objective`);
134
+ if (kind === "reorder_pending") validateOrder(plan, proposal, reasons);
135
+ if (kind === "revise_pending_wording" && revised(proposal, "revisedTitle", "title") === undefined && revised(proposal, "revisedObjective", "objective") === undefined) reasons.push("revise_pending_wording requires update");
136
+ if (kind === "revise_criterion") validateCriterion(plan, proposal, reasons);
137
+ }
138
+
139
+ function validateOrder(plan: UlwLoopPlan, proposal: object, reasons: string[]): void {
140
+ const requested = pendingOrder(proposal);
141
+ const pending = plan.goals.filter((item) => item.status === "pending" && item.steeringStatus === undefined).map((item) => item.id);
142
+ if (requested.length === 0) reasons.push("reorder_pending requires ids");
143
+ if (new Set(requested).size !== requested.length) reasons.push("duplicate pending id");
144
+ if (requested.some((id) => !pending.includes(id))) reasons.push("unknown pending id");
145
+ }
146
+
147
+ function validateCriterion(plan: UlwLoopPlan, proposal: object, reasons: string[]): void {
148
+ const target = goal(plan, targets(proposal)[0]);
149
+ const criterionId = text(proposal, "criterionId");
150
+ if (target === undefined) reasons.push("revise_criterion requires goalId");
151
+ else if (criterionId === undefined || target.successCriteria.every((item) => item.id !== criterionId)) reasons.push("revise_criterion requires criterionId");
152
+ const model = read(proposal, "userModel");
153
+ if (read(proposal, "scenario") === undefined && read(proposal, "expectedEvidence") === undefined && model === undefined) reasons.push("revise_criterion requires update");
154
+ if (model !== undefined && !isModel(model)) reasons.push("invalid userModel");
155
+ }
156
+
157
+ function nextId(plan: UlwLoopPlan, offset: number): string {
158
+ const max = plan.goals.reduce((current, item) => {
159
+ const digits = /^G(\d+)(?:-|$)/u.exec(item.id)?.[1];
160
+ return digits === undefined ? current : Math.max(current, Number(digits));
161
+ }, 0);
162
+ return `G${String(max + offset).padStart(3, "0")}`;
163
+ }
164
+
165
+ function makeGoal(plan: UlwLoopPlan, childGoal: UlwLoopSteeringChildGoal, evidence: string, now: string, offset: number): UlwLoopItem {
166
+ const id = nextId(plan, offset);
167
+ const digits = /^G(\d+)/u.exec(id)?.[1];
168
+ const goalIndex = digits === undefined ? plan.goals.length + offset - 1 : Number(digits) - 1;
169
+ return { id, title: childGoal.title, objective: childGoal.objective, status: "pending", successCriteria: seedDefaultSuccessCriteria(goalIndex, childGoal.objective), attempt: 0, createdAt: now, updatedAt: now, evidence };
170
+ }
171
+
172
+ export function applySteeringMutation(plan: UlwLoopPlan, proposal: UlwLoopSteeringProposal, audit: UlwLoopSteeringAudit): UlwLoopPlan {
173
+ const next = structuredClone(plan);
174
+ if (!audit.invariant.accepted) return next;
175
+ const now = proposal.now?.toISOString() ?? iso();
176
+ if (proposal.kind === "add_subgoal") next.goals.push(makeGoal(next, { title: proposal.title ?? "", objective: proposal.objective ?? "" }, proposal.evidence, now, 1));
177
+ if (proposal.kind === "reorder_pending") {
178
+ const order = pendingOrder(proposal);
179
+ next.goals = [...order.map((id) => goal(next, id)).filter((item): item is UlwLoopItem => item !== undefined), ...next.goals.filter((item) => !order.includes(item.id))];
180
+ }
181
+ if (proposal.kind === "revise_pending_wording") reviseWording(next, proposal, now);
182
+ if (proposal.kind === "split_subgoal" || proposal.kind === "mark_blocked_superseded") splitOrBlock(next, proposal, now);
183
+ if (proposal.kind === "revise_criterion") reviseCriterion(next, proposal, now);
184
+ if (proposal.kind !== "annotate_ledger") next.updatedAt = now;
185
+ return next;
186
+ }
187
+
188
+ function reviseWording(plan: UlwLoopPlan, proposal: UlwLoopSteeringProposal, now: string): void {
189
+ const target = goal(plan, targets(proposal)[0]);
190
+ if (target === undefined) return;
191
+ target.title = revised(proposal, "revisedTitle", "title") ?? target.title;
192
+ target.objective = revised(proposal, "revisedObjective", "objective") ?? target.objective;
193
+ target.steeringEvidence = proposal.evidence;
194
+ target.steeringRationale = proposal.rationale;
195
+ target.updatedAt = now;
196
+ }
197
+
198
+ function splitOrBlock(plan: UlwLoopPlan, proposal: UlwLoopSteeringProposal, now: string): void {
199
+ const target = goal(plan, targets(proposal)[0]);
200
+ if (target === undefined) return;
201
+ const replacements = children(proposal).map((item, index) => makeGoal(plan, item, proposal.evidence, now, index + 1));
202
+ target.steeringEvidence = proposal.evidence;
203
+ target.steeringRationale = proposal.rationale;
204
+ target.updatedAt = now;
205
+ if (replacements.length === 0) {
206
+ target.status = "blocked";
207
+ target.steeringStatus = "blocked";
208
+ target.blockedReason = proposal.blockedReason ?? proposal.rationale;
209
+ } else {
210
+ target.steeringStatus = "superseded";
211
+ target.supersededBy = replacements.map((item) => item.id);
212
+ for (const item of replacements) item.supersedes = [target.id];
213
+ plan.goals.splice(plan.goals.indexOf(target) + 1, 0, ...replacements);
214
+ }
215
+ if (plan.activeGoalId === target.id) delete plan.activeGoalId;
216
+ }
217
+
218
+ function reviseCriterion(plan: UlwLoopPlan, proposal: UlwLoopSteeringProposal, now: string): void {
219
+ const target = goal(plan, targets(proposal)[0]);
220
+ const index = target?.successCriteria.findIndex((item) => item.id === proposal.criterionId) ?? -1;
221
+ const current = target?.successCriteria[index];
222
+ if (target === undefined || current === undefined) return;
223
+ const model = read(proposal, "userModel");
224
+ target.successCriteria[index] = { ...current, scenario: text(proposal, "scenario") ?? current.scenario, expectedEvidence: text(proposal, "expectedEvidence") ?? current.expectedEvidence, userModel: isModel(model) ? model : current.userModel };
225
+ target.updatedAt = now;
226
+ }
227
+
228
+ function isProposal(value: unknown): value is UlwLoopSteeringProposal {
229
+ return isPlain(value) && isKind(read(value, "kind")) && isSource(read(value, "source")) && isText(read(value, "evidence")) && isText(read(value, "rationale"));
230
+ }
231
+
232
+ export function parseUlwLoopSteeringDirective(text: string): UlwLoopSteeringProposal | null {
233
+ const match = /(?:^|\s)(?:OMO_ULW_LOOP_STEER|omo\.ulw-loop\.steer|omo ulw-loop steer):\s*([\s\S]+)$/u.exec(text);
234
+ if (match?.[1] === undefined) return null;
235
+ try {
236
+ const parsed: unknown = JSON.parse(match[1].trim());
237
+ return isProposal(parsed) ? parsed : null;
238
+ } catch (error) {
239
+ if (error instanceof SyntaxError) return null;
240
+ throw error;
241
+ }
242
+ }
243
+
244
+ export async function steerUlwLoop(repoRoot: string, proposal: UlwLoopSteeringProposal, scope?: UlwLoopScope): Promise<SteerUlwLoopResult> {
245
+ return withUlwLoopMutationLock(repoRoot, scope, async () => {
246
+ const plan = await readUlwLoopPlan(repoRoot, scope);
247
+ const key = proposal.idempotencyKey ?? proposal.promptSignature;
248
+ const prior = key === undefined ? undefined : (await readSteeringLedgerEntries(repoRoot, scope)).find((entry) => entry.steering?.invariant.accepted === true && (entry.idempotencyKey === key || entry.steering.idempotencyKey === key || entry.steering.promptSignature === key));
249
+ if (prior?.steering !== undefined) return { plan, accepted: true, audit: { ...prior.steering, deduped: true }, rejectedReasons: [], deduped: true };
250
+ const audit = validateUlwLoopSteeringProposal(plan, proposal);
251
+ const accepted = audit.invariant.accepted;
252
+ const next = accepted ? applySteeringMutation(plan, proposal, audit) : plan;
253
+ const finalAudit: UlwLoopSteeringAudit = { ...audit, before: plan };
254
+ if (accepted) finalAudit.after = next;
255
+ if (accepted) await writePlan(repoRoot, next, scope);
256
+ await appendLedger(repoRoot, ledgerEntry(proposal, finalAudit, proposal.now?.toISOString() ?? iso()), scope);
257
+ return { plan: next, accepted, audit: finalAudit, rejectedReasons: audit.invariant.rejectedReasons, deduped: false };
258
+ });
259
+ }
260
+
261
+ function ledgerEntry(proposal: UlwLoopSteeringProposal, audit: UlwLoopSteeringAudit, at: string): UlwLoopLedgerEntry {
262
+ const entry: UlwLoopLedgerEntry = { at, kind: audit.invariant.accepted ? (proposal.kind === "revise_criterion" ? "criteria_revised" : "steering_accepted") : "steering_rejected", evidence: proposal.evidence, message: proposal.rationale, steering: audit, mutationKind: proposal.kind };
263
+ const goalId = audit.targetGoalIds[0];
264
+ if (goalId !== undefined) entry.goalId = goalId;
265
+ if (proposal.criterionId !== undefined) entry.criterionId = proposal.criterionId;
266
+ if (proposal.idempotencyKey !== undefined) entry.idempotencyKey = proposal.idempotencyKey;
267
+ if (audit.before !== undefined) entry.before = audit.before;
268
+ if (audit.after !== undefined) entry.after = audit.after;
269
+ return entry;
270
+ }