@polderlabs/bizar 6.2.4 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. package/.claude/CLAUDE.md +15 -0
  2. package/.claude/agents/_shared/AGENT_BASELINE.md +168 -0
  3. package/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
  4. package/.claude/agents/_shared/SKILLS.md +109 -0
  5. package/.claude/agents/agent-browser.md +80 -0
  6. package/.claude/agents/baldr.md +49 -0
  7. package/.claude/agents/forseti.md +51 -0
  8. package/.claude/agents/frigg.md +42 -0
  9. package/.claude/agents/heimdall.md +33 -0
  10. package/.claude/agents/hermod.md +53 -0
  11. package/.claude/agents/mimir.md +49 -0
  12. package/.claude/agents/odin.md +287 -0
  13. package/.claude/agents/quick.md +34 -0
  14. package/.claude/agents/semble-search.md +50 -0
  15. package/.claude/agents/thor.md +53 -0
  16. package/.claude/agents/tyr.md +56 -0
  17. package/.claude/agents/vidarr.md +54 -0
  18. package/.claude/agents/vor.md +53 -0
  19. package/.claude/commands/audit.md +25 -0
  20. package/.claude/commands/bizar.md +22 -0
  21. package/.claude/commands/explain.md +17 -0
  22. package/.claude/commands/init.md +29 -0
  23. package/.claude/commands/learn.md +44 -0
  24. package/.claude/commands/plan.md +35 -0
  25. package/.claude/commands/plow-through.md +50 -0
  26. package/.claude/commands/pr-review.md +49 -0
  27. package/.claude/commands/setup-provider.md +96 -0
  28. package/.claude/commands/tailscale-serve.md +100 -0
  29. package/.claude/commands/team.md +132 -0
  30. package/.claude/commands/test.md +62 -0
  31. package/.claude/commands/validate.md +68 -0
  32. package/.claude/commands/visual-plan.md +24 -0
  33. package/.claude/hooks/README.md +92 -0
  34. package/.claude/hooks/posttooluse-editwrite.mjs +91 -0
  35. package/.claude/hooks/pretooluse-bash.mjs +81 -0
  36. package/.claude/hooks/pretooluse-editwrite.mjs +139 -0
  37. package/.claude/hooks/sessionend-recall.mjs +74 -0
  38. package/.claude/hooks/sessionstart-prime.mjs +80 -0
  39. package/.claude/hooks/userpromptsubmit-tag.mjs +80 -0
  40. package/.claude/settings.json +116 -0
  41. package/.claude/skills/9router/SKILL.md +80 -0
  42. package/.claude/skills/9router-chat/SKILL.md +73 -0
  43. package/.claude/skills/9router-embeddings/SKILL.md +69 -0
  44. package/.claude/skills/9router-image/SKILL.md +86 -0
  45. package/.claude/skills/9router-stt/SKILL.md +79 -0
  46. package/.claude/skills/9router-tts/SKILL.md +80 -0
  47. package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
  48. package/.claude/skills/9router-web-search/SKILL.md +91 -0
  49. package/.claude/skills/bizar/README.md +9 -0
  50. package/.claude/skills/bizar/SKILL.md +450 -0
  51. package/.claude/skills/cpp-coding-standards/README.md +28 -0
  52. package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
  53. package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
  54. package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
  55. package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
  56. package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
  57. package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
  58. package/.claude/skills/cpp-testing/README.md +28 -0
  59. package/.claude/skills/cpp-testing/SKILL.md +304 -0
  60. package/.claude/skills/cpp-testing/references/coverage.md +370 -0
  61. package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
  62. package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
  63. package/.claude/skills/cpp-testing/references/mocking.md +364 -0
  64. package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
  65. package/.claude/skills/cubesandbox/SKILL.md +148 -0
  66. package/.claude/skills/embedded-esp-idf/README.md +41 -0
  67. package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
  68. package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
  69. package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
  70. package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
  71. package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
  72. package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
  73. package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
  74. package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
  75. package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
  76. package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
  77. package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
  78. package/.claude/skills/glyph/SKILL.md +163 -0
  79. package/.claude/skills/harness-engineering/SKILL.md +143 -0
  80. package/.claude/skills/lightrag/SKILL.md +81 -0
  81. package/.claude/skills/memory-protocol/SKILL.md +105 -0
  82. package/.claude/skills/obsidian/SKILL.md +306 -0
  83. package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
  84. package/.claude/skills/self-improvement/SKILL.md +64 -0
  85. package/README.md +87 -59
  86. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js → EnvVarsSection-B58aiJiE.js} +1 -1
  87. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js.map → EnvVarsSection-B58aiJiE.js.map} +1 -1
  88. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js → MobileChat-BJrqwVDd.js} +1 -1
  89. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js.map → MobileChat-BJrqwVDd.js.map} +1 -1
  90. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js → MobileSettings-CEQNJNLJ.js} +1 -1
  91. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js.map → MobileSettings-CEQNJNLJ.js.map} +1 -1
  92. package/bizar-dash/dist/assets/{main-DYiZqMrn.js → main-IvfQAOfy.js} +1 -1
  93. package/bizar-dash/dist/assets/{main-DYiZqMrn.js.map → main-IvfQAOfy.js.map} +1 -1
  94. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js → markdown-tOLaD6nm.js} +1 -1
  95. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js.map → markdown-tOLaD6nm.js.map} +1 -1
  96. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js → mobile-DYCHcUpq.js} +1 -1
  97. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js.map → mobile-DYCHcUpq.js.map} +1 -1
  98. package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js → mobile-layout-CBHjpwsb.js} +2 -2
  99. package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js.map → mobile-layout-CBHjpwsb.js.map} +1 -1
  100. package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js → useSlashCommands-Bd7_FA6U.js} +2 -2
  101. package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js.map → useSlashCommands-Bd7_FA6U.js.map} +1 -1
  102. package/bizar-dash/dist/assets/{vendor-CeHGtduv.js → vendor-C843201K.js} +12 -12
  103. package/bizar-dash/dist/assets/vendor-C843201K.js.map +1 -0
  104. package/bizar-dash/dist/index.html +6 -6
  105. package/bizar-dash/dist/mobile.html +2 -2
  106. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  107. package/bizar-dash/src/server/api.mjs +4 -4
  108. package/bizar-dash/src/server/background-store.mjs +15 -16
  109. package/bizar-dash/src/server/bg-poller.mjs +25 -35
  110. package/bizar-dash/src/server/bg-retry.mjs +66 -194
  111. package/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
  112. package/bizar-dash/src/server/claude-info.mjs +412 -0
  113. package/bizar-dash/src/server/{cline-runner.mjs → claude-runner.mjs} +53 -48
  114. package/bizar-dash/src/server/claude-sdk.mjs +191 -0
  115. package/bizar-dash/src/server/providers-store.mjs +22 -49
  116. package/bizar-dash/src/server/routes/background.mjs +24 -20
  117. package/bizar-dash/src/server/routes/chat.mjs +223 -326
  118. package/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
  119. package/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
  120. package/bizar-dash/src/server/routes/tasks.mjs +20 -28
  121. package/bizar-dash/src/server/task-delegator.mjs +76 -77
  122. package/bizar-dash/src/web/components/chat/useChat.ts +23 -27
  123. package/bizar-dash/src/web/views/Chat.tsx +8 -8
  124. package/cli/bin.mjs +31 -18
  125. package/cli/commands/claude-cmd.mjs +348 -0
  126. package/cli/commands/install.mjs +12 -11
  127. package/cli/commands/sandbox.mjs +220 -0
  128. package/cli/commands/validate.mjs +252 -288
  129. package/cli/dev-link.test.mjs +11 -11
  130. package/cli/doctor.mjs +131 -213
  131. package/cli/install.mjs +33 -37
  132. package/cli/install.test.mjs +9 -9
  133. package/cli/provision-claude.mjs +893 -0
  134. package/cli/provision.mjs +330 -226
  135. package/cli/provision.test.mjs +102 -0
  136. package/cli/utils.mjs +72 -58
  137. package/config/AGENTS.md +28 -28
  138. package/config/agents/_shared/AGENT_BASELINE.md +104 -684
  139. package/config/skills/bizar/SKILL.md +197 -0
  140. package/config/skills/cubesandbox/SKILL.md +148 -0
  141. package/config/skills/harness-engineering/SKILL.md +142 -0
  142. package/install.sh +66 -44
  143. package/package.json +19 -11
  144. package/packages/sdk/ARCHITECTURE.md +40 -36
  145. package/packages/sdk/package-lock.json +32 -0
  146. package/packages/sdk/package.json +15 -5
  147. package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
  148. package/packages/sdk/src/fingerprint.ts +0 -0
  149. package/packages/sdk/src/index.ts +38 -73
  150. package/packages/sdk/src/mcp/bin.ts +51 -0
  151. package/packages/sdk/src/mcp/server.ts +498 -0
  152. package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
  153. package/packages/sdk/tests/sdk.test.mjs +148 -0
  154. package/packages/sdk/vitest.config.ts +1 -1
  155. package/scripts/bh-full-e2e.mjs +166 -363
  156. package/scripts/check-deps.mjs +28 -46
  157. package/scripts/mirror-claude-md.sh +78 -0
  158. package/scripts/test-in-container.sh +157 -0
  159. package/templates/clean-state-checklist.md +3 -3
  160. package/templates/sprint-contract.md +2 -2
  161. package/bizar-dash/.bizar/activity.log +0 -3
  162. package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
  163. package/bizar-dash/.omx/state/session.json +0 -10
  164. package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
  165. package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
  166. package/bizar-dash/bizar-design/canvas.html +0 -281
  167. package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
  168. package/bizar-dash/bizar-design/components.css +0 -1665
  169. package/bizar-dash/bizar-design/components.html +0 -557
  170. package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
  171. package/bizar-dash/bizar-design/desktop/agents.html +0 -74
  172. package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
  173. package/bizar-dash/bizar-design/desktop/memory.html +0 -75
  174. package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
  175. package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
  176. package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
  177. package/bizar-dash/bizar-design/desktop/overview.html +0 -95
  178. package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
  179. package/bizar-dash/bizar-design/desktop/settings.html +0 -70
  180. package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
  181. package/bizar-dash/bizar-design/icons.svg +0 -44
  182. package/bizar-dash/bizar-design/index.html +0 -192
  183. package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
  184. package/bizar-dash/bizar-design/mobile/agents.html +0 -29
  185. package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
  186. package/bizar-dash/bizar-design/mobile/memory.html +0 -28
  187. package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
  188. package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
  189. package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
  190. package/bizar-dash/bizar-design/mobile/overview.html +0 -33
  191. package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
  192. package/bizar-dash/bizar-design/mobile/settings.html +0 -28
  193. package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
  194. package/bizar-dash/bizar-design/prototype.js +0 -114
  195. package/bizar-dash/bizar-design/tokens.css +0 -106
  196. package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
  197. package/bizar-dash/node_modules/.package-lock.json +0 -6
  198. package/bizar-dash/package-lock.json +0 -6
  199. package/bizar-dash/src/server/cline-sdk.mjs +0 -132
  200. package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
  201. package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
  202. package/cli/commands/cline-cmd.mjs +0 -289
  203. package/cli/commands/validate.test.mjs +0 -344
  204. package/cli/doctor.test.mjs +0 -350
  205. package/config/cline.json.template +0 -342
  206. package/packages/sdk/src/client.ts +0 -188
  207. package/packages/sdk/src/cline-events.ts +0 -134
  208. package/packages/sdk/src/cline-types.ts +0 -66
  209. package/packages/sdk/src/cline.ts +0 -339
  210. package/packages/sdk/src/errors.ts +0 -129
  211. package/packages/sdk/src/events.ts +0 -153
  212. package/packages/sdk/src/types.ts +0 -176
  213. package/packages/sdk/tests/client.test.ts +0 -217
  214. package/packages/sdk/tests/errors.test.ts +0 -108
  215. package/packages/sdk/tests/events.test.ts +0 -139
  216. package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
  217. package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
  218. package/plugins/bizar/ARCHITECTURE.md +0 -142
  219. package/plugins/bizar/CONSTRAINTS.md +0 -67
  220. package/plugins/bizar/LICENSE +0 -21
  221. package/plugins/bizar/README.md +0 -448
  222. package/plugins/bizar/index.ts +0 -872
  223. package/plugins/bizar/package.json +0 -39
  224. package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
  225. package/plugins/bizar/src/background-state.ts +0 -641
  226. package/plugins/bizar/src/background.ts +0 -1806
  227. package/plugins/bizar/src/cline-runner.ts +0 -203
  228. package/plugins/bizar/src/clineruntime.ts +0 -227
  229. package/plugins/bizar/src/commands-impl.ts +0 -151
  230. package/plugins/bizar/src/commands.ts +0 -1799
  231. package/plugins/bizar/src/compaction.d.mts +0 -48
  232. package/plugins/bizar/src/compaction.mjs +0 -192
  233. package/plugins/bizar/src/dashboard-client.ts +0 -233
  234. package/plugins/bizar/src/event-stream.ts +0 -606
  235. package/plugins/bizar/src/fingerprint.ts +0 -120
  236. package/plugins/bizar/src/handoff.ts +0 -79
  237. package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
  238. package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
  239. package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
  240. package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
  241. package/plugins/bizar/src/http-client.ts +0 -467
  242. package/plugins/bizar/src/key-rotation.ts +0 -218
  243. package/plugins/bizar/src/logger.ts +0 -144
  244. package/plugins/bizar/src/loop-engineering.ts +0 -241
  245. package/plugins/bizar/src/loop.ts +0 -176
  246. package/plugins/bizar/src/mistake-recovery.ts +0 -98
  247. package/plugins/bizar/src/odin.ts +0 -227
  248. package/plugins/bizar/src/options.ts +0 -470
  249. package/plugins/bizar/src/plan-fs.ts +0 -323
  250. package/plugins/bizar/src/reasoning-clean.ts +0 -454
  251. package/plugins/bizar/src/report.ts +0 -178
  252. package/plugins/bizar/src/research-prompt.ts +0 -35
  253. package/plugins/bizar/src/serve-info.ts +0 -228
  254. package/plugins/bizar/src/serve.ts +0 -496
  255. package/plugins/bizar/src/settings.ts +0 -349
  256. package/plugins/bizar/src/state.ts +0 -298
  257. package/plugins/bizar/src/tool-discipline.ts +0 -105
  258. package/plugins/bizar/src/tools/agent-browser.ts +0 -315
  259. package/plugins/bizar/src/tools/bg-collect.ts +0 -131
  260. package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
  261. package/plugins/bizar/src/tools/bg-kill.ts +0 -116
  262. package/plugins/bizar/src/tools/bg-pause.ts +0 -99
  263. package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
  264. package/plugins/bizar/src/tools/bg-resume.ts +0 -94
  265. package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
  266. package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
  267. package/plugins/bizar/src/tools/bg-status.ts +0 -130
  268. package/plugins/bizar/src/tools/graph-query.ts +0 -278
  269. package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
  270. package/plugins/bizar/src/tools/memory-list.ts +0 -43
  271. package/plugins/bizar/src/tools/memory-read.ts +0 -69
  272. package/plugins/bizar/src/tools/memory-search.ts +0 -47
  273. package/plugins/bizar/src/tools/memory-write.ts +0 -54
  274. package/plugins/bizar/src/tools/open-kb.ts +0 -198
  275. package/plugins/bizar/src/tools/plan-action.ts +0 -785
  276. package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
  277. package/plugins/bizar/src/tools/team-spawn.ts +0 -73
  278. package/plugins/bizar/src/tools/team-status.ts +0 -76
  279. package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
  280. package/plugins/bizar/src/trajectory.ts +0 -104
  281. package/plugins/bizar/tests/README.md +0 -99
  282. package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
  283. package/plugins/bizar/tests/background-state.test.ts +0 -277
  284. package/plugins/bizar/tests/background.test.ts +0 -402
  285. package/plugins/bizar/tests/block.test.ts +0 -195
  286. package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
  287. package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
  288. package/plugins/bizar/tests/commands-impl.test.ts +0 -316
  289. package/plugins/bizar/tests/commands.test.ts +0 -584
  290. package/plugins/bizar/tests/compaction.test.ts +0 -264
  291. package/plugins/bizar/tests/config.test.ts +0 -128
  292. package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
  293. package/plugins/bizar/tests/dispose.test.ts +0 -336
  294. package/plugins/bizar/tests/event-stream.test.ts +0 -409
  295. package/plugins/bizar/tests/event.test.ts +0 -262
  296. package/plugins/bizar/tests/fingerprint.test.ts +0 -162
  297. package/plugins/bizar/tests/http-client.test.ts +0 -404
  298. package/plugins/bizar/tests/init-helpers.test.ts +0 -203
  299. package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
  300. package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
  301. package/plugins/bizar/tests/key-rotation.test.ts +0 -396
  302. package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
  303. package/plugins/bizar/tests/loop.test.ts +0 -397
  304. package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
  305. package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
  306. package/plugins/bizar/tests/odin.test.ts +0 -125
  307. package/plugins/bizar/tests/options.test.ts +0 -329
  308. package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
  309. package/plugins/bizar/tests/safety.test.ts +0 -256
  310. package/plugins/bizar/tests/serve.test.ts +0 -339
  311. package/plugins/bizar/tests/settings.test.ts +0 -351
  312. package/plugins/bizar/tests/stall-think.test.ts +0 -750
  313. package/plugins/bizar/tests/state.test.ts +0 -276
  314. package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
  315. package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
  316. package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
  317. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
  318. package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
  319. package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
  320. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
  321. package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
  322. package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
  323. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
  324. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
  325. package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
  326. package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
  327. package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
  328. package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
  329. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
  330. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
  331. package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
  332. package/plugins/bizar/tsconfig.json +0 -29
@@ -1,144 +0,0 @@
1
- /**
2
- * Logger — thin wrapper over `client.app.log`.
3
- *
4
- * Spec requirements satisfied here:
5
- * - §6.5 — honors `BIZAR_LOG_LEVEL` env var (`debug` | `info` | `warn` | `error`,
6
- * default `info`, invalid values fall back to `info` with a warning).
7
- * - §7.6 — never accepts or emits raw tool args / session content. Every call
8
- * to `client.app.log` is `{ level, message }` (or the SDK's wrapped
9
- * `{ body: { service, level, message } }` shape) where `message` is a
10
- * static string the caller constructed. There is no second argument,
11
- * no metadata object, no structured logging payload.
12
- *
13
- * The logger swallows all errors from the underlying `client.app.log` call.
14
- * A failed log MUST NOT crash the plugin or block the tool hook.
15
- *
16
- * The interface is intentionally compatible with the `Logger` shape that
17
- * Thor's `StateStore` and `LogWriter` accept: a single `log(opts)` method
18
- * returning `void` (synchronous). We also expose level-specific convenience
19
- * methods (`debug` / `info` / `warn` / `error`) that all delegate to `log`.
20
- */
21
-
22
- export type LogLevel = "debug" | "info" | "warn" | "error";
23
-
24
- const LEVEL_ORDER: Record<LogLevel, number> = {
25
- debug: 0,
26
- info: 1,
27
- warn: 2,
28
- error: 3,
29
- };
30
-
31
- /**
32
- * Minimal client surface the logger depends on. The real cline client's
33
- * `app.log` is a generated SDK method with a complex Options<T> type; we
34
- * accept any object with a compatible `app.log` method and treat the body
35
- * as an opaque `unknown` at the boundary. The logger internally shapes the
36
- * call to the SDK's expected `{ body: { service, level, message } }` form.
37
- */
38
- export interface LoggerClient {
39
- app: {
40
- log: (input: unknown) => unknown;
41
- };
42
- }
43
-
44
- /**
45
- * The Logger interface matches the one defined in `state.ts` and `report.ts`
46
- * (Thor's modules). A single `log(opts)` method, synchronous, returns `void`.
47
- * The convenience methods are additive.
48
- */
49
- export interface Logger {
50
- log(opts: { level: LogLevel; message: string }): void;
51
- debug(message: string): void;
52
- info(message: string): void;
53
- warn(message: string): void;
54
- error(message: string): void;
55
- }
56
-
57
- interface ParsedLogLevel {
58
- level: LogLevel;
59
- wasInvalid: boolean;
60
- original: string | undefined;
61
- }
62
-
63
- function parseLogLevel(raw: string | undefined): ParsedLogLevel {
64
- if (raw === undefined || raw === "") {
65
- return { level: "info", wasInvalid: false, original: raw };
66
- }
67
- const lower = raw.toLowerCase();
68
- if (lower === "debug" || lower === "info" || lower === "warn" || lower === "error") {
69
- return { level: lower, wasInvalid: false, original: raw };
70
- }
71
- return { level: "info", wasInvalid: true, original: raw };
72
- }
73
-
74
- function readEnvLevel(): string | undefined {
75
- try {
76
- return typeof process !== "undefined" && process.env
77
- ? process.env.BIZAR_LOG_LEVEL
78
- : undefined;
79
- } catch {
80
- return undefined;
81
- }
82
- }
83
-
84
- /**
85
- * Service name stamped onto every log entry. Lets users filter app logs
86
- * by service (e.g. `bizar`) in their diagnostic tooling.
87
- */
88
- const SERVICE_NAME = "bizar";
89
-
90
- /**
91
- * Construct a Logger bound to the cline client.
92
- *
93
- * @param client The cline client (we use only `client.app.log`).
94
- * @param envLevel Optional override for `BIZAR_LOG_LEVEL`. If omitted, the
95
- * env var is read once. Env vars are read at plugin init;
96
- * mid-session changes are ignored (spec §6.5).
97
- */
98
- export function createLogger(client: LoggerClient, envLevel?: string): Logger {
99
- const raw = envLevel ?? readEnvLevel();
100
- const parsed = parseLogLevel(raw);
101
- const threshold = parsed.level;
102
-
103
- if (parsed.wasInvalid) {
104
- // Best-effort: warn about the invalid value, then proceed with "info".
105
- // We call `client.app.log` directly because the logger is not yet wired
106
- // to the threshold.
107
- try {
108
- client.app.log({
109
- body: { service: SERVICE_NAME, level: "warn", message: `bizar: invalid BIZAR_LOG_LEVEL "${parsed.original ?? ""}", falling back to "info"` },
110
- });
111
- } catch {
112
- // ignore — never let a warning crash init
113
- }
114
- }
115
-
116
- function emit(msgLevel: LogLevel, message: string): void {
117
- if (LEVEL_ORDER[msgLevel] < LEVEL_ORDER[threshold]) return;
118
- try {
119
- client.app.log({
120
- body: { service: SERVICE_NAME, level: msgLevel, message },
121
- });
122
- } catch {
123
- // Swallow — a failed log MUST NOT crash the plugin.
124
- }
125
- }
126
-
127
- return {
128
- log(opts) {
129
- emit(opts.level, opts.message);
130
- },
131
- debug(message) {
132
- emit("debug", message);
133
- },
134
- info(message) {
135
- emit("info", message);
136
- },
137
- warn(message) {
138
- emit("warn", message);
139
- },
140
- error(message) {
141
- emit("error", message);
142
- },
143
- };
144
- }
@@ -1,241 +0,0 @@
1
- /**
2
- * loop-engineering.ts
3
- *
4
- * v6.0.0 — Structured loop patterns for continuous agent execution.
5
- *
6
- * Inspired by:
7
- * - https://github.com/cobusgreyling/loop-engineering
8
- * - https://github.com/rudy2steiner/awesome-agent-loops
9
- *
10
- * Patterns supported (v1):
11
- *
12
- * 1. **ralph** — repeat until output contains `[STOP]` marker, or until
13
- * `maxIterations` is reached, or until a manual stop signal.
14
- * 2. **repl** — interactive, awaits user input between iterations
15
- * (not yet implemented in v1).
16
- * 3. **cron** — interval-based; reruns every N seconds.
17
- * 4. **plan-execute** — decompose once, iterate over subtasks.
18
- *
19
- * Loops are stored on disk as JSON files at:
20
- * ~/.bizar/loops/<loopId>.json
21
- *
22
- * Each loop has:
23
- * - id, pattern, task, status (running | stopped | done)
24
- * - iterations[] — log of { index, startedAt, durationMs, output, stopReason }
25
- * - context — pattern-specific config (interval, maxIterations, etc.)
26
- */
27
-
28
- import { mkdirSync, writeFileSync, readFileSync, existsSync, readdirSync, unlinkSync } from "node:fs";
29
- import { join } from "node:path";
30
- import { homedir } from "node:os";
31
-
32
- export type LoopPattern = "ralph" | "repl" | "cron" | "plan-execute";
33
- export type LoopStatus = "running" | "stopped" | "done";
34
-
35
- export interface LoopIteration {
36
- index: number;
37
- startedAt: string;
38
- durationMs: number;
39
- output: string;
40
- stopReason?: string;
41
- }
42
-
43
- export interface LoopContext {
44
- maxIterations: number;
45
- stopMarker?: string;
46
- intervalSeconds?: number;
47
- subtasks?: string[];
48
- }
49
-
50
- export interface Loop {
51
- id: string;
52
- pattern: LoopPattern;
53
- task: string;
54
- status: LoopStatus;
55
- createdAt: string;
56
- updatedAt: string;
57
- context: LoopContext;
58
- iterations: LoopIteration[];
59
- }
60
-
61
- const LOOPS_DIR = join(homedir(), ".bizar", "loops");
62
-
63
- function ensureLoopsDir(): void {
64
- if (!existsSync(LOOPS_DIR)) {
65
- mkdirSync(LOOPS_DIR, { recursive: true });
66
- }
67
- }
68
-
69
- function generateLoopId(): string {
70
- return `loop_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
71
- }
72
-
73
- export interface StartLoopInput {
74
- pattern: LoopPattern;
75
- task: string;
76
- context?: Partial<LoopContext>;
77
- }
78
-
79
- export interface StartLoopOutput {
80
- ok: true;
81
- loop: Loop;
82
- }
83
-
84
- export function startLoop(input: StartLoopInput): StartLoopOutput {
85
- ensureLoopsDir();
86
- const id = generateLoopId();
87
- const now = new Date().toISOString();
88
- const loop: Loop = {
89
- id,
90
- pattern: input.pattern,
91
- task: input.task,
92
- status: "running",
93
- createdAt: now,
94
- updatedAt: now,
95
- context: {
96
- maxIterations: input.context?.maxIterations ?? 10,
97
- stopMarker: input.context?.stopMarker,
98
- intervalSeconds: input.context?.intervalSeconds,
99
- subtasks: input.context?.subtasks,
100
- },
101
- iterations: [],
102
- };
103
- writeFileSync(join(LOOPS_DIR, `${id}.json`), JSON.stringify(loop, null, 2));
104
- return { ok: true, loop };
105
- }
106
-
107
- export function loadLoop(id: string): Loop | null {
108
- const path = join(LOOPS_DIR, `${id}.json`);
109
- if (!existsSync(path)) return null;
110
- return JSON.parse(readFileSync(path, "utf8")) as Loop;
111
- }
112
-
113
- export function saveLoop(loop: Loop): void {
114
- loop.updatedAt = new Date().toISOString();
115
- writeFileSync(join(LOOPS_DIR, `${loop.id}.json`), JSON.stringify(loop, null, 2));
116
- }
117
-
118
- /**
119
- * Append an iteration result to a loop and update its status if a stop
120
- * condition was met.
121
- */
122
- export function appendIteration(
123
- id: string,
124
- result: Omit<LoopIteration, "startedAt"> & { startedAt?: string },
125
- ): Loop | null {
126
- const loop = loadLoop(id);
127
- if (!loop) return null;
128
- const iter: LoopIteration = {
129
- index: loop.iterations.length,
130
- startedAt: result.startedAt ?? new Date().toISOString(),
131
- durationMs: result.durationMs,
132
- output: result.output,
133
- stopReason: result.stopReason,
134
- };
135
- loop.iterations.push(iter);
136
- if (loop.context.maxIterations > 0 && loop.iterations.length >= loop.context.maxIterations) {
137
- loop.status = "done";
138
- } else if (
139
- loop.pattern === "ralph" &&
140
- loop.context.stopMarker &&
141
- result.output.includes(loop.context.stopMarker)
142
- ) {
143
- loop.status = "done";
144
- iter.stopReason = `stop marker "${loop.context.stopMarker}" found`;
145
- }
146
- saveLoop(loop);
147
- return loop;
148
- }
149
-
150
- /**
151
- * Mark a loop as stopped (manual stop signal).
152
- *
153
- * If `reason` is given AND the loop has at least one iteration, attach
154
- * the reason to the most recent iteration. Otherwise, append a synthetic
155
- * "stopped" iteration so the reason is preserved in the audit log.
156
- */
157
- export function stopLoop(id: string, reason?: string): Loop | null {
158
- const loop = loadLoop(id);
159
- if (!loop) return null;
160
- loop.status = "stopped";
161
- if (reason) {
162
- if (loop.iterations.length > 0) {
163
- const last = loop.iterations[loop.iterations.length - 1];
164
- if (last) last.stopReason = reason;
165
- } else {
166
- // Append a synthetic iteration so the reason isn't lost.
167
- loop.iterations.push({
168
- index: 0,
169
- startedAt: new Date().toISOString(),
170
- durationMs: 0,
171
- output: "(loop stopped before any iterations ran)",
172
- stopReason: reason,
173
- });
174
- }
175
- }
176
- saveLoop(loop);
177
- return loop;
178
- }
179
-
180
- /**
181
- * Delete a loop from disk.
182
- */
183
- export function deleteLoop(id: string): boolean {
184
- const path = join(LOOPS_DIR, `${id}.json`);
185
- if (!existsSync(path)) return false;
186
- unlinkSync(path);
187
- return true;
188
- }
189
-
190
- /**
191
- * List all loops on disk, optionally filtered by status / pattern.
192
- */
193
- export function listLoops(filter?: { status?: LoopStatus; pattern?: LoopPattern }): Loop[] {
194
- ensureLoopsDir();
195
- const files = readdirSync(LOOPS_DIR).filter((f) => f.endsWith(".json"));
196
- const out: Loop[] = [];
197
- for (const f of files) {
198
- try {
199
- const l = JSON.parse(readFileSync(join(LOOPS_DIR, f), "utf8")) as Loop;
200
- if (filter?.status && l.status !== filter.status) continue;
201
- if (filter?.pattern && l.pattern !== filter.pattern) continue;
202
- out.push(l);
203
- } catch {
204
- // skip malformed
205
- }
206
- }
207
- return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
208
- }
209
-
210
- /**
211
- * Pattern execution: given a loop, return the prompt for the next
212
- * iteration and the stop marker to look for (if any).
213
- */
214
- export function buildNextIteration(loop: Loop): { prompt: string; stopMarker: string | null } {
215
- switch (loop.pattern) {
216
- case "ralph": {
217
- const stopMarker = loop.context.stopMarker ?? "[STOP]";
218
- const iterIndex = loop.iterations.length + 1;
219
- const prompt = [
220
- `Loop iteration ${iterIndex} of ${loop.context.maxIterations}.`,
221
- `Task: ${loop.task}`,
222
- ``,
223
- `Output the literal marker "${stopMarker}" on its own line when done.`,
224
- ].join("\n");
225
- return { prompt, stopMarker };
226
- }
227
- case "cron":
228
- return { prompt: loop.task, stopMarker: null };
229
- case "plan-execute": {
230
- const subs = loop.context.subtasks ?? [];
231
- const nextIdx = loop.iterations.length;
232
- const subtask = subs[nextIdx] ?? "(no more subtasks)";
233
- return {
234
- prompt: `Subtask ${nextIdx + 1} of ${subs.length}: ${subtask}`,
235
- stopMarker: null,
236
- };
237
- }
238
- case "repl":
239
- return { prompt: loop.task, stopMarker: null };
240
- }
241
- }
@@ -1,176 +0,0 @@
1
- /**
2
- * Loop — the threshold decision tree.
3
- *
4
- * Spec requirements satisfied here:
5
- * - §5.1 — algorithm. Count how many of the last `loopWindowSize` tool
6
- * calls share the given fingerprint. Re-scan the window each call.
7
- * - §5.4 — threshold table. The action returned by `decide()` corresponds
8
- * to the highest threshold that the count meets or exceeds.
9
- * - §5.5 — window vs counter semantics. The count is a re-scan of the
10
- * window, not a running counter. The intermediate non-matching calls
11
- * in the window do NOT "reset" anything; they just sit in the window
12
- * and shift older matching entries out as the window rolls forward.
13
- * - §7.2 — the `reason` field returned by `decide()` for warn/escalate/
14
- * block actions is a static message from `handoff.ts` with only the
15
- * tool name interpolated. No tool args, no LLM output, no agent-
16
- * controlled content is ever included.
17
- *
18
- * The `now` parameter is part of the public signature for API consistency
19
- * with the spec (§5.1 timing context) but is not consumed by the decision
20
- * logic — callers use it to timestamp the current tool call when adding it
21
- * to the state.
22
- */
23
-
24
- import type { SessionState } from "./state.js";
25
- import type { NormalizedOptions } from "./options.js";
26
- import {
27
- warnMessage,
28
- escalateMessage,
29
- blockMessage,
30
- } from "./handoff.js";
31
-
32
- /**
33
- * The decision returned by `decide()`. The `allow` variant carries no
34
- * payload; the three action variants carry the canonical handoff message
35
- * (via `reason`), the fingerprint that triggered the decision, and the
36
- * repetition count in the window.
37
- */
38
- export type Decision =
39
- | { action: "allow" }
40
- | {
41
- action: "warn" | "escalate" | "block";
42
- reason: string;
43
- fingerprint: string;
44
- count: number;
45
- };
46
-
47
- /**
48
- * Implicit "log a warning" threshold from spec §5.4 row 1. This is always
49
- * two below `loopThresholdWarn` so the gap between log-only and inject-warn
50
- * stays constant when the user reconfigures. We `max(1, …)` so a user who
51
- * sets `loopThresholdWarn = 1` does not push the log-only threshold below 1.
52
- */
53
- function logOnlyThreshold(options: NormalizedOptions): number {
54
- return Math.max(1, options.loopThresholdWarn - 2);
55
- }
56
-
57
- /**
58
- * Look at the last `loopWindowSize` tool calls and return those that share
59
- * the given fingerprint. The window is a slice of the most recent entries;
60
- * older entries are ignored (spec §5.1 step 3).
61
- */
62
- function windowMatches(
63
- state: SessionState,
64
- fingerprint: string,
65
- windowSize: number,
66
- ): { calls: SessionState["toolCalls"]; count: number } {
67
- if (state.toolCalls.length === 0 || windowSize <= 0) {
68
- return { calls: [], count: 0 };
69
- }
70
- const start = Math.max(0, state.toolCalls.length - windowSize);
71
- const window = state.toolCalls.slice(start);
72
- const matches = window.filter((c) => c.fingerprint === fingerprint);
73
- return { calls: matches, count: matches.length };
74
- }
75
-
76
- /**
77
- * Recover the tool name from any call in `matches` that shares the
78
- * fingerprint. The fingerprint is computed from `(tool, normalized args)`,
79
- * so every call with this fingerprint has the same tool name. If the
80
- * matches list is empty (should not happen when this is called — the
81
- * caller only invokes us when `count >= 1`), fall back to `"unknown"`.
82
- */
83
- function toolNameOf(matches: SessionState["toolCalls"]): string {
84
- const first = matches[0];
85
- return first ? first.tool : "unknown";
86
- }
87
-
88
- /**
89
- * Build a Decision payload for a non-allow action. Pulls the canonical
90
- * handoff message for the given action and the tool name recovered from
91
- * the matching window entries.
92
- */
93
- function payload(
94
- action: "warn" | "escalate" | "block",
95
- fingerprint: string,
96
- count: number,
97
- matches: SessionState["toolCalls"],
98
- ): Decision {
99
- const tool = toolNameOf(matches);
100
- const reason =
101
- action === "block"
102
- ? blockMessage(tool)
103
- : action === "escalate"
104
- ? escalateMessage(tool)
105
- : warnMessage(tool);
106
- return { action, reason, fingerprint, count };
107
- }
108
-
109
- /**
110
- * Decide what action to take for the current tool call.
111
- *
112
- * The function is pure: it does not mutate `state` and does not perform any
113
- * I/O. The caller (the `tool.execute.before` hook in `index.ts`) is
114
- * responsible for adding the current call to the state before invoking
115
- * `decide()`, and for acting on the returned decision (log / inject / throw).
116
- *
117
- * @param state The current session state. Must already include the
118
- * current tool call in `state.toolCalls` (the caller
119
- * appends it before calling `decide()`).
120
- * @param fingerprint The fingerprint of the current tool call.
121
- * @param now Current epoch milliseconds. Part of the public signature
122
- * for API consistency; not consumed by the decision logic.
123
- * @param options Normalized plugin options.
124
- */
125
- export function decide(
126
- state: SessionState,
127
- fingerprint: string,
128
- now: number,
129
- options: NormalizedOptions,
130
- ): Decision {
131
- // Step 1: scan the window.
132
- const { calls: matches, count } = windowMatches(
133
- state,
134
- fingerprint,
135
- options.loopWindowSize,
136
- );
137
-
138
- // Step 2: apply thresholds from highest to lowest.
139
- if (count >= options.loopThresholdBlock) {
140
- return payload("block", fingerprint, count, matches);
141
- }
142
- if (count >= options.loopThresholdEscalate) {
143
- return payload("escalate", fingerprint, count, matches);
144
- }
145
- if (count >= options.loopThresholdWarn) {
146
- return payload("warn", fingerprint, count, matches);
147
- }
148
-
149
- // Step 3: log-only band (spec §5.4 row 1). Sits between `allow` and the
150
- // inject-warn threshold. The caller distinguishes this case from
151
- // inject-warn by inspecting `count` against `options.loopThresholdWarn`.
152
- const logOnly = logOnlyThreshold(options);
153
- if (count >= logOnly) {
154
- return payload("warn", fingerprint, count, matches);
155
- }
156
-
157
- // `now` is accepted for API consistency; reference it so strict no-unused
158
- // linters do not flag the parameter.
159
- void now;
160
-
161
- return { action: "allow" };
162
- }
163
-
164
- /**
165
- * Convenience helper for the caller: given a `warn` decision, was this the
166
- * log-only band (no injection) or the inject-warn band? The caller uses
167
- * this to decide whether to write a `client.app.log` line or to set a
168
- * pending system-transform injection.
169
- */
170
- export function isLogOnlyWarn(
171
- decision: Decision,
172
- options: NormalizedOptions,
173
- ): boolean {
174
- if (decision.action !== "warn") return false;
175
- return decision.count < options.loopThresholdWarn;
176
- }
@@ -1,98 +0,0 @@
1
- /**
2
- * mistake-recovery.ts
3
- *
4
- * v6.0.1 — Built-in `onConsecutiveMistakeLimitReached` callback for the
5
- * Cline runtime.
6
- *
7
- * Why this exists:
8
- *
9
- * The Cline runtime aborts a session after `execution.maxConsecutiveMistakes`
10
- * identical-failure turns. The bundled CLI defaults this to 3 (via the
11
- * `--retries` flag); the SDK default is 6. When the model emits malformed
12
- * tool calls — e.g. `editor({ new_text: undefined })`, `ask_question({ options: null })`,
13
- * `run_commands({ ... })` rejected by Zod — the counter increments on every
14
- * iteration and the session is dead after a couple of bad turns.
15
- *
16
- * Rather than raising the threshold (which masks the model misbehaviour),
17
- * we install a `onConsecutiveMistakeLimitReached` callback that:
18
- *
19
- * • For recoverable mistakes (invalid_tool_call, tool_execution_failed),
20
- * injects a recovery notice into the conversation and resets the
21
- * counter. Cline's `MistakeTracker.record()` returns
22
- * `{ action: "continue", guidance: "..." }` and appends the guidance
23
- * as a user message, then continues the run.
24
- *
25
- * • For infra errors (api_error), stops immediately. Retrying a
26
- * network/provider failure is wasted work.
27
- *
28
- * This keeps the threshold tight (model discipline matters) while
29
- * preventing a single bad turn from killing a long-running task.
30
- */
31
-
32
- import type {
33
- ConsecutiveMistakeLimitContext,
34
- ConsecutiveMistakeLimitDecision,
35
- } from "@cline/shared";
36
-
37
- const RECOVERABLE_REASONS = new Set<ConsecutiveMistakeLimitContext["reason"]>([
38
- "invalid_tool_call",
39
- "tool_execution_failed",
40
- ]);
41
-
42
- export interface MistakeRecoveryOptions {
43
- /**
44
- * Called after the recovery notice is appended but before the run
45
- * continues. Receives the full context for observability.
46
- */
47
- onRecovery?: (ctx: ConsecutiveMistakeLimitContext, guidance: string) => void;
48
- /**
49
- * Override the recovery guidance text. Defaults to `BUILTIN_RECOVERY_GUIDANCE`.
50
- */
51
- guidance?: string;
52
- }
53
-
54
- /**
55
- * The default guidance appended to the conversation when consecutive
56
- * recoverable mistakes trip the limit. Kept terse on purpose — longer
57
- * text dilutes model attention.
58
- */
59
- export const BUILTIN_RECOVERY_GUIDANCE = [
60
- "You reached the consecutive-mistake limit. Before retrying:",
61
- "",
62
- "1. Re-read the failing tool's input schema. Every required field MUST be",
63
- " populated with a non-null value of the right type.",
64
- "2. For `editor`: `new_text` must be a non-empty string. If you intended",
65
- " to delete content, set `new_text` to \"\" (empty string) and use",
66
- " `applyPatch` or `delete_file` instead.",
67
- "3. For `ask_question`: `options` must be an array of ≥2 non-empty",
68
- " strings. Do not pass null, undefined, or arrays of length < 2.",
69
- "4. For `run_commands`: `commands` must be a non-empty array of strings.",
70
- "5. If you have made two mistakes on the SAME tool, switch tools or stop",
71
- " and explain in plain text what went wrong instead of retrying.",
72
- "",
73
- "Acknowledge this notice and continue.",
74
- ].join("\n");
75
-
76
- /**
77
- * Default stop reason when an unrecoverable mistake hits the limit.
78
- */
79
- export const BUILTIN_STOP_REASON = "consecutive api_errors — stopping without retry";
80
-
81
- /**
82
- * Build an `onConsecutiveMistakeLimitReached` callback.
83
- *
84
- * Pass the result directly to `cline.start({ config: { onConsecutiveMistakeLimitReached } })`.
85
- */
86
- export function buildMistakeRecovery(
87
- opts: MistakeRecoveryOptions = {},
88
- ): (ctx: ConsecutiveMistakeLimitContext) => Promise<ConsecutiveMistakeLimitDecision> | ConsecutiveMistakeLimitDecision {
89
- const guidance = opts.guidance ?? BUILTIN_RECOVERY_GUIDANCE;
90
- const onRecovery = opts.onRecovery;
91
- return (ctx) => {
92
- if (RECOVERABLE_REASONS.has(ctx.reason)) {
93
- onRecovery?.(ctx, guidance);
94
- return { action: "continue", guidance };
95
- }
96
- return { action: "stop", reason: BUILTIN_STOP_REASON };
97
- };
98
- }