opencode-repos 0.3.0 → 0.3.2

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/index.ts +25 -11
  2. package/package.json +27 -27
  3. package/src/__tests__/git.test.ts +33 -2
  4. package/src/git.ts +32 -5
  5. package/.sisyphus/boulder.json +0 -8
  6. package/.sisyphus/notepads/opencode-repos/decisions.md +0 -15
  7. package/.sisyphus/notepads/opencode-repos/learnings.md +0 -384
  8. package/.sisyphus/plans/opencode-repos.md +0 -987
  9. package/.tmux-sessionizer +0 -8
  10. package/TODO.md +0 -3
  11. package/oh-my-opencode/.github/FUNDING.yml +0 -15
  12. package/oh-my-opencode/.github/ISSUE_TEMPLATE/bug_report.yml +0 -129
  13. package/oh-my-opencode/.github/ISSUE_TEMPLATE/config.yml +0 -8
  14. package/oh-my-opencode/.github/ISSUE_TEMPLATE/feature_request.yml +0 -100
  15. package/oh-my-opencode/.github/ISSUE_TEMPLATE/general.yml +0 -83
  16. package/oh-my-opencode/.github/assets/google.jpg +0 -0
  17. package/oh-my-opencode/.github/assets/hero.jpg +0 -0
  18. package/oh-my-opencode/.github/assets/indent.jpg +0 -0
  19. package/oh-my-opencode/.github/assets/microsoft.jpg +0 -0
  20. package/oh-my-opencode/.github/assets/omo.png +0 -0
  21. package/oh-my-opencode/.github/assets/orchestrator-atlas.png +0 -0
  22. package/oh-my-opencode/.github/assets/sisyphus.png +0 -0
  23. package/oh-my-opencode/.github/assets/sisyphuslabs.png +0 -0
  24. package/oh-my-opencode/.github/pull_request_template.md +0 -34
  25. package/oh-my-opencode/.github/workflows/ci.yml +0 -138
  26. package/oh-my-opencode/.github/workflows/cla.yml +0 -41
  27. package/oh-my-opencode/.github/workflows/lint-workflows.yml +0 -22
  28. package/oh-my-opencode/.github/workflows/publish.yml +0 -165
  29. package/oh-my-opencode/.github/workflows/sisyphus-agent.yml +0 -500
  30. package/oh-my-opencode/.opencode/background-tasks.json +0 -27
  31. package/oh-my-opencode/.opencode/command/get-unpublished-changes.md +0 -84
  32. package/oh-my-opencode/.opencode/command/omomomo.md +0 -37
  33. package/oh-my-opencode/.opencode/command/publish.md +0 -257
  34. package/oh-my-opencode/AGENTS.md +0 -179
  35. package/oh-my-opencode/CLA.md +0 -58
  36. package/oh-my-opencode/CONTRIBUTING.md +0 -268
  37. package/oh-my-opencode/LICENSE.md +0 -82
  38. package/oh-my-opencode/README.ja.md +0 -370
  39. package/oh-my-opencode/README.md +0 -376
  40. package/oh-my-opencode/README.zh-cn.md +0 -380
  41. package/oh-my-opencode/assets/oh-my-opencode.schema.json +0 -2171
  42. package/oh-my-opencode/bin/oh-my-opencode.js +0 -80
  43. package/oh-my-opencode/bin/platform.js +0 -38
  44. package/oh-my-opencode/bin/platform.test.ts +0 -148
  45. package/oh-my-opencode/bun.lock +0 -314
  46. package/oh-my-opencode/bunfig.toml +0 -2
  47. package/oh-my-opencode/docs/category-skill-guide.md +0 -200
  48. package/oh-my-opencode/docs/cli-guide.md +0 -272
  49. package/oh-my-opencode/docs/configurations.md +0 -654
  50. package/oh-my-opencode/docs/features.md +0 -550
  51. package/oh-my-opencode/docs/guide/installation.md +0 -288
  52. package/oh-my-opencode/docs/guide/overview.md +0 -97
  53. package/oh-my-opencode/docs/guide/understanding-orchestration-system.md +0 -445
  54. package/oh-my-opencode/docs/orchestration-guide.md +0 -152
  55. package/oh-my-opencode/docs/ultrawork-manifesto.md +0 -197
  56. package/oh-my-opencode/package.json +0 -89
  57. package/oh-my-opencode/packages/darwin-arm64/bin/.gitkeep +0 -0
  58. package/oh-my-opencode/packages/darwin-arm64/package.json +0 -22
  59. package/oh-my-opencode/packages/darwin-x64/bin/.gitkeep +0 -0
  60. package/oh-my-opencode/packages/darwin-x64/package.json +0 -22
  61. package/oh-my-opencode/packages/linux-arm64/bin/.gitkeep +0 -0
  62. package/oh-my-opencode/packages/linux-arm64/package.json +0 -25
  63. package/oh-my-opencode/packages/linux-arm64-musl/bin/.gitkeep +0 -0
  64. package/oh-my-opencode/packages/linux-arm64-musl/package.json +0 -25
  65. package/oh-my-opencode/packages/linux-x64/bin/.gitkeep +0 -0
  66. package/oh-my-opencode/packages/linux-x64/package.json +0 -25
  67. package/oh-my-opencode/packages/linux-x64-musl/bin/.gitkeep +0 -0
  68. package/oh-my-opencode/packages/linux-x64-musl/package.json +0 -25
  69. package/oh-my-opencode/packages/windows-x64/bin/.gitkeep +0 -0
  70. package/oh-my-opencode/packages/windows-x64/package.json +0 -22
  71. package/oh-my-opencode/postinstall.mjs +0 -43
  72. package/oh-my-opencode/script/build-binaries.ts +0 -103
  73. package/oh-my-opencode/script/build-schema.ts +0 -28
  74. package/oh-my-opencode/script/generate-changelog.ts +0 -92
  75. package/oh-my-opencode/script/publish.ts +0 -344
  76. package/oh-my-opencode/signatures/cla.json +0 -676
  77. package/oh-my-opencode/src/agents/AGENTS.md +0 -67
  78. package/oh-my-opencode/src/agents/atlas.ts +0 -1383
  79. package/oh-my-opencode/src/agents/dynamic-agent-prompt-builder.ts +0 -400
  80. package/oh-my-opencode/src/agents/explore.ts +0 -122
  81. package/oh-my-opencode/src/agents/index.ts +0 -13
  82. package/oh-my-opencode/src/agents/librarian.ts +0 -326
  83. package/oh-my-opencode/src/agents/metis.ts +0 -315
  84. package/oh-my-opencode/src/agents/momus.test.ts +0 -57
  85. package/oh-my-opencode/src/agents/momus.ts +0 -444
  86. package/oh-my-opencode/src/agents/multimodal-looker.ts +0 -56
  87. package/oh-my-opencode/src/agents/oracle.ts +0 -122
  88. package/oh-my-opencode/src/agents/prometheus-prompt.test.ts +0 -22
  89. package/oh-my-opencode/src/agents/prometheus-prompt.ts +0 -1196
  90. package/oh-my-opencode/src/agents/sisyphus-junior.test.ts +0 -232
  91. package/oh-my-opencode/src/agents/sisyphus-junior.ts +0 -134
  92. package/oh-my-opencode/src/agents/sisyphus.ts +0 -633
  93. package/oh-my-opencode/src/agents/types.ts +0 -80
  94. package/oh-my-opencode/src/agents/utils.test.ts +0 -311
  95. package/oh-my-opencode/src/agents/utils.ts +0 -240
  96. package/oh-my-opencode/src/cli/AGENTS.md +0 -91
  97. package/oh-my-opencode/src/cli/config-manager.test.ts +0 -364
  98. package/oh-my-opencode/src/cli/config-manager.ts +0 -641
  99. package/oh-my-opencode/src/cli/doctor/checks/auth.test.ts +0 -114
  100. package/oh-my-opencode/src/cli/doctor/checks/auth.ts +0 -115
  101. package/oh-my-opencode/src/cli/doctor/checks/config.test.ts +0 -103
  102. package/oh-my-opencode/src/cli/doctor/checks/config.ts +0 -123
  103. package/oh-my-opencode/src/cli/doctor/checks/dependencies.test.ts +0 -152
  104. package/oh-my-opencode/src/cli/doctor/checks/dependencies.ts +0 -163
  105. package/oh-my-opencode/src/cli/doctor/checks/gh.test.ts +0 -151
  106. package/oh-my-opencode/src/cli/doctor/checks/gh.ts +0 -171
  107. package/oh-my-opencode/src/cli/doctor/checks/index.ts +0 -34
  108. package/oh-my-opencode/src/cli/doctor/checks/lsp.test.ts +0 -134
  109. package/oh-my-opencode/src/cli/doctor/checks/lsp.ts +0 -77
  110. package/oh-my-opencode/src/cli/doctor/checks/mcp.test.ts +0 -115
  111. package/oh-my-opencode/src/cli/doctor/checks/mcp.ts +0 -128
  112. package/oh-my-opencode/src/cli/doctor/checks/opencode.test.ts +0 -227
  113. package/oh-my-opencode/src/cli/doctor/checks/opencode.ts +0 -178
  114. package/oh-my-opencode/src/cli/doctor/checks/plugin.test.ts +0 -109
  115. package/oh-my-opencode/src/cli/doctor/checks/plugin.ts +0 -124
  116. package/oh-my-opencode/src/cli/doctor/checks/version.test.ts +0 -148
  117. package/oh-my-opencode/src/cli/doctor/checks/version.ts +0 -135
  118. package/oh-my-opencode/src/cli/doctor/constants.ts +0 -72
  119. package/oh-my-opencode/src/cli/doctor/formatter.test.ts +0 -218
  120. package/oh-my-opencode/src/cli/doctor/formatter.ts +0 -140
  121. package/oh-my-opencode/src/cli/doctor/index.ts +0 -11
  122. package/oh-my-opencode/src/cli/doctor/runner.test.ts +0 -153
  123. package/oh-my-opencode/src/cli/doctor/runner.ts +0 -132
  124. package/oh-my-opencode/src/cli/doctor/types.ts +0 -113
  125. package/oh-my-opencode/src/cli/get-local-version/formatter.ts +0 -66
  126. package/oh-my-opencode/src/cli/get-local-version/index.ts +0 -106
  127. package/oh-my-opencode/src/cli/get-local-version/types.ts +0 -14
  128. package/oh-my-opencode/src/cli/index.ts +0 -153
  129. package/oh-my-opencode/src/cli/install.ts +0 -523
  130. package/oh-my-opencode/src/cli/model-fallback.ts +0 -246
  131. package/oh-my-opencode/src/cli/run/completion.test.ts +0 -170
  132. package/oh-my-opencode/src/cli/run/completion.ts +0 -79
  133. package/oh-my-opencode/src/cli/run/events.test.ts +0 -155
  134. package/oh-my-opencode/src/cli/run/events.ts +0 -325
  135. package/oh-my-opencode/src/cli/run/index.ts +0 -2
  136. package/oh-my-opencode/src/cli/run/runner.ts +0 -159
  137. package/oh-my-opencode/src/cli/run/types.ts +0 -76
  138. package/oh-my-opencode/src/cli/types.ts +0 -40
  139. package/oh-my-opencode/src/config/index.ts +0 -26
  140. package/oh-my-opencode/src/config/schema.test.ts +0 -444
  141. package/oh-my-opencode/src/config/schema.ts +0 -339
  142. package/oh-my-opencode/src/features/AGENTS.md +0 -77
  143. package/oh-my-opencode/src/features/background-agent/concurrency.test.ts +0 -418
  144. package/oh-my-opencode/src/features/background-agent/concurrency.ts +0 -137
  145. package/oh-my-opencode/src/features/background-agent/index.ts +0 -3
  146. package/oh-my-opencode/src/features/background-agent/manager.test.ts +0 -1928
  147. package/oh-my-opencode/src/features/background-agent/manager.ts +0 -1335
  148. package/oh-my-opencode/src/features/background-agent/types.ts +0 -66
  149. package/oh-my-opencode/src/features/boulder-state/constants.ts +0 -13
  150. package/oh-my-opencode/src/features/boulder-state/index.ts +0 -3
  151. package/oh-my-opencode/src/features/boulder-state/storage.test.ts +0 -250
  152. package/oh-my-opencode/src/features/boulder-state/storage.ts +0 -150
  153. package/oh-my-opencode/src/features/boulder-state/types.ts +0 -26
  154. package/oh-my-opencode/src/features/builtin-commands/commands.ts +0 -89
  155. package/oh-my-opencode/src/features/builtin-commands/index.ts +0 -2
  156. package/oh-my-opencode/src/features/builtin-commands/templates/init-deep.ts +0 -300
  157. package/oh-my-opencode/src/features/builtin-commands/templates/ralph-loop.ts +0 -38
  158. package/oh-my-opencode/src/features/builtin-commands/templates/refactor.ts +0 -619
  159. package/oh-my-opencode/src/features/builtin-commands/templates/start-work.ts +0 -72
  160. package/oh-my-opencode/src/features/builtin-commands/types.ts +0 -9
  161. package/oh-my-opencode/src/features/builtin-skills/frontend-ui-ux/SKILL.md +0 -78
  162. package/oh-my-opencode/src/features/builtin-skills/git-master/SKILL.md +0 -1105
  163. package/oh-my-opencode/src/features/builtin-skills/index.ts +0 -2
  164. package/oh-my-opencode/src/features/builtin-skills/skills.ts +0 -1203
  165. package/oh-my-opencode/src/features/builtin-skills/types.ts +0 -16
  166. package/oh-my-opencode/src/features/claude-code-agent-loader/index.ts +0 -2
  167. package/oh-my-opencode/src/features/claude-code-agent-loader/loader.ts +0 -90
  168. package/oh-my-opencode/src/features/claude-code-agent-loader/types.ts +0 -17
  169. package/oh-my-opencode/src/features/claude-code-command-loader/index.ts +0 -2
  170. package/oh-my-opencode/src/features/claude-code-command-loader/loader.ts +0 -144
  171. package/oh-my-opencode/src/features/claude-code-command-loader/types.ts +0 -46
  172. package/oh-my-opencode/src/features/claude-code-mcp-loader/env-expander.ts +0 -27
  173. package/oh-my-opencode/src/features/claude-code-mcp-loader/index.ts +0 -11
  174. package/oh-my-opencode/src/features/claude-code-mcp-loader/loader.test.ts +0 -162
  175. package/oh-my-opencode/src/features/claude-code-mcp-loader/loader.ts +0 -113
  176. package/oh-my-opencode/src/features/claude-code-mcp-loader/transformer.ts +0 -53
  177. package/oh-my-opencode/src/features/claude-code-mcp-loader/types.ts +0 -42
  178. package/oh-my-opencode/src/features/claude-code-plugin-loader/index.ts +0 -3
  179. package/oh-my-opencode/src/features/claude-code-plugin-loader/loader.ts +0 -486
  180. package/oh-my-opencode/src/features/claude-code-plugin-loader/types.ts +0 -210
  181. package/oh-my-opencode/src/features/claude-code-session-state/index.ts +0 -1
  182. package/oh-my-opencode/src/features/claude-code-session-state/state.test.ts +0 -126
  183. package/oh-my-opencode/src/features/claude-code-session-state/state.ts +0 -37
  184. package/oh-my-opencode/src/features/context-injector/collector.test.ts +0 -330
  185. package/oh-my-opencode/src/features/context-injector/collector.ts +0 -85
  186. package/oh-my-opencode/src/features/context-injector/index.ts +0 -14
  187. package/oh-my-opencode/src/features/context-injector/injector.test.ts +0 -122
  188. package/oh-my-opencode/src/features/context-injector/injector.ts +0 -167
  189. package/oh-my-opencode/src/features/context-injector/types.ts +0 -91
  190. package/oh-my-opencode/src/features/hook-message-injector/constants.ts +0 -6
  191. package/oh-my-opencode/src/features/hook-message-injector/index.ts +0 -4
  192. package/oh-my-opencode/src/features/hook-message-injector/injector.ts +0 -195
  193. package/oh-my-opencode/src/features/hook-message-injector/types.ts +0 -47
  194. package/oh-my-opencode/src/features/opencode-skill-loader/async-loader.test.ts +0 -448
  195. package/oh-my-opencode/src/features/opencode-skill-loader/async-loader.ts +0 -180
  196. package/oh-my-opencode/src/features/opencode-skill-loader/blocking.test.ts +0 -210
  197. package/oh-my-opencode/src/features/opencode-skill-loader/blocking.ts +0 -62
  198. package/oh-my-opencode/src/features/opencode-skill-loader/discover-worker.ts +0 -59
  199. package/oh-my-opencode/src/features/opencode-skill-loader/index.ts +0 -4
  200. package/oh-my-opencode/src/features/opencode-skill-loader/loader.test.ts +0 -273
  201. package/oh-my-opencode/src/features/opencode-skill-loader/loader.ts +0 -259
  202. package/oh-my-opencode/src/features/opencode-skill-loader/merger.ts +0 -267
  203. package/oh-my-opencode/src/features/opencode-skill-loader/skill-content.test.ts +0 -267
  204. package/oh-my-opencode/src/features/opencode-skill-loader/skill-content.ts +0 -206
  205. package/oh-my-opencode/src/features/opencode-skill-loader/types.ts +0 -38
  206. package/oh-my-opencode/src/features/skill-mcp-manager/env-cleaner.test.ts +0 -201
  207. package/oh-my-opencode/src/features/skill-mcp-manager/env-cleaner.ts +0 -27
  208. package/oh-my-opencode/src/features/skill-mcp-manager/index.ts +0 -2
  209. package/oh-my-opencode/src/features/skill-mcp-manager/manager.test.ts +0 -611
  210. package/oh-my-opencode/src/features/skill-mcp-manager/manager.ts +0 -520
  211. package/oh-my-opencode/src/features/skill-mcp-manager/types.ts +0 -14
  212. package/oh-my-opencode/src/features/task-toast-manager/index.ts +0 -2
  213. package/oh-my-opencode/src/features/task-toast-manager/manager.test.ts +0 -249
  214. package/oh-my-opencode/src/features/task-toast-manager/manager.ts +0 -215
  215. package/oh-my-opencode/src/features/task-toast-manager/types.ts +0 -24
  216. package/oh-my-opencode/src/hooks/AGENTS.md +0 -73
  217. package/oh-my-opencode/src/hooks/agent-usage-reminder/constants.ts +0 -54
  218. package/oh-my-opencode/src/hooks/agent-usage-reminder/index.ts +0 -109
  219. package/oh-my-opencode/src/hooks/agent-usage-reminder/storage.ts +0 -42
  220. package/oh-my-opencode/src/hooks/agent-usage-reminder/types.ts +0 -6
  221. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts +0 -307
  222. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/executor.ts +0 -485
  223. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/index.ts +0 -151
  224. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/parser.ts +0 -201
  225. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts +0 -33
  226. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts +0 -184
  227. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-types.ts +0 -44
  228. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/storage.test.ts +0 -77
  229. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/storage.ts +0 -250
  230. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/types.ts +0 -42
  231. package/oh-my-opencode/src/hooks/atlas/index.test.ts +0 -953
  232. package/oh-my-opencode/src/hooks/atlas/index.ts +0 -771
  233. package/oh-my-opencode/src/hooks/auto-slash-command/constants.ts +0 -12
  234. package/oh-my-opencode/src/hooks/auto-slash-command/detector.test.ts +0 -296
  235. package/oh-my-opencode/src/hooks/auto-slash-command/detector.ts +0 -65
  236. package/oh-my-opencode/src/hooks/auto-slash-command/executor.ts +0 -205
  237. package/oh-my-opencode/src/hooks/auto-slash-command/index.test.ts +0 -254
  238. package/oh-my-opencode/src/hooks/auto-slash-command/index.ts +0 -89
  239. package/oh-my-opencode/src/hooks/auto-slash-command/types.ts +0 -23
  240. package/oh-my-opencode/src/hooks/auto-update-checker/cache.ts +0 -93
  241. package/oh-my-opencode/src/hooks/auto-update-checker/checker.test.ts +0 -24
  242. package/oh-my-opencode/src/hooks/auto-update-checker/checker.ts +0 -284
  243. package/oh-my-opencode/src/hooks/auto-update-checker/constants.ts +0 -64
  244. package/oh-my-opencode/src/hooks/auto-update-checker/index.test.ts +0 -254
  245. package/oh-my-opencode/src/hooks/auto-update-checker/index.ts +0 -260
  246. package/oh-my-opencode/src/hooks/auto-update-checker/types.ts +0 -29
  247. package/oh-my-opencode/src/hooks/background-compaction/index.ts +0 -87
  248. package/oh-my-opencode/src/hooks/background-notification/index.ts +0 -28
  249. package/oh-my-opencode/src/hooks/background-notification/types.ts +0 -5
  250. package/oh-my-opencode/src/hooks/claude-code-hooks/AGENTS.md +0 -70
  251. package/oh-my-opencode/src/hooks/claude-code-hooks/config-loader.ts +0 -107
  252. package/oh-my-opencode/src/hooks/claude-code-hooks/config.ts +0 -103
  253. package/oh-my-opencode/src/hooks/claude-code-hooks/index.ts +0 -401
  254. package/oh-my-opencode/src/hooks/claude-code-hooks/plugin-config.ts +0 -12
  255. package/oh-my-opencode/src/hooks/claude-code-hooks/post-tool-use.ts +0 -199
  256. package/oh-my-opencode/src/hooks/claude-code-hooks/pre-compact.ts +0 -109
  257. package/oh-my-opencode/src/hooks/claude-code-hooks/pre-tool-use.ts +0 -172
  258. package/oh-my-opencode/src/hooks/claude-code-hooks/stop.ts +0 -118
  259. package/oh-my-opencode/src/hooks/claude-code-hooks/todo.ts +0 -76
  260. package/oh-my-opencode/src/hooks/claude-code-hooks/tool-input-cache.ts +0 -47
  261. package/oh-my-opencode/src/hooks/claude-code-hooks/transcript.ts +0 -252
  262. package/oh-my-opencode/src/hooks/claude-code-hooks/types.ts +0 -204
  263. package/oh-my-opencode/src/hooks/claude-code-hooks/user-prompt-submit.ts +0 -117
  264. package/oh-my-opencode/src/hooks/comment-checker/cli.test.ts +0 -68
  265. package/oh-my-opencode/src/hooks/comment-checker/cli.ts +0 -221
  266. package/oh-my-opencode/src/hooks/comment-checker/downloader.ts +0 -196
  267. package/oh-my-opencode/src/hooks/comment-checker/index.ts +0 -171
  268. package/oh-my-opencode/src/hooks/comment-checker/types.ts +0 -33
  269. package/oh-my-opencode/src/hooks/compaction-context-injector/index.ts +0 -61
  270. package/oh-my-opencode/src/hooks/context-window-monitor.ts +0 -99
  271. package/oh-my-opencode/src/hooks/delegate-task-retry/index.test.ts +0 -119
  272. package/oh-my-opencode/src/hooks/delegate-task-retry/index.ts +0 -136
  273. package/oh-my-opencode/src/hooks/directory-agents-injector/constants.ts +0 -9
  274. package/oh-my-opencode/src/hooks/directory-agents-injector/index.ts +0 -182
  275. package/oh-my-opencode/src/hooks/directory-agents-injector/storage.ts +0 -48
  276. package/oh-my-opencode/src/hooks/directory-agents-injector/types.ts +0 -5
  277. package/oh-my-opencode/src/hooks/directory-readme-injector/constants.ts +0 -9
  278. package/oh-my-opencode/src/hooks/directory-readme-injector/index.ts +0 -177
  279. package/oh-my-opencode/src/hooks/directory-readme-injector/storage.ts +0 -48
  280. package/oh-my-opencode/src/hooks/directory-readme-injector/types.ts +0 -5
  281. package/oh-my-opencode/src/hooks/edit-error-recovery/index.test.ts +0 -126
  282. package/oh-my-opencode/src/hooks/edit-error-recovery/index.ts +0 -57
  283. package/oh-my-opencode/src/hooks/empty-task-response-detector.ts +0 -27
  284. package/oh-my-opencode/src/hooks/index.ts +0 -32
  285. package/oh-my-opencode/src/hooks/interactive-bash-session/constants.ts +0 -15
  286. package/oh-my-opencode/src/hooks/interactive-bash-session/index.ts +0 -262
  287. package/oh-my-opencode/src/hooks/interactive-bash-session/storage.ts +0 -59
  288. package/oh-my-opencode/src/hooks/interactive-bash-session/types.ts +0 -11
  289. package/oh-my-opencode/src/hooks/keyword-detector/constants.ts +0 -300
  290. package/oh-my-opencode/src/hooks/keyword-detector/detector.ts +0 -52
  291. package/oh-my-opencode/src/hooks/keyword-detector/index.test.ts +0 -529
  292. package/oh-my-opencode/src/hooks/keyword-detector/index.ts +0 -100
  293. package/oh-my-opencode/src/hooks/keyword-detector/types.ts +0 -4
  294. package/oh-my-opencode/src/hooks/non-interactive-env/constants.ts +0 -70
  295. package/oh-my-opencode/src/hooks/non-interactive-env/detector.ts +0 -19
  296. package/oh-my-opencode/src/hooks/non-interactive-env/index.test.ts +0 -323
  297. package/oh-my-opencode/src/hooks/non-interactive-env/index.ts +0 -63
  298. package/oh-my-opencode/src/hooks/non-interactive-env/types.ts +0 -3
  299. package/oh-my-opencode/src/hooks/prometheus-md-only/constants.ts +0 -32
  300. package/oh-my-opencode/src/hooks/prometheus-md-only/index.test.ts +0 -488
  301. package/oh-my-opencode/src/hooks/prometheus-md-only/index.ts +0 -136
  302. package/oh-my-opencode/src/hooks/ralph-loop/constants.ts +0 -5
  303. package/oh-my-opencode/src/hooks/ralph-loop/index.test.ts +0 -835
  304. package/oh-my-opencode/src/hooks/ralph-loop/index.ts +0 -417
  305. package/oh-my-opencode/src/hooks/ralph-loop/storage.ts +0 -115
  306. package/oh-my-opencode/src/hooks/ralph-loop/types.ts +0 -19
  307. package/oh-my-opencode/src/hooks/rules-injector/constants.ts +0 -30
  308. package/oh-my-opencode/src/hooks/rules-injector/finder.test.ts +0 -381
  309. package/oh-my-opencode/src/hooks/rules-injector/finder.ts +0 -263
  310. package/oh-my-opencode/src/hooks/rules-injector/index.ts +0 -223
  311. package/oh-my-opencode/src/hooks/rules-injector/matcher.ts +0 -63
  312. package/oh-my-opencode/src/hooks/rules-injector/parser.test.ts +0 -226
  313. package/oh-my-opencode/src/hooks/rules-injector/parser.ts +0 -211
  314. package/oh-my-opencode/src/hooks/rules-injector/storage.ts +0 -59
  315. package/oh-my-opencode/src/hooks/rules-injector/types.ts +0 -57
  316. package/oh-my-opencode/src/hooks/session-notification-utils.ts +0 -140
  317. package/oh-my-opencode/src/hooks/session-notification.test.ts +0 -361
  318. package/oh-my-opencode/src/hooks/session-notification.ts +0 -330
  319. package/oh-my-opencode/src/hooks/session-recovery/constants.ts +0 -10
  320. package/oh-my-opencode/src/hooks/session-recovery/index.test.ts +0 -223
  321. package/oh-my-opencode/src/hooks/session-recovery/index.ts +0 -435
  322. package/oh-my-opencode/src/hooks/session-recovery/storage.ts +0 -390
  323. package/oh-my-opencode/src/hooks/session-recovery/types.ts +0 -98
  324. package/oh-my-opencode/src/hooks/start-work/index.test.ts +0 -402
  325. package/oh-my-opencode/src/hooks/start-work/index.ts +0 -242
  326. package/oh-my-opencode/src/hooks/task-resume-info/index.ts +0 -36
  327. package/oh-my-opencode/src/hooks/think-mode/detector.ts +0 -57
  328. package/oh-my-opencode/src/hooks/think-mode/index.test.ts +0 -353
  329. package/oh-my-opencode/src/hooks/think-mode/index.ts +0 -89
  330. package/oh-my-opencode/src/hooks/think-mode/switcher.test.ts +0 -461
  331. package/oh-my-opencode/src/hooks/think-mode/switcher.ts +0 -222
  332. package/oh-my-opencode/src/hooks/think-mode/types.ts +0 -21
  333. package/oh-my-opencode/src/hooks/thinking-block-validator/index.ts +0 -171
  334. package/oh-my-opencode/src/hooks/todo-continuation-enforcer.test.ts +0 -876
  335. package/oh-my-opencode/src/hooks/todo-continuation-enforcer.ts +0 -480
  336. package/oh-my-opencode/src/hooks/tool-output-truncator.test.ts +0 -168
  337. package/oh-my-opencode/src/hooks/tool-output-truncator.ts +0 -61
  338. package/oh-my-opencode/src/index.ts +0 -589
  339. package/oh-my-opencode/src/mcp/AGENTS.md +0 -70
  340. package/oh-my-opencode/src/mcp/context7.ts +0 -6
  341. package/oh-my-opencode/src/mcp/grep-app.ts +0 -6
  342. package/oh-my-opencode/src/mcp/index.test.ts +0 -86
  343. package/oh-my-opencode/src/mcp/index.ts +0 -32
  344. package/oh-my-opencode/src/mcp/types.ts +0 -9
  345. package/oh-my-opencode/src/mcp/websearch.ts +0 -10
  346. package/oh-my-opencode/src/plugin-config.test.ts +0 -119
  347. package/oh-my-opencode/src/plugin-config.ts +0 -135
  348. package/oh-my-opencode/src/plugin-handlers/config-handler.test.ts +0 -103
  349. package/oh-my-opencode/src/plugin-handlers/config-handler.ts +0 -399
  350. package/oh-my-opencode/src/plugin-handlers/index.ts +0 -1
  351. package/oh-my-opencode/src/plugin-state.ts +0 -30
  352. package/oh-my-opencode/src/shared/AGENTS.md +0 -63
  353. package/oh-my-opencode/src/shared/agent-tool-restrictions.ts +0 -44
  354. package/oh-my-opencode/src/shared/agent-variant.test.ts +0 -83
  355. package/oh-my-opencode/src/shared/agent-variant.ts +0 -40
  356. package/oh-my-opencode/src/shared/claude-config-dir.test.ts +0 -60
  357. package/oh-my-opencode/src/shared/claude-config-dir.ts +0 -11
  358. package/oh-my-opencode/src/shared/command-executor.ts +0 -225
  359. package/oh-my-opencode/src/shared/config-errors.ts +0 -18
  360. package/oh-my-opencode/src/shared/config-path.ts +0 -47
  361. package/oh-my-opencode/src/shared/data-path.ts +0 -22
  362. package/oh-my-opencode/src/shared/deep-merge.test.ts +0 -336
  363. package/oh-my-opencode/src/shared/deep-merge.ts +0 -53
  364. package/oh-my-opencode/src/shared/dynamic-truncator.ts +0 -193
  365. package/oh-my-opencode/src/shared/external-plugin-detector.test.ts +0 -133
  366. package/oh-my-opencode/src/shared/external-plugin-detector.ts +0 -132
  367. package/oh-my-opencode/src/shared/file-reference-resolver.ts +0 -85
  368. package/oh-my-opencode/src/shared/file-utils.ts +0 -40
  369. package/oh-my-opencode/src/shared/first-message-variant.test.ts +0 -32
  370. package/oh-my-opencode/src/shared/first-message-variant.ts +0 -28
  371. package/oh-my-opencode/src/shared/frontmatter.test.ts +0 -262
  372. package/oh-my-opencode/src/shared/frontmatter.ts +0 -31
  373. package/oh-my-opencode/src/shared/hook-disabled.ts +0 -22
  374. package/oh-my-opencode/src/shared/index.ts +0 -29
  375. package/oh-my-opencode/src/shared/jsonc-parser.test.ts +0 -266
  376. package/oh-my-opencode/src/shared/jsonc-parser.ts +0 -66
  377. package/oh-my-opencode/src/shared/logger.ts +0 -20
  378. package/oh-my-opencode/src/shared/migration.test.ts +0 -602
  379. package/oh-my-opencode/src/shared/migration.ts +0 -191
  380. package/oh-my-opencode/src/shared/model-resolver.test.ts +0 -101
  381. package/oh-my-opencode/src/shared/model-resolver.ts +0 -35
  382. package/oh-my-opencode/src/shared/model-sanitizer.ts +0 -12
  383. package/oh-my-opencode/src/shared/opencode-config-dir.test.ts +0 -318
  384. package/oh-my-opencode/src/shared/opencode-config-dir.ts +0 -142
  385. package/oh-my-opencode/src/shared/opencode-version.test.ts +0 -223
  386. package/oh-my-opencode/src/shared/opencode-version.ts +0 -72
  387. package/oh-my-opencode/src/shared/pattern-matcher.ts +0 -29
  388. package/oh-my-opencode/src/shared/permission-compat.test.ts +0 -134
  389. package/oh-my-opencode/src/shared/permission-compat.ts +0 -77
  390. package/oh-my-opencode/src/shared/session-cursor.test.ts +0 -66
  391. package/oh-my-opencode/src/shared/session-cursor.ts +0 -85
  392. package/oh-my-opencode/src/shared/shell-env.test.ts +0 -278
  393. package/oh-my-opencode/src/shared/shell-env.ts +0 -111
  394. package/oh-my-opencode/src/shared/snake-case.ts +0 -49
  395. package/oh-my-opencode/src/shared/system-directive.ts +0 -40
  396. package/oh-my-opencode/src/shared/tool-name.ts +0 -26
  397. package/oh-my-opencode/src/shared/zip-extractor.ts +0 -83
  398. package/oh-my-opencode/src/tools/AGENTS.md +0 -74
  399. package/oh-my-opencode/src/tools/ast-grep/cli.ts +0 -230
  400. package/oh-my-opencode/src/tools/ast-grep/constants.ts +0 -261
  401. package/oh-my-opencode/src/tools/ast-grep/downloader.ts +0 -128
  402. package/oh-my-opencode/src/tools/ast-grep/index.ts +0 -13
  403. package/oh-my-opencode/src/tools/ast-grep/tools.ts +0 -112
  404. package/oh-my-opencode/src/tools/ast-grep/types.ts +0 -61
  405. package/oh-my-opencode/src/tools/ast-grep/utils.ts +0 -102
  406. package/oh-my-opencode/src/tools/background-task/constants.ts +0 -7
  407. package/oh-my-opencode/src/tools/background-task/index.ts +0 -7
  408. package/oh-my-opencode/src/tools/background-task/tools.ts +0 -479
  409. package/oh-my-opencode/src/tools/background-task/types.ts +0 -16
  410. package/oh-my-opencode/src/tools/call-omo-agent/constants.ts +0 -7
  411. package/oh-my-opencode/src/tools/call-omo-agent/index.ts +0 -3
  412. package/oh-my-opencode/src/tools/call-omo-agent/tools.ts +0 -338
  413. package/oh-my-opencode/src/tools/call-omo-agent/types.ts +0 -27
  414. package/oh-my-opencode/src/tools/delegate-task/constants.ts +0 -205
  415. package/oh-my-opencode/src/tools/delegate-task/index.ts +0 -3
  416. package/oh-my-opencode/src/tools/delegate-task/tools.test.ts +0 -1575
  417. package/oh-my-opencode/src/tools/delegate-task/tools.ts +0 -885
  418. package/oh-my-opencode/src/tools/delegate-task/types.ts +0 -9
  419. package/oh-my-opencode/src/tools/glob/cli.test.ts +0 -158
  420. package/oh-my-opencode/src/tools/glob/cli.ts +0 -191
  421. package/oh-my-opencode/src/tools/glob/constants.ts +0 -12
  422. package/oh-my-opencode/src/tools/glob/index.ts +0 -3
  423. package/oh-my-opencode/src/tools/glob/tools.ts +0 -41
  424. package/oh-my-opencode/src/tools/glob/types.ts +0 -22
  425. package/oh-my-opencode/src/tools/glob/utils.ts +0 -26
  426. package/oh-my-opencode/src/tools/grep/cli.ts +0 -229
  427. package/oh-my-opencode/src/tools/grep/constants.ts +0 -127
  428. package/oh-my-opencode/src/tools/grep/downloader.test.ts +0 -103
  429. package/oh-my-opencode/src/tools/grep/downloader.ts +0 -145
  430. package/oh-my-opencode/src/tools/grep/index.ts +0 -3
  431. package/oh-my-opencode/src/tools/grep/tools.ts +0 -40
  432. package/oh-my-opencode/src/tools/grep/types.ts +0 -39
  433. package/oh-my-opencode/src/tools/grep/utils.ts +0 -53
  434. package/oh-my-opencode/src/tools/index.ts +0 -72
  435. package/oh-my-opencode/src/tools/interactive-bash/constants.ts +0 -18
  436. package/oh-my-opencode/src/tools/interactive-bash/index.ts +0 -4
  437. package/oh-my-opencode/src/tools/interactive-bash/tools.ts +0 -126
  438. package/oh-my-opencode/src/tools/interactive-bash/utils.ts +0 -71
  439. package/oh-my-opencode/src/tools/look-at/constants.ts +0 -3
  440. package/oh-my-opencode/src/tools/look-at/index.ts +0 -3
  441. package/oh-my-opencode/src/tools/look-at/tools.test.ts +0 -73
  442. package/oh-my-opencode/src/tools/look-at/tools.ts +0 -173
  443. package/oh-my-opencode/src/tools/look-at/types.ts +0 -4
  444. package/oh-my-opencode/src/tools/lsp/client.ts +0 -596
  445. package/oh-my-opencode/src/tools/lsp/config.test.ts +0 -130
  446. package/oh-my-opencode/src/tools/lsp/config.ts +0 -285
  447. package/oh-my-opencode/src/tools/lsp/constants.ts +0 -390
  448. package/oh-my-opencode/src/tools/lsp/index.ts +0 -7
  449. package/oh-my-opencode/src/tools/lsp/tools.ts +0 -261
  450. package/oh-my-opencode/src/tools/lsp/types.ts +0 -124
  451. package/oh-my-opencode/src/tools/lsp/utils.ts +0 -406
  452. package/oh-my-opencode/src/tools/session-manager/constants.ts +0 -97
  453. package/oh-my-opencode/src/tools/session-manager/index.ts +0 -3
  454. package/oh-my-opencode/src/tools/session-manager/storage.test.ts +0 -315
  455. package/oh-my-opencode/src/tools/session-manager/storage.ts +0 -238
  456. package/oh-my-opencode/src/tools/session-manager/tools.test.ts +0 -124
  457. package/oh-my-opencode/src/tools/session-manager/tools.ts +0 -146
  458. package/oh-my-opencode/src/tools/session-manager/types.ts +0 -99
  459. package/oh-my-opencode/src/tools/session-manager/utils.test.ts +0 -160
  460. package/oh-my-opencode/src/tools/session-manager/utils.ts +0 -199
  461. package/oh-my-opencode/src/tools/skill/constants.ts +0 -8
  462. package/oh-my-opencode/src/tools/skill/index.ts +0 -3
  463. package/oh-my-opencode/src/tools/skill/tools.test.ts +0 -239
  464. package/oh-my-opencode/src/tools/skill/tools.ts +0 -200
  465. package/oh-my-opencode/src/tools/skill/types.ts +0 -31
  466. package/oh-my-opencode/src/tools/skill-mcp/constants.ts +0 -3
  467. package/oh-my-opencode/src/tools/skill-mcp/index.ts +0 -3
  468. package/oh-my-opencode/src/tools/skill-mcp/tools.test.ts +0 -215
  469. package/oh-my-opencode/src/tools/skill-mcp/tools.ts +0 -172
  470. package/oh-my-opencode/src/tools/skill-mcp/types.ts +0 -8
  471. package/oh-my-opencode/src/tools/slashcommand/index.ts +0 -2
  472. package/oh-my-opencode/src/tools/slashcommand/tools.ts +0 -252
  473. package/oh-my-opencode/src/tools/slashcommand/types.ts +0 -28
  474. package/oh-my-opencode/test-setup.ts +0 -6
  475. package/oh-my-opencode/tsconfig.json +0 -20
@@ -1,529 +0,0 @@
1
- import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
2
- import { createKeywordDetectorHook } from "./index"
3
- import { setMainSession, updateSessionAgent, clearSessionAgent, _resetForTesting } from "../../features/claude-code-session-state"
4
- import { ContextCollector } from "../../features/context-injector"
5
- import * as sharedModule from "../../shared"
6
- import * as sessionState from "../../features/claude-code-session-state"
7
-
8
- describe("keyword-detector registers to ContextCollector", () => {
9
- let logCalls: Array<{ msg: string; data?: unknown }>
10
- let logSpy: ReturnType<typeof spyOn>
11
- let getMainSessionSpy: ReturnType<typeof spyOn>
12
-
13
- beforeEach(() => {
14
- _resetForTesting()
15
- logCalls = []
16
- logSpy = spyOn(sharedModule, "log").mockImplementation((msg: string, data?: unknown) => {
17
- logCalls.push({ msg, data })
18
- })
19
- })
20
-
21
- afterEach(() => {
22
- logSpy?.mockRestore()
23
- getMainSessionSpy?.mockRestore()
24
- })
25
-
26
- function createMockPluginInput() {
27
- return {
28
- client: {
29
- tui: {
30
- showToast: async () => {},
31
- },
32
- },
33
- } as any
34
- }
35
-
36
- test("should register ultrawork keyword to ContextCollector", async () => {
37
- // #given - a fresh ContextCollector and keyword-detector hook
38
- const collector = new ContextCollector()
39
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
40
- const sessionID = "test-session-123"
41
- const output = {
42
- message: {} as Record<string, unknown>,
43
- parts: [{ type: "text", text: "ultrawork do something" }],
44
- }
45
-
46
- // #when - keyword detection runs
47
- await hook["chat.message"]({ sessionID }, output)
48
-
49
- // #then - ultrawork context should be registered in collector
50
- expect(collector.hasPending(sessionID)).toBe(true)
51
- const pending = collector.getPending(sessionID)
52
- expect(pending.entries.length).toBeGreaterThan(0)
53
- expect(pending.entries[0].source).toBe("keyword-detector")
54
- expect(pending.entries[0].id).toBe("keyword-ultrawork")
55
- })
56
-
57
- test("should register search keyword to ContextCollector", async () => {
58
- // #given - mock getMainSessionID to return our session (isolate from global state)
59
- const collector = new ContextCollector()
60
- const sessionID = "search-test-session"
61
- getMainSessionSpy = spyOn(sessionState, "getMainSessionID").mockReturnValue(sessionID)
62
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
63
- const output = {
64
- message: {} as Record<string, unknown>,
65
- parts: [{ type: "text", text: "search for the bug" }],
66
- }
67
-
68
- // #when - keyword detection runs
69
- await hook["chat.message"]({ sessionID }, output)
70
-
71
- // #then - search context should be registered in collector
72
- expect(collector.hasPending(sessionID)).toBe(true)
73
- const pending = collector.getPending(sessionID)
74
- expect(pending.entries.some((e) => e.id === "keyword-search")).toBe(true)
75
- })
76
-
77
- test("should NOT register to collector when no keywords detected", async () => {
78
- // #given - no keywords in message
79
- const collector = new ContextCollector()
80
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
81
- const sessionID = "test-session"
82
- const output = {
83
- message: {} as Record<string, unknown>,
84
- parts: [{ type: "text", text: "just a normal message" }],
85
- }
86
-
87
- // #when - keyword detection runs
88
- await hook["chat.message"]({ sessionID }, output)
89
-
90
- // #then - nothing should be registered
91
- expect(collector.hasPending(sessionID)).toBe(false)
92
- })
93
- })
94
-
95
- describe("keyword-detector session filtering", () => {
96
- let logCalls: Array<{ msg: string; data?: unknown }>
97
- let logSpy: ReturnType<typeof spyOn>
98
-
99
- beforeEach(() => {
100
- setMainSession(undefined)
101
- logCalls = []
102
- logSpy = spyOn(sharedModule, "log").mockImplementation((msg: string, data?: unknown) => {
103
- logCalls.push({ msg, data })
104
- })
105
- })
106
-
107
- afterEach(() => {
108
- logSpy?.mockRestore()
109
- setMainSession(undefined)
110
- })
111
-
112
- function createMockPluginInput(options: { toastCalls?: string[] } = {}) {
113
- const toastCalls = options.toastCalls ?? []
114
- return {
115
- client: {
116
- tui: {
117
- showToast: async (opts: any) => {
118
- toastCalls.push(opts.body.title)
119
- },
120
- },
121
- },
122
- } as any
123
- }
124
-
125
- test("should skip non-ultrawork keywords in non-main session (using mainSessionID check)", async () => {
126
- // #given - main session is set, different session submits search keyword
127
- const mainSessionID = "main-123"
128
- const subagentSessionID = "subagent-456"
129
- setMainSession(mainSessionID)
130
-
131
- const hook = createKeywordDetectorHook(createMockPluginInput())
132
- const output = {
133
- message: {} as Record<string, unknown>,
134
- parts: [{ type: "text", text: "search mode 찾아줘" }],
135
- }
136
-
137
- // #when - non-main session triggers keyword detection
138
- await hook["chat.message"](
139
- { sessionID: subagentSessionID },
140
- output
141
- )
142
-
143
- // #then - search keyword should be filtered out based on mainSessionID comparison
144
- const skipLog = logCalls.find(c => c.msg.includes("Skipping non-ultrawork keywords in non-main session"))
145
- expect(skipLog).toBeDefined()
146
- })
147
-
148
- test("should allow ultrawork keywords in non-main session", async () => {
149
- // #given - main session is set, different session submits ultrawork keyword
150
- const mainSessionID = "main-123"
151
- const subagentSessionID = "subagent-456"
152
- setMainSession(mainSessionID)
153
-
154
- const toastCalls: string[] = []
155
- const hook = createKeywordDetectorHook(createMockPluginInput({ toastCalls }))
156
- const output = {
157
- message: {} as Record<string, unknown>,
158
- parts: [{ type: "text", text: "ultrawork mode" }],
159
- }
160
-
161
- // #when - non-main session triggers ultrawork keyword
162
- await hook["chat.message"](
163
- { sessionID: subagentSessionID },
164
- output
165
- )
166
-
167
- // #then - ultrawork should still work (variant set to max)
168
- expect(output.message.variant).toBe("max")
169
- expect(toastCalls).toContain("Ultrawork Mode Activated")
170
- })
171
-
172
- test("should allow all keywords in main session", async () => {
173
- // #given - main session submits search keyword
174
- const mainSessionID = "main-123"
175
- setMainSession(mainSessionID)
176
-
177
- const hook = createKeywordDetectorHook(createMockPluginInput())
178
- const output = {
179
- message: {} as Record<string, unknown>,
180
- parts: [{ type: "text", text: "search mode 찾아줘" }],
181
- }
182
-
183
- // #when - main session triggers keyword detection
184
- await hook["chat.message"](
185
- { sessionID: mainSessionID },
186
- output
187
- )
188
-
189
- // #then - search keyword should be detected (output unchanged but detection happens)
190
- // Note: search keywords don't set variant, they inject messages via context-injector
191
- // This test verifies the detection logic runs without filtering
192
- expect(output.message.variant).toBeUndefined() // search doesn't set variant
193
- })
194
-
195
- test("should allow all keywords when mainSessionID is not set", async () => {
196
- // #given - no main session set (early startup or standalone mode)
197
- setMainSession(undefined)
198
-
199
- const toastCalls: string[] = []
200
- const hook = createKeywordDetectorHook(createMockPluginInput({ toastCalls }))
201
- const output = {
202
- message: {} as Record<string, unknown>,
203
- parts: [{ type: "text", text: "ultrawork search" }],
204
- }
205
-
206
- // #when - any session triggers keyword detection
207
- await hook["chat.message"](
208
- { sessionID: "any-session" },
209
- output
210
- )
211
-
212
- // #then - all keywords should work
213
- expect(output.message.variant).toBe("max")
214
- expect(toastCalls).toContain("Ultrawork Mode Activated")
215
- })
216
-
217
- test("should not override existing variant", async () => {
218
- // #given - main session set with pre-existing variant
219
- setMainSession("main-123")
220
-
221
- const toastCalls: string[] = []
222
- const hook = createKeywordDetectorHook(createMockPluginInput({ toastCalls }))
223
- const output = {
224
- message: { variant: "low" } as Record<string, unknown>,
225
- parts: [{ type: "text", text: "ultrawork mode" }],
226
- }
227
-
228
- // #when - ultrawork keyword triggers
229
- await hook["chat.message"](
230
- { sessionID: "main-123" },
231
- output
232
- )
233
-
234
- // #then - existing variant should remain
235
- expect(output.message.variant).toBe("low")
236
- expect(toastCalls).toContain("Ultrawork Mode Activated")
237
- })
238
- })
239
-
240
- describe("keyword-detector word boundary", () => {
241
- let logCalls: Array<{ msg: string; data?: unknown }>
242
- let logSpy: ReturnType<typeof spyOn>
243
-
244
- beforeEach(() => {
245
- setMainSession(undefined)
246
- logCalls = []
247
- logSpy = spyOn(sharedModule, "log").mockImplementation((msg: string, data?: unknown) => {
248
- logCalls.push({ msg, data })
249
- })
250
- })
251
-
252
- afterEach(() => {
253
- logSpy?.mockRestore()
254
- setMainSession(undefined)
255
- })
256
-
257
- function createMockPluginInput(options: { toastCalls?: string[] } = {}) {
258
- const toastCalls = options.toastCalls ?? []
259
- return {
260
- client: {
261
- tui: {
262
- showToast: async (opts: any) => {
263
- toastCalls.push(opts.body.title)
264
- },
265
- },
266
- },
267
- } as any
268
- }
269
-
270
- test("should NOT trigger ultrawork on partial matches like 'StatefulWidget' containing 'ulw'", async () => {
271
- // #given - text contains 'ulw' as part of another word (StatefulWidget)
272
- setMainSession(undefined)
273
-
274
- const toastCalls: string[] = []
275
- const hook = createKeywordDetectorHook(createMockPluginInput({ toastCalls }))
276
- const output = {
277
- message: {} as Record<string, unknown>,
278
- parts: [{ type: "text", text: "refactor the StatefulWidget component" }],
279
- }
280
-
281
- // #when - message with partial 'ulw' match is processed
282
- await hook["chat.message"](
283
- { sessionID: "any-session" },
284
- output
285
- )
286
-
287
- // #then - ultrawork should NOT be triggered
288
- expect(output.message.variant).toBeUndefined()
289
- expect(toastCalls).not.toContain("Ultrawork Mode Activated")
290
- })
291
-
292
- test("should trigger ultrawork on standalone 'ulw' keyword", async () => {
293
- // #given - text contains standalone 'ulw'
294
- setMainSession(undefined)
295
-
296
- const toastCalls: string[] = []
297
- const hook = createKeywordDetectorHook(createMockPluginInput({ toastCalls }))
298
- const output = {
299
- message: {} as Record<string, unknown>,
300
- parts: [{ type: "text", text: "ulw do this task" }],
301
- }
302
-
303
- // #when - message with standalone 'ulw' is processed
304
- await hook["chat.message"](
305
- { sessionID: "any-session" },
306
- output
307
- )
308
-
309
- // #then - ultrawork should be triggered
310
- expect(output.message.variant).toBe("max")
311
- expect(toastCalls).toContain("Ultrawork Mode Activated")
312
- })
313
-
314
- test("should NOT trigger ultrawork on file references containing 'ulw' substring", async () => {
315
- // #given - file reference contains 'ulw' as substring
316
- setMainSession(undefined)
317
-
318
- const toastCalls: string[] = []
319
- const hook = createKeywordDetectorHook(createMockPluginInput({ toastCalls }))
320
- const output = {
321
- message: {} as Record<string, unknown>,
322
- parts: [{ type: "text", text: "@StatefulWidget.tsx please review this file" }],
323
- }
324
-
325
- // #when - message referencing file with 'ulw' substring is processed
326
- await hook["chat.message"](
327
- { sessionID: "any-session" },
328
- output
329
- )
330
-
331
- // #then - ultrawork should NOT be triggered
332
- expect(output.message.variant).toBeUndefined()
333
- expect(toastCalls).not.toContain("Ultrawork Mode Activated")
334
- })
335
- })
336
-
337
- describe("keyword-detector agent-specific ultrawork messages", () => {
338
- let logCalls: Array<{ msg: string; data?: unknown }>
339
- let logSpy: ReturnType<typeof spyOn>
340
-
341
- beforeEach(() => {
342
- setMainSession(undefined)
343
- logCalls = []
344
- logSpy = spyOn(sharedModule, "log").mockImplementation((msg: string, data?: unknown) => {
345
- logCalls.push({ msg, data })
346
- })
347
- })
348
-
349
- afterEach(() => {
350
- logSpy?.mockRestore()
351
- setMainSession(undefined)
352
- })
353
-
354
- function createMockPluginInput() {
355
- return {
356
- client: {
357
- tui: {
358
- showToast: async () => {},
359
- },
360
- },
361
- } as any
362
- }
363
-
364
- test("should use planner-specific ultrawork message when agent is prometheus", async () => {
365
- // #given - collector and prometheus agent
366
- const collector = new ContextCollector()
367
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
368
- const sessionID = "prometheus-session"
369
- const output = {
370
- message: {} as Record<string, unknown>,
371
- parts: [{ type: "text", text: "ultrawork plan this feature" }],
372
- }
373
-
374
- // #when - ultrawork keyword detected with prometheus agent
375
- await hook["chat.message"]({ sessionID, agent: "prometheus" }, output)
376
-
377
- // #then - should use planner-specific message with "YOU ARE A PLANNER" content
378
- const pending = collector.getPending(sessionID)
379
- const ultraworkEntry = pending.entries.find((e) => e.id === "keyword-ultrawork")
380
- expect(ultraworkEntry).toBeDefined()
381
- expect(ultraworkEntry!.content).toContain("YOU ARE A PLANNER, NOT AN IMPLEMENTER")
382
- expect(ultraworkEntry!.content).not.toContain("YOU MUST LEVERAGE ALL AVAILABLE AGENTS")
383
- })
384
-
385
- test("should use planner-specific ultrawork message when agent name contains 'planner'", async () => {
386
- // #given - collector and agent with 'planner' in name
387
- const collector = new ContextCollector()
388
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
389
- const sessionID = "planner-session"
390
- const output = {
391
- message: {} as Record<string, unknown>,
392
- parts: [{ type: "text", text: "ulw create a work plan" }],
393
- }
394
-
395
- // #when - ultrawork keyword detected with planner agent
396
- await hook["chat.message"]({ sessionID, agent: "Prometheus (Planner)" }, output)
397
-
398
- // #then - should use planner-specific message
399
- const pending = collector.getPending(sessionID)
400
- const ultraworkEntry = pending.entries.find((e) => e.id === "keyword-ultrawork")
401
- expect(ultraworkEntry).toBeDefined()
402
- expect(ultraworkEntry!.content).toContain("YOU ARE A PLANNER, NOT AN IMPLEMENTER")
403
- })
404
-
405
- test("should use normal ultrawork message when agent is Sisyphus", async () => {
406
- // #given - collector and Sisyphus agent
407
- const collector = new ContextCollector()
408
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
409
- const sessionID = "sisyphus-session"
410
- const output = {
411
- message: {} as Record<string, unknown>,
412
- parts: [{ type: "text", text: "ultrawork implement this feature" }],
413
- }
414
-
415
- // #when - ultrawork keyword detected with Sisyphus agent
416
- await hook["chat.message"]({ sessionID, agent: "Sisyphus" }, output)
417
-
418
- // #then - should use normal ultrawork message with agent utilization instructions
419
- const pending = collector.getPending(sessionID)
420
- const ultraworkEntry = pending.entries.find((e) => e.id === "keyword-ultrawork")
421
- expect(ultraworkEntry).toBeDefined()
422
- expect(ultraworkEntry!.content).toContain("YOU MUST LEVERAGE ALL AVAILABLE AGENTS")
423
- expect(ultraworkEntry!.content).not.toContain("YOU ARE A PLANNER, NOT AN IMPLEMENTER")
424
- })
425
-
426
- test("should use normal ultrawork message when agent is undefined", async () => {
427
- // #given - collector with no agent specified
428
- const collector = new ContextCollector()
429
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
430
- const sessionID = "no-agent-session"
431
- const output = {
432
- message: {} as Record<string, unknown>,
433
- parts: [{ type: "text", text: "ultrawork do something" }],
434
- }
435
-
436
- // #when - ultrawork keyword detected without agent
437
- await hook["chat.message"]({ sessionID }, output)
438
-
439
- // #then - should use normal ultrawork message (default behavior)
440
- const pending = collector.getPending(sessionID)
441
- const ultraworkEntry = pending.entries.find((e) => e.id === "keyword-ultrawork")
442
- expect(ultraworkEntry).toBeDefined()
443
- expect(ultraworkEntry!.content).toContain("YOU MUST LEVERAGE ALL AVAILABLE AGENTS")
444
- expect(ultraworkEntry!.content).not.toContain("YOU ARE A PLANNER, NOT AN IMPLEMENTER")
445
- })
446
-
447
- test("should switch from planner to normal message when agent changes", async () => {
448
- // #given - two sessions, one with prometheus, one with sisyphus
449
- const collector = new ContextCollector()
450
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
451
-
452
- // First session with prometheus
453
- const prometheusSessionID = "prometheus-first"
454
- const prometheusOutput = {
455
- message: {} as Record<string, unknown>,
456
- parts: [{ type: "text", text: "ultrawork plan" }],
457
- }
458
- await hook["chat.message"]({ sessionID: prometheusSessionID, agent: "prometheus" }, prometheusOutput)
459
-
460
- // Second session with sisyphus
461
- const sisyphusSessionID = "sisyphus-second"
462
- const sisyphusOutput = {
463
- message: {} as Record<string, unknown>,
464
- parts: [{ type: "text", text: "ultrawork implement" }],
465
- }
466
- await hook["chat.message"]({ sessionID: sisyphusSessionID, agent: "Sisyphus" }, sisyphusOutput)
467
-
468
- // #then - each session should have the correct message type
469
- const prometheusPending = collector.getPending(prometheusSessionID)
470
- const prometheusEntry = prometheusPending.entries.find((e) => e.id === "keyword-ultrawork")
471
- expect(prometheusEntry!.content).toContain("YOU ARE A PLANNER, NOT AN IMPLEMENTER")
472
-
473
- const sisyphusPending = collector.getPending(sisyphusSessionID)
474
- const sisyphusEntry = sisyphusPending.entries.find((e) => e.id === "keyword-ultrawork")
475
- expect(sisyphusEntry!.content).toContain("YOU MUST LEVERAGE ALL AVAILABLE AGENTS")
476
- })
477
-
478
- test("should use session state agent over stale input.agent (bug fix)", async () => {
479
- // #given - same session, agent switched from prometheus to sisyphus in session state
480
- const collector = new ContextCollector()
481
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
482
- const sessionID = "same-session-agent-switch"
483
-
484
- // Simulate: session state was updated to sisyphus (by index.ts updateSessionAgent)
485
- updateSessionAgent(sessionID, "Sisyphus")
486
-
487
- const output = {
488
- message: {} as Record<string, unknown>,
489
- parts: [{ type: "text", text: "ultrawork implement this" }],
490
- }
491
-
492
- // #when - hook receives stale input.agent="prometheus" but session state says "Sisyphus"
493
- await hook["chat.message"]({ sessionID, agent: "prometheus" }, output)
494
-
495
- // #then - should use Sisyphus from session state, NOT prometheus from stale input
496
- const pending = collector.getPending(sessionID)
497
- const ultraworkEntry = pending.entries.find((e) => e.id === "keyword-ultrawork")
498
- expect(ultraworkEntry).toBeDefined()
499
- expect(ultraworkEntry!.content).toContain("YOU MUST LEVERAGE ALL AVAILABLE AGENTS")
500
- expect(ultraworkEntry!.content).not.toContain("YOU ARE A PLANNER, NOT AN IMPLEMENTER")
501
-
502
- // cleanup
503
- clearSessionAgent(sessionID)
504
- })
505
-
506
- test("should fall back to input.agent when session state is empty", async () => {
507
- // #given - no session state, only input.agent available
508
- const collector = new ContextCollector()
509
- const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
510
- const sessionID = "no-session-state"
511
-
512
- // Ensure no session state
513
- clearSessionAgent(sessionID)
514
-
515
- const output = {
516
- message: {} as Record<string, unknown>,
517
- parts: [{ type: "text", text: "ultrawork plan this" }],
518
- }
519
-
520
- // #when - hook receives input.agent="prometheus" with no session state
521
- await hook["chat.message"]({ sessionID, agent: "prometheus" }, output)
522
-
523
- // #then - should use prometheus from input.agent as fallback
524
- const pending = collector.getPending(sessionID)
525
- const ultraworkEntry = pending.entries.find((e) => e.id === "keyword-ultrawork")
526
- expect(ultraworkEntry).toBeDefined()
527
- expect(ultraworkEntry!.content).toContain("YOU ARE A PLANNER, NOT AN IMPLEMENTER")
528
- })
529
- })
@@ -1,100 +0,0 @@
1
- import type { PluginInput } from "@opencode-ai/plugin"
2
- import { detectKeywordsWithType, extractPromptText, removeCodeBlocks } from "./detector"
3
- import { log } from "../../shared"
4
- import { isSystemDirective } from "../../shared/system-directive"
5
- import { getMainSessionID, getSessionAgent, subagentSessions } from "../../features/claude-code-session-state"
6
- import type { ContextCollector } from "../../features/context-injector"
7
-
8
- export * from "./detector"
9
- export * from "./constants"
10
- export * from "./types"
11
-
12
- export function createKeywordDetectorHook(ctx: PluginInput, collector?: ContextCollector) {
13
- return {
14
- "chat.message": async (
15
- input: {
16
- sessionID: string
17
- agent?: string
18
- model?: { providerID: string; modelID: string }
19
- messageID?: string
20
- },
21
- output: {
22
- message: Record<string, unknown>
23
- parts: Array<{ type: string; text?: string; [key: string]: unknown }>
24
- }
25
- ): Promise<void> => {
26
- const promptText = extractPromptText(output.parts)
27
-
28
- if (isSystemDirective(promptText)) {
29
- log(`[keyword-detector] Skipping system directive message`, { sessionID: input.sessionID })
30
- return
31
- }
32
-
33
- const currentAgent = getSessionAgent(input.sessionID) ?? input.agent
34
- let detectedKeywords = detectKeywordsWithType(removeCodeBlocks(promptText), currentAgent)
35
-
36
- if (detectedKeywords.length === 0) {
37
- return
38
- }
39
-
40
- // Skip keyword detection for background task sessions to prevent mode injection
41
- // (e.g., [analyze-mode]) which incorrectly triggers Prometheus restrictions
42
- const isBackgroundTaskSession = subagentSessions.has(input.sessionID)
43
- if (isBackgroundTaskSession) {
44
- return
45
- }
46
-
47
- const mainSessionID = getMainSessionID()
48
- const isNonMainSession = mainSessionID && input.sessionID !== mainSessionID
49
-
50
- if (isNonMainSession) {
51
- detectedKeywords = detectedKeywords.filter((k) => k.type === "ultrawork")
52
- if (detectedKeywords.length === 0) {
53
- log(`[keyword-detector] Skipping non-ultrawork keywords in non-main session`, {
54
- sessionID: input.sessionID,
55
- mainSessionID,
56
- })
57
- return
58
- }
59
- }
60
-
61
- const hasUltrawork = detectedKeywords.some((k) => k.type === "ultrawork")
62
- if (hasUltrawork) {
63
- log(`[keyword-detector] Ultrawork mode activated`, { sessionID: input.sessionID })
64
-
65
- if (output.message.variant === undefined) {
66
- output.message.variant = "max"
67
- }
68
-
69
- ctx.client.tui
70
- .showToast({
71
- body: {
72
- title: "Ultrawork Mode Activated",
73
- message: "Maximum precision engaged. All agents at your disposal.",
74
- variant: "success" as const,
75
- duration: 3000,
76
- },
77
- })
78
- .catch((err) =>
79
- log(`[keyword-detector] Failed to show toast`, { error: err, sessionID: input.sessionID })
80
- )
81
- }
82
-
83
- if (collector) {
84
- for (const keyword of detectedKeywords) {
85
- collector.register(input.sessionID, {
86
- id: `keyword-${keyword.type}`,
87
- source: "keyword-detector",
88
- content: keyword.message,
89
- priority: keyword.type === "ultrawork" ? "critical" : "high",
90
- })
91
- }
92
- }
93
-
94
- log(`[keyword-detector] Detected ${detectedKeywords.length} keywords`, {
95
- sessionID: input.sessionID,
96
- types: detectedKeywords.map((k) => k.type),
97
- })
98
- },
99
- }
100
- }
@@ -1,4 +0,0 @@
1
- export interface KeywordDetectorState {
2
- detected: boolean
3
- injected: boolean
4
- }