opencode-repos 0.1.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 (477) hide show
  1. package/AGENTS.md +180 -0
  2. package/README.md +103 -3
  3. package/TODO.md +3 -0
  4. package/bun.lock +0 -85
  5. package/index.ts +1585 -153
  6. package/oh-my-opencode/.github/FUNDING.yml +15 -0
  7. package/oh-my-opencode/.github/ISSUE_TEMPLATE/bug_report.yml +129 -0
  8. package/oh-my-opencode/.github/ISSUE_TEMPLATE/config.yml +8 -0
  9. package/oh-my-opencode/.github/ISSUE_TEMPLATE/feature_request.yml +100 -0
  10. package/oh-my-opencode/.github/ISSUE_TEMPLATE/general.yml +83 -0
  11. package/oh-my-opencode/.github/assets/google.jpg +0 -0
  12. package/oh-my-opencode/.github/assets/hero.jpg +0 -0
  13. package/oh-my-opencode/.github/assets/indent.jpg +0 -0
  14. package/oh-my-opencode/.github/assets/microsoft.jpg +0 -0
  15. package/oh-my-opencode/.github/assets/omo.png +0 -0
  16. package/oh-my-opencode/.github/assets/orchestrator-atlas.png +0 -0
  17. package/oh-my-opencode/.github/assets/sisyphus.png +0 -0
  18. package/oh-my-opencode/.github/assets/sisyphuslabs.png +0 -0
  19. package/oh-my-opencode/.github/pull_request_template.md +34 -0
  20. package/oh-my-opencode/.github/workflows/ci.yml +138 -0
  21. package/oh-my-opencode/.github/workflows/cla.yml +41 -0
  22. package/oh-my-opencode/.github/workflows/lint-workflows.yml +22 -0
  23. package/oh-my-opencode/.github/workflows/publish.yml +165 -0
  24. package/oh-my-opencode/.github/workflows/sisyphus-agent.yml +500 -0
  25. package/oh-my-opencode/.opencode/background-tasks.json +27 -0
  26. package/oh-my-opencode/.opencode/command/get-unpublished-changes.md +84 -0
  27. package/oh-my-opencode/.opencode/command/omomomo.md +37 -0
  28. package/oh-my-opencode/.opencode/command/publish.md +257 -0
  29. package/oh-my-opencode/AGENTS.md +179 -0
  30. package/oh-my-opencode/CLA.md +58 -0
  31. package/oh-my-opencode/CONTRIBUTING.md +268 -0
  32. package/oh-my-opencode/LICENSE.md +82 -0
  33. package/oh-my-opencode/README.ja.md +370 -0
  34. package/oh-my-opencode/README.md +376 -0
  35. package/oh-my-opencode/README.zh-cn.md +380 -0
  36. package/oh-my-opencode/assets/oh-my-opencode.schema.json +2171 -0
  37. package/oh-my-opencode/bin/oh-my-opencode.js +80 -0
  38. package/oh-my-opencode/bin/platform.js +38 -0
  39. package/oh-my-opencode/bin/platform.test.ts +148 -0
  40. package/oh-my-opencode/bun.lock +314 -0
  41. package/oh-my-opencode/bunfig.toml +2 -0
  42. package/oh-my-opencode/docs/category-skill-guide.md +200 -0
  43. package/oh-my-opencode/docs/cli-guide.md +272 -0
  44. package/oh-my-opencode/docs/configurations.md +654 -0
  45. package/oh-my-opencode/docs/features.md +550 -0
  46. package/oh-my-opencode/docs/guide/installation.md +288 -0
  47. package/oh-my-opencode/docs/guide/overview.md +97 -0
  48. package/oh-my-opencode/docs/guide/understanding-orchestration-system.md +445 -0
  49. package/oh-my-opencode/docs/orchestration-guide.md +152 -0
  50. package/oh-my-opencode/docs/ultrawork-manifesto.md +197 -0
  51. package/oh-my-opencode/package.json +89 -0
  52. package/oh-my-opencode/packages/darwin-arm64/bin/.gitkeep +0 -0
  53. package/oh-my-opencode/packages/darwin-arm64/package.json +22 -0
  54. package/oh-my-opencode/packages/darwin-x64/bin/.gitkeep +0 -0
  55. package/oh-my-opencode/packages/darwin-x64/package.json +22 -0
  56. package/oh-my-opencode/packages/linux-arm64/bin/.gitkeep +0 -0
  57. package/oh-my-opencode/packages/linux-arm64/package.json +25 -0
  58. package/oh-my-opencode/packages/linux-arm64-musl/bin/.gitkeep +0 -0
  59. package/oh-my-opencode/packages/linux-arm64-musl/package.json +25 -0
  60. package/oh-my-opencode/packages/linux-x64/bin/.gitkeep +0 -0
  61. package/oh-my-opencode/packages/linux-x64/package.json +25 -0
  62. package/oh-my-opencode/packages/linux-x64-musl/bin/.gitkeep +0 -0
  63. package/oh-my-opencode/packages/linux-x64-musl/package.json +25 -0
  64. package/oh-my-opencode/packages/windows-x64/bin/.gitkeep +0 -0
  65. package/oh-my-opencode/packages/windows-x64/package.json +22 -0
  66. package/oh-my-opencode/postinstall.mjs +43 -0
  67. package/oh-my-opencode/script/build-binaries.ts +103 -0
  68. package/oh-my-opencode/script/build-schema.ts +28 -0
  69. package/oh-my-opencode/script/generate-changelog.ts +92 -0
  70. package/oh-my-opencode/script/publish.ts +344 -0
  71. package/oh-my-opencode/signatures/cla.json +676 -0
  72. package/oh-my-opencode/src/agents/AGENTS.md +67 -0
  73. package/oh-my-opencode/src/agents/atlas.ts +1383 -0
  74. package/oh-my-opencode/src/agents/dynamic-agent-prompt-builder.ts +400 -0
  75. package/oh-my-opencode/src/agents/explore.ts +122 -0
  76. package/oh-my-opencode/src/agents/index.ts +13 -0
  77. package/oh-my-opencode/src/agents/librarian.ts +326 -0
  78. package/oh-my-opencode/src/agents/metis.ts +315 -0
  79. package/oh-my-opencode/src/agents/momus.test.ts +57 -0
  80. package/oh-my-opencode/src/agents/momus.ts +444 -0
  81. package/oh-my-opencode/src/agents/multimodal-looker.ts +56 -0
  82. package/oh-my-opencode/src/agents/oracle.ts +122 -0
  83. package/oh-my-opencode/src/agents/prometheus-prompt.test.ts +22 -0
  84. package/oh-my-opencode/src/agents/prometheus-prompt.ts +1196 -0
  85. package/oh-my-opencode/src/agents/sisyphus-junior.test.ts +232 -0
  86. package/oh-my-opencode/src/agents/sisyphus-junior.ts +134 -0
  87. package/oh-my-opencode/src/agents/sisyphus.ts +633 -0
  88. package/oh-my-opencode/src/agents/types.ts +80 -0
  89. package/oh-my-opencode/src/agents/utils.test.ts +311 -0
  90. package/oh-my-opencode/src/agents/utils.ts +240 -0
  91. package/oh-my-opencode/src/cli/AGENTS.md +91 -0
  92. package/oh-my-opencode/src/cli/config-manager.test.ts +364 -0
  93. package/oh-my-opencode/src/cli/config-manager.ts +641 -0
  94. package/oh-my-opencode/src/cli/doctor/checks/auth.test.ts +114 -0
  95. package/oh-my-opencode/src/cli/doctor/checks/auth.ts +115 -0
  96. package/oh-my-opencode/src/cli/doctor/checks/config.test.ts +103 -0
  97. package/oh-my-opencode/src/cli/doctor/checks/config.ts +123 -0
  98. package/oh-my-opencode/src/cli/doctor/checks/dependencies.test.ts +152 -0
  99. package/oh-my-opencode/src/cli/doctor/checks/dependencies.ts +163 -0
  100. package/oh-my-opencode/src/cli/doctor/checks/gh.test.ts +151 -0
  101. package/oh-my-opencode/src/cli/doctor/checks/gh.ts +171 -0
  102. package/oh-my-opencode/src/cli/doctor/checks/index.ts +34 -0
  103. package/oh-my-opencode/src/cli/doctor/checks/lsp.test.ts +134 -0
  104. package/oh-my-opencode/src/cli/doctor/checks/lsp.ts +77 -0
  105. package/oh-my-opencode/src/cli/doctor/checks/mcp.test.ts +115 -0
  106. package/oh-my-opencode/src/cli/doctor/checks/mcp.ts +128 -0
  107. package/oh-my-opencode/src/cli/doctor/checks/opencode.test.ts +227 -0
  108. package/oh-my-opencode/src/cli/doctor/checks/opencode.ts +178 -0
  109. package/oh-my-opencode/src/cli/doctor/checks/plugin.test.ts +109 -0
  110. package/oh-my-opencode/src/cli/doctor/checks/plugin.ts +124 -0
  111. package/oh-my-opencode/src/cli/doctor/checks/version.test.ts +148 -0
  112. package/oh-my-opencode/src/cli/doctor/checks/version.ts +135 -0
  113. package/oh-my-opencode/src/cli/doctor/constants.ts +72 -0
  114. package/oh-my-opencode/src/cli/doctor/formatter.test.ts +218 -0
  115. package/oh-my-opencode/src/cli/doctor/formatter.ts +140 -0
  116. package/oh-my-opencode/src/cli/doctor/index.ts +11 -0
  117. package/oh-my-opencode/src/cli/doctor/runner.test.ts +153 -0
  118. package/oh-my-opencode/src/cli/doctor/runner.ts +132 -0
  119. package/oh-my-opencode/src/cli/doctor/types.ts +113 -0
  120. package/oh-my-opencode/src/cli/get-local-version/formatter.ts +66 -0
  121. package/oh-my-opencode/src/cli/get-local-version/index.ts +106 -0
  122. package/oh-my-opencode/src/cli/get-local-version/types.ts +14 -0
  123. package/oh-my-opencode/src/cli/index.ts +153 -0
  124. package/oh-my-opencode/src/cli/install.ts +523 -0
  125. package/oh-my-opencode/src/cli/model-fallback.ts +246 -0
  126. package/oh-my-opencode/src/cli/run/completion.test.ts +170 -0
  127. package/oh-my-opencode/src/cli/run/completion.ts +79 -0
  128. package/oh-my-opencode/src/cli/run/events.test.ts +155 -0
  129. package/oh-my-opencode/src/cli/run/events.ts +325 -0
  130. package/oh-my-opencode/src/cli/run/index.ts +2 -0
  131. package/oh-my-opencode/src/cli/run/runner.ts +159 -0
  132. package/oh-my-opencode/src/cli/run/types.ts +76 -0
  133. package/oh-my-opencode/src/cli/types.ts +40 -0
  134. package/oh-my-opencode/src/config/index.ts +26 -0
  135. package/oh-my-opencode/src/config/schema.test.ts +444 -0
  136. package/oh-my-opencode/src/config/schema.ts +339 -0
  137. package/oh-my-opencode/src/features/AGENTS.md +77 -0
  138. package/oh-my-opencode/src/features/background-agent/concurrency.test.ts +418 -0
  139. package/oh-my-opencode/src/features/background-agent/concurrency.ts +137 -0
  140. package/oh-my-opencode/src/features/background-agent/index.ts +3 -0
  141. package/oh-my-opencode/src/features/background-agent/manager.test.ts +1928 -0
  142. package/oh-my-opencode/src/features/background-agent/manager.ts +1335 -0
  143. package/oh-my-opencode/src/features/background-agent/types.ts +66 -0
  144. package/oh-my-opencode/src/features/boulder-state/constants.ts +13 -0
  145. package/oh-my-opencode/src/features/boulder-state/index.ts +3 -0
  146. package/oh-my-opencode/src/features/boulder-state/storage.test.ts +250 -0
  147. package/oh-my-opencode/src/features/boulder-state/storage.ts +150 -0
  148. package/oh-my-opencode/src/features/boulder-state/types.ts +26 -0
  149. package/oh-my-opencode/src/features/builtin-commands/commands.ts +89 -0
  150. package/oh-my-opencode/src/features/builtin-commands/index.ts +2 -0
  151. package/oh-my-opencode/src/features/builtin-commands/templates/init-deep.ts +300 -0
  152. package/oh-my-opencode/src/features/builtin-commands/templates/ralph-loop.ts +38 -0
  153. package/oh-my-opencode/src/features/builtin-commands/templates/refactor.ts +619 -0
  154. package/oh-my-opencode/src/features/builtin-commands/templates/start-work.ts +72 -0
  155. package/oh-my-opencode/src/features/builtin-commands/types.ts +9 -0
  156. package/oh-my-opencode/src/features/builtin-skills/frontend-ui-ux/SKILL.md +78 -0
  157. package/oh-my-opencode/src/features/builtin-skills/git-master/SKILL.md +1105 -0
  158. package/oh-my-opencode/src/features/builtin-skills/index.ts +2 -0
  159. package/oh-my-opencode/src/features/builtin-skills/skills.ts +1203 -0
  160. package/oh-my-opencode/src/features/builtin-skills/types.ts +16 -0
  161. package/oh-my-opencode/src/features/claude-code-agent-loader/index.ts +2 -0
  162. package/oh-my-opencode/src/features/claude-code-agent-loader/loader.ts +90 -0
  163. package/oh-my-opencode/src/features/claude-code-agent-loader/types.ts +17 -0
  164. package/oh-my-opencode/src/features/claude-code-command-loader/index.ts +2 -0
  165. package/oh-my-opencode/src/features/claude-code-command-loader/loader.ts +144 -0
  166. package/oh-my-opencode/src/features/claude-code-command-loader/types.ts +46 -0
  167. package/oh-my-opencode/src/features/claude-code-mcp-loader/env-expander.ts +27 -0
  168. package/oh-my-opencode/src/features/claude-code-mcp-loader/index.ts +11 -0
  169. package/oh-my-opencode/src/features/claude-code-mcp-loader/loader.test.ts +162 -0
  170. package/oh-my-opencode/src/features/claude-code-mcp-loader/loader.ts +113 -0
  171. package/oh-my-opencode/src/features/claude-code-mcp-loader/transformer.ts +53 -0
  172. package/oh-my-opencode/src/features/claude-code-mcp-loader/types.ts +42 -0
  173. package/oh-my-opencode/src/features/claude-code-plugin-loader/index.ts +3 -0
  174. package/oh-my-opencode/src/features/claude-code-plugin-loader/loader.ts +486 -0
  175. package/oh-my-opencode/src/features/claude-code-plugin-loader/types.ts +210 -0
  176. package/oh-my-opencode/src/features/claude-code-session-state/index.ts +1 -0
  177. package/oh-my-opencode/src/features/claude-code-session-state/state.test.ts +126 -0
  178. package/oh-my-opencode/src/features/claude-code-session-state/state.ts +37 -0
  179. package/oh-my-opencode/src/features/context-injector/collector.test.ts +330 -0
  180. package/oh-my-opencode/src/features/context-injector/collector.ts +85 -0
  181. package/oh-my-opencode/src/features/context-injector/index.ts +14 -0
  182. package/oh-my-opencode/src/features/context-injector/injector.test.ts +122 -0
  183. package/oh-my-opencode/src/features/context-injector/injector.ts +167 -0
  184. package/oh-my-opencode/src/features/context-injector/types.ts +91 -0
  185. package/oh-my-opencode/src/features/hook-message-injector/constants.ts +6 -0
  186. package/oh-my-opencode/src/features/hook-message-injector/index.ts +4 -0
  187. package/oh-my-opencode/src/features/hook-message-injector/injector.ts +195 -0
  188. package/oh-my-opencode/src/features/hook-message-injector/types.ts +47 -0
  189. package/oh-my-opencode/src/features/opencode-skill-loader/async-loader.test.ts +448 -0
  190. package/oh-my-opencode/src/features/opencode-skill-loader/async-loader.ts +180 -0
  191. package/oh-my-opencode/src/features/opencode-skill-loader/blocking.test.ts +210 -0
  192. package/oh-my-opencode/src/features/opencode-skill-loader/blocking.ts +62 -0
  193. package/oh-my-opencode/src/features/opencode-skill-loader/discover-worker.ts +59 -0
  194. package/oh-my-opencode/src/features/opencode-skill-loader/index.ts +4 -0
  195. package/oh-my-opencode/src/features/opencode-skill-loader/loader.test.ts +273 -0
  196. package/oh-my-opencode/src/features/opencode-skill-loader/loader.ts +259 -0
  197. package/oh-my-opencode/src/features/opencode-skill-loader/merger.ts +267 -0
  198. package/oh-my-opencode/src/features/opencode-skill-loader/skill-content.test.ts +267 -0
  199. package/oh-my-opencode/src/features/opencode-skill-loader/skill-content.ts +206 -0
  200. package/oh-my-opencode/src/features/opencode-skill-loader/types.ts +38 -0
  201. package/oh-my-opencode/src/features/skill-mcp-manager/env-cleaner.test.ts +201 -0
  202. package/oh-my-opencode/src/features/skill-mcp-manager/env-cleaner.ts +27 -0
  203. package/oh-my-opencode/src/features/skill-mcp-manager/index.ts +2 -0
  204. package/oh-my-opencode/src/features/skill-mcp-manager/manager.test.ts +611 -0
  205. package/oh-my-opencode/src/features/skill-mcp-manager/manager.ts +520 -0
  206. package/oh-my-opencode/src/features/skill-mcp-manager/types.ts +14 -0
  207. package/oh-my-opencode/src/features/task-toast-manager/index.ts +2 -0
  208. package/oh-my-opencode/src/features/task-toast-manager/manager.test.ts +249 -0
  209. package/oh-my-opencode/src/features/task-toast-manager/manager.ts +215 -0
  210. package/oh-my-opencode/src/features/task-toast-manager/types.ts +24 -0
  211. package/oh-my-opencode/src/hooks/AGENTS.md +73 -0
  212. package/oh-my-opencode/src/hooks/agent-usage-reminder/constants.ts +54 -0
  213. package/oh-my-opencode/src/hooks/agent-usage-reminder/index.ts +109 -0
  214. package/oh-my-opencode/src/hooks/agent-usage-reminder/storage.ts +42 -0
  215. package/oh-my-opencode/src/hooks/agent-usage-reminder/types.ts +6 -0
  216. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts +307 -0
  217. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/executor.ts +485 -0
  218. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/index.ts +151 -0
  219. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/parser.ts +201 -0
  220. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts +33 -0
  221. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts +184 -0
  222. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-types.ts +44 -0
  223. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/storage.test.ts +77 -0
  224. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/storage.ts +250 -0
  225. package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/types.ts +42 -0
  226. package/oh-my-opencode/src/hooks/atlas/index.test.ts +953 -0
  227. package/oh-my-opencode/src/hooks/atlas/index.ts +771 -0
  228. package/oh-my-opencode/src/hooks/auto-slash-command/constants.ts +12 -0
  229. package/oh-my-opencode/src/hooks/auto-slash-command/detector.test.ts +296 -0
  230. package/oh-my-opencode/src/hooks/auto-slash-command/detector.ts +65 -0
  231. package/oh-my-opencode/src/hooks/auto-slash-command/executor.ts +205 -0
  232. package/oh-my-opencode/src/hooks/auto-slash-command/index.test.ts +254 -0
  233. package/oh-my-opencode/src/hooks/auto-slash-command/index.ts +89 -0
  234. package/oh-my-opencode/src/hooks/auto-slash-command/types.ts +23 -0
  235. package/oh-my-opencode/src/hooks/auto-update-checker/cache.ts +93 -0
  236. package/oh-my-opencode/src/hooks/auto-update-checker/checker.test.ts +24 -0
  237. package/oh-my-opencode/src/hooks/auto-update-checker/checker.ts +284 -0
  238. package/oh-my-opencode/src/hooks/auto-update-checker/constants.ts +64 -0
  239. package/oh-my-opencode/src/hooks/auto-update-checker/index.test.ts +254 -0
  240. package/oh-my-opencode/src/hooks/auto-update-checker/index.ts +260 -0
  241. package/oh-my-opencode/src/hooks/auto-update-checker/types.ts +29 -0
  242. package/oh-my-opencode/src/hooks/background-compaction/index.ts +87 -0
  243. package/oh-my-opencode/src/hooks/background-notification/index.ts +28 -0
  244. package/oh-my-opencode/src/hooks/background-notification/types.ts +5 -0
  245. package/oh-my-opencode/src/hooks/claude-code-hooks/AGENTS.md +70 -0
  246. package/oh-my-opencode/src/hooks/claude-code-hooks/config-loader.ts +107 -0
  247. package/oh-my-opencode/src/hooks/claude-code-hooks/config.ts +103 -0
  248. package/oh-my-opencode/src/hooks/claude-code-hooks/index.ts +401 -0
  249. package/oh-my-opencode/src/hooks/claude-code-hooks/plugin-config.ts +12 -0
  250. package/oh-my-opencode/src/hooks/claude-code-hooks/post-tool-use.ts +199 -0
  251. package/oh-my-opencode/src/hooks/claude-code-hooks/pre-compact.ts +109 -0
  252. package/oh-my-opencode/src/hooks/claude-code-hooks/pre-tool-use.ts +172 -0
  253. package/oh-my-opencode/src/hooks/claude-code-hooks/stop.ts +118 -0
  254. package/oh-my-opencode/src/hooks/claude-code-hooks/todo.ts +76 -0
  255. package/oh-my-opencode/src/hooks/claude-code-hooks/tool-input-cache.ts +47 -0
  256. package/oh-my-opencode/src/hooks/claude-code-hooks/transcript.ts +252 -0
  257. package/oh-my-opencode/src/hooks/claude-code-hooks/types.ts +204 -0
  258. package/oh-my-opencode/src/hooks/claude-code-hooks/user-prompt-submit.ts +117 -0
  259. package/oh-my-opencode/src/hooks/comment-checker/cli.test.ts +68 -0
  260. package/oh-my-opencode/src/hooks/comment-checker/cli.ts +221 -0
  261. package/oh-my-opencode/src/hooks/comment-checker/downloader.ts +196 -0
  262. package/oh-my-opencode/src/hooks/comment-checker/index.ts +171 -0
  263. package/oh-my-opencode/src/hooks/comment-checker/types.ts +33 -0
  264. package/oh-my-opencode/src/hooks/compaction-context-injector/index.ts +61 -0
  265. package/oh-my-opencode/src/hooks/context-window-monitor.ts +99 -0
  266. package/oh-my-opencode/src/hooks/delegate-task-retry/index.test.ts +119 -0
  267. package/oh-my-opencode/src/hooks/delegate-task-retry/index.ts +136 -0
  268. package/oh-my-opencode/src/hooks/directory-agents-injector/constants.ts +9 -0
  269. package/oh-my-opencode/src/hooks/directory-agents-injector/index.ts +182 -0
  270. package/oh-my-opencode/src/hooks/directory-agents-injector/storage.ts +48 -0
  271. package/oh-my-opencode/src/hooks/directory-agents-injector/types.ts +5 -0
  272. package/oh-my-opencode/src/hooks/directory-readme-injector/constants.ts +9 -0
  273. package/oh-my-opencode/src/hooks/directory-readme-injector/index.ts +177 -0
  274. package/oh-my-opencode/src/hooks/directory-readme-injector/storage.ts +48 -0
  275. package/oh-my-opencode/src/hooks/directory-readme-injector/types.ts +5 -0
  276. package/oh-my-opencode/src/hooks/edit-error-recovery/index.test.ts +126 -0
  277. package/oh-my-opencode/src/hooks/edit-error-recovery/index.ts +57 -0
  278. package/oh-my-opencode/src/hooks/empty-task-response-detector.ts +27 -0
  279. package/oh-my-opencode/src/hooks/index.ts +32 -0
  280. package/oh-my-opencode/src/hooks/interactive-bash-session/constants.ts +15 -0
  281. package/oh-my-opencode/src/hooks/interactive-bash-session/index.ts +262 -0
  282. package/oh-my-opencode/src/hooks/interactive-bash-session/storage.ts +59 -0
  283. package/oh-my-opencode/src/hooks/interactive-bash-session/types.ts +11 -0
  284. package/oh-my-opencode/src/hooks/keyword-detector/constants.ts +300 -0
  285. package/oh-my-opencode/src/hooks/keyword-detector/detector.ts +52 -0
  286. package/oh-my-opencode/src/hooks/keyword-detector/index.test.ts +529 -0
  287. package/oh-my-opencode/src/hooks/keyword-detector/index.ts +100 -0
  288. package/oh-my-opencode/src/hooks/keyword-detector/types.ts +4 -0
  289. package/oh-my-opencode/src/hooks/non-interactive-env/constants.ts +70 -0
  290. package/oh-my-opencode/src/hooks/non-interactive-env/detector.ts +19 -0
  291. package/oh-my-opencode/src/hooks/non-interactive-env/index.test.ts +323 -0
  292. package/oh-my-opencode/src/hooks/non-interactive-env/index.ts +63 -0
  293. package/oh-my-opencode/src/hooks/non-interactive-env/types.ts +3 -0
  294. package/oh-my-opencode/src/hooks/prometheus-md-only/constants.ts +32 -0
  295. package/oh-my-opencode/src/hooks/prometheus-md-only/index.test.ts +488 -0
  296. package/oh-my-opencode/src/hooks/prometheus-md-only/index.ts +136 -0
  297. package/oh-my-opencode/src/hooks/ralph-loop/constants.ts +5 -0
  298. package/oh-my-opencode/src/hooks/ralph-loop/index.test.ts +835 -0
  299. package/oh-my-opencode/src/hooks/ralph-loop/index.ts +417 -0
  300. package/oh-my-opencode/src/hooks/ralph-loop/storage.ts +115 -0
  301. package/oh-my-opencode/src/hooks/ralph-loop/types.ts +19 -0
  302. package/oh-my-opencode/src/hooks/rules-injector/constants.ts +30 -0
  303. package/oh-my-opencode/src/hooks/rules-injector/finder.test.ts +381 -0
  304. package/oh-my-opencode/src/hooks/rules-injector/finder.ts +263 -0
  305. package/oh-my-opencode/src/hooks/rules-injector/index.ts +223 -0
  306. package/oh-my-opencode/src/hooks/rules-injector/matcher.ts +63 -0
  307. package/oh-my-opencode/src/hooks/rules-injector/parser.test.ts +226 -0
  308. package/oh-my-opencode/src/hooks/rules-injector/parser.ts +211 -0
  309. package/oh-my-opencode/src/hooks/rules-injector/storage.ts +59 -0
  310. package/oh-my-opencode/src/hooks/rules-injector/types.ts +57 -0
  311. package/oh-my-opencode/src/hooks/session-notification-utils.ts +140 -0
  312. package/oh-my-opencode/src/hooks/session-notification.test.ts +361 -0
  313. package/oh-my-opencode/src/hooks/session-notification.ts +330 -0
  314. package/oh-my-opencode/src/hooks/session-recovery/constants.ts +10 -0
  315. package/oh-my-opencode/src/hooks/session-recovery/index.test.ts +223 -0
  316. package/oh-my-opencode/src/hooks/session-recovery/index.ts +435 -0
  317. package/oh-my-opencode/src/hooks/session-recovery/storage.ts +390 -0
  318. package/oh-my-opencode/src/hooks/session-recovery/types.ts +98 -0
  319. package/oh-my-opencode/src/hooks/start-work/index.test.ts +402 -0
  320. package/oh-my-opencode/src/hooks/start-work/index.ts +242 -0
  321. package/oh-my-opencode/src/hooks/task-resume-info/index.ts +36 -0
  322. package/oh-my-opencode/src/hooks/think-mode/detector.ts +57 -0
  323. package/oh-my-opencode/src/hooks/think-mode/index.test.ts +353 -0
  324. package/oh-my-opencode/src/hooks/think-mode/index.ts +89 -0
  325. package/oh-my-opencode/src/hooks/think-mode/switcher.test.ts +461 -0
  326. package/oh-my-opencode/src/hooks/think-mode/switcher.ts +222 -0
  327. package/oh-my-opencode/src/hooks/think-mode/types.ts +21 -0
  328. package/oh-my-opencode/src/hooks/thinking-block-validator/index.ts +171 -0
  329. package/oh-my-opencode/src/hooks/todo-continuation-enforcer.test.ts +876 -0
  330. package/oh-my-opencode/src/hooks/todo-continuation-enforcer.ts +480 -0
  331. package/oh-my-opencode/src/hooks/tool-output-truncator.test.ts +168 -0
  332. package/oh-my-opencode/src/hooks/tool-output-truncator.ts +61 -0
  333. package/oh-my-opencode/src/index.ts +589 -0
  334. package/oh-my-opencode/src/mcp/AGENTS.md +70 -0
  335. package/oh-my-opencode/src/mcp/context7.ts +6 -0
  336. package/oh-my-opencode/src/mcp/grep-app.ts +6 -0
  337. package/oh-my-opencode/src/mcp/index.test.ts +86 -0
  338. package/oh-my-opencode/src/mcp/index.ts +32 -0
  339. package/oh-my-opencode/src/mcp/types.ts +9 -0
  340. package/oh-my-opencode/src/mcp/websearch.ts +10 -0
  341. package/oh-my-opencode/src/plugin-config.test.ts +119 -0
  342. package/oh-my-opencode/src/plugin-config.ts +135 -0
  343. package/oh-my-opencode/src/plugin-handlers/config-handler.test.ts +103 -0
  344. package/oh-my-opencode/src/plugin-handlers/config-handler.ts +399 -0
  345. package/oh-my-opencode/src/plugin-handlers/index.ts +1 -0
  346. package/oh-my-opencode/src/plugin-state.ts +30 -0
  347. package/oh-my-opencode/src/shared/AGENTS.md +63 -0
  348. package/oh-my-opencode/src/shared/agent-tool-restrictions.ts +44 -0
  349. package/oh-my-opencode/src/shared/agent-variant.test.ts +83 -0
  350. package/oh-my-opencode/src/shared/agent-variant.ts +40 -0
  351. package/oh-my-opencode/src/shared/claude-config-dir.test.ts +60 -0
  352. package/oh-my-opencode/src/shared/claude-config-dir.ts +11 -0
  353. package/oh-my-opencode/src/shared/command-executor.ts +225 -0
  354. package/oh-my-opencode/src/shared/config-errors.ts +18 -0
  355. package/oh-my-opencode/src/shared/config-path.ts +47 -0
  356. package/oh-my-opencode/src/shared/data-path.ts +22 -0
  357. package/oh-my-opencode/src/shared/deep-merge.test.ts +336 -0
  358. package/oh-my-opencode/src/shared/deep-merge.ts +53 -0
  359. package/oh-my-opencode/src/shared/dynamic-truncator.ts +193 -0
  360. package/oh-my-opencode/src/shared/external-plugin-detector.test.ts +133 -0
  361. package/oh-my-opencode/src/shared/external-plugin-detector.ts +132 -0
  362. package/oh-my-opencode/src/shared/file-reference-resolver.ts +85 -0
  363. package/oh-my-opencode/src/shared/file-utils.ts +40 -0
  364. package/oh-my-opencode/src/shared/first-message-variant.test.ts +32 -0
  365. package/oh-my-opencode/src/shared/first-message-variant.ts +28 -0
  366. package/oh-my-opencode/src/shared/frontmatter.test.ts +262 -0
  367. package/oh-my-opencode/src/shared/frontmatter.ts +31 -0
  368. package/oh-my-opencode/src/shared/hook-disabled.ts +22 -0
  369. package/oh-my-opencode/src/shared/index.ts +29 -0
  370. package/oh-my-opencode/src/shared/jsonc-parser.test.ts +266 -0
  371. package/oh-my-opencode/src/shared/jsonc-parser.ts +66 -0
  372. package/oh-my-opencode/src/shared/logger.ts +20 -0
  373. package/oh-my-opencode/src/shared/migration.test.ts +602 -0
  374. package/oh-my-opencode/src/shared/migration.ts +191 -0
  375. package/oh-my-opencode/src/shared/model-resolver.test.ts +101 -0
  376. package/oh-my-opencode/src/shared/model-resolver.ts +35 -0
  377. package/oh-my-opencode/src/shared/model-sanitizer.ts +12 -0
  378. package/oh-my-opencode/src/shared/opencode-config-dir.test.ts +318 -0
  379. package/oh-my-opencode/src/shared/opencode-config-dir.ts +142 -0
  380. package/oh-my-opencode/src/shared/opencode-version.test.ts +223 -0
  381. package/oh-my-opencode/src/shared/opencode-version.ts +72 -0
  382. package/oh-my-opencode/src/shared/pattern-matcher.ts +29 -0
  383. package/oh-my-opencode/src/shared/permission-compat.test.ts +134 -0
  384. package/oh-my-opencode/src/shared/permission-compat.ts +77 -0
  385. package/oh-my-opencode/src/shared/session-cursor.test.ts +66 -0
  386. package/oh-my-opencode/src/shared/session-cursor.ts +85 -0
  387. package/oh-my-opencode/src/shared/shell-env.test.ts +278 -0
  388. package/oh-my-opencode/src/shared/shell-env.ts +111 -0
  389. package/oh-my-opencode/src/shared/snake-case.ts +49 -0
  390. package/oh-my-opencode/src/shared/system-directive.ts +40 -0
  391. package/oh-my-opencode/src/shared/tool-name.ts +26 -0
  392. package/oh-my-opencode/src/shared/zip-extractor.ts +83 -0
  393. package/oh-my-opencode/src/tools/AGENTS.md +74 -0
  394. package/oh-my-opencode/src/tools/ast-grep/cli.ts +230 -0
  395. package/oh-my-opencode/src/tools/ast-grep/constants.ts +261 -0
  396. package/oh-my-opencode/src/tools/ast-grep/downloader.ts +128 -0
  397. package/oh-my-opencode/src/tools/ast-grep/index.ts +13 -0
  398. package/oh-my-opencode/src/tools/ast-grep/tools.ts +112 -0
  399. package/oh-my-opencode/src/tools/ast-grep/types.ts +61 -0
  400. package/oh-my-opencode/src/tools/ast-grep/utils.ts +102 -0
  401. package/oh-my-opencode/src/tools/background-task/constants.ts +7 -0
  402. package/oh-my-opencode/src/tools/background-task/index.ts +7 -0
  403. package/oh-my-opencode/src/tools/background-task/tools.ts +479 -0
  404. package/oh-my-opencode/src/tools/background-task/types.ts +16 -0
  405. package/oh-my-opencode/src/tools/call-omo-agent/constants.ts +7 -0
  406. package/oh-my-opencode/src/tools/call-omo-agent/index.ts +3 -0
  407. package/oh-my-opencode/src/tools/call-omo-agent/tools.ts +338 -0
  408. package/oh-my-opencode/src/tools/call-omo-agent/types.ts +27 -0
  409. package/oh-my-opencode/src/tools/delegate-task/constants.ts +205 -0
  410. package/oh-my-opencode/src/tools/delegate-task/index.ts +3 -0
  411. package/oh-my-opencode/src/tools/delegate-task/tools.test.ts +1575 -0
  412. package/oh-my-opencode/src/tools/delegate-task/tools.ts +885 -0
  413. package/oh-my-opencode/src/tools/delegate-task/types.ts +9 -0
  414. package/oh-my-opencode/src/tools/glob/cli.test.ts +158 -0
  415. package/oh-my-opencode/src/tools/glob/cli.ts +191 -0
  416. package/oh-my-opencode/src/tools/glob/constants.ts +12 -0
  417. package/oh-my-opencode/src/tools/glob/index.ts +3 -0
  418. package/oh-my-opencode/src/tools/glob/tools.ts +41 -0
  419. package/oh-my-opencode/src/tools/glob/types.ts +22 -0
  420. package/oh-my-opencode/src/tools/glob/utils.ts +26 -0
  421. package/oh-my-opencode/src/tools/grep/cli.ts +229 -0
  422. package/oh-my-opencode/src/tools/grep/constants.ts +127 -0
  423. package/oh-my-opencode/src/tools/grep/downloader.test.ts +103 -0
  424. package/oh-my-opencode/src/tools/grep/downloader.ts +145 -0
  425. package/oh-my-opencode/src/tools/grep/index.ts +3 -0
  426. package/oh-my-opencode/src/tools/grep/tools.ts +40 -0
  427. package/oh-my-opencode/src/tools/grep/types.ts +39 -0
  428. package/oh-my-opencode/src/tools/grep/utils.ts +53 -0
  429. package/oh-my-opencode/src/tools/index.ts +72 -0
  430. package/oh-my-opencode/src/tools/interactive-bash/constants.ts +18 -0
  431. package/oh-my-opencode/src/tools/interactive-bash/index.ts +4 -0
  432. package/oh-my-opencode/src/tools/interactive-bash/tools.ts +126 -0
  433. package/oh-my-opencode/src/tools/interactive-bash/utils.ts +71 -0
  434. package/oh-my-opencode/src/tools/look-at/constants.ts +3 -0
  435. package/oh-my-opencode/src/tools/look-at/index.ts +3 -0
  436. package/oh-my-opencode/src/tools/look-at/tools.test.ts +73 -0
  437. package/oh-my-opencode/src/tools/look-at/tools.ts +173 -0
  438. package/oh-my-opencode/src/tools/look-at/types.ts +4 -0
  439. package/oh-my-opencode/src/tools/lsp/client.ts +596 -0
  440. package/oh-my-opencode/src/tools/lsp/config.test.ts +130 -0
  441. package/oh-my-opencode/src/tools/lsp/config.ts +285 -0
  442. package/oh-my-opencode/src/tools/lsp/constants.ts +390 -0
  443. package/oh-my-opencode/src/tools/lsp/index.ts +7 -0
  444. package/oh-my-opencode/src/tools/lsp/tools.ts +261 -0
  445. package/oh-my-opencode/src/tools/lsp/types.ts +124 -0
  446. package/oh-my-opencode/src/tools/lsp/utils.ts +406 -0
  447. package/oh-my-opencode/src/tools/session-manager/constants.ts +97 -0
  448. package/oh-my-opencode/src/tools/session-manager/index.ts +3 -0
  449. package/oh-my-opencode/src/tools/session-manager/storage.test.ts +315 -0
  450. package/oh-my-opencode/src/tools/session-manager/storage.ts +238 -0
  451. package/oh-my-opencode/src/tools/session-manager/tools.test.ts +124 -0
  452. package/oh-my-opencode/src/tools/session-manager/tools.ts +146 -0
  453. package/oh-my-opencode/src/tools/session-manager/types.ts +99 -0
  454. package/oh-my-opencode/src/tools/session-manager/utils.test.ts +160 -0
  455. package/oh-my-opencode/src/tools/session-manager/utils.ts +199 -0
  456. package/oh-my-opencode/src/tools/skill/constants.ts +8 -0
  457. package/oh-my-opencode/src/tools/skill/index.ts +3 -0
  458. package/oh-my-opencode/src/tools/skill/tools.test.ts +239 -0
  459. package/oh-my-opencode/src/tools/skill/tools.ts +200 -0
  460. package/oh-my-opencode/src/tools/skill/types.ts +31 -0
  461. package/oh-my-opencode/src/tools/skill-mcp/constants.ts +3 -0
  462. package/oh-my-opencode/src/tools/skill-mcp/index.ts +3 -0
  463. package/oh-my-opencode/src/tools/skill-mcp/tools.test.ts +215 -0
  464. package/oh-my-opencode/src/tools/skill-mcp/tools.ts +172 -0
  465. package/oh-my-opencode/src/tools/skill-mcp/types.ts +8 -0
  466. package/oh-my-opencode/src/tools/slashcommand/index.ts +2 -0
  467. package/oh-my-opencode/src/tools/slashcommand/tools.ts +252 -0
  468. package/oh-my-opencode/src/tools/slashcommand/types.ts +28 -0
  469. package/oh-my-opencode/test-setup.ts +6 -0
  470. package/oh-my-opencode/tsconfig.json +20 -0
  471. package/package.json +1 -4
  472. package/src/__tests__/git.test.ts +7 -2
  473. package/src/__tests__/manifest.test.ts +5 -5
  474. package/src/agents/repo-explorer.ts +2 -1
  475. package/src/git.ts +18 -3
  476. package/src/manifest.ts +22 -15
  477. package/src/scanner.ts +41 -32
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Claude Code Plugin Types
3
+ *
4
+ * Type definitions for Claude Code plugin system compatibility.
5
+ * Based on https://code.claude.com/docs/en/plugins-reference
6
+ */
7
+
8
+ export type PluginScope = "user" | "project" | "local" | "managed"
9
+
10
+ /**
11
+ * Plugin installation entry in installed_plugins.json
12
+ */
13
+ export interface PluginInstallation {
14
+ scope: PluginScope
15
+ installPath: string
16
+ version: string
17
+ installedAt: string
18
+ lastUpdated: string
19
+ gitCommitSha?: string
20
+ isLocal?: boolean
21
+ }
22
+
23
+ /**
24
+ * Installed plugins database v1 (legacy)
25
+ * plugins stored as direct objects
26
+ */
27
+ export interface InstalledPluginsDatabaseV1 {
28
+ version: 1
29
+ plugins: Record<string, PluginInstallation>
30
+ }
31
+
32
+ /**
33
+ * Installed plugins database v2 (current)
34
+ * plugins stored as arrays
35
+ */
36
+ export interface InstalledPluginsDatabaseV2 {
37
+ version: 2
38
+ plugins: Record<string, PluginInstallation[]>
39
+ }
40
+
41
+ /**
42
+ * Installed plugins database structure
43
+ * Located at ~/.claude/plugins/installed_plugins.json
44
+ */
45
+ export type InstalledPluginsDatabase = InstalledPluginsDatabaseV1 | InstalledPluginsDatabaseV2
46
+
47
+ /**
48
+ * Plugin author information
49
+ */
50
+ export interface PluginAuthor {
51
+ name?: string
52
+ email?: string
53
+ url?: string
54
+ }
55
+
56
+ /**
57
+ * Plugin manifest (plugin.json)
58
+ * Located at <plugin_root>/.claude-plugin/plugin.json
59
+ */
60
+ export interface PluginManifest {
61
+ name: string
62
+ version?: string
63
+ description?: string
64
+ author?: PluginAuthor
65
+ homepage?: string
66
+ repository?: string
67
+ license?: string
68
+ keywords?: string[]
69
+
70
+ // Component paths (can be string or array)
71
+ commands?: string | string[]
72
+ agents?: string | string[]
73
+ skills?: string | string[]
74
+ hooks?: string | HooksConfig
75
+ mcpServers?: string | McpServersConfig
76
+ lspServers?: string | LspServersConfig
77
+ outputStyles?: string | string[]
78
+ }
79
+
80
+ /**
81
+ * Hooks configuration
82
+ */
83
+ export interface HookEntry {
84
+ type: "command" | "prompt" | "agent"
85
+ command?: string
86
+ prompt?: string
87
+ agent?: string
88
+ }
89
+
90
+ export interface HookMatcher {
91
+ matcher?: string
92
+ hooks: HookEntry[]
93
+ }
94
+
95
+ export interface HooksConfig {
96
+ hooks?: {
97
+ PreToolUse?: HookMatcher[]
98
+ PostToolUse?: HookMatcher[]
99
+ PostToolUseFailure?: HookMatcher[]
100
+ PermissionRequest?: HookMatcher[]
101
+ UserPromptSubmit?: HookMatcher[]
102
+ Notification?: HookMatcher[]
103
+ Stop?: HookMatcher[]
104
+ SubagentStart?: HookMatcher[]
105
+ SubagentStop?: HookMatcher[]
106
+ SessionStart?: HookMatcher[]
107
+ SessionEnd?: HookMatcher[]
108
+ PreCompact?: HookMatcher[]
109
+ }
110
+ }
111
+
112
+ /**
113
+ * MCP servers configuration in plugin
114
+ */
115
+ export interface PluginMcpServer {
116
+ command?: string
117
+ args?: string[]
118
+ env?: Record<string, string>
119
+ cwd?: string
120
+ url?: string
121
+ type?: "stdio" | "http" | "sse"
122
+ disabled?: boolean
123
+ }
124
+
125
+ export interface McpServersConfig {
126
+ mcpServers?: Record<string, PluginMcpServer>
127
+ }
128
+
129
+ /**
130
+ * LSP server configuration
131
+ */
132
+ export interface LspServerConfig {
133
+ command: string
134
+ args?: string[]
135
+ extensionToLanguage: Record<string, string>
136
+ transport?: "stdio" | "socket"
137
+ env?: Record<string, string>
138
+ initializationOptions?: Record<string, unknown>
139
+ settings?: Record<string, unknown>
140
+ workspaceFolder?: string
141
+ startupTimeout?: number
142
+ shutdownTimeout?: number
143
+ restartOnCrash?: boolean
144
+ maxRestarts?: number
145
+ loggingConfig?: {
146
+ args?: string[]
147
+ env?: Record<string, string>
148
+ }
149
+ }
150
+
151
+ export interface LspServersConfig {
152
+ [language: string]: LspServerConfig
153
+ }
154
+
155
+ /**
156
+ * Loaded plugin with all resolved components
157
+ */
158
+ export interface LoadedPlugin {
159
+ name: string
160
+ version: string
161
+ scope: PluginScope
162
+ installPath: string
163
+ manifest?: PluginManifest
164
+ pluginKey: string
165
+
166
+ // Resolved paths for components
167
+ commandsDir?: string
168
+ agentsDir?: string
169
+ skillsDir?: string
170
+ hooksPath?: string
171
+ mcpPath?: string
172
+ lspPath?: string
173
+ }
174
+
175
+ /**
176
+ * Plugin load result with all components
177
+ */
178
+ export interface PluginLoadResult {
179
+ plugins: LoadedPlugin[]
180
+ errors: PluginLoadError[]
181
+ }
182
+
183
+ export interface PluginLoadError {
184
+ pluginKey: string
185
+ installPath: string
186
+ error: string
187
+ }
188
+
189
+ /**
190
+ * Claude settings from ~/.claude/settings.json
191
+ */
192
+ export interface ClaudeSettings {
193
+ enabledPlugins?: Record<string, boolean>
194
+ // Other settings we don't use
195
+ [key: string]: unknown
196
+ }
197
+
198
+ /**
199
+ * Plugin loader options
200
+ */
201
+ export interface PluginLoaderOptions {
202
+ /**
203
+ * Override enabled plugins from oh-my-opencode config.
204
+ * Key format: "pluginName@marketplace" (e.g., "shell-scripting@claude-code-workflows")
205
+ * Value: true = enabled, false = disabled
206
+ *
207
+ * This takes precedence over ~/.claude/settings.json enabledPlugins
208
+ */
209
+ enabledPluginsOverride?: Record<string, boolean>
210
+ }
@@ -0,0 +1 @@
1
+ export * from "./state"
@@ -0,0 +1,126 @@
1
+ import { describe, test, expect, beforeEach } from "bun:test"
2
+ import {
3
+ setSessionAgent,
4
+ getSessionAgent,
5
+ clearSessionAgent,
6
+ updateSessionAgent,
7
+ setMainSession,
8
+ getMainSessionID,
9
+ _resetForTesting,
10
+ } from "./state"
11
+
12
+ describe("claude-code-session-state", () => {
13
+ beforeEach(() => {
14
+ // #given - clean state before each test
15
+ _resetForTesting()
16
+ clearSessionAgent("test-session-1")
17
+ clearSessionAgent("test-session-2")
18
+ clearSessionAgent("test-prometheus-session")
19
+ })
20
+
21
+ describe("setSessionAgent", () => {
22
+ test("should store agent for session", () => {
23
+ // #given
24
+ const sessionID = "test-session-1"
25
+ const agent = "Prometheus (Planner)"
26
+
27
+ // #when
28
+ setSessionAgent(sessionID, agent)
29
+
30
+ // #then
31
+ expect(getSessionAgent(sessionID)).toBe(agent)
32
+ })
33
+
34
+ test("should NOT overwrite existing agent (first-write wins)", () => {
35
+ // #given
36
+ const sessionID = "test-session-1"
37
+ setSessionAgent(sessionID, "Prometheus (Planner)")
38
+
39
+ // #when - try to overwrite
40
+ setSessionAgent(sessionID, "Sisyphus")
41
+
42
+ // #then - first agent preserved
43
+ expect(getSessionAgent(sessionID)).toBe("Prometheus (Planner)")
44
+ })
45
+
46
+ test("should return undefined for unknown session", () => {
47
+ // #given - no session set
48
+
49
+ // #when / #then
50
+ expect(getSessionAgent("unknown-session")).toBeUndefined()
51
+ })
52
+ })
53
+
54
+ describe("updateSessionAgent", () => {
55
+ test("should overwrite existing agent", () => {
56
+ // #given
57
+ const sessionID = "test-session-1"
58
+ setSessionAgent(sessionID, "Prometheus (Planner)")
59
+
60
+ // #when - force update
61
+ updateSessionAgent(sessionID, "Sisyphus")
62
+
63
+ // #then
64
+ expect(getSessionAgent(sessionID)).toBe("Sisyphus")
65
+ })
66
+ })
67
+
68
+ describe("clearSessionAgent", () => {
69
+ test("should remove agent from session", () => {
70
+ // #given
71
+ const sessionID = "test-session-1"
72
+ setSessionAgent(sessionID, "Prometheus (Planner)")
73
+ expect(getSessionAgent(sessionID)).toBe("Prometheus (Planner)")
74
+
75
+ // #when
76
+ clearSessionAgent(sessionID)
77
+
78
+ // #then
79
+ expect(getSessionAgent(sessionID)).toBeUndefined()
80
+ })
81
+ })
82
+
83
+ describe("mainSessionID", () => {
84
+ test("should store and retrieve main session ID", () => {
85
+ // #given
86
+ const mainID = "main-session-123"
87
+
88
+ // #when
89
+ setMainSession(mainID)
90
+
91
+ // #then
92
+ expect(getMainSessionID()).toBe(mainID)
93
+ })
94
+
95
+ test.skip("should return undefined when not set", () => {
96
+ // #given - not set
97
+ // TODO: Fix flaky test - parallel test execution causes state pollution
98
+ // #then
99
+ expect(getMainSessionID()).toBeUndefined()
100
+ })
101
+ })
102
+
103
+ describe("prometheus-md-only integration scenario", () => {
104
+ test("should correctly identify Prometheus agent for permission checks", () => {
105
+ // #given - Prometheus session
106
+ const sessionID = "test-prometheus-session"
107
+ const prometheusAgent = "Prometheus (Planner)"
108
+
109
+ // #when - agent is set (simulating chat.message hook)
110
+ setSessionAgent(sessionID, prometheusAgent)
111
+
112
+ // #then - getSessionAgent returns correct agent for prometheus-md-only hook
113
+ const agent = getSessionAgent(sessionID)
114
+ expect(agent).toBe("Prometheus (Planner)")
115
+ expect(["Prometheus (Planner)"].includes(agent!)).toBe(true)
116
+ })
117
+
118
+ test("should return undefined when agent not set (bug scenario)", () => {
119
+ // #given - session exists but no agent set (the bug)
120
+ const sessionID = "test-prometheus-session"
121
+
122
+ // #when / #then - this is the bug: agent is undefined
123
+ expect(getSessionAgent(sessionID)).toBeUndefined()
124
+ })
125
+ })
126
+ })
@@ -0,0 +1,37 @@
1
+ export const subagentSessions = new Set<string>()
2
+
3
+ let _mainSessionID: string | undefined
4
+
5
+ export function setMainSession(id: string | undefined) {
6
+ _mainSessionID = id
7
+ }
8
+
9
+ export function getMainSessionID(): string | undefined {
10
+ return _mainSessionID
11
+ }
12
+
13
+ /** @internal For testing only */
14
+ export function _resetForTesting(): void {
15
+ _mainSessionID = undefined
16
+ subagentSessions.clear()
17
+ }
18
+
19
+ const sessionAgentMap = new Map<string, string>()
20
+
21
+ export function setSessionAgent(sessionID: string, agent: string): void {
22
+ if (!sessionAgentMap.has(sessionID)) {
23
+ sessionAgentMap.set(sessionID, agent)
24
+ }
25
+ }
26
+
27
+ export function updateSessionAgent(sessionID: string, agent: string): void {
28
+ sessionAgentMap.set(sessionID, agent)
29
+ }
30
+
31
+ export function getSessionAgent(sessionID: string): string | undefined {
32
+ return sessionAgentMap.get(sessionID)
33
+ }
34
+
35
+ export function clearSessionAgent(sessionID: string): void {
36
+ sessionAgentMap.delete(sessionID)
37
+ }
@@ -0,0 +1,330 @@
1
+ import { describe, it, expect, beforeEach } from "bun:test"
2
+ import { ContextCollector } from "./collector"
3
+ import type { ContextPriority, ContextSourceType } from "./types"
4
+
5
+ describe("ContextCollector", () => {
6
+ let collector: ContextCollector
7
+
8
+ beforeEach(() => {
9
+ collector = new ContextCollector()
10
+ })
11
+
12
+ describe("register", () => {
13
+ it("registers context for a session", () => {
14
+ // #given
15
+ const sessionID = "ses_test1"
16
+ const options = {
17
+ id: "ulw-context",
18
+ source: "keyword-detector" as ContextSourceType,
19
+ content: "Ultrawork mode activated",
20
+ }
21
+
22
+ // #when
23
+ collector.register(sessionID, options)
24
+
25
+ // #then
26
+ const pending = collector.getPending(sessionID)
27
+ expect(pending.hasContent).toBe(true)
28
+ expect(pending.entries).toHaveLength(1)
29
+ expect(pending.entries[0].content).toBe("Ultrawork mode activated")
30
+ })
31
+
32
+ it("assigns default priority of 'normal' when not specified", () => {
33
+ // #given
34
+ const sessionID = "ses_test2"
35
+
36
+ // #when
37
+ collector.register(sessionID, {
38
+ id: "test",
39
+ source: "keyword-detector",
40
+ content: "test content",
41
+ })
42
+
43
+ // #then
44
+ const pending = collector.getPending(sessionID)
45
+ expect(pending.entries[0].priority).toBe("normal")
46
+ })
47
+
48
+ it("uses specified priority", () => {
49
+ // #given
50
+ const sessionID = "ses_test3"
51
+
52
+ // #when
53
+ collector.register(sessionID, {
54
+ id: "critical-context",
55
+ source: "keyword-detector",
56
+ content: "critical content",
57
+ priority: "critical",
58
+ })
59
+
60
+ // #then
61
+ const pending = collector.getPending(sessionID)
62
+ expect(pending.entries[0].priority).toBe("critical")
63
+ })
64
+
65
+ it("deduplicates by source + id combination", () => {
66
+ // #given
67
+ const sessionID = "ses_test4"
68
+ const options = {
69
+ id: "ulw-context",
70
+ source: "keyword-detector" as ContextSourceType,
71
+ content: "First content",
72
+ }
73
+
74
+ // #when
75
+ collector.register(sessionID, options)
76
+ collector.register(sessionID, { ...options, content: "Updated content" })
77
+
78
+ // #then
79
+ const pending = collector.getPending(sessionID)
80
+ expect(pending.entries).toHaveLength(1)
81
+ expect(pending.entries[0].content).toBe("Updated content")
82
+ })
83
+
84
+ it("allows same id from different sources", () => {
85
+ // #given
86
+ const sessionID = "ses_test5"
87
+
88
+ // #when
89
+ collector.register(sessionID, {
90
+ id: "context-1",
91
+ source: "keyword-detector",
92
+ content: "From keyword-detector",
93
+ })
94
+ collector.register(sessionID, {
95
+ id: "context-1",
96
+ source: "rules-injector",
97
+ content: "From rules-injector",
98
+ })
99
+
100
+ // #then
101
+ const pending = collector.getPending(sessionID)
102
+ expect(pending.entries).toHaveLength(2)
103
+ })
104
+ })
105
+
106
+ describe("getPending", () => {
107
+ it("returns empty result for session with no context", () => {
108
+ // #given
109
+ const sessionID = "ses_empty"
110
+
111
+ // #when
112
+ const pending = collector.getPending(sessionID)
113
+
114
+ // #then
115
+ expect(pending.hasContent).toBe(false)
116
+ expect(pending.entries).toHaveLength(0)
117
+ expect(pending.merged).toBe("")
118
+ })
119
+
120
+ it("merges multiple contexts with separator", () => {
121
+ // #given
122
+ const sessionID = "ses_merge"
123
+ collector.register(sessionID, {
124
+ id: "ctx-1",
125
+ source: "keyword-detector",
126
+ content: "First context",
127
+ })
128
+ collector.register(sessionID, {
129
+ id: "ctx-2",
130
+ source: "rules-injector",
131
+ content: "Second context",
132
+ })
133
+
134
+ // #when
135
+ const pending = collector.getPending(sessionID)
136
+
137
+ // #then
138
+ expect(pending.hasContent).toBe(true)
139
+ expect(pending.merged).toContain("First context")
140
+ expect(pending.merged).toContain("Second context")
141
+ })
142
+
143
+ it("orders contexts by priority (critical > high > normal > low)", () => {
144
+ // #given
145
+ const sessionID = "ses_priority"
146
+ collector.register(sessionID, {
147
+ id: "low",
148
+ source: "custom",
149
+ content: "LOW",
150
+ priority: "low",
151
+ })
152
+ collector.register(sessionID, {
153
+ id: "critical",
154
+ source: "custom",
155
+ content: "CRITICAL",
156
+ priority: "critical",
157
+ })
158
+ collector.register(sessionID, {
159
+ id: "normal",
160
+ source: "custom",
161
+ content: "NORMAL",
162
+ priority: "normal",
163
+ })
164
+ collector.register(sessionID, {
165
+ id: "high",
166
+ source: "custom",
167
+ content: "HIGH",
168
+ priority: "high",
169
+ })
170
+
171
+ // #when
172
+ const pending = collector.getPending(sessionID)
173
+
174
+ // #then
175
+ const order = pending.entries.map((e) => e.priority)
176
+ expect(order).toEqual(["critical", "high", "normal", "low"])
177
+ })
178
+
179
+ it("maintains registration order within same priority", () => {
180
+ // #given
181
+ const sessionID = "ses_order"
182
+ collector.register(sessionID, {
183
+ id: "first",
184
+ source: "custom",
185
+ content: "First",
186
+ priority: "normal",
187
+ })
188
+ collector.register(sessionID, {
189
+ id: "second",
190
+ source: "custom",
191
+ content: "Second",
192
+ priority: "normal",
193
+ })
194
+ collector.register(sessionID, {
195
+ id: "third",
196
+ source: "custom",
197
+ content: "Third",
198
+ priority: "normal",
199
+ })
200
+
201
+ // #when
202
+ const pending = collector.getPending(sessionID)
203
+
204
+ // #then
205
+ const ids = pending.entries.map((e) => e.id)
206
+ expect(ids).toEqual(["first", "second", "third"])
207
+ })
208
+ })
209
+
210
+ describe("consume", () => {
211
+ it("clears pending context for session", () => {
212
+ // #given
213
+ const sessionID = "ses_consume"
214
+ collector.register(sessionID, {
215
+ id: "ctx",
216
+ source: "keyword-detector",
217
+ content: "test",
218
+ })
219
+
220
+ // #when
221
+ collector.consume(sessionID)
222
+
223
+ // #then
224
+ const pending = collector.getPending(sessionID)
225
+ expect(pending.hasContent).toBe(false)
226
+ })
227
+
228
+ it("returns the consumed context", () => {
229
+ // #given
230
+ const sessionID = "ses_consume_return"
231
+ collector.register(sessionID, {
232
+ id: "ctx",
233
+ source: "keyword-detector",
234
+ content: "test content",
235
+ })
236
+
237
+ // #when
238
+ const consumed = collector.consume(sessionID)
239
+
240
+ // #then
241
+ expect(consumed.hasContent).toBe(true)
242
+ expect(consumed.entries[0].content).toBe("test content")
243
+ })
244
+
245
+ it("does not affect other sessions", () => {
246
+ // #given
247
+ const session1 = "ses_1"
248
+ const session2 = "ses_2"
249
+ collector.register(session1, {
250
+ id: "ctx",
251
+ source: "keyword-detector",
252
+ content: "session 1",
253
+ })
254
+ collector.register(session2, {
255
+ id: "ctx",
256
+ source: "keyword-detector",
257
+ content: "session 2",
258
+ })
259
+
260
+ // #when
261
+ collector.consume(session1)
262
+
263
+ // #then
264
+ expect(collector.getPending(session1).hasContent).toBe(false)
265
+ expect(collector.getPending(session2).hasContent).toBe(true)
266
+ })
267
+ })
268
+
269
+ describe("clear", () => {
270
+ it("removes all context for a session", () => {
271
+ // #given
272
+ const sessionID = "ses_clear"
273
+ collector.register(sessionID, {
274
+ id: "ctx-1",
275
+ source: "keyword-detector",
276
+ content: "test 1",
277
+ })
278
+ collector.register(sessionID, {
279
+ id: "ctx-2",
280
+ source: "rules-injector",
281
+ content: "test 2",
282
+ })
283
+
284
+ // #when
285
+ collector.clear(sessionID)
286
+
287
+ // #then
288
+ expect(collector.getPending(sessionID).hasContent).toBe(false)
289
+ })
290
+ })
291
+
292
+ describe("hasPending", () => {
293
+ it("returns true when session has pending context", () => {
294
+ // #given
295
+ const sessionID = "ses_has"
296
+ collector.register(sessionID, {
297
+ id: "ctx",
298
+ source: "keyword-detector",
299
+ content: "test",
300
+ })
301
+
302
+ // #when / #then
303
+ expect(collector.hasPending(sessionID)).toBe(true)
304
+ })
305
+
306
+ it("returns false when session has no pending context", () => {
307
+ // #given
308
+ const sessionID = "ses_empty"
309
+
310
+ // #when / #then
311
+ expect(collector.hasPending(sessionID)).toBe(false)
312
+ })
313
+
314
+ it("returns false after consume", () => {
315
+ // #given
316
+ const sessionID = "ses_after_consume"
317
+ collector.register(sessionID, {
318
+ id: "ctx",
319
+ source: "keyword-detector",
320
+ content: "test",
321
+ })
322
+
323
+ // #when
324
+ collector.consume(sessionID)
325
+
326
+ // #then
327
+ expect(collector.hasPending(sessionID)).toBe(false)
328
+ })
329
+ })
330
+ })