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,876 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test } from "bun:test"
2
-
3
- import type { BackgroundManager } from "../features/background-agent"
4
- import { setMainSession, subagentSessions, _resetForTesting } from "../features/claude-code-session-state"
5
- import { createTodoContinuationEnforcer } from "./todo-continuation-enforcer"
6
-
7
- describe("todo-continuation-enforcer", () => {
8
- let promptCalls: Array<{ sessionID: string; agent?: string; model?: { providerID?: string; modelID?: string }; text: string }>
9
- let toastCalls: Array<{ title: string; message: string }>
10
-
11
- interface MockMessage {
12
- info: {
13
- id: string
14
- role: "user" | "assistant"
15
- error?: { name: string; data?: { message: string } }
16
- }
17
- }
18
-
19
- let mockMessages: MockMessage[] = []
20
-
21
- function createMockPluginInput() {
22
- return {
23
- client: {
24
- session: {
25
- todo: async () => ({ data: [
26
- { id: "1", content: "Task 1", status: "pending", priority: "high" },
27
- { id: "2", content: "Task 2", status: "completed", priority: "medium" },
28
- ]}),
29
- messages: async () => ({ data: mockMessages }),
30
- prompt: async (opts: any) => {
31
- promptCalls.push({
32
- sessionID: opts.path.id,
33
- agent: opts.body.agent,
34
- model: opts.body.model,
35
- text: opts.body.parts[0].text,
36
- })
37
- return {}
38
- },
39
- },
40
- tui: {
41
- showToast: async (opts: any) => {
42
- toastCalls.push({
43
- title: opts.body.title,
44
- message: opts.body.message,
45
- })
46
- return {}
47
- },
48
- },
49
- },
50
- directory: "/tmp/test",
51
- } as any
52
- }
53
-
54
- function createMockBackgroundManager(runningTasks: boolean = false): BackgroundManager {
55
- return {
56
- getTasksByParentSession: () => runningTasks
57
- ? [{ status: "running" }]
58
- : [],
59
- } as any
60
- }
61
-
62
- beforeEach(() => {
63
- _resetForTesting()
64
- promptCalls = []
65
- toastCalls = []
66
- mockMessages = []
67
- })
68
-
69
- afterEach(() => {
70
- _resetForTesting()
71
- })
72
-
73
- test("should inject continuation when idle with incomplete todos", async () => {
74
- // #given - main session with incomplete todos
75
- const sessionID = "main-123"
76
- setMainSession(sessionID)
77
-
78
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {
79
- backgroundManager: createMockBackgroundManager(false),
80
- })
81
-
82
- // #when - session goes idle
83
- await hook.handler({
84
- event: { type: "session.idle", properties: { sessionID } },
85
- })
86
-
87
- // #then - countdown toast shown
88
- await new Promise(r => setTimeout(r, 100))
89
- expect(toastCalls.length).toBeGreaterThanOrEqual(1)
90
- expect(toastCalls[0].title).toBe("Todo Continuation")
91
-
92
- // #then - after countdown, continuation injected
93
- await new Promise(r => setTimeout(r, 2500))
94
- expect(promptCalls.length).toBe(1)
95
- expect(promptCalls[0].text).toContain("TODO CONTINUATION")
96
- })
97
-
98
- test("should not inject when all todos are complete", async () => {
99
- // #given - session with all todos complete
100
- const sessionID = "main-456"
101
- setMainSession(sessionID)
102
-
103
- const mockInput = createMockPluginInput()
104
- mockInput.client.session.todo = async () => ({ data: [
105
- { id: "1", content: "Task 1", status: "completed", priority: "high" },
106
- ]})
107
-
108
- const hook = createTodoContinuationEnforcer(mockInput, {})
109
-
110
- // #when - session goes idle
111
- await hook.handler({
112
- event: { type: "session.idle", properties: { sessionID } },
113
- })
114
-
115
- await new Promise(r => setTimeout(r, 3000))
116
-
117
- // #then - no continuation injected
118
- expect(promptCalls).toHaveLength(0)
119
- })
120
-
121
- test("should not inject when background tasks are running", async () => {
122
- // #given - session with running background tasks
123
- const sessionID = "main-789"
124
- setMainSession(sessionID)
125
-
126
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {
127
- backgroundManager: createMockBackgroundManager(true),
128
- })
129
-
130
- // #when - session goes idle
131
- await hook.handler({
132
- event: { type: "session.idle", properties: { sessionID } },
133
- })
134
-
135
- await new Promise(r => setTimeout(r, 3000))
136
-
137
- // #then - no continuation injected
138
- expect(promptCalls).toHaveLength(0)
139
- })
140
-
141
- test("should not inject for non-main session", async () => {
142
- // #given - main session set, different session goes idle
143
- setMainSession("main-session")
144
- const otherSession = "other-session"
145
-
146
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
147
-
148
- // #when - non-main session goes idle
149
- await hook.handler({
150
- event: { type: "session.idle", properties: { sessionID: otherSession } },
151
- })
152
-
153
- await new Promise(r => setTimeout(r, 3000))
154
-
155
- // #then - no continuation injected
156
- expect(promptCalls).toHaveLength(0)
157
- })
158
-
159
- test("should inject for background task session (subagent)", async () => {
160
- // #given - main session set, background task session registered
161
- setMainSession("main-session")
162
- const bgTaskSession = "bg-task-session"
163
- subagentSessions.add(bgTaskSession)
164
-
165
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
166
-
167
- // #when - background task session goes idle
168
- await hook.handler({
169
- event: { type: "session.idle", properties: { sessionID: bgTaskSession } },
170
- })
171
-
172
- // #then - continuation injected for background task session
173
- await new Promise(r => setTimeout(r, 2500))
174
- expect(promptCalls.length).toBe(1)
175
- expect(promptCalls[0].sessionID).toBe(bgTaskSession)
176
- })
177
-
178
-
179
-
180
- test("should cancel countdown on user message after grace period", async () => {
181
- // #given - session starting countdown
182
- const sessionID = "main-cancel"
183
- setMainSession(sessionID)
184
-
185
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
186
-
187
- // #when - session goes idle
188
- await hook.handler({
189
- event: { type: "session.idle", properties: { sessionID } },
190
- })
191
-
192
- // #when - wait past grace period (500ms), then user sends message
193
- await new Promise(r => setTimeout(r, 600))
194
- await hook.handler({
195
- event: {
196
- type: "message.updated",
197
- properties: { info: { sessionID, role: "user" } }
198
- },
199
- })
200
-
201
- // #then - wait past countdown time and verify no injection (countdown was cancelled)
202
- await new Promise(r => setTimeout(r, 2500))
203
- expect(promptCalls).toHaveLength(0)
204
- })
205
-
206
- test("should ignore user message within grace period", async () => {
207
- // #given - session starting countdown
208
- const sessionID = "main-grace"
209
- setMainSession(sessionID)
210
-
211
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
212
-
213
- // #when - session goes idle
214
- await hook.handler({
215
- event: { type: "session.idle", properties: { sessionID } },
216
- })
217
-
218
- // #when - user message arrives within grace period (immediately)
219
- await hook.handler({
220
- event: {
221
- type: "message.updated",
222
- properties: { info: { sessionID, role: "user" } }
223
- },
224
- })
225
-
226
- // #then - countdown should continue (message was ignored)
227
- // wait past 2s countdown and verify injection happens
228
- await new Promise(r => setTimeout(r, 2500))
229
- expect(promptCalls).toHaveLength(1)
230
- })
231
-
232
- test("should cancel countdown on assistant activity", async () => {
233
- // #given - session starting countdown
234
- const sessionID = "main-assistant"
235
- setMainSession(sessionID)
236
-
237
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
238
-
239
- // #when - session goes idle
240
- await hook.handler({
241
- event: { type: "session.idle", properties: { sessionID } },
242
- })
243
-
244
- // #when - assistant starts responding
245
- await new Promise(r => setTimeout(r, 500))
246
- await hook.handler({
247
- event: {
248
- type: "message.part.updated",
249
- properties: { info: { sessionID, role: "assistant" } }
250
- },
251
- })
252
-
253
- await new Promise(r => setTimeout(r, 3000))
254
-
255
- // #then - no continuation injected (cancelled)
256
- expect(promptCalls).toHaveLength(0)
257
- })
258
-
259
- test("should cancel countdown on tool execution", async () => {
260
- // #given - session starting countdown
261
- const sessionID = "main-tool"
262
- setMainSession(sessionID)
263
-
264
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
265
-
266
- // #when - session goes idle
267
- await hook.handler({
268
- event: { type: "session.idle", properties: { sessionID } },
269
- })
270
-
271
- // #when - tool starts executing
272
- await new Promise(r => setTimeout(r, 500))
273
- await hook.handler({
274
- event: { type: "tool.execute.before", properties: { sessionID } },
275
- })
276
-
277
- await new Promise(r => setTimeout(r, 3000))
278
-
279
- // #then - no continuation injected (cancelled)
280
- expect(promptCalls).toHaveLength(0)
281
- })
282
-
283
- test("should skip injection during recovery mode", async () => {
284
- // #given - session in recovery mode
285
- const sessionID = "main-recovery"
286
- setMainSession(sessionID)
287
-
288
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
289
-
290
- // #when - mark as recovering
291
- hook.markRecovering(sessionID)
292
-
293
- // #when - session goes idle
294
- await hook.handler({
295
- event: { type: "session.idle", properties: { sessionID } },
296
- })
297
-
298
- await new Promise(r => setTimeout(r, 3000))
299
-
300
- // #then - no continuation injected
301
- expect(promptCalls).toHaveLength(0)
302
- })
303
-
304
- test("should inject after recovery complete", async () => {
305
- // #given - session was in recovery, now complete
306
- const sessionID = "main-recovery-done"
307
- setMainSession(sessionID)
308
-
309
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
310
-
311
- // #when - mark as recovering then complete
312
- hook.markRecovering(sessionID)
313
- hook.markRecoveryComplete(sessionID)
314
-
315
- // #when - session goes idle
316
- await hook.handler({
317
- event: { type: "session.idle", properties: { sessionID } },
318
- })
319
-
320
- await new Promise(r => setTimeout(r, 3000))
321
-
322
- // #then - continuation injected
323
- expect(promptCalls.length).toBe(1)
324
- })
325
-
326
- test("should cleanup on session deleted", async () => {
327
- // #given - session starting countdown
328
- const sessionID = "main-delete"
329
- setMainSession(sessionID)
330
-
331
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
332
-
333
- // #when - session goes idle
334
- await hook.handler({
335
- event: { type: "session.idle", properties: { sessionID } },
336
- })
337
-
338
- // #when - session is deleted during countdown
339
- await new Promise(r => setTimeout(r, 500))
340
- await hook.handler({
341
- event: { type: "session.deleted", properties: { info: { id: sessionID } } },
342
- })
343
-
344
- await new Promise(r => setTimeout(r, 3000))
345
-
346
- // #then - no continuation injected (cleaned up)
347
- expect(promptCalls).toHaveLength(0)
348
- })
349
-
350
- test("should accept skipAgents option without error", async () => {
351
- // #given - session with skipAgents configured for Prometheus
352
- const sessionID = "main-prometheus-option"
353
- setMainSession(sessionID)
354
-
355
- // #when - create hook with skipAgents option (should not throw)
356
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {
357
- skipAgents: ["Prometheus (Planner)", "custom-agent"],
358
- })
359
-
360
- // #then - handler works without error
361
- await hook.handler({
362
- event: { type: "session.idle", properties: { sessionID } },
363
- })
364
-
365
- await new Promise(r => setTimeout(r, 100))
366
- expect(toastCalls.length).toBeGreaterThanOrEqual(1)
367
- })
368
-
369
- test("should show countdown toast updates", async () => {
370
- // #given - session with incomplete todos
371
- const sessionID = "main-toast"
372
- setMainSession(sessionID)
373
-
374
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
375
-
376
- // #when - session goes idle
377
- await hook.handler({
378
- event: { type: "session.idle", properties: { sessionID } },
379
- })
380
-
381
- // #then - multiple toast updates during countdown (2s countdown = 2 toasts: "2s" and "1s")
382
- await new Promise(r => setTimeout(r, 2500))
383
- expect(toastCalls.length).toBeGreaterThanOrEqual(2)
384
- expect(toastCalls[0].message).toContain("2s")
385
- })
386
-
387
- test("should not have 10s throttle between injections", async () => {
388
- // #given - new hook instance (no prior state)
389
- const sessionID = "main-no-throttle"
390
- setMainSession(sessionID)
391
-
392
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
393
-
394
- // #when - first idle cycle completes
395
- await hook.handler({
396
- event: { type: "session.idle", properties: { sessionID } },
397
- })
398
- await new Promise(r => setTimeout(r, 3500))
399
-
400
- // #then - first injection happened
401
- expect(promptCalls.length).toBe(1)
402
-
403
- // #when - immediately trigger second idle (no 10s wait needed)
404
- await hook.handler({
405
- event: { type: "session.idle", properties: { sessionID } },
406
- })
407
- await new Promise(r => setTimeout(r, 3500))
408
-
409
- // #then - second injection also happened (no throttle blocking)
410
- expect(promptCalls.length).toBe(2)
411
- }, { timeout: 15000 })
412
-
413
-
414
-
415
-
416
-
417
-
418
-
419
- test("should NOT skip for non-abort errors even if immediately before idle", async () => {
420
- // #given - session with incomplete todos
421
- const sessionID = "main-noabort-error"
422
- setMainSession(sessionID)
423
-
424
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
425
-
426
- // #when - non-abort error occurs (e.g., network error, API error)
427
- await hook.handler({
428
- event: {
429
- type: "session.error",
430
- properties: {
431
- sessionID,
432
- error: { name: "NetworkError", message: "Connection failed" }
433
- }
434
- },
435
- })
436
-
437
- // #when - session goes idle immediately after
438
- await hook.handler({
439
- event: { type: "session.idle", properties: { sessionID } },
440
- })
441
-
442
- await new Promise(r => setTimeout(r, 2500))
443
-
444
- // #then - continuation injected (non-abort errors don't block)
445
- expect(promptCalls.length).toBe(1)
446
- })
447
-
448
-
449
-
450
-
451
-
452
- // ============================================================
453
- // API-BASED ABORT DETECTION TESTS
454
- // These tests verify that abort is detected by checking
455
- // the last assistant message's error field via session.messages API
456
- // ============================================================
457
-
458
- test("should skip injection when last assistant message has MessageAbortedError", async () => {
459
- // #given - session where last assistant message was aborted
460
- const sessionID = "main-api-abort"
461
- setMainSession(sessionID)
462
-
463
- mockMessages = [
464
- { info: { id: "msg-1", role: "user" } },
465
- { info: { id: "msg-2", role: "assistant", error: { name: "MessageAbortedError", data: { message: "The operation was aborted" } } } },
466
- ]
467
-
468
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
469
-
470
- // #when - session goes idle
471
- await hook.handler({
472
- event: { type: "session.idle", properties: { sessionID } },
473
- })
474
-
475
- await new Promise(r => setTimeout(r, 3000))
476
-
477
- // #then - no continuation (last message was aborted)
478
- expect(promptCalls).toHaveLength(0)
479
- })
480
-
481
- test("should inject when last assistant message has no error", async () => {
482
- // #given - session where last assistant message completed normally
483
- const sessionID = "main-api-no-error"
484
- setMainSession(sessionID)
485
-
486
- mockMessages = [
487
- { info: { id: "msg-1", role: "user" } },
488
- { info: { id: "msg-2", role: "assistant" } },
489
- ]
490
-
491
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
492
-
493
- // #when - session goes idle
494
- await hook.handler({
495
- event: { type: "session.idle", properties: { sessionID } },
496
- })
497
-
498
- await new Promise(r => setTimeout(r, 3000))
499
-
500
- // #then - continuation injected (no abort)
501
- expect(promptCalls.length).toBe(1)
502
- })
503
-
504
- test("should inject when last message is from user (not assistant)", async () => {
505
- // #given - session where last message is from user
506
- const sessionID = "main-api-user-last"
507
- setMainSession(sessionID)
508
-
509
- mockMessages = [
510
- { info: { id: "msg-1", role: "assistant" } },
511
- { info: { id: "msg-2", role: "user" } },
512
- ]
513
-
514
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
515
-
516
- // #when - session goes idle
517
- await hook.handler({
518
- event: { type: "session.idle", properties: { sessionID } },
519
- })
520
-
521
- await new Promise(r => setTimeout(r, 3000))
522
-
523
- // #then - continuation injected (last message is user, not aborted assistant)
524
- expect(promptCalls.length).toBe(1)
525
- })
526
-
527
- test("should skip when last assistant message has any abort-like error", async () => {
528
- // #given - session where last assistant message has AbortError (DOMException style)
529
- const sessionID = "main-api-abort-dom"
530
- setMainSession(sessionID)
531
-
532
- mockMessages = [
533
- { info: { id: "msg-1", role: "user" } },
534
- { info: { id: "msg-2", role: "assistant", error: { name: "AbortError" } } },
535
- ]
536
-
537
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
538
-
539
- // #when - session goes idle
540
- await hook.handler({
541
- event: { type: "session.idle", properties: { sessionID } },
542
- })
543
-
544
- await new Promise(r => setTimeout(r, 3000))
545
-
546
- // #then - no continuation (abort error detected)
547
- expect(promptCalls).toHaveLength(0)
548
- })
549
-
550
- test("should skip injection when abort detected via session.error event (event-based, primary)", async () => {
551
- // #given - session with incomplete todos
552
- const sessionID = "main-event-abort"
553
- setMainSession(sessionID)
554
- mockMessages = [
555
- { info: { id: "msg-1", role: "user" } },
556
- { info: { id: "msg-2", role: "assistant" } },
557
- ]
558
-
559
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
560
-
561
- // #when - abort error event fires
562
- await hook.handler({
563
- event: {
564
- type: "session.error",
565
- properties: { sessionID, error: { name: "MessageAbortedError" } },
566
- },
567
- })
568
-
569
- // #when - session goes idle immediately after
570
- await hook.handler({
571
- event: { type: "session.idle", properties: { sessionID } },
572
- })
573
-
574
- await new Promise(r => setTimeout(r, 3000))
575
-
576
- // #then - no continuation (abort detected via event)
577
- expect(promptCalls).toHaveLength(0)
578
- })
579
-
580
- test("should skip injection when AbortError detected via session.error event", async () => {
581
- // #given - session with incomplete todos
582
- const sessionID = "main-event-abort-dom"
583
- setMainSession(sessionID)
584
- mockMessages = [
585
- { info: { id: "msg-1", role: "user" } },
586
- { info: { id: "msg-2", role: "assistant" } },
587
- ]
588
-
589
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
590
-
591
- // #when - AbortError event fires
592
- await hook.handler({
593
- event: {
594
- type: "session.error",
595
- properties: { sessionID, error: { name: "AbortError" } },
596
- },
597
- })
598
-
599
- // #when - session goes idle
600
- await hook.handler({
601
- event: { type: "session.idle", properties: { sessionID } },
602
- })
603
-
604
- await new Promise(r => setTimeout(r, 3000))
605
-
606
- // #then - no continuation (abort detected via event)
607
- expect(promptCalls).toHaveLength(0)
608
- })
609
-
610
- test("should inject when abort flag is stale (>3s old)", async () => {
611
- // #given - session with incomplete todos and old abort timestamp
612
- const sessionID = "main-stale-abort"
613
- setMainSession(sessionID)
614
- mockMessages = [
615
- { info: { id: "msg-1", role: "user" } },
616
- { info: { id: "msg-2", role: "assistant" } },
617
- ]
618
-
619
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
620
-
621
- // #when - abort error fires
622
- await hook.handler({
623
- event: {
624
- type: "session.error",
625
- properties: { sessionID, error: { name: "MessageAbortedError" } },
626
- },
627
- })
628
-
629
- // #when - wait >3s then idle fires
630
- await new Promise(r => setTimeout(r, 3100))
631
-
632
- await hook.handler({
633
- event: { type: "session.idle", properties: { sessionID } },
634
- })
635
-
636
- await new Promise(r => setTimeout(r, 3000))
637
-
638
- // #then - continuation injected (abort flag is stale)
639
- expect(promptCalls.length).toBeGreaterThan(0)
640
- }, 10000)
641
-
642
- test("should clear abort flag on user message activity", async () => {
643
- // #given - session with abort detected
644
- const sessionID = "main-clear-on-user"
645
- setMainSession(sessionID)
646
- mockMessages = [
647
- { info: { id: "msg-1", role: "user" } },
648
- { info: { id: "msg-2", role: "assistant" } },
649
- ]
650
-
651
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
652
-
653
- // #when - abort error fires
654
- await hook.handler({
655
- event: {
656
- type: "session.error",
657
- properties: { sessionID, error: { name: "MessageAbortedError" } },
658
- },
659
- })
660
-
661
- // #when - user sends new message (clears abort flag)
662
- await new Promise(r => setTimeout(r, 600))
663
- await hook.handler({
664
- event: {
665
- type: "message.updated",
666
- properties: { info: { sessionID, role: "user" } },
667
- },
668
- })
669
-
670
- // #when - session goes idle
671
- await hook.handler({
672
- event: { type: "session.idle", properties: { sessionID } },
673
- })
674
-
675
- await new Promise(r => setTimeout(r, 3000))
676
-
677
- // #then - continuation injected (abort flag was cleared by user activity)
678
- expect(promptCalls.length).toBeGreaterThan(0)
679
- })
680
-
681
- test("should clear abort flag on assistant message activity", async () => {
682
- // #given - session with abort detected
683
- const sessionID = "main-clear-on-assistant"
684
- setMainSession(sessionID)
685
- mockMessages = [
686
- { info: { id: "msg-1", role: "user" } },
687
- { info: { id: "msg-2", role: "assistant" } },
688
- ]
689
-
690
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
691
-
692
- // #when - abort error fires
693
- await hook.handler({
694
- event: {
695
- type: "session.error",
696
- properties: { sessionID, error: { name: "MessageAbortedError" } },
697
- },
698
- })
699
-
700
- // #when - assistant starts responding (clears abort flag)
701
- await hook.handler({
702
- event: {
703
- type: "message.updated",
704
- properties: { info: { sessionID, role: "assistant" } },
705
- },
706
- })
707
-
708
- // #when - session goes idle
709
- await hook.handler({
710
- event: { type: "session.idle", properties: { sessionID } },
711
- })
712
-
713
- await new Promise(r => setTimeout(r, 3000))
714
-
715
- // #then - continuation injected (abort flag was cleared by assistant activity)
716
- expect(promptCalls.length).toBeGreaterThan(0)
717
- })
718
-
719
- test("should clear abort flag on tool execution", async () => {
720
- // #given - session with abort detected
721
- const sessionID = "main-clear-on-tool"
722
- setMainSession(sessionID)
723
- mockMessages = [
724
- { info: { id: "msg-1", role: "user" } },
725
- { info: { id: "msg-2", role: "assistant" } },
726
- ]
727
-
728
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
729
-
730
- // #when - abort error fires
731
- await hook.handler({
732
- event: {
733
- type: "session.error",
734
- properties: { sessionID, error: { name: "MessageAbortedError" } },
735
- },
736
- })
737
-
738
- // #when - tool executes (clears abort flag)
739
- await hook.handler({
740
- event: {
741
- type: "tool.execute.before",
742
- properties: { sessionID },
743
- },
744
- })
745
-
746
- // #when - session goes idle
747
- await hook.handler({
748
- event: { type: "session.idle", properties: { sessionID } },
749
- })
750
-
751
- await new Promise(r => setTimeout(r, 3000))
752
-
753
- // #then - continuation injected (abort flag was cleared by tool execution)
754
- expect(promptCalls.length).toBeGreaterThan(0)
755
- })
756
-
757
- test("should use event-based detection even when API indicates no abort (event wins)", async () => {
758
- // #given - session with abort event but API shows no error
759
- const sessionID = "main-event-wins"
760
- setMainSession(sessionID)
761
- mockMessages = [
762
- { info: { id: "msg-1", role: "user" } },
763
- { info: { id: "msg-2", role: "assistant" } },
764
- ]
765
-
766
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
767
-
768
- // #when - abort error event fires (but API doesn't have it yet)
769
- await hook.handler({
770
- event: {
771
- type: "session.error",
772
- properties: { sessionID, error: { name: "MessageAbortedError" } },
773
- },
774
- })
775
-
776
- // #when - session goes idle
777
- await hook.handler({
778
- event: { type: "session.idle", properties: { sessionID } },
779
- })
780
-
781
- await new Promise(r => setTimeout(r, 3000))
782
-
783
- // #then - no continuation (event-based detection wins over API)
784
- expect(promptCalls).toHaveLength(0)
785
- })
786
-
787
- test("should use API fallback when event is missed but API shows abort", async () => {
788
- // #given - session where event was missed but API shows abort
789
- const sessionID = "main-api-fallback"
790
- setMainSession(sessionID)
791
- mockMessages = [
792
- { info: { id: "msg-1", role: "user" } },
793
- { info: { id: "msg-2", role: "assistant", error: { name: "MessageAbortedError" } } },
794
- ]
795
-
796
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
797
-
798
- // #when - session goes idle without prior session.error event
799
- await hook.handler({
800
- event: { type: "session.idle", properties: { sessionID } },
801
- })
802
-
803
- await new Promise(r => setTimeout(r, 3000))
804
-
805
- // #then - no continuation (API fallback detected the abort)
806
- expect(promptCalls).toHaveLength(0)
807
- })
808
-
809
- test("should pass model property in prompt call (undefined when no message context)", async () => {
810
- // #given - session with incomplete todos, no prior message context available
811
- const sessionID = "main-model-preserve"
812
- setMainSession(sessionID)
813
-
814
- const hook = createTodoContinuationEnforcer(createMockPluginInput(), {
815
- backgroundManager: createMockBackgroundManager(false),
816
- })
817
-
818
- // #when - session goes idle and continuation is injected
819
- await hook.handler({
820
- event: { type: "session.idle", properties: { sessionID } },
821
- })
822
-
823
- await new Promise(r => setTimeout(r, 2500))
824
-
825
- // #then - prompt call made, model is undefined when no context (expected behavior)
826
- expect(promptCalls.length).toBe(1)
827
- expect(promptCalls[0].text).toContain("TODO CONTINUATION")
828
- expect("model" in promptCalls[0]).toBe(true)
829
- })
830
-
831
- test("should extract model from assistant message with flat modelID/providerID", async () => {
832
- // #given - session with assistant message that has flat modelID/providerID (OpenCode API format)
833
- const sessionID = "main-assistant-model"
834
- setMainSession(sessionID)
835
-
836
- // OpenCode returns assistant messages with flat modelID/providerID, not nested model object
837
- const mockMessagesWithAssistant = [
838
- { info: { id: "msg-1", role: "user", agent: "Sisyphus", model: { providerID: "openai", modelID: "gpt-5.2" } } },
839
- { info: { id: "msg-2", role: "assistant", agent: "Sisyphus", modelID: "gpt-5.2", providerID: "openai" } },
840
- ]
841
-
842
- const mockInput = {
843
- client: {
844
- session: {
845
- todo: async () => ({
846
- data: [{ id: "1", content: "Task 1", status: "pending", priority: "high" }],
847
- }),
848
- messages: async () => ({ data: mockMessagesWithAssistant }),
849
- prompt: async (opts: any) => {
850
- promptCalls.push({
851
- sessionID: opts.path.id,
852
- agent: opts.body.agent,
853
- model: opts.body.model,
854
- text: opts.body.parts[0].text,
855
- })
856
- return {}
857
- },
858
- },
859
- tui: { showToast: async () => ({}) },
860
- },
861
- directory: "/tmp/test",
862
- } as any
863
-
864
- const hook = createTodoContinuationEnforcer(mockInput, {
865
- backgroundManager: createMockBackgroundManager(false),
866
- })
867
-
868
- // #when - session goes idle
869
- await hook.handler({ event: { type: "session.idle", properties: { sessionID } } })
870
- await new Promise(r => setTimeout(r, 2500))
871
-
872
- // #then - model should be extracted from assistant message's flat modelID/providerID
873
- expect(promptCalls.length).toBe(1)
874
- expect(promptCalls[0].model).toEqual({ providerID: "openai", modelID: "gpt-5.2" })
875
- })
876
- })