@polderlabs/bizar 6.2.5 → 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 (329) 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 +17 -18
  125. package/cli/commands/claude-cmd.mjs +348 -0
  126. package/cli/commands/install.mjs +12 -11
  127. package/cli/commands/validate.mjs +252 -325
  128. package/cli/dev-link.test.mjs +11 -11
  129. package/cli/doctor.mjs +131 -213
  130. package/cli/install.mjs +33 -37
  131. package/cli/install.test.mjs +9 -9
  132. package/cli/provision-claude.mjs +893 -0
  133. package/cli/provision.mjs +224 -227
  134. package/cli/utils.mjs +72 -58
  135. package/config/AGENTS.md +28 -28
  136. package/install.sh +66 -44
  137. package/package.json +19 -11
  138. package/packages/sdk/ARCHITECTURE.md +40 -36
  139. package/packages/sdk/package-lock.json +32 -0
  140. package/packages/sdk/package.json +15 -5
  141. package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
  142. package/packages/sdk/src/fingerprint.ts +0 -0
  143. package/packages/sdk/src/index.ts +38 -73
  144. package/packages/sdk/src/mcp/bin.ts +51 -0
  145. package/packages/sdk/src/mcp/server.ts +498 -0
  146. package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
  147. package/packages/sdk/tests/sdk.test.mjs +148 -0
  148. package/packages/sdk/vitest.config.ts +1 -1
  149. package/scripts/bh-full-e2e.mjs +166 -363
  150. package/scripts/check-deps.mjs +28 -46
  151. package/scripts/mirror-claude-md.sh +78 -0
  152. package/scripts/test-in-container.sh +31 -9
  153. package/templates/clean-state-checklist.md +3 -3
  154. package/templates/sprint-contract.md +2 -2
  155. package/bizar-dash/.bizar/activity.log +0 -3
  156. package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
  157. package/bizar-dash/.omx/state/session.json +0 -10
  158. package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
  159. package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
  160. package/bizar-dash/bizar-design/canvas.html +0 -281
  161. package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
  162. package/bizar-dash/bizar-design/components.css +0 -1665
  163. package/bizar-dash/bizar-design/components.html +0 -557
  164. package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
  165. package/bizar-dash/bizar-design/desktop/agents.html +0 -74
  166. package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
  167. package/bizar-dash/bizar-design/desktop/memory.html +0 -75
  168. package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
  169. package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
  170. package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
  171. package/bizar-dash/bizar-design/desktop/overview.html +0 -95
  172. package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
  173. package/bizar-dash/bizar-design/desktop/settings.html +0 -70
  174. package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
  175. package/bizar-dash/bizar-design/icons.svg +0 -44
  176. package/bizar-dash/bizar-design/index.html +0 -192
  177. package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
  178. package/bizar-dash/bizar-design/mobile/agents.html +0 -29
  179. package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
  180. package/bizar-dash/bizar-design/mobile/memory.html +0 -28
  181. package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
  182. package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
  183. package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
  184. package/bizar-dash/bizar-design/mobile/overview.html +0 -33
  185. package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
  186. package/bizar-dash/bizar-design/mobile/settings.html +0 -28
  187. package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
  188. package/bizar-dash/bizar-design/prototype.js +0 -114
  189. package/bizar-dash/bizar-design/tokens.css +0 -106
  190. package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
  191. package/bizar-dash/node_modules/.package-lock.json +0 -6
  192. package/bizar-dash/package-lock.json +0 -6
  193. package/bizar-dash/src/server/cline-sdk.mjs +0 -132
  194. package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
  195. package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
  196. package/cli/commands/cline-cmd.mjs +0 -289
  197. package/cli/commands/validate.test.mjs +0 -379
  198. package/cli/doctor.test.mjs +0 -350
  199. package/config/cline.json.template +0 -342
  200. package/packages/sdk/src/client.ts +0 -188
  201. package/packages/sdk/src/cline-events.ts +0 -134
  202. package/packages/sdk/src/cline-types.ts +0 -66
  203. package/packages/sdk/src/cline.ts +0 -339
  204. package/packages/sdk/src/errors.ts +0 -129
  205. package/packages/sdk/src/events.ts +0 -153
  206. package/packages/sdk/src/types.ts +0 -176
  207. package/packages/sdk/tests/client.test.ts +0 -217
  208. package/packages/sdk/tests/errors.test.ts +0 -108
  209. package/packages/sdk/tests/events.test.ts +0 -139
  210. package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
  211. package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
  212. package/plugins/bizar/ARCHITECTURE.md +0 -142
  213. package/plugins/bizar/CONSTRAINTS.md +0 -67
  214. package/plugins/bizar/LICENSE +0 -21
  215. package/plugins/bizar/README.md +0 -448
  216. package/plugins/bizar/index.ts +0 -925
  217. package/plugins/bizar/package.json +0 -39
  218. package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
  219. package/plugins/bizar/src/background-state.ts +0 -641
  220. package/plugins/bizar/src/background.ts +0 -1806
  221. package/plugins/bizar/src/cline-runner.ts +0 -203
  222. package/plugins/bizar/src/clineruntime.ts +0 -227
  223. package/plugins/bizar/src/commands-impl.ts +0 -151
  224. package/plugins/bizar/src/commands.ts +0 -1799
  225. package/plugins/bizar/src/compaction.d.mts +0 -48
  226. package/plugins/bizar/src/compaction.mjs +0 -192
  227. package/plugins/bizar/src/dashboard-client.ts +0 -233
  228. package/plugins/bizar/src/event-stream.ts +0 -606
  229. package/plugins/bizar/src/fingerprint.ts +0 -120
  230. package/plugins/bizar/src/handoff.ts +0 -79
  231. package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
  232. package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
  233. package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
  234. package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
  235. package/plugins/bizar/src/http-client.ts +0 -467
  236. package/plugins/bizar/src/key-rotation.ts +0 -218
  237. package/plugins/bizar/src/logger.ts +0 -144
  238. package/plugins/bizar/src/loop-engineering.ts +0 -241
  239. package/plugins/bizar/src/loop.ts +0 -176
  240. package/plugins/bizar/src/mistake-recovery.ts +0 -98
  241. package/plugins/bizar/src/odin.ts +0 -227
  242. package/plugins/bizar/src/options.ts +0 -470
  243. package/plugins/bizar/src/plan-fs.ts +0 -323
  244. package/plugins/bizar/src/reasoning-clean.ts +0 -454
  245. package/plugins/bizar/src/report.ts +0 -178
  246. package/plugins/bizar/src/research-prompt.ts +0 -35
  247. package/plugins/bizar/src/serve-info.ts +0 -228
  248. package/plugins/bizar/src/serve.ts +0 -496
  249. package/plugins/bizar/src/settings.ts +0 -349
  250. package/plugins/bizar/src/state.ts +0 -298
  251. package/plugins/bizar/src/tool-discipline.ts +0 -105
  252. package/plugins/bizar/src/tools/agent-browser.ts +0 -315
  253. package/plugins/bizar/src/tools/bg-collect.ts +0 -131
  254. package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
  255. package/plugins/bizar/src/tools/bg-kill.ts +0 -116
  256. package/plugins/bizar/src/tools/bg-pause.ts +0 -99
  257. package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
  258. package/plugins/bizar/src/tools/bg-resume.ts +0 -94
  259. package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
  260. package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
  261. package/plugins/bizar/src/tools/bg-status.ts +0 -130
  262. package/plugins/bizar/src/tools/graph-query.ts +0 -278
  263. package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
  264. package/plugins/bizar/src/tools/memory-list.ts +0 -43
  265. package/plugins/bizar/src/tools/memory-read.ts +0 -69
  266. package/plugins/bizar/src/tools/memory-search.ts +0 -47
  267. package/plugins/bizar/src/tools/memory-write.ts +0 -54
  268. package/plugins/bizar/src/tools/open-kb.ts +0 -198
  269. package/plugins/bizar/src/tools/plan-action.ts +0 -785
  270. package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
  271. package/plugins/bizar/src/tools/sandbox.ts +0 -232
  272. package/plugins/bizar/src/tools/team-spawn.ts +0 -73
  273. package/plugins/bizar/src/tools/team-status.ts +0 -76
  274. package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
  275. package/plugins/bizar/src/trajectory.ts +0 -104
  276. package/plugins/bizar/tests/README.md +0 -99
  277. package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
  278. package/plugins/bizar/tests/background-state.test.ts +0 -277
  279. package/plugins/bizar/tests/background.test.ts +0 -402
  280. package/plugins/bizar/tests/block.test.ts +0 -195
  281. package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
  282. package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
  283. package/plugins/bizar/tests/commands-impl.test.ts +0 -316
  284. package/plugins/bizar/tests/commands.test.ts +0 -584
  285. package/plugins/bizar/tests/compaction.test.ts +0 -264
  286. package/plugins/bizar/tests/config.test.ts +0 -128
  287. package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
  288. package/plugins/bizar/tests/dispose.test.ts +0 -336
  289. package/plugins/bizar/tests/event-stream.test.ts +0 -409
  290. package/plugins/bizar/tests/event.test.ts +0 -262
  291. package/plugins/bizar/tests/fingerprint.test.ts +0 -190
  292. package/plugins/bizar/tests/http-client.test.ts +0 -404
  293. package/plugins/bizar/tests/init-helpers.test.ts +0 -203
  294. package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
  295. package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
  296. package/plugins/bizar/tests/key-rotation.test.ts +0 -396
  297. package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
  298. package/plugins/bizar/tests/loop.test.ts +0 -397
  299. package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
  300. package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
  301. package/plugins/bizar/tests/odin.test.ts +0 -125
  302. package/plugins/bizar/tests/options.test.ts +0 -329
  303. package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
  304. package/plugins/bizar/tests/safety.test.ts +0 -281
  305. package/plugins/bizar/tests/serve.test.ts +0 -339
  306. package/plugins/bizar/tests/settings.test.ts +0 -351
  307. package/plugins/bizar/tests/stall-think.test.ts +0 -750
  308. package/plugins/bizar/tests/state.test.ts +0 -276
  309. package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
  310. package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
  311. package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
  312. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
  313. package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
  314. package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
  315. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
  316. package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
  317. package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
  318. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
  319. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
  320. package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
  321. package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
  322. package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
  323. package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
  324. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
  325. package/plugins/bizar/tests/tools/sandbox.test.ts +0 -117
  326. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
  327. package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
  328. package/plugins/bizar/tsconfig.json +0 -29
  329. package/scripts/mirror-agents-md.sh +0 -69
@@ -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
- }