opencode-repos 0.2.0 → 0.3.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 (475) hide show
  1. package/AGENTS.md +180 -0
  2. package/README.md +103 -3
  3. package/TODO.md +3 -0
  4. package/index.ts +1590 -158
  5. package/oh-my-opencode/.github/FUNDING.yml +15 -0
  6. package/oh-my-opencode/.github/ISSUE_TEMPLATE/bug_report.yml +129 -0
  7. package/oh-my-opencode/.github/ISSUE_TEMPLATE/config.yml +8 -0
  8. package/oh-my-opencode/.github/ISSUE_TEMPLATE/feature_request.yml +100 -0
  9. package/oh-my-opencode/.github/ISSUE_TEMPLATE/general.yml +83 -0
  10. package/oh-my-opencode/.github/assets/google.jpg +0 -0
  11. package/oh-my-opencode/.github/assets/hero.jpg +0 -0
  12. package/oh-my-opencode/.github/assets/indent.jpg +0 -0
  13. package/oh-my-opencode/.github/assets/microsoft.jpg +0 -0
  14. package/oh-my-opencode/.github/assets/omo.png +0 -0
  15. package/oh-my-opencode/.github/assets/orchestrator-atlas.png +0 -0
  16. package/oh-my-opencode/.github/assets/sisyphus.png +0 -0
  17. package/oh-my-opencode/.github/assets/sisyphuslabs.png +0 -0
  18. package/oh-my-opencode/.github/pull_request_template.md +34 -0
  19. package/oh-my-opencode/.github/workflows/ci.yml +138 -0
  20. package/oh-my-opencode/.github/workflows/cla.yml +41 -0
  21. package/oh-my-opencode/.github/workflows/lint-workflows.yml +22 -0
  22. package/oh-my-opencode/.github/workflows/publish.yml +165 -0
  23. package/oh-my-opencode/.github/workflows/sisyphus-agent.yml +500 -0
  24. package/oh-my-opencode/.opencode/background-tasks.json +27 -0
  25. package/oh-my-opencode/.opencode/command/get-unpublished-changes.md +84 -0
  26. package/oh-my-opencode/.opencode/command/omomomo.md +37 -0
  27. package/oh-my-opencode/.opencode/command/publish.md +257 -0
  28. package/oh-my-opencode/AGENTS.md +179 -0
  29. package/oh-my-opencode/CLA.md +58 -0
  30. package/oh-my-opencode/CONTRIBUTING.md +268 -0
  31. package/oh-my-opencode/LICENSE.md +82 -0
  32. package/oh-my-opencode/README.ja.md +370 -0
  33. package/oh-my-opencode/README.md +376 -0
  34. package/oh-my-opencode/README.zh-cn.md +380 -0
  35. package/oh-my-opencode/assets/oh-my-opencode.schema.json +2171 -0
  36. package/oh-my-opencode/bin/oh-my-opencode.js +80 -0
  37. package/oh-my-opencode/bin/platform.js +38 -0
  38. package/oh-my-opencode/bin/platform.test.ts +148 -0
  39. package/oh-my-opencode/bun.lock +314 -0
  40. package/oh-my-opencode/bunfig.toml +2 -0
  41. package/oh-my-opencode/docs/category-skill-guide.md +200 -0
  42. package/oh-my-opencode/docs/cli-guide.md +272 -0
  43. package/oh-my-opencode/docs/configurations.md +654 -0
  44. package/oh-my-opencode/docs/features.md +550 -0
  45. package/oh-my-opencode/docs/guide/installation.md +288 -0
  46. package/oh-my-opencode/docs/guide/overview.md +97 -0
  47. package/oh-my-opencode/docs/guide/understanding-orchestration-system.md +445 -0
  48. package/oh-my-opencode/docs/orchestration-guide.md +152 -0
  49. package/oh-my-opencode/docs/ultrawork-manifesto.md +197 -0
  50. package/oh-my-opencode/package.json +89 -0
  51. package/oh-my-opencode/packages/darwin-arm64/bin/.gitkeep +0 -0
  52. package/oh-my-opencode/packages/darwin-arm64/package.json +22 -0
  53. package/oh-my-opencode/packages/darwin-x64/bin/.gitkeep +0 -0
  54. package/oh-my-opencode/packages/darwin-x64/package.json +22 -0
  55. package/oh-my-opencode/packages/linux-arm64/bin/.gitkeep +0 -0
  56. package/oh-my-opencode/packages/linux-arm64/package.json +25 -0
  57. package/oh-my-opencode/packages/linux-arm64-musl/bin/.gitkeep +0 -0
  58. package/oh-my-opencode/packages/linux-arm64-musl/package.json +25 -0
  59. package/oh-my-opencode/packages/linux-x64/bin/.gitkeep +0 -0
  60. package/oh-my-opencode/packages/linux-x64/package.json +25 -0
  61. package/oh-my-opencode/packages/linux-x64-musl/bin/.gitkeep +0 -0
  62. package/oh-my-opencode/packages/linux-x64-musl/package.json +25 -0
  63. package/oh-my-opencode/packages/windows-x64/bin/.gitkeep +0 -0
  64. package/oh-my-opencode/packages/windows-x64/package.json +22 -0
  65. package/oh-my-opencode/postinstall.mjs +43 -0
  66. package/oh-my-opencode/script/build-binaries.ts +103 -0
  67. package/oh-my-opencode/script/build-schema.ts +28 -0
  68. package/oh-my-opencode/script/generate-changelog.ts +92 -0
  69. package/oh-my-opencode/script/publish.ts +344 -0
  70. package/oh-my-opencode/signatures/cla.json +676 -0
  71. package/oh-my-opencode/src/agents/AGENTS.md +67 -0
  72. package/oh-my-opencode/src/agents/atlas.ts +1383 -0
  73. package/oh-my-opencode/src/agents/dynamic-agent-prompt-builder.ts +400 -0
  74. package/oh-my-opencode/src/agents/explore.ts +122 -0
  75. package/oh-my-opencode/src/agents/index.ts +13 -0
  76. package/oh-my-opencode/src/agents/librarian.ts +326 -0
  77. package/oh-my-opencode/src/agents/metis.ts +315 -0
  78. package/oh-my-opencode/src/agents/momus.test.ts +57 -0
  79. package/oh-my-opencode/src/agents/momus.ts +444 -0
  80. package/oh-my-opencode/src/agents/multimodal-looker.ts +56 -0
  81. package/oh-my-opencode/src/agents/oracle.ts +122 -0
  82. package/oh-my-opencode/src/agents/prometheus-prompt.test.ts +22 -0
  83. package/oh-my-opencode/src/agents/prometheus-prompt.ts +1196 -0
  84. package/oh-my-opencode/src/agents/sisyphus-junior.test.ts +232 -0
  85. package/oh-my-opencode/src/agents/sisyphus-junior.ts +134 -0
  86. package/oh-my-opencode/src/agents/sisyphus.ts +633 -0
  87. package/oh-my-opencode/src/agents/types.ts +80 -0
  88. package/oh-my-opencode/src/agents/utils.test.ts +311 -0
  89. package/oh-my-opencode/src/agents/utils.ts +240 -0
  90. package/oh-my-opencode/src/cli/AGENTS.md +91 -0
  91. package/oh-my-opencode/src/cli/config-manager.test.ts +364 -0
  92. package/oh-my-opencode/src/cli/config-manager.ts +641 -0
  93. package/oh-my-opencode/src/cli/doctor/checks/auth.test.ts +114 -0
  94. package/oh-my-opencode/src/cli/doctor/checks/auth.ts +115 -0
  95. package/oh-my-opencode/src/cli/doctor/checks/config.test.ts +103 -0
  96. package/oh-my-opencode/src/cli/doctor/checks/config.ts +123 -0
  97. package/oh-my-opencode/src/cli/doctor/checks/dependencies.test.ts +152 -0
  98. package/oh-my-opencode/src/cli/doctor/checks/dependencies.ts +163 -0
  99. package/oh-my-opencode/src/cli/doctor/checks/gh.test.ts +151 -0
  100. package/oh-my-opencode/src/cli/doctor/checks/gh.ts +171 -0
  101. package/oh-my-opencode/src/cli/doctor/checks/index.ts +34 -0
  102. package/oh-my-opencode/src/cli/doctor/checks/lsp.test.ts +134 -0
  103. package/oh-my-opencode/src/cli/doctor/checks/lsp.ts +77 -0
  104. package/oh-my-opencode/src/cli/doctor/checks/mcp.test.ts +115 -0
  105. package/oh-my-opencode/src/cli/doctor/checks/mcp.ts +128 -0
  106. package/oh-my-opencode/src/cli/doctor/checks/opencode.test.ts +227 -0
  107. package/oh-my-opencode/src/cli/doctor/checks/opencode.ts +178 -0
  108. package/oh-my-opencode/src/cli/doctor/checks/plugin.test.ts +109 -0
  109. package/oh-my-opencode/src/cli/doctor/checks/plugin.ts +124 -0
  110. package/oh-my-opencode/src/cli/doctor/checks/version.test.ts +148 -0
  111. package/oh-my-opencode/src/cli/doctor/checks/version.ts +135 -0
  112. package/oh-my-opencode/src/cli/doctor/constants.ts +72 -0
  113. package/oh-my-opencode/src/cli/doctor/formatter.test.ts +218 -0
  114. package/oh-my-opencode/src/cli/doctor/formatter.ts +140 -0
  115. package/oh-my-opencode/src/cli/doctor/index.ts +11 -0
  116. package/oh-my-opencode/src/cli/doctor/runner.test.ts +153 -0
  117. package/oh-my-opencode/src/cli/doctor/runner.ts +132 -0
  118. package/oh-my-opencode/src/cli/doctor/types.ts +113 -0
  119. package/oh-my-opencode/src/cli/get-local-version/formatter.ts +66 -0
  120. package/oh-my-opencode/src/cli/get-local-version/index.ts +106 -0
  121. package/oh-my-opencode/src/cli/get-local-version/types.ts +14 -0
  122. package/oh-my-opencode/src/cli/index.ts +153 -0
  123. package/oh-my-opencode/src/cli/install.ts +523 -0
  124. package/oh-my-opencode/src/cli/model-fallback.ts +246 -0
  125. package/oh-my-opencode/src/cli/run/completion.test.ts +170 -0
  126. package/oh-my-opencode/src/cli/run/completion.ts +79 -0
  127. package/oh-my-opencode/src/cli/run/events.test.ts +155 -0
  128. package/oh-my-opencode/src/cli/run/events.ts +325 -0
  129. package/oh-my-opencode/src/cli/run/index.ts +2 -0
  130. package/oh-my-opencode/src/cli/run/runner.ts +159 -0
  131. package/oh-my-opencode/src/cli/run/types.ts +76 -0
  132. package/oh-my-opencode/src/cli/types.ts +40 -0
  133. package/oh-my-opencode/src/config/index.ts +26 -0
  134. package/oh-my-opencode/src/config/schema.test.ts +444 -0
  135. package/oh-my-opencode/src/config/schema.ts +339 -0
  136. package/oh-my-opencode/src/features/AGENTS.md +77 -0
  137. package/oh-my-opencode/src/features/background-agent/concurrency.test.ts +418 -0
  138. package/oh-my-opencode/src/features/background-agent/concurrency.ts +137 -0
  139. package/oh-my-opencode/src/features/background-agent/index.ts +3 -0
  140. package/oh-my-opencode/src/features/background-agent/manager.test.ts +1928 -0
  141. package/oh-my-opencode/src/features/background-agent/manager.ts +1335 -0
  142. package/oh-my-opencode/src/features/background-agent/types.ts +66 -0
  143. package/oh-my-opencode/src/features/boulder-state/constants.ts +13 -0
  144. package/oh-my-opencode/src/features/boulder-state/index.ts +3 -0
  145. package/oh-my-opencode/src/features/boulder-state/storage.test.ts +250 -0
  146. package/oh-my-opencode/src/features/boulder-state/storage.ts +150 -0
  147. package/oh-my-opencode/src/features/boulder-state/types.ts +26 -0
  148. package/oh-my-opencode/src/features/builtin-commands/commands.ts +89 -0
  149. package/oh-my-opencode/src/features/builtin-commands/index.ts +2 -0
  150. package/oh-my-opencode/src/features/builtin-commands/templates/init-deep.ts +300 -0
  151. package/oh-my-opencode/src/features/builtin-commands/templates/ralph-loop.ts +38 -0
  152. package/oh-my-opencode/src/features/builtin-commands/templates/refactor.ts +619 -0
  153. package/oh-my-opencode/src/features/builtin-commands/templates/start-work.ts +72 -0
  154. package/oh-my-opencode/src/features/builtin-commands/types.ts +9 -0
  155. package/oh-my-opencode/src/features/builtin-skills/frontend-ui-ux/SKILL.md +78 -0
  156. package/oh-my-opencode/src/features/builtin-skills/git-master/SKILL.md +1105 -0
  157. package/oh-my-opencode/src/features/builtin-skills/index.ts +2 -0
  158. package/oh-my-opencode/src/features/builtin-skills/skills.ts +1203 -0
  159. package/oh-my-opencode/src/features/builtin-skills/types.ts +16 -0
  160. package/oh-my-opencode/src/features/claude-code-agent-loader/index.ts +2 -0
  161. package/oh-my-opencode/src/features/claude-code-agent-loader/loader.ts +90 -0
  162. package/oh-my-opencode/src/features/claude-code-agent-loader/types.ts +17 -0
  163. package/oh-my-opencode/src/features/claude-code-command-loader/index.ts +2 -0
  164. package/oh-my-opencode/src/features/claude-code-command-loader/loader.ts +144 -0
  165. package/oh-my-opencode/src/features/claude-code-command-loader/types.ts +46 -0
  166. package/oh-my-opencode/src/features/claude-code-mcp-loader/env-expander.ts +27 -0
  167. package/oh-my-opencode/src/features/claude-code-mcp-loader/index.ts +11 -0
  168. package/oh-my-opencode/src/features/claude-code-mcp-loader/loader.test.ts +162 -0
  169. package/oh-my-opencode/src/features/claude-code-mcp-loader/loader.ts +113 -0
  170. package/oh-my-opencode/src/features/claude-code-mcp-loader/transformer.ts +53 -0
  171. package/oh-my-opencode/src/features/claude-code-mcp-loader/types.ts +42 -0
  172. package/oh-my-opencode/src/features/claude-code-plugin-loader/index.ts +3 -0
  173. package/oh-my-opencode/src/features/claude-code-plugin-loader/loader.ts +486 -0
  174. package/oh-my-opencode/src/features/claude-code-plugin-loader/types.ts +210 -0
  175. package/oh-my-opencode/src/features/claude-code-session-state/index.ts +1 -0
  176. package/oh-my-opencode/src/features/claude-code-session-state/state.test.ts +126 -0
  177. package/oh-my-opencode/src/features/claude-code-session-state/state.ts +37 -0
  178. package/oh-my-opencode/src/features/context-injector/collector.test.ts +330 -0
  179. package/oh-my-opencode/src/features/context-injector/collector.ts +85 -0
  180. package/oh-my-opencode/src/features/context-injector/index.ts +14 -0
  181. package/oh-my-opencode/src/features/context-injector/injector.test.ts +122 -0
  182. package/oh-my-opencode/src/features/context-injector/injector.ts +167 -0
  183. package/oh-my-opencode/src/features/context-injector/types.ts +91 -0
  184. package/oh-my-opencode/src/features/hook-message-injector/constants.ts +6 -0
  185. package/oh-my-opencode/src/features/hook-message-injector/index.ts +4 -0
  186. package/oh-my-opencode/src/features/hook-message-injector/injector.ts +195 -0
  187. package/oh-my-opencode/src/features/hook-message-injector/types.ts +47 -0
  188. package/oh-my-opencode/src/features/opencode-skill-loader/async-loader.test.ts +448 -0
  189. package/oh-my-opencode/src/features/opencode-skill-loader/async-loader.ts +180 -0
  190. package/oh-my-opencode/src/features/opencode-skill-loader/blocking.test.ts +210 -0
  191. package/oh-my-opencode/src/features/opencode-skill-loader/blocking.ts +62 -0
  192. package/oh-my-opencode/src/features/opencode-skill-loader/discover-worker.ts +59 -0
  193. package/oh-my-opencode/src/features/opencode-skill-loader/index.ts +4 -0
  194. package/oh-my-opencode/src/features/opencode-skill-loader/loader.test.ts +273 -0
  195. package/oh-my-opencode/src/features/opencode-skill-loader/loader.ts +259 -0
  196. package/oh-my-opencode/src/features/opencode-skill-loader/merger.ts +267 -0
  197. package/oh-my-opencode/src/features/opencode-skill-loader/skill-content.test.ts +267 -0
  198. package/oh-my-opencode/src/features/opencode-skill-loader/skill-content.ts +206 -0
  199. package/oh-my-opencode/src/features/opencode-skill-loader/types.ts +38 -0
  200. package/oh-my-opencode/src/features/skill-mcp-manager/env-cleaner.test.ts +201 -0
  201. package/oh-my-opencode/src/features/skill-mcp-manager/env-cleaner.ts +27 -0
  202. package/oh-my-opencode/src/features/skill-mcp-manager/index.ts +2 -0
  203. package/oh-my-opencode/src/features/skill-mcp-manager/manager.test.ts +611 -0
  204. package/oh-my-opencode/src/features/skill-mcp-manager/manager.ts +520 -0
  205. package/oh-my-opencode/src/features/skill-mcp-manager/types.ts +14 -0
  206. package/oh-my-opencode/src/features/task-toast-manager/index.ts +2 -0
  207. package/oh-my-opencode/src/features/task-toast-manager/manager.test.ts +249 -0
  208. package/oh-my-opencode/src/features/task-toast-manager/manager.ts +215 -0
  209. package/oh-my-opencode/src/features/task-toast-manager/types.ts +24 -0
  210. package/oh-my-opencode/src/hooks/AGENTS.md +73 -0
  211. package/oh-my-opencode/src/hooks/agent-usage-reminder/constants.ts +54 -0
  212. package/oh-my-opencode/src/hooks/agent-usage-reminder/index.ts +109 -0
  213. package/oh-my-opencode/src/hooks/agent-usage-reminder/storage.ts +42 -0
  214. package/oh-my-opencode/src/hooks/agent-usage-reminder/types.ts +6 -0
  215. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts +307 -0
  216. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/executor.ts +485 -0
  217. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/index.ts +151 -0
  218. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/parser.ts +201 -0
  219. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts +33 -0
  220. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts +184 -0
  221. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-types.ts +44 -0
  222. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/storage.test.ts +77 -0
  223. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/storage.ts +250 -0
  224. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/types.ts +42 -0
  225. package/oh-my-opencode/src/hooks/atlas/index.test.ts +953 -0
  226. package/oh-my-opencode/src/hooks/atlas/index.ts +771 -0
  227. package/oh-my-opencode/src/hooks/auto-slash-command/constants.ts +12 -0
  228. package/oh-my-opencode/src/hooks/auto-slash-command/detector.test.ts +296 -0
  229. package/oh-my-opencode/src/hooks/auto-slash-command/detector.ts +65 -0
  230. package/oh-my-opencode/src/hooks/auto-slash-command/executor.ts +205 -0
  231. package/oh-my-opencode/src/hooks/auto-slash-command/index.test.ts +254 -0
  232. package/oh-my-opencode/src/hooks/auto-slash-command/index.ts +89 -0
  233. package/oh-my-opencode/src/hooks/auto-slash-command/types.ts +23 -0
  234. package/oh-my-opencode/src/hooks/auto-update-checker/cache.ts +93 -0
  235. package/oh-my-opencode/src/hooks/auto-update-checker/checker.test.ts +24 -0
  236. package/oh-my-opencode/src/hooks/auto-update-checker/checker.ts +284 -0
  237. package/oh-my-opencode/src/hooks/auto-update-checker/constants.ts +64 -0
  238. package/oh-my-opencode/src/hooks/auto-update-checker/index.test.ts +254 -0
  239. package/oh-my-opencode/src/hooks/auto-update-checker/index.ts +260 -0
  240. package/oh-my-opencode/src/hooks/auto-update-checker/types.ts +29 -0
  241. package/oh-my-opencode/src/hooks/background-compaction/index.ts +87 -0
  242. package/oh-my-opencode/src/hooks/background-notification/index.ts +28 -0
  243. package/oh-my-opencode/src/hooks/background-notification/types.ts +5 -0
  244. package/oh-my-opencode/src/hooks/claude-code-hooks/AGENTS.md +70 -0
  245. package/oh-my-opencode/src/hooks/claude-code-hooks/config-loader.ts +107 -0
  246. package/oh-my-opencode/src/hooks/claude-code-hooks/config.ts +103 -0
  247. package/oh-my-opencode/src/hooks/claude-code-hooks/index.ts +401 -0
  248. package/oh-my-opencode/src/hooks/claude-code-hooks/plugin-config.ts +12 -0
  249. package/oh-my-opencode/src/hooks/claude-code-hooks/post-tool-use.ts +199 -0
  250. package/oh-my-opencode/src/hooks/claude-code-hooks/pre-compact.ts +109 -0
  251. package/oh-my-opencode/src/hooks/claude-code-hooks/pre-tool-use.ts +172 -0
  252. package/oh-my-opencode/src/hooks/claude-code-hooks/stop.ts +118 -0
  253. package/oh-my-opencode/src/hooks/claude-code-hooks/todo.ts +76 -0
  254. package/oh-my-opencode/src/hooks/claude-code-hooks/tool-input-cache.ts +47 -0
  255. package/oh-my-opencode/src/hooks/claude-code-hooks/transcript.ts +252 -0
  256. package/oh-my-opencode/src/hooks/claude-code-hooks/types.ts +204 -0
  257. package/oh-my-opencode/src/hooks/claude-code-hooks/user-prompt-submit.ts +117 -0
  258. package/oh-my-opencode/src/hooks/comment-checker/cli.test.ts +68 -0
  259. package/oh-my-opencode/src/hooks/comment-checker/cli.ts +221 -0
  260. package/oh-my-opencode/src/hooks/comment-checker/downloader.ts +196 -0
  261. package/oh-my-opencode/src/hooks/comment-checker/index.ts +171 -0
  262. package/oh-my-opencode/src/hooks/comment-checker/types.ts +33 -0
  263. package/oh-my-opencode/src/hooks/compaction-context-injector/index.ts +61 -0
  264. package/oh-my-opencode/src/hooks/context-window-monitor.ts +99 -0
  265. package/oh-my-opencode/src/hooks/delegate-task-retry/index.test.ts +119 -0
  266. package/oh-my-opencode/src/hooks/delegate-task-retry/index.ts +136 -0
  267. package/oh-my-opencode/src/hooks/directory-agents-injector/constants.ts +9 -0
  268. package/oh-my-opencode/src/hooks/directory-agents-injector/index.ts +182 -0
  269. package/oh-my-opencode/src/hooks/directory-agents-injector/storage.ts +48 -0
  270. package/oh-my-opencode/src/hooks/directory-agents-injector/types.ts +5 -0
  271. package/oh-my-opencode/src/hooks/directory-readme-injector/constants.ts +9 -0
  272. package/oh-my-opencode/src/hooks/directory-readme-injector/index.ts +177 -0
  273. package/oh-my-opencode/src/hooks/directory-readme-injector/storage.ts +48 -0
  274. package/oh-my-opencode/src/hooks/directory-readme-injector/types.ts +5 -0
  275. package/oh-my-opencode/src/hooks/edit-error-recovery/index.test.ts +126 -0
  276. package/oh-my-opencode/src/hooks/edit-error-recovery/index.ts +57 -0
  277. package/oh-my-opencode/src/hooks/empty-task-response-detector.ts +27 -0
  278. package/oh-my-opencode/src/hooks/index.ts +32 -0
  279. package/oh-my-opencode/src/hooks/interactive-bash-session/constants.ts +15 -0
  280. package/oh-my-opencode/src/hooks/interactive-bash-session/index.ts +262 -0
  281. package/oh-my-opencode/src/hooks/interactive-bash-session/storage.ts +59 -0
  282. package/oh-my-opencode/src/hooks/interactive-bash-session/types.ts +11 -0
  283. package/oh-my-opencode/src/hooks/keyword-detector/constants.ts +300 -0
  284. package/oh-my-opencode/src/hooks/keyword-detector/detector.ts +52 -0
  285. package/oh-my-opencode/src/hooks/keyword-detector/index.test.ts +529 -0
  286. package/oh-my-opencode/src/hooks/keyword-detector/index.ts +100 -0
  287. package/oh-my-opencode/src/hooks/keyword-detector/types.ts +4 -0
  288. package/oh-my-opencode/src/hooks/non-interactive-env/constants.ts +70 -0
  289. package/oh-my-opencode/src/hooks/non-interactive-env/detector.ts +19 -0
  290. package/oh-my-opencode/src/hooks/non-interactive-env/index.test.ts +323 -0
  291. package/oh-my-opencode/src/hooks/non-interactive-env/index.ts +63 -0
  292. package/oh-my-opencode/src/hooks/non-interactive-env/types.ts +3 -0
  293. package/oh-my-opencode/src/hooks/prometheus-md-only/constants.ts +32 -0
  294. package/oh-my-opencode/src/hooks/prometheus-md-only/index.test.ts +488 -0
  295. package/oh-my-opencode/src/hooks/prometheus-md-only/index.ts +136 -0
  296. package/oh-my-opencode/src/hooks/ralph-loop/constants.ts +5 -0
  297. package/oh-my-opencode/src/hooks/ralph-loop/index.test.ts +835 -0
  298. package/oh-my-opencode/src/hooks/ralph-loop/index.ts +417 -0
  299. package/oh-my-opencode/src/hooks/ralph-loop/storage.ts +115 -0
  300. package/oh-my-opencode/src/hooks/ralph-loop/types.ts +19 -0
  301. package/oh-my-opencode/src/hooks/rules-injector/constants.ts +30 -0
  302. package/oh-my-opencode/src/hooks/rules-injector/finder.test.ts +381 -0
  303. package/oh-my-opencode/src/hooks/rules-injector/finder.ts +263 -0
  304. package/oh-my-opencode/src/hooks/rules-injector/index.ts +223 -0
  305. package/oh-my-opencode/src/hooks/rules-injector/matcher.ts +63 -0
  306. package/oh-my-opencode/src/hooks/rules-injector/parser.test.ts +226 -0
  307. package/oh-my-opencode/src/hooks/rules-injector/parser.ts +211 -0
  308. package/oh-my-opencode/src/hooks/rules-injector/storage.ts +59 -0
  309. package/oh-my-opencode/src/hooks/rules-injector/types.ts +57 -0
  310. package/oh-my-opencode/src/hooks/session-notification-utils.ts +140 -0
  311. package/oh-my-opencode/src/hooks/session-notification.test.ts +361 -0
  312. package/oh-my-opencode/src/hooks/session-notification.ts +330 -0
  313. package/oh-my-opencode/src/hooks/session-recovery/constants.ts +10 -0
  314. package/oh-my-opencode/src/hooks/session-recovery/index.test.ts +223 -0
  315. package/oh-my-opencode/src/hooks/session-recovery/index.ts +435 -0
  316. package/oh-my-opencode/src/hooks/session-recovery/storage.ts +390 -0
  317. package/oh-my-opencode/src/hooks/session-recovery/types.ts +98 -0
  318. package/oh-my-opencode/src/hooks/start-work/index.test.ts +402 -0
  319. package/oh-my-opencode/src/hooks/start-work/index.ts +242 -0
  320. package/oh-my-opencode/src/hooks/task-resume-info/index.ts +36 -0
  321. package/oh-my-opencode/src/hooks/think-mode/detector.ts +57 -0
  322. package/oh-my-opencode/src/hooks/think-mode/index.test.ts +353 -0
  323. package/oh-my-opencode/src/hooks/think-mode/index.ts +89 -0
  324. package/oh-my-opencode/src/hooks/think-mode/switcher.test.ts +461 -0
  325. package/oh-my-opencode/src/hooks/think-mode/switcher.ts +222 -0
  326. package/oh-my-opencode/src/hooks/think-mode/types.ts +21 -0
  327. package/oh-my-opencode/src/hooks/thinking-block-validator/index.ts +171 -0
  328. package/oh-my-opencode/src/hooks/todo-continuation-enforcer.test.ts +876 -0
  329. package/oh-my-opencode/src/hooks/todo-continuation-enforcer.ts +480 -0
  330. package/oh-my-opencode/src/hooks/tool-output-truncator.test.ts +168 -0
  331. package/oh-my-opencode/src/hooks/tool-output-truncator.ts +61 -0
  332. package/oh-my-opencode/src/index.ts +589 -0
  333. package/oh-my-opencode/src/mcp/AGENTS.md +70 -0
  334. package/oh-my-opencode/src/mcp/context7.ts +6 -0
  335. package/oh-my-opencode/src/mcp/grep-app.ts +6 -0
  336. package/oh-my-opencode/src/mcp/index.test.ts +86 -0
  337. package/oh-my-opencode/src/mcp/index.ts +32 -0
  338. package/oh-my-opencode/src/mcp/types.ts +9 -0
  339. package/oh-my-opencode/src/mcp/websearch.ts +10 -0
  340. package/oh-my-opencode/src/plugin-config.test.ts +119 -0
  341. package/oh-my-opencode/src/plugin-config.ts +135 -0
  342. package/oh-my-opencode/src/plugin-handlers/config-handler.test.ts +103 -0
  343. package/oh-my-opencode/src/plugin-handlers/config-handler.ts +399 -0
  344. package/oh-my-opencode/src/plugin-handlers/index.ts +1 -0
  345. package/oh-my-opencode/src/plugin-state.ts +30 -0
  346. package/oh-my-opencode/src/shared/AGENTS.md +63 -0
  347. package/oh-my-opencode/src/shared/agent-tool-restrictions.ts +44 -0
  348. package/oh-my-opencode/src/shared/agent-variant.test.ts +83 -0
  349. package/oh-my-opencode/src/shared/agent-variant.ts +40 -0
  350. package/oh-my-opencode/src/shared/claude-config-dir.test.ts +60 -0
  351. package/oh-my-opencode/src/shared/claude-config-dir.ts +11 -0
  352. package/oh-my-opencode/src/shared/command-executor.ts +225 -0
  353. package/oh-my-opencode/src/shared/config-errors.ts +18 -0
  354. package/oh-my-opencode/src/shared/config-path.ts +47 -0
  355. package/oh-my-opencode/src/shared/data-path.ts +22 -0
  356. package/oh-my-opencode/src/shared/deep-merge.test.ts +336 -0
  357. package/oh-my-opencode/src/shared/deep-merge.ts +53 -0
  358. package/oh-my-opencode/src/shared/dynamic-truncator.ts +193 -0
  359. package/oh-my-opencode/src/shared/external-plugin-detector.test.ts +133 -0
  360. package/oh-my-opencode/src/shared/external-plugin-detector.ts +132 -0
  361. package/oh-my-opencode/src/shared/file-reference-resolver.ts +85 -0
  362. package/oh-my-opencode/src/shared/file-utils.ts +40 -0
  363. package/oh-my-opencode/src/shared/first-message-variant.test.ts +32 -0
  364. package/oh-my-opencode/src/shared/first-message-variant.ts +28 -0
  365. package/oh-my-opencode/src/shared/frontmatter.test.ts +262 -0
  366. package/oh-my-opencode/src/shared/frontmatter.ts +31 -0
  367. package/oh-my-opencode/src/shared/hook-disabled.ts +22 -0
  368. package/oh-my-opencode/src/shared/index.ts +29 -0
  369. package/oh-my-opencode/src/shared/jsonc-parser.test.ts +266 -0
  370. package/oh-my-opencode/src/shared/jsonc-parser.ts +66 -0
  371. package/oh-my-opencode/src/shared/logger.ts +20 -0
  372. package/oh-my-opencode/src/shared/migration.test.ts +602 -0
  373. package/oh-my-opencode/src/shared/migration.ts +191 -0
  374. package/oh-my-opencode/src/shared/model-resolver.test.ts +101 -0
  375. package/oh-my-opencode/src/shared/model-resolver.ts +35 -0
  376. package/oh-my-opencode/src/shared/model-sanitizer.ts +12 -0
  377. package/oh-my-opencode/src/shared/opencode-config-dir.test.ts +318 -0
  378. package/oh-my-opencode/src/shared/opencode-config-dir.ts +142 -0
  379. package/oh-my-opencode/src/shared/opencode-version.test.ts +223 -0
  380. package/oh-my-opencode/src/shared/opencode-version.ts +72 -0
  381. package/oh-my-opencode/src/shared/pattern-matcher.ts +29 -0
  382. package/oh-my-opencode/src/shared/permission-compat.test.ts +134 -0
  383. package/oh-my-opencode/src/shared/permission-compat.ts +77 -0
  384. package/oh-my-opencode/src/shared/session-cursor.test.ts +66 -0
  385. package/oh-my-opencode/src/shared/session-cursor.ts +85 -0
  386. package/oh-my-opencode/src/shared/shell-env.test.ts +278 -0
  387. package/oh-my-opencode/src/shared/shell-env.ts +111 -0
  388. package/oh-my-opencode/src/shared/snake-case.ts +49 -0
  389. package/oh-my-opencode/src/shared/system-directive.ts +40 -0
  390. package/oh-my-opencode/src/shared/tool-name.ts +26 -0
  391. package/oh-my-opencode/src/shared/zip-extractor.ts +83 -0
  392. package/oh-my-opencode/src/tools/AGENTS.md +74 -0
  393. package/oh-my-opencode/src/tools/ast-grep/cli.ts +230 -0
  394. package/oh-my-opencode/src/tools/ast-grep/constants.ts +261 -0
  395. package/oh-my-opencode/src/tools/ast-grep/downloader.ts +128 -0
  396. package/oh-my-opencode/src/tools/ast-grep/index.ts +13 -0
  397. package/oh-my-opencode/src/tools/ast-grep/tools.ts +112 -0
  398. package/oh-my-opencode/src/tools/ast-grep/types.ts +61 -0
  399. package/oh-my-opencode/src/tools/ast-grep/utils.ts +102 -0
  400. package/oh-my-opencode/src/tools/background-task/constants.ts +7 -0
  401. package/oh-my-opencode/src/tools/background-task/index.ts +7 -0
  402. package/oh-my-opencode/src/tools/background-task/tools.ts +479 -0
  403. package/oh-my-opencode/src/tools/background-task/types.ts +16 -0
  404. package/oh-my-opencode/src/tools/call-omo-agent/constants.ts +7 -0
  405. package/oh-my-opencode/src/tools/call-omo-agent/index.ts +3 -0
  406. package/oh-my-opencode/src/tools/call-omo-agent/tools.ts +338 -0
  407. package/oh-my-opencode/src/tools/call-omo-agent/types.ts +27 -0
  408. package/oh-my-opencode/src/tools/delegate-task/constants.ts +205 -0
  409. package/oh-my-opencode/src/tools/delegate-task/index.ts +3 -0
  410. package/oh-my-opencode/src/tools/delegate-task/tools.test.ts +1575 -0
  411. package/oh-my-opencode/src/tools/delegate-task/tools.ts +885 -0
  412. package/oh-my-opencode/src/tools/delegate-task/types.ts +9 -0
  413. package/oh-my-opencode/src/tools/glob/cli.test.ts +158 -0
  414. package/oh-my-opencode/src/tools/glob/cli.ts +191 -0
  415. package/oh-my-opencode/src/tools/glob/constants.ts +12 -0
  416. package/oh-my-opencode/src/tools/glob/index.ts +3 -0
  417. package/oh-my-opencode/src/tools/glob/tools.ts +41 -0
  418. package/oh-my-opencode/src/tools/glob/types.ts +22 -0
  419. package/oh-my-opencode/src/tools/glob/utils.ts +26 -0
  420. package/oh-my-opencode/src/tools/grep/cli.ts +229 -0
  421. package/oh-my-opencode/src/tools/grep/constants.ts +127 -0
  422. package/oh-my-opencode/src/tools/grep/downloader.test.ts +103 -0
  423. package/oh-my-opencode/src/tools/grep/downloader.ts +145 -0
  424. package/oh-my-opencode/src/tools/grep/index.ts +3 -0
  425. package/oh-my-opencode/src/tools/grep/tools.ts +40 -0
  426. package/oh-my-opencode/src/tools/grep/types.ts +39 -0
  427. package/oh-my-opencode/src/tools/grep/utils.ts +53 -0
  428. package/oh-my-opencode/src/tools/index.ts +72 -0
  429. package/oh-my-opencode/src/tools/interactive-bash/constants.ts +18 -0
  430. package/oh-my-opencode/src/tools/interactive-bash/index.ts +4 -0
  431. package/oh-my-opencode/src/tools/interactive-bash/tools.ts +126 -0
  432. package/oh-my-opencode/src/tools/interactive-bash/utils.ts +71 -0
  433. package/oh-my-opencode/src/tools/look-at/constants.ts +3 -0
  434. package/oh-my-opencode/src/tools/look-at/index.ts +3 -0
  435. package/oh-my-opencode/src/tools/look-at/tools.test.ts +73 -0
  436. package/oh-my-opencode/src/tools/look-at/tools.ts +173 -0
  437. package/oh-my-opencode/src/tools/look-at/types.ts +4 -0
  438. package/oh-my-opencode/src/tools/lsp/client.ts +596 -0
  439. package/oh-my-opencode/src/tools/lsp/config.test.ts +130 -0
  440. package/oh-my-opencode/src/tools/lsp/config.ts +285 -0
  441. package/oh-my-opencode/src/tools/lsp/constants.ts +390 -0
  442. package/oh-my-opencode/src/tools/lsp/index.ts +7 -0
  443. package/oh-my-opencode/src/tools/lsp/tools.ts +261 -0
  444. package/oh-my-opencode/src/tools/lsp/types.ts +124 -0
  445. package/oh-my-opencode/src/tools/lsp/utils.ts +406 -0
  446. package/oh-my-opencode/src/tools/session-manager/constants.ts +97 -0
  447. package/oh-my-opencode/src/tools/session-manager/index.ts +3 -0
  448. package/oh-my-opencode/src/tools/session-manager/storage.test.ts +315 -0
  449. package/oh-my-opencode/src/tools/session-manager/storage.ts +238 -0
  450. package/oh-my-opencode/src/tools/session-manager/tools.test.ts +124 -0
  451. package/oh-my-opencode/src/tools/session-manager/tools.ts +146 -0
  452. package/oh-my-opencode/src/tools/session-manager/types.ts +99 -0
  453. package/oh-my-opencode/src/tools/session-manager/utils.test.ts +160 -0
  454. package/oh-my-opencode/src/tools/session-manager/utils.ts +199 -0
  455. package/oh-my-opencode/src/tools/skill/constants.ts +8 -0
  456. package/oh-my-opencode/src/tools/skill/index.ts +3 -0
  457. package/oh-my-opencode/src/tools/skill/tools.test.ts +239 -0
  458. package/oh-my-opencode/src/tools/skill/tools.ts +200 -0
  459. package/oh-my-opencode/src/tools/skill/types.ts +31 -0
  460. package/oh-my-opencode/src/tools/skill-mcp/constants.ts +3 -0
  461. package/oh-my-opencode/src/tools/skill-mcp/index.ts +3 -0
  462. package/oh-my-opencode/src/tools/skill-mcp/tools.test.ts +215 -0
  463. package/oh-my-opencode/src/tools/skill-mcp/tools.ts +172 -0
  464. package/oh-my-opencode/src/tools/skill-mcp/types.ts +8 -0
  465. package/oh-my-opencode/src/tools/slashcommand/index.ts +2 -0
  466. package/oh-my-opencode/src/tools/slashcommand/tools.ts +252 -0
  467. package/oh-my-opencode/src/tools/slashcommand/types.ts +28 -0
  468. package/oh-my-opencode/test-setup.ts +6 -0
  469. package/oh-my-opencode/tsconfig.json +20 -0
  470. package/package.json +1 -1
  471. package/src/__tests__/git.test.ts +7 -2
  472. package/src/__tests__/manifest.test.ts +5 -5
  473. package/src/agents/repo-explorer.ts +2 -1
  474. package/src/git.ts +18 -3
  475. package/src/manifest.ts +22 -15
@@ -0,0 +1,252 @@
1
+ import { join } from "path"
2
+ import { mkdirSync, appendFileSync, existsSync, writeFileSync, unlinkSync } from "fs"
3
+ import { tmpdir } from "os"
4
+ import { randomUUID } from "crypto"
5
+ import type { TranscriptEntry } from "./types"
6
+ import { transformToolName } from "../../shared/tool-name"
7
+ import { getClaudeConfigDir } from "../../shared"
8
+
9
+ const TRANSCRIPT_DIR = join(getClaudeConfigDir(), "transcripts")
10
+
11
+ export function getTranscriptPath(sessionId: string): string {
12
+ return join(TRANSCRIPT_DIR, `${sessionId}.jsonl`)
13
+ }
14
+
15
+ function ensureTranscriptDir(): void {
16
+ if (!existsSync(TRANSCRIPT_DIR)) {
17
+ mkdirSync(TRANSCRIPT_DIR, { recursive: true })
18
+ }
19
+ }
20
+
21
+ export function appendTranscriptEntry(
22
+ sessionId: string,
23
+ entry: TranscriptEntry
24
+ ): void {
25
+ ensureTranscriptDir()
26
+ const path = getTranscriptPath(sessionId)
27
+ const line = JSON.stringify(entry) + "\n"
28
+ appendFileSync(path, line)
29
+ }
30
+
31
+ export function recordToolUse(
32
+ sessionId: string,
33
+ toolName: string,
34
+ toolInput: Record<string, unknown>
35
+ ): void {
36
+ appendTranscriptEntry(sessionId, {
37
+ type: "tool_use",
38
+ timestamp: new Date().toISOString(),
39
+ tool_name: toolName,
40
+ tool_input: toolInput,
41
+ })
42
+ }
43
+
44
+ export function recordToolResult(
45
+ sessionId: string,
46
+ toolName: string,
47
+ toolInput: Record<string, unknown>,
48
+ toolOutput: Record<string, unknown>
49
+ ): void {
50
+ appendTranscriptEntry(sessionId, {
51
+ type: "tool_result",
52
+ timestamp: new Date().toISOString(),
53
+ tool_name: toolName,
54
+ tool_input: toolInput,
55
+ tool_output: toolOutput,
56
+ })
57
+ }
58
+
59
+ export function recordUserMessage(
60
+ sessionId: string,
61
+ content: string
62
+ ): void {
63
+ appendTranscriptEntry(sessionId, {
64
+ type: "user",
65
+ timestamp: new Date().toISOString(),
66
+ content,
67
+ })
68
+ }
69
+
70
+ export function recordAssistantMessage(
71
+ sessionId: string,
72
+ content: string
73
+ ): void {
74
+ appendTranscriptEntry(sessionId, {
75
+ type: "assistant",
76
+ timestamp: new Date().toISOString(),
77
+ content,
78
+ })
79
+ }
80
+
81
+ // ============================================================================
82
+ // Claude Code Compatible Transcript Builder (PORT FROM DISABLED)
83
+ // ============================================================================
84
+
85
+ /**
86
+ * OpenCode API response type (loosely typed)
87
+ */
88
+ interface OpenCodeMessagePart {
89
+ type: string
90
+ tool?: string
91
+ state?: {
92
+ status?: string
93
+ input?: Record<string, unknown>
94
+ }
95
+ }
96
+
97
+ interface OpenCodeMessage {
98
+ info?: {
99
+ role?: string
100
+ }
101
+ parts?: OpenCodeMessagePart[]
102
+ }
103
+
104
+ /**
105
+ * Claude Code compatible transcript entry (from disabled file)
106
+ */
107
+ interface DisabledTranscriptEntry {
108
+ type: "assistant"
109
+ message: {
110
+ role: "assistant"
111
+ content: Array<{
112
+ type: "tool_use"
113
+ name: string
114
+ input: Record<string, unknown>
115
+ }>
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Build Claude Code compatible transcript from session messages
121
+ *
122
+ * PORT FROM DISABLED: This calls client.session.messages() API to fetch
123
+ * the full session history and builds a JSONL file in Claude Code format.
124
+ *
125
+ * @param client OpenCode client instance
126
+ * @param sessionId Session ID
127
+ * @param directory Working directory
128
+ * @param currentToolName Current tool being executed (added as last entry)
129
+ * @param currentToolInput Current tool input
130
+ * @returns Temp file path (caller must call deleteTempTranscript!)
131
+ */
132
+ export async function buildTranscriptFromSession(
133
+ client: {
134
+ session: {
135
+ messages: (opts: { path: { id: string }; query?: { directory: string } }) => Promise<unknown>
136
+ }
137
+ },
138
+ sessionId: string,
139
+ directory: string,
140
+ currentToolName: string,
141
+ currentToolInput: Record<string, unknown>
142
+ ): Promise<string | null> {
143
+ try {
144
+ const response = await client.session.messages({
145
+ path: { id: sessionId },
146
+ query: { directory },
147
+ })
148
+
149
+ // Handle various response formats
150
+ const messages = (response as { "200"?: unknown[]; data?: unknown[] })["200"]
151
+ ?? (response as { data?: unknown[] }).data
152
+ ?? (Array.isArray(response) ? response : [])
153
+
154
+ const entries: string[] = []
155
+
156
+ if (Array.isArray(messages)) {
157
+ for (const msg of messages as OpenCodeMessage[]) {
158
+ if (msg.info?.role !== "assistant") continue
159
+
160
+ for (const part of msg.parts || []) {
161
+ if (part.type !== "tool") continue
162
+ if (part.state?.status !== "completed") continue
163
+ if (!part.state?.input) continue
164
+
165
+ const rawToolName = part.tool as string
166
+ const toolName = transformToolName(rawToolName)
167
+
168
+ const entry: DisabledTranscriptEntry = {
169
+ type: "assistant",
170
+ message: {
171
+ role: "assistant",
172
+ content: [
173
+ {
174
+ type: "tool_use",
175
+ name: toolName,
176
+ input: part.state.input,
177
+ },
178
+ ],
179
+ },
180
+ }
181
+ entries.push(JSON.stringify(entry))
182
+ }
183
+ }
184
+ }
185
+
186
+ // Always add current tool call as the last entry
187
+ const currentEntry: DisabledTranscriptEntry = {
188
+ type: "assistant",
189
+ message: {
190
+ role: "assistant",
191
+ content: [
192
+ {
193
+ type: "tool_use",
194
+ name: transformToolName(currentToolName),
195
+ input: currentToolInput,
196
+ },
197
+ ],
198
+ },
199
+ }
200
+ entries.push(JSON.stringify(currentEntry))
201
+
202
+ // Write to temp file
203
+ const tempPath = join(
204
+ tmpdir(),
205
+ `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`
206
+ )
207
+ writeFileSync(tempPath, entries.join("\n") + "\n")
208
+
209
+ return tempPath
210
+ } catch {
211
+ // CRITICAL FIX: Even on API failure, create file with current tool entry only
212
+ // (matching original disabled behavior - never return null with incompatible format)
213
+ try {
214
+ const currentEntry: DisabledTranscriptEntry = {
215
+ type: "assistant",
216
+ message: {
217
+ role: "assistant",
218
+ content: [
219
+ {
220
+ type: "tool_use",
221
+ name: transformToolName(currentToolName),
222
+ input: currentToolInput,
223
+ },
224
+ ],
225
+ },
226
+ }
227
+ const tempPath = join(
228
+ tmpdir(),
229
+ `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`
230
+ )
231
+ writeFileSync(tempPath, JSON.stringify(currentEntry) + "\n")
232
+ return tempPath
233
+ } catch {
234
+ // If even this fails, return null (truly catastrophic failure)
235
+ return null
236
+ }
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Delete temp transcript file (call in finally block)
242
+ *
243
+ * PORT FROM DISABLED: Cleanup mechanism to avoid disk accumulation
244
+ */
245
+ export function deleteTempTranscript(path: string | null): void {
246
+ if (!path) return
247
+ try {
248
+ unlinkSync(path)
249
+ } catch {
250
+ // Ignore deletion errors
251
+ }
252
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Claude Code Hooks Type Definitions
3
+ * Maps Claude Code hook concepts to OpenCode plugin events
4
+ */
5
+
6
+ export type ClaudeHookEvent =
7
+ | "PreToolUse"
8
+ | "PostToolUse"
9
+ | "UserPromptSubmit"
10
+ | "Stop"
11
+ | "PreCompact"
12
+
13
+ export interface HookMatcher {
14
+ matcher: string
15
+ hooks: HookCommand[]
16
+ }
17
+
18
+ export interface HookCommand {
19
+ type: "command"
20
+ command: string
21
+ }
22
+
23
+ export interface ClaudeHooksConfig {
24
+ PreToolUse?: HookMatcher[]
25
+ PostToolUse?: HookMatcher[]
26
+ UserPromptSubmit?: HookMatcher[]
27
+ Stop?: HookMatcher[]
28
+ PreCompact?: HookMatcher[]
29
+ }
30
+
31
+ export interface PreToolUseInput {
32
+ session_id: string
33
+ transcript_path?: string
34
+ cwd: string
35
+ permission_mode?: PermissionMode
36
+ hook_event_name: "PreToolUse"
37
+ tool_name: string
38
+ tool_input: Record<string, unknown>
39
+ tool_use_id?: string
40
+ hook_source?: HookSource
41
+ }
42
+
43
+ export interface PostToolUseInput {
44
+ session_id: string
45
+ transcript_path?: string
46
+ cwd: string
47
+ permission_mode?: PermissionMode
48
+ hook_event_name: "PostToolUse"
49
+ tool_name: string
50
+ tool_input: Record<string, unknown>
51
+ tool_response: {
52
+ title?: string
53
+ output?: string
54
+ [key: string]: unknown
55
+ }
56
+ tool_use_id?: string
57
+ hook_source?: HookSource
58
+ }
59
+
60
+ export interface UserPromptSubmitInput {
61
+ session_id: string
62
+ cwd: string
63
+ permission_mode?: PermissionMode
64
+ hook_event_name: "UserPromptSubmit"
65
+ prompt: string
66
+ session?: {
67
+ id: string
68
+ }
69
+ hook_source?: HookSource
70
+ }
71
+
72
+ export type PermissionMode = "default" | "plan" | "acceptEdits" | "bypassPermissions"
73
+
74
+ export type HookSource = "opencode-plugin"
75
+
76
+ export interface StopInput {
77
+ session_id: string
78
+ transcript_path?: string
79
+ cwd: string
80
+ permission_mode?: PermissionMode
81
+ hook_event_name: "Stop"
82
+ stop_hook_active: boolean
83
+ todo_path?: string
84
+ hook_source?: HookSource
85
+ }
86
+
87
+ export interface PreCompactInput {
88
+ session_id: string
89
+ cwd: string
90
+ hook_event_name: "PreCompact"
91
+ hook_source?: HookSource
92
+ }
93
+
94
+ export type PermissionDecision = "allow" | "deny" | "ask"
95
+
96
+ /**
97
+ * Common JSON fields for all hook outputs (Claude Code spec)
98
+ */
99
+ export interface HookCommonOutput {
100
+ /** If false, Claude stops entirely */
101
+ continue?: boolean
102
+ /** Message shown to user when continue=false */
103
+ stopReason?: string
104
+ /** Suppress output from transcript */
105
+ suppressOutput?: boolean
106
+ /** Warning/message displayed to user */
107
+ systemMessage?: string
108
+ }
109
+
110
+ export interface PreToolUseOutput extends HookCommonOutput {
111
+ /** Deprecated: use hookSpecificOutput.permissionDecision instead */
112
+ decision?: "allow" | "deny" | "approve" | "block" | "ask"
113
+ /** Deprecated: use hookSpecificOutput.permissionDecisionReason instead */
114
+ reason?: string
115
+ hookSpecificOutput?: {
116
+ hookEventName: "PreToolUse"
117
+ permissionDecision: PermissionDecision
118
+ permissionDecisionReason?: string
119
+ updatedInput?: Record<string, unknown>
120
+ }
121
+ }
122
+
123
+ export interface PostToolUseOutput extends HookCommonOutput {
124
+ decision?: "block"
125
+ reason?: string
126
+ hookSpecificOutput?: {
127
+ hookEventName: "PostToolUse"
128
+ /** Additional context to provide to Claude */
129
+ additionalContext?: string
130
+ }
131
+ }
132
+
133
+ export interface HookResult {
134
+ exitCode: number
135
+ stdout?: string
136
+ stderr?: string
137
+ }
138
+
139
+ export interface TranscriptEntry {
140
+ type: "tool_use" | "tool_result" | "user" | "assistant"
141
+ timestamp: string
142
+ tool_name?: string
143
+ tool_input?: Record<string, unknown>
144
+ tool_output?: Record<string, unknown>
145
+ content?: string
146
+ }
147
+
148
+ export interface TodoItem {
149
+ id: string
150
+ content: string
151
+ status: "pending" | "in_progress" | "completed" | "cancelled"
152
+ priority?: "low" | "medium" | "high"
153
+ created_at: string
154
+ updated_at?: string
155
+ }
156
+
157
+ export interface ClaudeCodeTodoItem {
158
+ content: string
159
+ status: string // "pending" | "in_progress" | "completed"
160
+ activeForm: string
161
+ }
162
+
163
+ export interface TodoFile {
164
+ session_id: string
165
+ items: TodoItem[]
166
+ created_at: string
167
+ updated_at: string
168
+ }
169
+
170
+ export interface StopOutput {
171
+ decision?: "block" | "continue"
172
+ reason?: string
173
+ stop_hook_active?: boolean
174
+ permission_mode?: PermissionMode
175
+ inject_prompt?: string
176
+ }
177
+
178
+ export interface PreCompactOutput extends HookCommonOutput {
179
+ /** Additional context to inject into compaction prompt */
180
+ context?: string[]
181
+ hookSpecificOutput?: {
182
+ hookEventName: "PreCompact"
183
+ /** Additional context strings to inject */
184
+ additionalContext?: string[]
185
+ }
186
+ }
187
+
188
+ export type ClaudeCodeContent =
189
+ | { type: "text"; text: string }
190
+ | { type: "tool_use"; id: string; name: string; input: Record<string, unknown> }
191
+ | { type: "tool_result"; tool_use_id: string; content: string }
192
+
193
+ export interface ClaudeCodeMessage {
194
+ type: "user" | "assistant"
195
+ message: {
196
+ role: "user" | "assistant"
197
+ content: ClaudeCodeContent[]
198
+ }
199
+ }
200
+
201
+ export interface PluginConfig {
202
+ disabledHooks?: boolean | ClaudeHookEvent[]
203
+ keywordDetectorDisabled?: boolean
204
+ }
@@ -0,0 +1,117 @@
1
+ import type {
2
+ UserPromptSubmitInput,
3
+ PostToolUseOutput,
4
+ ClaudeHooksConfig,
5
+ } from "./types"
6
+ import { findMatchingHooks, executeHookCommand, log } from "../../shared"
7
+ import { DEFAULT_CONFIG } from "./plugin-config"
8
+ import { isHookCommandDisabled, type PluginExtendedConfig } from "./config-loader"
9
+
10
+ const USER_PROMPT_SUBMIT_TAG_OPEN = "<user-prompt-submit-hook>"
11
+ const USER_PROMPT_SUBMIT_TAG_CLOSE = "</user-prompt-submit-hook>"
12
+
13
+ export interface MessagePart {
14
+ type: "text" | "tool_use" | "tool_result"
15
+ text?: string
16
+ [key: string]: unknown
17
+ }
18
+
19
+ export interface UserPromptSubmitContext {
20
+ sessionId: string
21
+ parentSessionId?: string
22
+ prompt: string
23
+ parts: MessagePart[]
24
+ cwd: string
25
+ permissionMode?: "default" | "acceptEdits" | "bypassPermissions"
26
+ }
27
+
28
+ export interface UserPromptSubmitResult {
29
+ block: boolean
30
+ reason?: string
31
+ modifiedParts: MessagePart[]
32
+ messages: string[]
33
+ }
34
+
35
+ export async function executeUserPromptSubmitHooks(
36
+ ctx: UserPromptSubmitContext,
37
+ config: ClaudeHooksConfig | null,
38
+ extendedConfig?: PluginExtendedConfig | null
39
+ ): Promise<UserPromptSubmitResult> {
40
+ const modifiedParts = ctx.parts
41
+ const messages: string[] = []
42
+
43
+ if (ctx.parentSessionId) {
44
+ return { block: false, modifiedParts, messages }
45
+ }
46
+
47
+ if (
48
+ ctx.prompt.includes(USER_PROMPT_SUBMIT_TAG_OPEN) &&
49
+ ctx.prompt.includes(USER_PROMPT_SUBMIT_TAG_CLOSE)
50
+ ) {
51
+ return { block: false, modifiedParts, messages }
52
+ }
53
+
54
+ if (!config) {
55
+ return { block: false, modifiedParts, messages }
56
+ }
57
+
58
+ const matchers = findMatchingHooks(config, "UserPromptSubmit")
59
+ if (matchers.length === 0) {
60
+ return { block: false, modifiedParts, messages }
61
+ }
62
+
63
+ const stdinData: UserPromptSubmitInput = {
64
+ session_id: ctx.sessionId,
65
+ cwd: ctx.cwd,
66
+ permission_mode: ctx.permissionMode ?? "bypassPermissions",
67
+ hook_event_name: "UserPromptSubmit",
68
+ prompt: ctx.prompt,
69
+ session: { id: ctx.sessionId },
70
+ hook_source: "opencode-plugin",
71
+ }
72
+
73
+ for (const matcher of matchers) {
74
+ for (const hook of matcher.hooks) {
75
+ if (hook.type !== "command") continue
76
+
77
+ if (isHookCommandDisabled("UserPromptSubmit", hook.command, extendedConfig ?? null)) {
78
+ log("UserPromptSubmit hook command skipped (disabled by config)", { command: hook.command })
79
+ continue
80
+ }
81
+
82
+ const result = await executeHookCommand(
83
+ hook.command,
84
+ JSON.stringify(stdinData),
85
+ ctx.cwd,
86
+ { forceZsh: DEFAULT_CONFIG.forceZsh, zshPath: DEFAULT_CONFIG.zshPath }
87
+ )
88
+
89
+ if (result.stdout) {
90
+ const output = result.stdout.trim()
91
+ if (output.startsWith(USER_PROMPT_SUBMIT_TAG_OPEN)) {
92
+ messages.push(output)
93
+ } else {
94
+ messages.push(`${USER_PROMPT_SUBMIT_TAG_OPEN}\n${output}\n${USER_PROMPT_SUBMIT_TAG_CLOSE}`)
95
+ }
96
+ }
97
+
98
+ if (result.exitCode !== 0) {
99
+ try {
100
+ const output = JSON.parse(result.stdout || "{}") as PostToolUseOutput
101
+ if (output.decision === "block") {
102
+ return {
103
+ block: true,
104
+ reason: output.reason || result.stderr,
105
+ modifiedParts,
106
+ messages,
107
+ }
108
+ }
109
+ } catch {
110
+ // Ignore JSON parse errors
111
+ }
112
+ }
113
+ }
114
+ }
115
+
116
+ return { block: false, modifiedParts, messages }
117
+ }
@@ -0,0 +1,68 @@
1
+ import { describe, test, expect, beforeEach, mock } from "bun:test"
2
+
3
+ describe("comment-checker CLI path resolution", () => {
4
+ describe("lazy initialization", () => {
5
+ // #given module is imported
6
+ // #when COMMENT_CHECKER_CLI_PATH is accessed
7
+ // #then findCommentCheckerPathSync should NOT have been called during import
8
+
9
+ test("getCommentCheckerPathSync should be lazy - not called on module import", async () => {
10
+ // #given a fresh module import
11
+ // We need to verify that importing the module doesn't immediately call findCommentCheckerPathSync
12
+
13
+ // #when we import the module
14
+ const cliModule = await import("./cli")
15
+
16
+ // #then getCommentCheckerPathSync should exist and be callable
17
+ expect(typeof cliModule.getCommentCheckerPathSync).toBe("function")
18
+
19
+ // The key test: calling getCommentCheckerPathSync should work
20
+ // (we can't easily test that it wasn't called on import without mocking,
21
+ // but we can verify the function exists and returns expected types)
22
+ const result = cliModule.getCommentCheckerPathSync()
23
+ expect(result === null || typeof result === "string").toBe(true)
24
+ })
25
+
26
+ test("getCommentCheckerPathSync should cache result after first call", async () => {
27
+ // #given getCommentCheckerPathSync is called once
28
+ const cliModule = await import("./cli")
29
+ const firstResult = cliModule.getCommentCheckerPathSync()
30
+
31
+ // #when called again
32
+ const secondResult = cliModule.getCommentCheckerPathSync()
33
+
34
+ // #then should return same cached result
35
+ expect(secondResult).toBe(firstResult)
36
+ })
37
+
38
+ test("COMMENT_CHECKER_CLI_PATH export should not exist (removed for lazy loading)", async () => {
39
+ // #given the cli module
40
+ const cliModule = await import("./cli")
41
+
42
+ // #when checking for COMMENT_CHECKER_CLI_PATH
43
+ // #then it should not exist (replaced with lazy getter)
44
+ expect("COMMENT_CHECKER_CLI_PATH" in cliModule).toBe(false)
45
+ })
46
+ })
47
+
48
+ describe("runCommentChecker", () => {
49
+ test("should use getCommentCheckerPathSync for fallback path resolution", async () => {
50
+ // #given runCommentChecker is called without explicit path
51
+ const { runCommentChecker } = await import("./cli")
52
+
53
+ // #when called with input containing no comments
54
+ const result = await runCommentChecker({
55
+ session_id: "test",
56
+ tool_name: "Write",
57
+ transcript_path: "",
58
+ cwd: "/tmp",
59
+ hook_event_name: "PostToolUse",
60
+ tool_input: { file_path: "/tmp/test.ts", content: "const x = 1" },
61
+ })
62
+
63
+ // #then should return CheckResult type (binary may or may not exist)
64
+ expect(typeof result.hasComments).toBe("boolean")
65
+ expect(typeof result.message).toBe("string")
66
+ })
67
+ })
68
+ })