opencode-repos 0.3.0 → 0.3.1

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 +10 -6
  2. package/package.json +1 -1
  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,835 +0,0 @@
1
- import { describe, expect, test, beforeEach, afterEach } from "bun:test"
2
- import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
3
- import { join } from "node:path"
4
- import { tmpdir } from "node:os"
5
- import { createRalphLoopHook } from "./index"
6
- import { readState, writeState, clearState } from "./storage"
7
- import type { RalphLoopState } from "./types"
8
-
9
- describe("ralph-loop", () => {
10
- const TEST_DIR = join(tmpdir(), "ralph-loop-test-" + Date.now())
11
- let promptCalls: Array<{ sessionID: string; text: string }>
12
- let toastCalls: Array<{ title: string; message: string; variant: string }>
13
- let messagesCalls: Array<{ sessionID: string }>
14
- let mockSessionMessages: Array<{ info?: { role?: string }; parts?: Array<{ type: string; text?: string }> }>
15
-
16
- function createMockPluginInput() {
17
- return {
18
- client: {
19
- session: {
20
- prompt: async (opts: { path: { id: string }; body: { parts: Array<{ type: string; text: string }> } }) => {
21
- promptCalls.push({
22
- sessionID: opts.path.id,
23
- text: opts.body.parts[0].text,
24
- })
25
- return {}
26
- },
27
- messages: async (opts: { path: { id: string } }) => {
28
- messagesCalls.push({ sessionID: opts.path.id })
29
- return { data: mockSessionMessages }
30
- },
31
- },
32
- tui: {
33
- showToast: async (opts: { body: { title: string; message: string; variant: string } }) => {
34
- toastCalls.push({
35
- title: opts.body.title,
36
- message: opts.body.message,
37
- variant: opts.body.variant,
38
- })
39
- return {}
40
- },
41
- },
42
- },
43
- directory: TEST_DIR,
44
- } as unknown as Parameters<typeof createRalphLoopHook>[0]
45
- }
46
-
47
- beforeEach(() => {
48
- promptCalls = []
49
- toastCalls = []
50
- messagesCalls = []
51
- mockSessionMessages = []
52
-
53
- if (!existsSync(TEST_DIR)) {
54
- mkdirSync(TEST_DIR, { recursive: true })
55
- }
56
-
57
- clearState(TEST_DIR)
58
- })
59
-
60
- afterEach(() => {
61
- clearState(TEST_DIR)
62
- if (existsSync(TEST_DIR)) {
63
- rmSync(TEST_DIR, { recursive: true, force: true })
64
- }
65
- })
66
-
67
- describe("storage", () => {
68
- test("should write and read state correctly", () => {
69
- // #given - a state object
70
- const state: RalphLoopState = {
71
- active: true,
72
- iteration: 1,
73
- max_iterations: 50,
74
- completion_promise: "DONE",
75
- started_at: "2025-12-30T01:00:00Z",
76
- prompt: "Build a REST API",
77
- session_id: "test-session-123",
78
- }
79
-
80
- // #when - write and read state
81
- const writeSuccess = writeState(TEST_DIR, state)
82
- const readResult = readState(TEST_DIR)
83
-
84
- // #then - state should match
85
- expect(writeSuccess).toBe(true)
86
- expect(readResult).not.toBeNull()
87
- expect(readResult?.active).toBe(true)
88
- expect(readResult?.iteration).toBe(1)
89
- expect(readResult?.max_iterations).toBe(50)
90
- expect(readResult?.completion_promise).toBe("DONE")
91
- expect(readResult?.prompt).toBe("Build a REST API")
92
- expect(readResult?.session_id).toBe("test-session-123")
93
- })
94
-
95
- test("should handle ultrawork field", () => {
96
- // #given - a state object with ultrawork enabled
97
- const state: RalphLoopState = {
98
- active: true,
99
- iteration: 1,
100
- max_iterations: 50,
101
- completion_promise: "DONE",
102
- started_at: "2025-12-30T01:00:00Z",
103
- prompt: "Build a REST API",
104
- session_id: "test-session-123",
105
- ultrawork: true,
106
- }
107
-
108
- // #when - write and read state
109
- writeState(TEST_DIR, state)
110
- const readResult = readState(TEST_DIR)
111
-
112
- // #then - ultrawork field should be preserved
113
- expect(readResult?.ultrawork).toBe(true)
114
- })
115
-
116
- test("should return null for non-existent state", () => {
117
- // #given - no state file exists
118
- // #when - read state
119
- const result = readState(TEST_DIR)
120
-
121
- // #then - should return null
122
- expect(result).toBeNull()
123
- })
124
-
125
- test("should clear state correctly", () => {
126
- // #given - existing state
127
- const state: RalphLoopState = {
128
- active: true,
129
- iteration: 1,
130
- max_iterations: 50,
131
- completion_promise: "DONE",
132
- started_at: "2025-12-30T01:00:00Z",
133
- prompt: "Test prompt",
134
- }
135
- writeState(TEST_DIR, state)
136
-
137
- // #when - clear state
138
- const clearSuccess = clearState(TEST_DIR)
139
- const readResult = readState(TEST_DIR)
140
-
141
- // #then - state should be cleared
142
- expect(clearSuccess).toBe(true)
143
- expect(readResult).toBeNull()
144
- })
145
-
146
- test("should handle multiline prompts", () => {
147
- // #given - state with multiline prompt
148
- const state: RalphLoopState = {
149
- active: true,
150
- iteration: 1,
151
- max_iterations: 10,
152
- completion_promise: "FINISHED",
153
- started_at: "2025-12-30T02:00:00Z",
154
- prompt: "Build a feature\nwith multiple lines\nand requirements",
155
- }
156
-
157
- // #when - write and read
158
- writeState(TEST_DIR, state)
159
- const readResult = readState(TEST_DIR)
160
-
161
- // #then - multiline prompt preserved
162
- expect(readResult?.prompt).toBe("Build a feature\nwith multiple lines\nand requirements")
163
- })
164
- })
165
-
166
- describe("hook", () => {
167
- test("should start loop and write state", () => {
168
- // #given - hook instance
169
- const hook = createRalphLoopHook(createMockPluginInput())
170
-
171
- // #when - start loop
172
- const success = hook.startLoop("session-123", "Build something", {
173
- maxIterations: 25,
174
- completionPromise: "FINISHED",
175
- })
176
-
177
- // #then - state should be written
178
- expect(success).toBe(true)
179
- const state = hook.getState()
180
- expect(state?.active).toBe(true)
181
- expect(state?.iteration).toBe(1)
182
- expect(state?.max_iterations).toBe(25)
183
- expect(state?.completion_promise).toBe("FINISHED")
184
- expect(state?.prompt).toBe("Build something")
185
- expect(state?.session_id).toBe("session-123")
186
- })
187
-
188
- test("should accept ultrawork option in startLoop", () => {
189
- // #given - hook instance
190
- const hook = createRalphLoopHook(createMockPluginInput())
191
-
192
- // #when - start loop with ultrawork
193
- hook.startLoop("session-123", "Build something", { ultrawork: true })
194
-
195
- // #then - state should have ultrawork=true
196
- const state = hook.getState()
197
- expect(state?.ultrawork).toBe(true)
198
- })
199
-
200
- test("should handle missing ultrawork option in startLoop", () => {
201
- // #given - hook instance
202
- const hook = createRalphLoopHook(createMockPluginInput())
203
-
204
- // #when - start loop without ultrawork
205
- hook.startLoop("session-123", "Build something")
206
-
207
- // #then - state should have ultrawork=undefined
208
- const state = hook.getState()
209
- expect(state?.ultrawork).toBeUndefined()
210
- })
211
-
212
- test("should inject continuation when loop active and no completion detected", async () => {
213
- // #given - active loop state
214
- const hook = createRalphLoopHook(createMockPluginInput())
215
- hook.startLoop("session-123", "Build a feature", { maxIterations: 10 })
216
-
217
- // #when - session goes idle
218
- await hook.event({
219
- event: {
220
- type: "session.idle",
221
- properties: { sessionID: "session-123" },
222
- },
223
- })
224
-
225
- // #then - continuation should be injected
226
- expect(promptCalls.length).toBe(1)
227
- expect(promptCalls[0].sessionID).toBe("session-123")
228
- expect(promptCalls[0].text).toContain("RALPH LOOP")
229
- expect(promptCalls[0].text).toContain("Build a feature")
230
- expect(promptCalls[0].text).toContain("2/10")
231
-
232
- // #then - iteration should be incremented
233
- const state = hook.getState()
234
- expect(state?.iteration).toBe(2)
235
- })
236
-
237
- test("should stop loop when max iterations reached", async () => {
238
- // #given - loop at max iteration
239
- const hook = createRalphLoopHook(createMockPluginInput())
240
- hook.startLoop("session-123", "Build something", { maxIterations: 2 })
241
-
242
- const state = hook.getState()!
243
- state.iteration = 2
244
- writeState(TEST_DIR, state)
245
-
246
- // #when - session goes idle
247
- await hook.event({
248
- event: {
249
- type: "session.idle",
250
- properties: { sessionID: "session-123" },
251
- },
252
- })
253
-
254
- // #then - no continuation injected
255
- expect(promptCalls.length).toBe(0)
256
-
257
- // #then - warning toast shown
258
- expect(toastCalls.length).toBe(1)
259
- expect(toastCalls[0].title).toBe("Ralph Loop Stopped")
260
- expect(toastCalls[0].variant).toBe("warning")
261
-
262
- // #then - state should be cleared
263
- expect(hook.getState()).toBeNull()
264
- })
265
-
266
- test("should cancel loop via cancelLoop", () => {
267
- // #given - active loop
268
- const hook = createRalphLoopHook(createMockPluginInput())
269
- hook.startLoop("session-123", "Test task")
270
-
271
- // #when - cancel loop
272
- const success = hook.cancelLoop("session-123")
273
-
274
- // #then - loop cancelled
275
- expect(success).toBe(true)
276
- expect(hook.getState()).toBeNull()
277
- })
278
-
279
- test("should not cancel loop for different session", () => {
280
- // #given - active loop for session-123
281
- const hook = createRalphLoopHook(createMockPluginInput())
282
- hook.startLoop("session-123", "Test task")
283
-
284
- // #when - try to cancel for different session
285
- const success = hook.cancelLoop("session-456")
286
-
287
- // #then - cancel should fail
288
- expect(success).toBe(false)
289
- expect(hook.getState()).not.toBeNull()
290
- })
291
-
292
- test("should skip injection during recovery", async () => {
293
- // #given - active loop and session in recovery
294
- const hook = createRalphLoopHook(createMockPluginInput())
295
- hook.startLoop("session-123", "Test task")
296
-
297
- await hook.event({
298
- event: {
299
- type: "session.error",
300
- properties: { sessionID: "session-123", error: new Error("test") },
301
- },
302
- })
303
-
304
- // #when - session goes idle immediately
305
- await hook.event({
306
- event: {
307
- type: "session.idle",
308
- properties: { sessionID: "session-123" },
309
- },
310
- })
311
-
312
- // #then - no continuation injected
313
- expect(promptCalls.length).toBe(0)
314
- })
315
-
316
- test("should clear state on session deletion", async () => {
317
- // #given - active loop
318
- const hook = createRalphLoopHook(createMockPluginInput())
319
- hook.startLoop("session-123", "Test task")
320
-
321
- // #when - session deleted
322
- await hook.event({
323
- event: {
324
- type: "session.deleted",
325
- properties: { info: { id: "session-123" } },
326
- },
327
- })
328
-
329
- // #then - state should be cleared
330
- expect(hook.getState()).toBeNull()
331
- })
332
-
333
- test("should not inject for different session than loop owner", async () => {
334
- // #given - loop owned by session-123
335
- const hook = createRalphLoopHook(createMockPluginInput())
336
- hook.startLoop("session-123", "Test task")
337
-
338
- // #when - different session goes idle
339
- await hook.event({
340
- event: {
341
- type: "session.idle",
342
- properties: { sessionID: "session-456" },
343
- },
344
- })
345
-
346
- // #then - no continuation injected
347
- expect(promptCalls.length).toBe(0)
348
- })
349
-
350
- test("should clear orphaned state when original session no longer exists", async () => {
351
- // #given - state file exists from a previous session that no longer exists
352
- const state: RalphLoopState = {
353
- active: true,
354
- iteration: 3,
355
- max_iterations: 50,
356
- completion_promise: "DONE",
357
- started_at: "2025-12-30T01:00:00Z",
358
- prompt: "Build something",
359
- session_id: "orphaned-session-999", // This session no longer exists
360
- }
361
- writeState(TEST_DIR, state)
362
-
363
- // Mock sessionExists to return false for the orphaned session
364
- const hook = createRalphLoopHook(createMockPluginInput(), {
365
- checkSessionExists: async (sessionID: string) => {
366
- // Orphaned session doesn't exist, current session does
367
- return sessionID !== "orphaned-session-999"
368
- },
369
- })
370
-
371
- // #when - a new session goes idle (different from the orphaned session in state)
372
- await hook.event({
373
- event: {
374
- type: "session.idle",
375
- properties: { sessionID: "new-session-456" },
376
- },
377
- })
378
-
379
- // #then - orphaned state should be cleared
380
- expect(hook.getState()).toBeNull()
381
- // #then - no continuation injected (state was cleared, not resumed)
382
- expect(promptCalls.length).toBe(0)
383
- })
384
-
385
- test("should NOT clear state when original session still exists (different active session)", async () => {
386
- // #given - state file exists from a session that still exists
387
- const state: RalphLoopState = {
388
- active: true,
389
- iteration: 2,
390
- max_iterations: 50,
391
- completion_promise: "DONE",
392
- started_at: "2025-12-30T01:00:00Z",
393
- prompt: "Build something",
394
- session_id: "active-session-123", // This session still exists
395
- }
396
- writeState(TEST_DIR, state)
397
-
398
- // Mock sessionExists to return true for the active session
399
- const hook = createRalphLoopHook(createMockPluginInput(), {
400
- checkSessionExists: async (sessionID: string) => {
401
- // Original session still exists
402
- return sessionID === "active-session-123" || sessionID === "new-session-456"
403
- },
404
- })
405
-
406
- // #when - a different session goes idle
407
- await hook.event({
408
- event: {
409
- type: "session.idle",
410
- properties: { sessionID: "new-session-456" },
411
- },
412
- })
413
-
414
- // #then - state should NOT be cleared (original session still active)
415
- expect(hook.getState()).not.toBeNull()
416
- expect(hook.getState()?.session_id).toBe("active-session-123")
417
- // #then - no continuation injected (it's a different session's loop)
418
- expect(promptCalls.length).toBe(0)
419
- })
420
-
421
- test("should use default config values", () => {
422
- // #given - hook with config
423
- const hook = createRalphLoopHook(createMockPluginInput(), {
424
- config: {
425
- enabled: true,
426
- default_max_iterations: 200,
427
- },
428
- })
429
-
430
- // #when - start loop without options
431
- hook.startLoop("session-123", "Test task")
432
-
433
- // #then - should use config defaults
434
- const state = hook.getState()
435
- expect(state?.max_iterations).toBe(200)
436
- })
437
-
438
- test("should not inject when no loop is active", async () => {
439
- // #given - no active loop
440
- const hook = createRalphLoopHook(createMockPluginInput())
441
-
442
- // #when - session goes idle
443
- await hook.event({
444
- event: {
445
- type: "session.idle",
446
- properties: { sessionID: "session-123" },
447
- },
448
- })
449
-
450
- // #then - no continuation injected
451
- expect(promptCalls.length).toBe(0)
452
- })
453
-
454
- test("should detect completion promise and stop loop", async () => {
455
- // #given - active loop with transcript containing completion
456
- const transcriptPath = join(TEST_DIR, "transcript.jsonl")
457
- const hook = createRalphLoopHook(createMockPluginInput(), {
458
- getTranscriptPath: () => transcriptPath,
459
- })
460
- hook.startLoop("session-123", "Build something", { completionPromise: "COMPLETE" })
461
-
462
- writeFileSync(transcriptPath, JSON.stringify({ content: "Task done <promise>COMPLETE</promise>" }))
463
-
464
- // #when - session goes idle (transcriptPath now derived from sessionID via getTranscriptPath)
465
- await hook.event({
466
- event: {
467
- type: "session.idle",
468
- properties: { sessionID: "session-123" },
469
- },
470
- })
471
-
472
- // #then - loop completed, no continuation
473
- expect(promptCalls.length).toBe(0)
474
- expect(toastCalls.some((t) => t.title === "Ralph Loop Complete!")).toBe(true)
475
- expect(hook.getState()).toBeNull()
476
- })
477
-
478
- test("should detect completion promise via session messages API", async () => {
479
- // #given - active loop with assistant message containing completion promise
480
- mockSessionMessages = [
481
- { info: { role: "user" }, parts: [{ type: "text", text: "Build something" }] },
482
- { info: { role: "assistant" }, parts: [{ type: "text", text: "I have completed the task. <promise>API_DONE</promise>" }] },
483
- ]
484
- const hook = createRalphLoopHook(createMockPluginInput(), {
485
- getTranscriptPath: () => join(TEST_DIR, "nonexistent.jsonl"),
486
- })
487
- hook.startLoop("session-123", "Build something", { completionPromise: "API_DONE" })
488
-
489
- // #when - session goes idle
490
- await hook.event({
491
- event: {
492
- type: "session.idle",
493
- properties: { sessionID: "session-123" },
494
- },
495
- })
496
-
497
- // #then - loop completed via API detection, no continuation
498
- expect(promptCalls.length).toBe(0)
499
- expect(toastCalls.some((t) => t.title === "Ralph Loop Complete!")).toBe(true)
500
- expect(hook.getState()).toBeNull()
501
-
502
- // #then - messages API was called with correct session ID
503
- expect(messagesCalls.length).toBe(1)
504
- expect(messagesCalls[0].sessionID).toBe("session-123")
505
- })
506
-
507
- test("should handle multiple iterations correctly", async () => {
508
- // #given - active loop
509
- const hook = createRalphLoopHook(createMockPluginInput())
510
- hook.startLoop("session-123", "Build feature", { maxIterations: 5 })
511
-
512
- // #when - multiple idle events
513
- await hook.event({
514
- event: { type: "session.idle", properties: { sessionID: "session-123" } },
515
- })
516
- await hook.event({
517
- event: { type: "session.idle", properties: { sessionID: "session-123" } },
518
- })
519
-
520
- // #then - iteration incremented correctly
521
- expect(hook.getState()?.iteration).toBe(3)
522
- expect(promptCalls.length).toBe(2)
523
- })
524
-
525
- test("should include prompt and promise in continuation message", async () => {
526
- // #given - loop with specific prompt and promise
527
- const hook = createRalphLoopHook(createMockPluginInput())
528
- hook.startLoop("session-123", "Create a calculator app", {
529
- completionPromise: "CALCULATOR_DONE",
530
- maxIterations: 10,
531
- })
532
-
533
- // #when - session goes idle
534
- await hook.event({
535
- event: { type: "session.idle", properties: { sessionID: "session-123" } },
536
- })
537
-
538
- // #then - continuation includes original task and promise
539
- expect(promptCalls[0].text).toContain("Create a calculator app")
540
- expect(promptCalls[0].text).toContain("<promise>CALCULATOR_DONE</promise>")
541
- })
542
-
543
- test("should clear loop state on user abort (MessageAbortedError)", async () => {
544
- // #given - active loop
545
- const hook = createRalphLoopHook(createMockPluginInput())
546
- hook.startLoop("session-123", "Build something")
547
- expect(hook.getState()).not.toBeNull()
548
-
549
- // #when - user aborts (Ctrl+C)
550
- await hook.event({
551
- event: {
552
- type: "session.error",
553
- properties: {
554
- sessionID: "session-123",
555
- error: { name: "MessageAbortedError", message: "User aborted" },
556
- },
557
- },
558
- })
559
-
560
- // #then - loop state should be cleared immediately
561
- expect(hook.getState()).toBeNull()
562
- })
563
-
564
- test("should NOT set recovery mode on user abort", async () => {
565
- // #given - active loop
566
- const hook = createRalphLoopHook(createMockPluginInput())
567
- hook.startLoop("session-123", "Build something")
568
-
569
- // #when - user aborts (Ctrl+C)
570
- await hook.event({
571
- event: {
572
- type: "session.error",
573
- properties: {
574
- sessionID: "session-123",
575
- error: { name: "MessageAbortedError" },
576
- },
577
- },
578
- })
579
-
580
- // Start a new loop
581
- hook.startLoop("session-123", "New task")
582
-
583
- // #when - session goes idle immediately (should work, no recovery mode)
584
- await hook.event({
585
- event: { type: "session.idle", properties: { sessionID: "session-123" } },
586
- })
587
-
588
- // #then - continuation should be injected (not blocked by recovery)
589
- expect(promptCalls.length).toBe(1)
590
- })
591
-
592
- test("should only check LAST assistant message for completion", async () => {
593
- // #given - multiple assistant messages, only first has completion promise
594
- mockSessionMessages = [
595
- { info: { role: "user" }, parts: [{ type: "text", text: "Start task" }] },
596
- { info: { role: "assistant" }, parts: [{ type: "text", text: "I'll work on it. <promise>DONE</promise>" }] },
597
- { info: { role: "user" }, parts: [{ type: "text", text: "Continue" }] },
598
- { info: { role: "assistant" }, parts: [{ type: "text", text: "Working on more features..." }] },
599
- ]
600
- const hook = createRalphLoopHook(createMockPluginInput(), {
601
- getTranscriptPath: () => join(TEST_DIR, "nonexistent.jsonl"),
602
- })
603
- hook.startLoop("session-123", "Build something", { completionPromise: "DONE" })
604
-
605
- // #when - session goes idle
606
- await hook.event({
607
- event: { type: "session.idle", properties: { sessionID: "session-123" } },
608
- })
609
-
610
- // #then - loop should continue (last message has no completion promise)
611
- expect(promptCalls.length).toBe(1)
612
- expect(hook.getState()?.iteration).toBe(2)
613
- })
614
-
615
- test("should detect completion only in LAST assistant message", async () => {
616
- // #given - last assistant message has completion promise
617
- mockSessionMessages = [
618
- { info: { role: "user" }, parts: [{ type: "text", text: "Start task" }] },
619
- { info: { role: "assistant" }, parts: [{ type: "text", text: "Starting work..." }] },
620
- { info: { role: "user" }, parts: [{ type: "text", text: "Continue" }] },
621
- { info: { role: "assistant" }, parts: [{ type: "text", text: "Task complete! <promise>DONE</promise>" }] },
622
- ]
623
- const hook = createRalphLoopHook(createMockPluginInput(), {
624
- getTranscriptPath: () => join(TEST_DIR, "nonexistent.jsonl"),
625
- })
626
- hook.startLoop("session-123", "Build something", { completionPromise: "DONE" })
627
-
628
- // #when - session goes idle
629
- await hook.event({
630
- event: { type: "session.idle", properties: { sessionID: "session-123" } },
631
- })
632
-
633
- // #then - loop should complete (last message has completion promise)
634
- expect(promptCalls.length).toBe(0)
635
- expect(toastCalls.some((t) => t.title === "Ralph Loop Complete!")).toBe(true)
636
- expect(hook.getState()).toBeNull()
637
- })
638
-
639
- test("should allow starting new loop while previous loop is active (different session)", async () => {
640
- // #given - active loop in session A
641
- const hook = createRalphLoopHook(createMockPluginInput())
642
- hook.startLoop("session-A", "First task", { maxIterations: 10 })
643
- expect(hook.getState()?.session_id).toBe("session-A")
644
- expect(hook.getState()?.prompt).toBe("First task")
645
-
646
- // #when - start new loop in session B (without completing A)
647
- hook.startLoop("session-B", "Second task", { maxIterations: 20 })
648
-
649
- // #then - state should be overwritten with session B's loop
650
- expect(hook.getState()?.session_id).toBe("session-B")
651
- expect(hook.getState()?.prompt).toBe("Second task")
652
- expect(hook.getState()?.max_iterations).toBe(20)
653
- expect(hook.getState()?.iteration).toBe(1)
654
-
655
- // #when - session B goes idle
656
- await hook.event({
657
- event: { type: "session.idle", properties: { sessionID: "session-B" } },
658
- })
659
-
660
- // #then - continuation should be injected for session B
661
- expect(promptCalls.length).toBe(1)
662
- expect(promptCalls[0].sessionID).toBe("session-B")
663
- expect(promptCalls[0].text).toContain("Second task")
664
- expect(promptCalls[0].text).toContain("2/20")
665
-
666
- // #then - iteration incremented
667
- expect(hook.getState()?.iteration).toBe(2)
668
- })
669
-
670
- test("should allow starting new loop in same session (restart)", async () => {
671
- // #given - active loop in session A at iteration 5
672
- const hook = createRalphLoopHook(createMockPluginInput())
673
- hook.startLoop("session-A", "First task", { maxIterations: 10 })
674
-
675
- // Simulate some iterations
676
- await hook.event({
677
- event: { type: "session.idle", properties: { sessionID: "session-A" } },
678
- })
679
- await hook.event({
680
- event: { type: "session.idle", properties: { sessionID: "session-A" } },
681
- })
682
- expect(hook.getState()?.iteration).toBe(3)
683
- expect(promptCalls.length).toBe(2)
684
-
685
- // #when - start NEW loop in same session (restart)
686
- hook.startLoop("session-A", "Restarted task", { maxIterations: 50 })
687
-
688
- // #then - state should be reset to iteration 1 with new prompt
689
- expect(hook.getState()?.session_id).toBe("session-A")
690
- expect(hook.getState()?.prompt).toBe("Restarted task")
691
- expect(hook.getState()?.max_iterations).toBe(50)
692
- expect(hook.getState()?.iteration).toBe(1)
693
-
694
- // #when - session goes idle
695
- promptCalls = [] // Reset to check new continuation
696
- await hook.event({
697
- event: { type: "session.idle", properties: { sessionID: "session-A" } },
698
- })
699
-
700
- // #then - continuation should use new task
701
- expect(promptCalls.length).toBe(1)
702
- expect(promptCalls[0].text).toContain("Restarted task")
703
- expect(promptCalls[0].text).toContain("2/50")
704
- })
705
-
706
- test("should check transcript BEFORE API to optimize performance", async () => {
707
- // #given - transcript has completion promise
708
- const transcriptPath = join(TEST_DIR, "transcript.jsonl")
709
- writeFileSync(transcriptPath, JSON.stringify({ content: "<promise>DONE</promise>" }))
710
- mockSessionMessages = [
711
- { info: { role: "assistant" }, parts: [{ type: "text", text: "No promise here" }] },
712
- ]
713
- const hook = createRalphLoopHook(createMockPluginInput(), {
714
- getTranscriptPath: () => transcriptPath,
715
- })
716
- hook.startLoop("session-123", "Build something", { completionPromise: "DONE" })
717
-
718
- // #when - session goes idle
719
- await hook.event({
720
- event: {
721
- type: "session.idle",
722
- properties: { sessionID: "session-123" },
723
- },
724
- })
725
-
726
- // #then - should complete via transcript (API not called when transcript succeeds)
727
- expect(promptCalls.length).toBe(0)
728
- expect(hook.getState()).toBeNull()
729
- // API should NOT be called since transcript found completion
730
- expect(messagesCalls.length).toBe(0)
731
- })
732
-
733
- test("should show ultrawork completion toast", async () => {
734
- // #given - hook with ultrawork mode and completion in transcript
735
- const transcriptPath = join(TEST_DIR, "transcript.jsonl")
736
- const hook = createRalphLoopHook(createMockPluginInput(), {
737
- getTranscriptPath: () => transcriptPath,
738
- })
739
- writeFileSync(transcriptPath, JSON.stringify({ content: "<promise>DONE</promise>" }))
740
- hook.startLoop("test-id", "Build API", { ultrawork: true })
741
-
742
- // #when - idle event triggered
743
- await hook.event({ event: { type: "session.idle", properties: { sessionID: "test-id" } } })
744
-
745
- // #then - ultrawork toast shown
746
- const completionToast = toastCalls.find(t => t.title === "ULTRAWORK LOOP COMPLETE!")
747
- expect(completionToast).toBeDefined()
748
- expect(completionToast!.message).toMatch(/JUST ULW ULW!/)
749
- })
750
-
751
- test("should show regular completion toast when ultrawork disabled", async () => {
752
- // #given - hook without ultrawork
753
- const transcriptPath = join(TEST_DIR, "transcript.jsonl")
754
- const hook = createRalphLoopHook(createMockPluginInput(), {
755
- getTranscriptPath: () => transcriptPath,
756
- })
757
- writeFileSync(transcriptPath, JSON.stringify({ content: "<promise>DONE</promise>" }))
758
- hook.startLoop("test-id", "Build API")
759
-
760
- // #when - idle event triggered
761
- await hook.event({ event: { type: "session.idle", properties: { sessionID: "test-id" } } })
762
-
763
- // #then - regular toast shown
764
- expect(toastCalls.some(t => t.title === "Ralph Loop Complete!")).toBe(true)
765
- })
766
-
767
- test("should prepend ultrawork to continuation prompt when ultrawork=true", async () => {
768
- // #given - hook with ultrawork mode enabled
769
- const hook = createRalphLoopHook(createMockPluginInput())
770
- hook.startLoop("session-123", "Build API", { ultrawork: true })
771
-
772
- // #when - session goes idle (continuation triggered)
773
- await hook.event({
774
- event: { type: "session.idle", properties: { sessionID: "session-123" } },
775
- })
776
-
777
- // #then - prompt should start with "ultrawork "
778
- expect(promptCalls.length).toBe(1)
779
- expect(promptCalls[0].text).toMatch(/^ultrawork /)
780
- })
781
-
782
- test("should NOT prepend ultrawork to continuation prompt when ultrawork=false", async () => {
783
- // #given - hook without ultrawork mode
784
- const hook = createRalphLoopHook(createMockPluginInput())
785
- hook.startLoop("session-123", "Build API")
786
-
787
- // #when - session goes idle (continuation triggered)
788
- await hook.event({
789
- event: { type: "session.idle", properties: { sessionID: "session-123" } },
790
- })
791
-
792
- // #then - prompt should NOT start with "ultrawork "
793
- expect(promptCalls.length).toBe(1)
794
- expect(promptCalls[0].text).not.toMatch(/^ultrawork /)
795
- })
796
- })
797
-
798
- describe("API timeout protection", () => {
799
- // FIXME: Flaky in CI - times out intermittently
800
- test.skip("should not hang when session.messages() times out", async () => {
801
- // #given - slow API that takes longer than timeout
802
- const slowMock = {
803
- ...createMockPluginInput(),
804
- client: {
805
- ...createMockPluginInput().client,
806
- session: {
807
- ...createMockPluginInput().client.session,
808
- messages: async () => {
809
- // Simulate slow API (would hang without timeout)
810
- await new Promise((resolve) => setTimeout(resolve, 10000))
811
- return { data: [] }
812
- },
813
- },
814
- },
815
- }
816
- const hook = createRalphLoopHook(slowMock as any, {
817
- getTranscriptPath: () => join(TEST_DIR, "nonexistent.jsonl"),
818
- apiTimeout: 100, // 100ms timeout for test
819
- })
820
- hook.startLoop("session-123", "Build something")
821
-
822
- // #when - session goes idle (API will timeout)
823
- const startTime = Date.now()
824
- await hook.event({
825
- event: { type: "session.idle", properties: { sessionID: "session-123" } },
826
- })
827
- const elapsed = Date.now() - startTime
828
-
829
- // #then - should complete within timeout + buffer (not hang for 10s)
830
- expect(elapsed).toBeLessThan(500)
831
- // #then - loop should continue (API timeout = no completion detected)
832
- expect(promptCalls.length).toBe(1)
833
- })
834
- })
835
- })