@polderlabs/bizar 6.2.5 → 7.0.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 (540) 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/hooks/worker-suggest.mjs +110 -0
  41. package/.claude/settings.json +125 -0
  42. package/.claude/skills/9router/SKILL.md +80 -0
  43. package/.claude/skills/9router-chat/SKILL.md +73 -0
  44. package/.claude/skills/9router-embeddings/SKILL.md +69 -0
  45. package/.claude/skills/9router-image/SKILL.md +86 -0
  46. package/.claude/skills/9router-stt/SKILL.md +79 -0
  47. package/.claude/skills/9router-tts/SKILL.md +80 -0
  48. package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
  49. package/.claude/skills/9router-web-search/SKILL.md +91 -0
  50. package/.claude/skills/bizar/README.md +9 -0
  51. package/.claude/skills/bizar/SKILL.md +450 -0
  52. package/.claude/skills/cpp-coding-standards/README.md +28 -0
  53. package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
  54. package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
  55. package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
  56. package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
  57. package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
  58. package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
  59. package/.claude/skills/cpp-testing/README.md +28 -0
  60. package/.claude/skills/cpp-testing/SKILL.md +304 -0
  61. package/.claude/skills/cpp-testing/references/coverage.md +370 -0
  62. package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
  63. package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
  64. package/.claude/skills/cpp-testing/references/mocking.md +364 -0
  65. package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
  66. package/.claude/skills/cubesandbox/SKILL.md +148 -0
  67. package/.claude/skills/embedded-esp-idf/README.md +41 -0
  68. package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
  69. package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
  70. package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
  71. package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
  72. package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
  73. package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
  74. package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
  75. package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
  76. package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
  77. package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
  78. package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
  79. package/.claude/skills/glyph/SKILL.md +163 -0
  80. package/.claude/skills/harness-engineering/SKILL.md +143 -0
  81. package/.claude/skills/lightrag/SKILL.md +81 -0
  82. package/.claude/skills/memory-protocol/SKILL.md +105 -0
  83. package/.claude/skills/obsidian/SKILL.md +306 -0
  84. package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
  85. package/.claude/skills/self-improvement/SKILL.md +64 -0
  86. package/README.md +87 -59
  87. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js → EnvVarsSection-CW6fWKds.js} +3 -3
  88. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js.map → EnvVarsSection-CW6fWKds.js.map} +1 -1
  89. package/bizar-dash/dist/assets/MobileChat-D7zRhU9K.js +1 -0
  90. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js.map → MobileChat-D7zRhU9K.js.map} +1 -1
  91. package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +1 -0
  92. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js.map → MobileSettings-K-sNsn_r.js.map} +1 -1
  93. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js → Toast-WTxc3m2g.js} +1 -1
  94. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js.map → Toast-WTxc3m2g.js.map} +1 -1
  95. package/bizar-dash/dist/assets/flow-BpU0-gK2.js +1 -0
  96. package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -0
  97. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js +1 -0
  98. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js.map +1 -0
  99. package/bizar-dash/dist/assets/{icons-Do5N2jmX.js → icons-B0AKnYI3.js} +98 -103
  100. package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -0
  101. package/bizar-dash/dist/assets/main-C-Md3DaY.css +1 -0
  102. package/bizar-dash/dist/assets/main-CO8fIxQK.js +18 -0
  103. package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +1 -0
  104. package/bizar-dash/dist/assets/markdown-w2bDDkAH.js +1 -0
  105. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js.map → markdown-w2bDDkAH.js.map} +1 -1
  106. package/bizar-dash/dist/assets/mobile-DXYCA0hC.js +1 -0
  107. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js.map → mobile-DXYCA0hC.js.map} +1 -1
  108. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js +2 -0
  109. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js.map +1 -0
  110. package/bizar-dash/dist/assets/react-vendor-BnuhLJ6X.css +1 -0
  111. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js +46 -0
  112. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -0
  113. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js +2 -0
  114. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js.map +1 -0
  115. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js +45 -0
  116. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -0
  117. package/bizar-dash/dist/index.html +12 -10
  118. package/bizar-dash/dist/mobile.html +7 -4
  119. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  120. package/bizar-dash/src/server/api.mjs +15 -4
  121. package/bizar-dash/src/server/background-store.mjs +15 -16
  122. package/bizar-dash/src/server/bg-poller.mjs +25 -35
  123. package/bizar-dash/src/server/bg-retry.mjs +66 -194
  124. package/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
  125. package/bizar-dash/src/server/claude-info.mjs +412 -0
  126. package/bizar-dash/src/server/{cline-runner.mjs → claude-runner.mjs} +53 -48
  127. package/bizar-dash/src/server/claude-sdk.mjs +191 -0
  128. package/bizar-dash/src/server/memory-consolidator.mjs +218 -0
  129. package/bizar-dash/src/server/memory-distillation.mjs +296 -0
  130. package/bizar-dash/src/server/providers-store.mjs +22 -49
  131. package/bizar-dash/src/server/routes/background.mjs +24 -20
  132. package/bizar-dash/src/server/routes/chat.mjs +223 -326
  133. package/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
  134. package/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
  135. package/bizar-dash/src/server/routes/distill.mjs +129 -0
  136. package/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
  137. package/bizar-dash/src/server/routes/tasks.mjs +20 -28
  138. package/bizar-dash/src/server/task-delegator.mjs +76 -77
  139. package/bizar-dash/src/web/App.tsx +4 -0
  140. package/bizar-dash/src/web/components/Tag.tsx +18 -5
  141. package/bizar-dash/src/web/components/Topbar.tsx +3 -0
  142. package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +126 -0
  143. package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +163 -0
  144. package/bizar-dash/src/web/components/agents/QualityGates.tsx +123 -0
  145. package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +127 -0
  146. package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +148 -0
  147. package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +160 -0
  148. package/bizar-dash/src/web/components/chat/useChat.ts +23 -27
  149. package/bizar-dash/src/web/components/goals/GoalInput.tsx +86 -0
  150. package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +111 -0
  151. package/bizar-dash/src/web/lib/goapPlanner.ts +614 -0
  152. package/bizar-dash/src/web/lib/types.ts +25 -0
  153. package/bizar-dash/src/web/styles/agents-redesign.css +311 -0
  154. package/bizar-dash/src/web/styles/main.css +251 -0
  155. package/bizar-dash/src/web/styles/tasks-redesign.css +231 -0
  156. package/bizar-dash/src/web/ui/controls/Button.tsx +77 -0
  157. package/bizar-dash/src/web/ui/controls/Checkbox.tsx +95 -0
  158. package/bizar-dash/src/web/ui/controls/IconButton.tsx +66 -0
  159. package/bizar-dash/src/web/ui/controls/Kbd.tsx +24 -0
  160. package/bizar-dash/src/web/ui/controls/NumberInput.tsx +77 -0
  161. package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +109 -0
  162. package/bizar-dash/src/web/ui/controls/SearchInput.tsx +91 -0
  163. package/bizar-dash/src/web/ui/controls/Select.tsx +92 -0
  164. package/bizar-dash/src/web/ui/controls/Slider.tsx +70 -0
  165. package/bizar-dash/src/web/ui/controls/TextInput.tsx +67 -0
  166. package/bizar-dash/src/web/ui/controls/Toggle.tsx +79 -0
  167. package/bizar-dash/src/web/ui/controls/controls.css +454 -0
  168. package/bizar-dash/src/web/ui/controls/index.ts +33 -0
  169. package/bizar-dash/src/web/ui/data/BarChart.tsx +60 -0
  170. package/bizar-dash/src/web/ui/data/DataTable.tsx +216 -0
  171. package/bizar-dash/src/web/ui/data/EmptyState.tsx +60 -0
  172. package/bizar-dash/src/web/ui/data/ErrorState.tsx +56 -0
  173. package/bizar-dash/src/web/ui/data/KeyValueList.tsx +106 -0
  174. package/bizar-dash/src/web/ui/data/LoadingState.tsx +65 -0
  175. package/bizar-dash/src/web/ui/data/Sparkline.tsx +87 -0
  176. package/bizar-dash/src/web/ui/data/StatTile.tsx +87 -0
  177. package/bizar-dash/src/web/ui/data/data.css +535 -0
  178. package/bizar-dash/src/web/ui/data/index.ts +31 -0
  179. package/bizar-dash/src/web/ui/feedback/Badge.tsx +49 -0
  180. package/bizar-dash/src/web/ui/feedback/Dialog.tsx +209 -0
  181. package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +69 -0
  182. package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +50 -0
  183. package/bizar-dash/src/web/ui/feedback/Toast.tsx +200 -0
  184. package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +126 -0
  185. package/bizar-dash/src/web/ui/feedback/feedback.css +314 -0
  186. package/bizar-dash/src/web/ui/feedback/index.ts +43 -0
  187. package/bizar-dash/src/web/ui/index.ts +56 -0
  188. package/bizar-dash/src/web/ui/layout/AppShell.tsx +51 -0
  189. package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +97 -0
  190. package/bizar-dash/src/web/ui/layout/Panel.tsx +73 -0
  191. package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +39 -0
  192. package/bizar-dash/src/web/ui/layout/Sidebar.tsx +131 -0
  193. package/bizar-dash/src/web/ui/layout/Tabs.tsx +133 -0
  194. package/bizar-dash/src/web/ui/layout/Topbar.tsx +42 -0
  195. package/bizar-dash/src/web/ui/layout/index.ts +33 -0
  196. package/bizar-dash/src/web/ui/layout/layout.css +413 -0
  197. package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +199 -0
  198. package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +95 -0
  199. package/bizar-dash/src/web/ui/navigation/NavLink.tsx +93 -0
  200. package/bizar-dash/src/web/ui/navigation/index.ts +17 -0
  201. package/bizar-dash/src/web/ui/navigation/navigation.css +343 -0
  202. package/bizar-dash/src/web/ui/primitives/Box.tsx +91 -0
  203. package/bizar-dash/src/web/ui/primitives/Grid.tsx +49 -0
  204. package/bizar-dash/src/web/ui/primitives/Inline.tsx +55 -0
  205. package/bizar-dash/src/web/ui/primitives/Separator.tsx +46 -0
  206. package/bizar-dash/src/web/ui/primitives/Stack.tsx +54 -0
  207. package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +26 -0
  208. package/bizar-dash/src/web/ui/primitives/index.ts +23 -0
  209. package/bizar-dash/src/web/ui/primitives/primitives.css +183 -0
  210. package/bizar-dash/src/web/ui/styles/globals.css +86 -0
  211. package/bizar-dash/src/web/ui/styles/reset.css +125 -0
  212. package/bizar-dash/src/web/ui/styles/tokens.css +195 -0
  213. package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +142 -0
  214. package/bizar-dash/src/web/ui/theme/tokens.ts +131 -0
  215. package/bizar-dash/src/web/ui/theme/useTheme.ts +22 -0
  216. package/bizar-dash/src/web/ui/utils/cx.ts +42 -0
  217. package/bizar-dash/src/web/views/Agents.tsx +506 -266
  218. package/bizar-dash/src/web/views/Chat.tsx +8 -8
  219. package/bizar-dash/src/web/views/GoalPlanner.tsx +158 -0
  220. package/bizar-dash/src/web/views/Overview.tsx +996 -448
  221. package/bizar-dash/src/web/views/Tasks.tsx +277 -273
  222. package/bizar-dash/tests/communication-log.test.tsx +67 -0
  223. package/bizar-dash/tests/dep-graph.test.tsx +40 -0
  224. package/bizar-dash/tests/event-log.test.tsx +61 -0
  225. package/bizar-dash/tests/goal-input.test.tsx +72 -0
  226. package/bizar-dash/tests/goap-planner.test.ts +68 -0
  227. package/bizar-dash/tests/quality-gates.test.tsx +59 -0
  228. package/bizar-dash/tests/setup.ts +31 -1
  229. package/bizar-dash/tests/ui/controls/Button.test.tsx +50 -0
  230. package/bizar-dash/tests/ui/controls/Checkbox.test.tsx +44 -0
  231. package/bizar-dash/tests/ui/controls/IconButton.test.tsx +37 -0
  232. package/bizar-dash/tests/ui/controls/Kbd.test.tsx +39 -0
  233. package/bizar-dash/tests/ui/controls/NumberInput.test.tsx +56 -0
  234. package/bizar-dash/tests/ui/controls/RadioGroup.test.tsx +58 -0
  235. package/bizar-dash/tests/ui/controls/SearchInput.test.tsx +52 -0
  236. package/bizar-dash/tests/ui/controls/Select.test.tsx +66 -0
  237. package/bizar-dash/tests/ui/controls/Slider.test.tsx +41 -0
  238. package/bizar-dash/tests/ui/controls/TextInput.test.tsx +44 -0
  239. package/bizar-dash/tests/ui/controls/Toggle.test.tsx +39 -0
  240. package/bizar-dash/tests/ui/data/BarChart.test.tsx +55 -0
  241. package/bizar-dash/tests/ui/data/DataTable.test.tsx +112 -0
  242. package/bizar-dash/tests/ui/data/EmptyState.test.tsx +57 -0
  243. package/bizar-dash/tests/ui/data/ErrorState.test.tsx +47 -0
  244. package/bizar-dash/tests/ui/data/KeyValueList.test.tsx +59 -0
  245. package/bizar-dash/tests/ui/data/LoadingState.test.tsx +37 -0
  246. package/bizar-dash/tests/ui/data/Sparkline.test.tsx +56 -0
  247. package/bizar-dash/tests/ui/data/StatTile.test.tsx +69 -0
  248. package/bizar-dash/tests/ui/feedback/Badge.test.tsx +41 -0
  249. package/bizar-dash/tests/ui/feedback/Dialog.test.tsx +99 -0
  250. package/bizar-dash/tests/ui/feedback/ProgressBar.test.tsx +66 -0
  251. package/bizar-dash/tests/ui/feedback/StatusDot.test.tsx +41 -0
  252. package/bizar-dash/tests/ui/feedback/Toast.test.tsx +124 -0
  253. package/bizar-dash/tests/ui/feedback/Tooltip.test.tsx +102 -0
  254. package/bizar-dash/tests/ui/layout/AppShell.test.tsx +50 -0
  255. package/bizar-dash/tests/ui/layout/Breadcrumbs.test.tsx +85 -0
  256. package/bizar-dash/tests/ui/layout/Panel.test.tsx +52 -0
  257. package/bizar-dash/tests/ui/layout/PanelHeader.test.tsx +32 -0
  258. package/bizar-dash/tests/ui/layout/Sidebar.test.tsx +95 -0
  259. package/bizar-dash/tests/ui/layout/Tabs.test.tsx +87 -0
  260. package/bizar-dash/tests/ui/layout/Topbar.test.tsx +41 -0
  261. package/bizar-dash/tests/ui/navigation/CommandPalette.test.tsx +105 -0
  262. package/bizar-dash/tests/ui/navigation/NavGroup.test.tsx +55 -0
  263. package/bizar-dash/tests/ui/navigation/NavLink.test.tsx +61 -0
  264. package/bizar-dash/tests/ui/primitives/Box.test.tsx +49 -0
  265. package/bizar-dash/tests/ui/primitives/Grid.test.tsx +37 -0
  266. package/bizar-dash/tests/ui/primitives/Inline.test.tsx +33 -0
  267. package/bizar-dash/tests/ui/primitives/Separator.test.tsx +34 -0
  268. package/bizar-dash/tests/ui/primitives/Stack.test.tsx +45 -0
  269. package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +27 -0
  270. package/bizar-dash/tests/views/Agents.test.tsx +359 -0
  271. package/bizar-dash/tests/views/Overview.test.tsx +413 -0
  272. package/bizar-dash/tests/views/Tasks.test.tsx +250 -0
  273. package/bizar-dash/vitest.config.ts +3 -1
  274. package/cli/__tests__/cost-gate.test.mjs +301 -0
  275. package/cli/__tests__/feature-list-bridge.test.mjs +371 -0
  276. package/cli/bin.mjs +55 -18
  277. package/cli/commands/claim.mjs +282 -0
  278. package/cli/commands/claude-cmd.mjs +348 -0
  279. package/cli/commands/cost.mjs +279 -0
  280. package/cli/commands/install.mjs +12 -11
  281. package/cli/commands/validate.mjs +252 -325
  282. package/cli/cost-gate.mjs +501 -0
  283. package/cli/dev-link.test.mjs +11 -11
  284. package/cli/doctor.mjs +131 -213
  285. package/cli/feature-list-bridge.mjs +400 -0
  286. package/cli/install.mjs +33 -37
  287. package/cli/install.test.mjs +9 -9
  288. package/cli/memory-constants.mjs +17 -0
  289. package/cli/provision-claude.mjs +893 -0
  290. package/cli/provision.mjs +224 -227
  291. package/cli/utils.mjs +72 -58
  292. package/cli/worker-dispatcher.mjs +259 -0
  293. package/cli/worker-dispatcher.test.mjs +204 -0
  294. package/config/AGENTS.md +28 -28
  295. package/config/trigger-patterns.json +186 -0
  296. package/install.sh +66 -44
  297. package/package.json +19 -11
  298. package/packages/sdk/ARCHITECTURE.md +40 -36
  299. package/packages/sdk/package.json +15 -5
  300. package/packages/sdk/src/agent-registry.ts +304 -0
  301. package/packages/sdk/src/consensus/byzantine.ts +587 -0
  302. package/packages/sdk/src/consensus/index.ts +147 -0
  303. package/packages/sdk/src/consensus/queen.ts +173 -0
  304. package/packages/sdk/src/consensus/types.ts +199 -0
  305. package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
  306. package/packages/sdk/src/federation/audit.ts +156 -0
  307. package/packages/sdk/src/federation/budget.ts +269 -0
  308. package/packages/sdk/src/federation/envelope.ts +144 -0
  309. package/packages/sdk/src/federation/hmac.ts +160 -0
  310. package/packages/sdk/src/federation/index.ts +443 -0
  311. package/packages/sdk/src/federation/pii.ts +241 -0
  312. package/packages/sdk/src/federation/policy.ts +112 -0
  313. package/packages/sdk/src/federation/trust.ts +146 -0
  314. package/packages/sdk/src/fingerprint.ts +0 -0
  315. package/packages/sdk/src/index.ts +101 -69
  316. package/packages/sdk/src/mcp/bin.ts +51 -0
  317. package/packages/sdk/src/mcp/server.ts +848 -0
  318. package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
  319. package/packages/sdk/src/router/codemod-intent.ts +125 -0
  320. package/packages/sdk/src/router/index.ts +247 -0
  321. package/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
  322. package/packages/sdk/src/router/memory-distillation.ts +249 -0
  323. package/packages/sdk/src/router/model-router.ts +235 -0
  324. package/packages/sdk/src/router/q-learning-router.ts +304 -0
  325. package/packages/sdk/src/swarm-topology.ts +279 -0
  326. package/packages/sdk/tests/agent-registry.test.ts +285 -0
  327. package/packages/sdk/tests/consensus.test.ts +376 -0
  328. package/packages/sdk/tests/federation/audit.test.ts +164 -0
  329. package/packages/sdk/tests/federation/budget.test.ts +189 -0
  330. package/packages/sdk/tests/federation/envelope.test.ts +120 -0
  331. package/packages/sdk/tests/federation/hmac.test.ts +194 -0
  332. package/packages/sdk/tests/federation/orchestrator.test.ts +176 -0
  333. package/packages/sdk/tests/federation/pii.test.ts +106 -0
  334. package/packages/sdk/tests/federation/policy.test.ts +140 -0
  335. package/packages/sdk/tests/federation/trust.test.ts +124 -0
  336. package/packages/sdk/tests/mcp-tools.test.ts +204 -0
  337. package/packages/sdk/tests/memory-distillation.test.mjs +186 -0
  338. package/packages/sdk/tests/model-router.test.mjs +108 -0
  339. package/packages/sdk/tests/q-learning-router.test.mjs +100 -0
  340. package/packages/sdk/tests/router-orchestrator.test.mjs +172 -0
  341. package/packages/sdk/tests/router.test.mjs +91 -0
  342. package/packages/sdk/tests/sdk.test.mjs +172 -0
  343. package/packages/sdk/tests/swarm-topology.test.ts +258 -0
  344. package/packages/sdk/vitest.config.ts +1 -1
  345. package/scripts/bh-full-e2e.mjs +167 -368
  346. package/scripts/check-deps.mjs +28 -46
  347. package/scripts/mirror-claude-md.sh +78 -0
  348. package/scripts/test-in-container.sh +31 -9
  349. package/templates/clean-state-checklist.md +3 -3
  350. package/templates/sprint-contract.md +2 -2
  351. package/bizar-dash/.bizar/activity.log +0 -3
  352. package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
  353. package/bizar-dash/.omx/state/session.json +0 -10
  354. package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
  355. package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
  356. package/bizar-dash/bizar-design/canvas.html +0 -281
  357. package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
  358. package/bizar-dash/bizar-design/components.css +0 -1665
  359. package/bizar-dash/bizar-design/components.html +0 -557
  360. package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
  361. package/bizar-dash/bizar-design/desktop/agents.html +0 -74
  362. package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
  363. package/bizar-dash/bizar-design/desktop/memory.html +0 -75
  364. package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
  365. package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
  366. package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
  367. package/bizar-dash/bizar-design/desktop/overview.html +0 -95
  368. package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
  369. package/bizar-dash/bizar-design/desktop/settings.html +0 -70
  370. package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
  371. package/bizar-dash/bizar-design/icons.svg +0 -44
  372. package/bizar-dash/bizar-design/index.html +0 -192
  373. package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
  374. package/bizar-dash/bizar-design/mobile/agents.html +0 -29
  375. package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
  376. package/bizar-dash/bizar-design/mobile/memory.html +0 -28
  377. package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
  378. package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
  379. package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
  380. package/bizar-dash/bizar-design/mobile/overview.html +0 -33
  381. package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
  382. package/bizar-dash/bizar-design/mobile/settings.html +0 -28
  383. package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
  384. package/bizar-dash/bizar-design/prototype.js +0 -114
  385. package/bizar-dash/bizar-design/tokens.css +0 -106
  386. package/bizar-dash/dist/assets/MobileChat-BnKN_Ks_.js +0 -1
  387. package/bizar-dash/dist/assets/MobileSettings-DjCPxC-Q.js +0 -1
  388. package/bizar-dash/dist/assets/icons-Do5N2jmX.js.map +0 -1
  389. package/bizar-dash/dist/assets/main-DYiZqMrn.js +0 -18
  390. package/bizar-dash/dist/assets/main-DYiZqMrn.js.map +0 -1
  391. package/bizar-dash/dist/assets/main-ietCEg_R.css +0 -1
  392. package/bizar-dash/dist/assets/markdown-C6mXtQxD.js +0 -1
  393. package/bizar-dash/dist/assets/mobile-CMHqtLV2.js +0 -1
  394. package/bizar-dash/dist/assets/mobile-layout-3jIhHX_p.js +0 -2
  395. package/bizar-dash/dist/assets/mobile-layout-3jIhHX_p.js.map +0 -1
  396. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js +0 -40
  397. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js.map +0 -1
  398. package/bizar-dash/dist/assets/useSlashCommands-DtITw8Xv.js +0 -2
  399. package/bizar-dash/dist/assets/useSlashCommands-DtITw8Xv.js.map +0 -1
  400. package/bizar-dash/dist/assets/vendor-CeHGtduv.js +0 -29
  401. package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
  402. package/bizar-dash/node_modules/.package-lock.json +0 -6
  403. package/bizar-dash/package-lock.json +0 -6
  404. package/bizar-dash/src/server/cline-sdk.mjs +0 -132
  405. package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
  406. package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
  407. package/cli/commands/cline-cmd.mjs +0 -289
  408. package/cli/commands/validate.test.mjs +0 -379
  409. package/cli/doctor.test.mjs +0 -350
  410. package/config/cline.json.template +0 -342
  411. package/packages/sdk/src/client.ts +0 -188
  412. package/packages/sdk/src/cline-events.ts +0 -134
  413. package/packages/sdk/src/cline-types.ts +0 -66
  414. package/packages/sdk/src/cline.ts +0 -339
  415. package/packages/sdk/src/errors.ts +0 -129
  416. package/packages/sdk/src/events.ts +0 -153
  417. package/packages/sdk/src/types.ts +0 -176
  418. package/packages/sdk/tests/client.test.ts +0 -217
  419. package/packages/sdk/tests/errors.test.ts +0 -108
  420. package/packages/sdk/tests/events.test.ts +0 -139
  421. package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
  422. package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
  423. package/plugins/bizar/ARCHITECTURE.md +0 -142
  424. package/plugins/bizar/CONSTRAINTS.md +0 -67
  425. package/plugins/bizar/LICENSE +0 -21
  426. package/plugins/bizar/README.md +0 -448
  427. package/plugins/bizar/index.ts +0 -925
  428. package/plugins/bizar/package.json +0 -39
  429. package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
  430. package/plugins/bizar/src/background-state.ts +0 -641
  431. package/plugins/bizar/src/background.ts +0 -1806
  432. package/plugins/bizar/src/cline-runner.ts +0 -203
  433. package/plugins/bizar/src/clineruntime.ts +0 -227
  434. package/plugins/bizar/src/commands-impl.ts +0 -151
  435. package/plugins/bizar/src/commands.ts +0 -1799
  436. package/plugins/bizar/src/compaction.d.mts +0 -48
  437. package/plugins/bizar/src/compaction.mjs +0 -192
  438. package/plugins/bizar/src/dashboard-client.ts +0 -233
  439. package/plugins/bizar/src/event-stream.ts +0 -606
  440. package/plugins/bizar/src/fingerprint.ts +0 -120
  441. package/plugins/bizar/src/handoff.ts +0 -79
  442. package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
  443. package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
  444. package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
  445. package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
  446. package/plugins/bizar/src/http-client.ts +0 -467
  447. package/plugins/bizar/src/key-rotation.ts +0 -218
  448. package/plugins/bizar/src/logger.ts +0 -144
  449. package/plugins/bizar/src/loop-engineering.ts +0 -241
  450. package/plugins/bizar/src/loop.ts +0 -176
  451. package/plugins/bizar/src/mistake-recovery.ts +0 -98
  452. package/plugins/bizar/src/odin.ts +0 -227
  453. package/plugins/bizar/src/options.ts +0 -470
  454. package/plugins/bizar/src/plan-fs.ts +0 -323
  455. package/plugins/bizar/src/reasoning-clean.ts +0 -454
  456. package/plugins/bizar/src/report.ts +0 -178
  457. package/plugins/bizar/src/research-prompt.ts +0 -35
  458. package/plugins/bizar/src/serve-info.ts +0 -228
  459. package/plugins/bizar/src/serve.ts +0 -496
  460. package/plugins/bizar/src/settings.ts +0 -349
  461. package/plugins/bizar/src/state.ts +0 -298
  462. package/plugins/bizar/src/tool-discipline.ts +0 -105
  463. package/plugins/bizar/src/tools/agent-browser.ts +0 -315
  464. package/plugins/bizar/src/tools/bg-collect.ts +0 -131
  465. package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
  466. package/plugins/bizar/src/tools/bg-kill.ts +0 -116
  467. package/plugins/bizar/src/tools/bg-pause.ts +0 -99
  468. package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
  469. package/plugins/bizar/src/tools/bg-resume.ts +0 -94
  470. package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
  471. package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
  472. package/plugins/bizar/src/tools/bg-status.ts +0 -130
  473. package/plugins/bizar/src/tools/graph-query.ts +0 -278
  474. package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
  475. package/plugins/bizar/src/tools/memory-list.ts +0 -43
  476. package/plugins/bizar/src/tools/memory-read.ts +0 -69
  477. package/plugins/bizar/src/tools/memory-search.ts +0 -47
  478. package/plugins/bizar/src/tools/memory-write.ts +0 -54
  479. package/plugins/bizar/src/tools/open-kb.ts +0 -198
  480. package/plugins/bizar/src/tools/plan-action.ts +0 -785
  481. package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
  482. package/plugins/bizar/src/tools/sandbox.ts +0 -232
  483. package/plugins/bizar/src/tools/team-spawn.ts +0 -73
  484. package/plugins/bizar/src/tools/team-status.ts +0 -76
  485. package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
  486. package/plugins/bizar/src/trajectory.ts +0 -104
  487. package/plugins/bizar/tests/README.md +0 -99
  488. package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
  489. package/plugins/bizar/tests/background-state.test.ts +0 -277
  490. package/plugins/bizar/tests/background.test.ts +0 -402
  491. package/plugins/bizar/tests/block.test.ts +0 -195
  492. package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
  493. package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
  494. package/plugins/bizar/tests/commands-impl.test.ts +0 -316
  495. package/plugins/bizar/tests/commands.test.ts +0 -584
  496. package/plugins/bizar/tests/compaction.test.ts +0 -264
  497. package/plugins/bizar/tests/config.test.ts +0 -128
  498. package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
  499. package/plugins/bizar/tests/dispose.test.ts +0 -336
  500. package/plugins/bizar/tests/event-stream.test.ts +0 -409
  501. package/plugins/bizar/tests/event.test.ts +0 -262
  502. package/plugins/bizar/tests/fingerprint.test.ts +0 -190
  503. package/plugins/bizar/tests/http-client.test.ts +0 -404
  504. package/plugins/bizar/tests/init-helpers.test.ts +0 -203
  505. package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
  506. package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
  507. package/plugins/bizar/tests/key-rotation.test.ts +0 -396
  508. package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
  509. package/plugins/bizar/tests/loop.test.ts +0 -397
  510. package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
  511. package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
  512. package/plugins/bizar/tests/odin.test.ts +0 -125
  513. package/plugins/bizar/tests/options.test.ts +0 -329
  514. package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
  515. package/plugins/bizar/tests/safety.test.ts +0 -281
  516. package/plugins/bizar/tests/serve.test.ts +0 -339
  517. package/plugins/bizar/tests/settings.test.ts +0 -351
  518. package/plugins/bizar/tests/stall-think.test.ts +0 -750
  519. package/plugins/bizar/tests/state.test.ts +0 -276
  520. package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
  521. package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
  522. package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
  523. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
  524. package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
  525. package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
  526. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
  527. package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
  528. package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
  529. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
  530. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
  531. package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
  532. package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
  533. package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
  534. package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
  535. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
  536. package/plugins/bizar/tests/tools/sandbox.test.ts +0 -117
  537. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
  538. package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
  539. package/plugins/bizar/tsconfig.json +0 -29
  540. package/scripts/mirror-agents-md.sh +0 -69
@@ -0,0 +1,501 @@
1
+ // @ts-nocheck — declaration emit for the `Database` / `Statement`
2
+ // private types from better-sqlite3 is not currently exported by the
3
+ // better-sqlite3 type package, so .d.ts generation for this .mjs
4
+ // module fails with TS9006. The runtime is correct; once better-sqlite3
5
+ // ships exported types (or F-035 lands with a wrapper), the
6
+ // @ts-nocheck can come off.
7
+ // (The directive is placed BEFORE the docblock header below so
8
+ // TypeScript's parser doesn't trip on the `<uuid>` / `<env>` tokens
9
+ // inside the JSDoc body.)
10
+
11
+ /**
12
+ * cli/cost-gate.mjs
13
+ *
14
+ * F-035 (MetaHarness) — atomic SQLite-backed room-budget tracker.
15
+ *
16
+ * Source-of-truth port from
17
+ * ruflo/v3/@claude-flow/cli/src/business-pods/bbs-budget-tracker.ts:151
18
+ * (AtomicBbsRoomBudgetTracker — ADR-164.1 §3-§5)
19
+ *
20
+ * The contract:
21
+ * - `registerRoom(roomId, capUsd)` is idempotent (upsert by id).
22
+ * - `reserve(roomId, callerId, amount, opts?)` atomically checks
23
+ * the budget AND inserts a 'reserved' transaction inside one
24
+ * `BEGIN IMMEDIATE` transaction (Bizar's L10 cost-gate constraint).
25
+ * - `commit(txId, actualUsd)` flips the row to 'committed' (or
26
+ * 'committed_post_expiry' + `COMMIT_AFTER_EXPIRY` warning if the
27
+ * reservation already expired — the API spend already happened,
28
+ * so we accept the charge and emit a warning).
29
+ * - `release(txId)` flips a still-'reserved' row to 'released';
30
+ * any other state returns ALREADY_FINALIZED.
31
+ * - `status(roomId)` returns { capUsd, spentUsd, remainingUsd }
32
+ * computed from the committed + live-reserved ledger.
33
+ * - `sweepExpired(nowMs?)` is exposed for callers to drive
34
+ * periodically (the pod-tick mjs stub uses 5s sweep).
35
+ *
36
+ * State machine (per ADR-164.1 §3, §5.3):
37
+ * reserved -> committed
38
+ * reserved -> released
39
+ * reserved -> expired (sweepExpired, before any commit)
40
+ * reserved -> committed_post_expiry (commit lands after expires_at)
41
+ *
42
+ * Atomicity guarantees:
43
+ * - WAL (PRAGMA journal_mode = WAL) so reads don't block writes.
44
+ * - `busy_timeout = 500` so concurrent reserves get a brief retry
45
+ * window for SQLITE_BUSY instead of failing immediately.
46
+ * - All reserve/commit/release run inside a single `BEGIN IMMEDIATE`
47
+ * transaction so the lock acquisition + state mutation are atomic.
48
+ *
49
+ * Schema (per feature spec):
50
+ * rooms(id TEXT PRIMARY KEY, monthly_cap_usd REAL, spent_usd REAL,
51
+ * last_reset_at INTEGER)
52
+ * transactions(id INTEGER PRIMARY KEY, room_id TEXT, kind TEXT,
53
+ * amount_usd REAL, ts INTEGER, metadata TEXT)
54
+ *
55
+ * IDs:
56
+ * transaction id is string-shaped (`tx-<uuid>`) so the result type
57
+ * can carry it back through JSON. The `kind` column is one of
58
+ * 'reserved' | 'committed' | 'released' | 'expired' | 'committed_post_expiry'.
59
+ *
60
+ * Expiry window:
61
+ * - default 60_000 ms (overridable per `reserve()` call)
62
+ * - clamped to [5_000, 300_000] ms (ADR-164.1 §3.2)
63
+ * - overridable globally via BIZAR_COST_RESERVATION_EXPIRY_MS env var
64
+ */
65
+
66
+ import { randomUUID } from 'node:crypto';
67
+ import { mkdirSync } from 'node:fs';
68
+ import { dirname } from 'node:path';
69
+
70
+ // better-sqlite3's Database / Statement types are not currently exported by
71
+ // the @types/better-sqlite3 package, so we use a structural cast to keep
72
+ // both runtime behavior and declaration emit happy.
73
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ const Database = (await import('better-sqlite3')).default;
75
+
76
+ // ── Constants (kept in this module so the CLI doesn't depend on
77
+ // cli/memory-constants.mjs for the cost gate) ──────────────────────
78
+
79
+ export const RESERVATION_EXPIRY_FLOOR_MS = 5_000;
80
+ export const RESERVATION_EXPIRY_CEILING_MS = 300_000;
81
+ export const RESERVATION_EXPIRY_DEFAULT_MS = 60_000;
82
+
83
+ const TX_STATES = new Set([
84
+ 'reserved',
85
+ 'committed',
86
+ 'released',
87
+ 'expired',
88
+ 'committed_post_expiry',
89
+ ]);
90
+
91
+ export function clampReservationExpiry(raw) {
92
+ if (raw === undefined || raw === null || !Number.isFinite(Number(raw))) {
93
+ const envVal = Number(process.env.BIZAR_COST_RESERVATION_EXPIRY_MS);
94
+ if (Number.isFinite(envVal) && envVal > 0) {
95
+ return Math.max(
96
+ RESERVATION_EXPIRY_FLOOR_MS,
97
+ Math.min(RESERVATION_EXPIRY_CEILING_MS, envVal),
98
+ );
99
+ }
100
+ return RESERVATION_EXPIRY_DEFAULT_MS;
101
+ }
102
+ const n = Number(raw);
103
+ return Math.max(
104
+ RESERVATION_EXPIRY_FLOOR_MS,
105
+ Math.min(RESERVATION_EXPIRY_CEILING_MS, n),
106
+ );
107
+ }
108
+
109
+ const SCHEMA_SQL = `
110
+ PRAGMA journal_mode = WAL;
111
+ PRAGMA synchronous = NORMAL;
112
+ PRAGMA busy_timeout = 500;
113
+
114
+ CREATE TABLE IF NOT EXISTS rooms (
115
+ id TEXT NOT NULL PRIMARY KEY,
116
+ monthly_cap_usd REAL NOT NULL CHECK (monthly_cap_usd >= 0),
117
+ spent_usd REAL NOT NULL DEFAULT 0 CHECK (spent_usd >= 0),
118
+ last_reset_at INTEGER NOT NULL
119
+ );
120
+
121
+ CREATE TABLE IF NOT EXISTS transactions (
122
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
123
+ tx_id TEXT NOT NULL UNIQUE,
124
+ room_id TEXT NOT NULL REFERENCES rooms(id),
125
+ kind TEXT NOT NULL CHECK (kind IN ('reserved','committed','released','expired','committed_post_expiry')),
126
+ amount_usd REAL NOT NULL,
127
+ caller_id TEXT NOT NULL DEFAULT '',
128
+ ts INTEGER NOT NULL,
129
+ expires_at INTEGER,
130
+ committed_at INTEGER,
131
+ metadata TEXT NOT NULL DEFAULT '{}'
132
+ );
133
+
134
+ CREATE INDEX IF NOT EXISTS idx_tx_room_state_ts
135
+ ON transactions (room_id, kind, ts);
136
+ CREATE INDEX IF NOT EXISTS idx_tx_state_expires
137
+ ON transactions (kind, expires_at);
138
+ `;
139
+
140
+ // ── Result shapes ─────────────────────────────────────────────────────
141
+
142
+ /**
143
+ * @typedef {Object} ReserveResult
144
+ * @property {boolean} ok
145
+ * @property {string} [txId]
146
+ * @property {number} [expiresAt]
147
+ * @property {number} [remainingAfterReserve]
148
+ * @property {string} [error] 'BUDGET_EXCEEDED' | 'ROOM_NOT_FOUND'
149
+ */
150
+
151
+ /**
152
+ * @typedef {Object} CommitResult
153
+ * @property {boolean} ok
154
+ * @property {boolean} [committed]
155
+ * @property {string} [warned] 'COMMIT_AFTER_EXPIRY'
156
+ * @property {number} [finalRemaining]
157
+ * @property {string} [error] 'NOT_FOUND' | 'ALREADY_FINALIZED'
158
+ */
159
+
160
+ /**
161
+ * @typedef {Object} ReleaseResult
162
+ * @property {boolean} ok
163
+ * @property {boolean} [released]
164
+ * @property {string} [error] 'NOT_FOUND' | 'ALREADY_FINALIZED'
165
+ */
166
+
167
+ /**
168
+ * @typedef {Object} RoomStatus
169
+ * @property {string} roomId
170
+ * @property {number} capUsd
171
+ * @property {number} spentUsd
172
+ * @property {number} reservedUsd
173
+ * @property {number} remainingUsd
174
+ * @property {number} txCount
175
+ * @property {number} [lastResetAt]
176
+ */
177
+
178
+ // ── CostGate ──────────────────────────────────────────────────────────
179
+
180
+ export class CostGate {
181
+ /**
182
+ * @param {string|object} opts Either a path string or an
183
+ * `{dbPath, clock, logger}` options bag.
184
+ */
185
+ constructor(opts = {}) {
186
+ if (typeof opts === 'string') {
187
+ this.dbPath = opts;
188
+ this.clock = () => Date.now();
189
+ this.logger = null;
190
+ } else {
191
+ this.dbPath = opts.dbPath;
192
+ this.clock = opts.clock || (() => Date.now());
193
+ this.logger = opts.logger || null;
194
+ }
195
+ if (!this.dbPath) {
196
+ throw new Error('CostGate requires dbPath');
197
+ }
198
+ mkdirSync(dirname(this.dbPath), { recursive: true });
199
+ /** @type {import('better-sqlite3').Database} */
200
+ this.db = new Database(this.dbPath);
201
+ this.db.exec(SCHEMA_SQL);
202
+ // Lock down the mode after first PRAGMA above.
203
+ this.db.pragma('journal_mode = WAL');
204
+ this.db.pragma('synchronous = NORMAL');
205
+ this.db.pragma('busy_timeout = 500');
206
+
207
+ // Prepared statements — re-bind per call so better-sqlite3 doesn't
208
+ // trip on changing SQL text.
209
+ /** @type {{ [k: string]: import('better-sqlite3').Statement<any[], any> }} */
210
+ this._stmts = {
211
+ registerRoom: this.db.prepare(
212
+ `INSERT INTO rooms (id, monthly_cap_usd, spent_usd, last_reset_at)
213
+ VALUES (?, ?, 0, ?)
214
+ ON CONFLICT(id) DO UPDATE SET monthly_cap_usd = excluded.monthly_cap_usd`,
215
+ ),
216
+ getRoom: this.db.prepare(
217
+ `SELECT id, monthly_cap_usd, spent_usd, last_reset_at FROM rooms WHERE id = ?`,
218
+ ),
219
+ listRooms: this.db.prepare(
220
+ `SELECT id, monthly_cap_usd, spent_usd, last_reset_at FROM rooms ORDER BY id`,
221
+ ),
222
+ insertTx: this.db.prepare(
223
+ `INSERT INTO transactions
224
+ (tx_id, room_id, kind, amount_usd, caller_id, ts, expires_at, committed_at, metadata)
225
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
226
+ ),
227
+ getTx: this.db.prepare(
228
+ `SELECT tx_id, room_id, kind, amount_usd, caller_id, ts, expires_at, committed_at
229
+ FROM transactions WHERE tx_id = ?`,
230
+ ),
231
+ totalsThisCycle: this.db.prepare(
232
+ `SELECT
233
+ COALESCE(SUM(CASE WHEN kind IN ('committed','committed_post_expiry')
234
+ THEN amount_usd ELSE 0 END), 0) AS committed_total,
235
+ COALESCE(SUM(CASE WHEN kind = 'reserved'
236
+ AND (expires_at IS NULL OR expires_at > ?)
237
+ THEN amount_usd ELSE 0 END), 0) AS reserved_total
238
+ FROM transactions
239
+ WHERE room_id = ?`,
240
+ ),
241
+ setSpentUsd: this.db.prepare(
242
+ `UPDATE rooms SET spent_usd = ? WHERE id = ?`,
243
+ ),
244
+ flipTxState: this.db.prepare(
245
+ `UPDATE transactions SET kind = ?, committed_at = ? WHERE tx_id = ?`,
246
+ ),
247
+ sweepExpired: this.db.prepare(
248
+ `UPDATE transactions SET kind = 'expired'
249
+ WHERE kind = 'reserved' AND expires_at IS NOT NULL AND expires_at < ?`,
250
+ ),
251
+ listTxForRoom: this.db.prepare(
252
+ `SELECT tx_id, room_id, kind, amount_usd, caller_id, ts, expires_at, committed_at
253
+ FROM transactions WHERE room_id = ? ORDER BY ts`,
254
+ ),
255
+ txCountForRoom: this.db.prepare(
256
+ `SELECT COUNT(*) AS n FROM transactions WHERE room_id = ?`,
257
+ ),
258
+ };
259
+ }
260
+
261
+ close() {
262
+ try { this.db.close(); } catch (_e) { /* ignore double-close */ }
263
+ }
264
+
265
+ // ── Register ──────────────────────────────────────────────────────
266
+
267
+ registerRoom(roomId, capUsd) {
268
+ if (!roomId || typeof roomId !== 'string') {
269
+ throw new Error('roomId must be a non-empty string');
270
+ }
271
+ const cap = Number(capUsd);
272
+ if (!Number.isFinite(cap) || cap < 0) {
273
+ throw new Error('capUsd must be a non-negative finite number');
274
+ }
275
+ this._stmts.registerRoom.run(roomId, cap, this.clock());
276
+ return { ok: true, roomId, capUsd: cap };
277
+ }
278
+
279
+ // ── Reserve ───────────────────────────────────────────────────────
280
+ /**
281
+ * Atomically reserve budget inside a BEGIN IMMEDIATE transaction.
282
+ * @returns {ReserveResult}
283
+ */
284
+ reserve(roomId, callerId, estimatedUsd, opts = {}) {
285
+ if (!Number.isFinite(Number(estimatedUsd)) || Number(estimatedUsd) < 0) {
286
+ throw new Error('estimatedUsd must be a non-negative finite number');
287
+ }
288
+ const amount = Number(estimatedUsd);
289
+ const expiryMs = clampReservationExpiry(opts.expiryMs);
290
+ const metadata = opts.metadata ? JSON.stringify(opts.metadata) : '{}';
291
+
292
+ const nowMs = this.clock();
293
+ const txId = `tx-${randomUUID()}`;
294
+ const expiresAt = nowMs + expiryMs;
295
+
296
+ // better-sqlite3 auto-commits each .run(). For atomicity we use the
297
+ // `transaction()` builder, which produces a single function that
298
+ // wraps all the .run() / .get() calls inside BEGIN/COMMIT (and
299
+ // ROLLBACK on throw). ADR-164.1 §3.2 explicitly mandates
300
+ // BEGIN IMMEDIATE — better-sqlite3 always opens with
301
+ // BEGIN DEFERRED by default; we force it via `BEGIN IMMEDIATE` for
302
+ // the atomic reserve flow by writing the transaction() builder
303
+ // as a single BEGIN IMMEDIATE block.
304
+ const reserveTxn = this.db.transaction(() => {
305
+ const room = this._stmts.getRoom.get(roomId);
306
+ if (!room) {
307
+ return { ok: false, error: 'ROOM_NOT_FOUND' };
308
+ }
309
+ const capUsd = Number(room.monthly_cap_usd);
310
+ const totals = this._stmts.totalsThisCycle.get(nowMs, roomId);
311
+ const committed = Number(totals?.committed_total ?? 0);
312
+ const reserved = Number(totals?.reserved_total ?? 0);
313
+ const projected = committed + reserved + amount;
314
+ if (projected > capUsd + 1e-9) {
315
+ return {
316
+ ok: false,
317
+ error: 'BUDGET_EXCEEDED',
318
+ committed,
319
+ reserved,
320
+ capUsd,
321
+ };
322
+ }
323
+ this._stmts.insertTx.run(
324
+ txId,
325
+ roomId,
326
+ 'reserved',
327
+ amount,
328
+ callerId || '',
329
+ nowMs,
330
+ expiresAt,
331
+ null,
332
+ metadata,
333
+ );
334
+ return {
335
+ ok: true,
336
+ txId,
337
+ expiresAt,
338
+ remainingAfterReserve: capUsd - projected,
339
+ };
340
+ });
341
+ // Force BEGIN IMMEDIATE so we hold the write lock the entire
342
+ // time the cap check + insert runs (ADR-164.1 §3.2 + Bizar's
343
+ // "concurrent reserves must not double-spend" constraint).
344
+ reserveTxn.immediate;
345
+ const result = reserveTxn.immediate();
346
+ if (result.ok) {
347
+ if (this.logger) this.logger.info?.('cost.reserve', result);
348
+ }
349
+ return result;
350
+ }
351
+
352
+ // ── Commit ────────────────────────────────────────────────────────
353
+ /**
354
+ * Commit the reservation with the actual cost. Late commits are
355
+ * accepted (warn: 'COMMIT_AFTER_EXPIRY').
356
+ * @returns {CommitResult}
357
+ */
358
+ commit(txId, actualUsd) {
359
+ if (!Number.isFinite(Number(actualUsd)) || Number(actualUsd) < 0) {
360
+ throw new Error('actualUsd must be a non-negative finite number');
361
+ }
362
+ const amount = Number(actualUsd);
363
+ const nowMs = this.clock();
364
+
365
+ const updateAmountAndState = this.db.prepare(
366
+ `UPDATE transactions SET kind = ?, amount_usd = ?, committed_at = ? WHERE tx_id = ?`,
367
+ );
368
+
369
+ const commitTxn = this.db.transaction(() => {
370
+ const row = this._stmts.getTx.get(txId);
371
+ if (!row) return { ok: false, error: 'NOT_FOUND' };
372
+ if (row.kind === 'committed' || row.kind === 'committed_post_expiry' || row.kind === 'released') {
373
+ return { ok: false, error: 'ALREADY_FINALIZED' };
374
+ }
375
+
376
+ // Late commit? Even if the row's state is still 'reserved' (or
377
+ // 'expired' if a sweeper beat us to it), the expires_at may
378
+ // have already passed. ADR-164.1 §5.3 — accept the charge and
379
+ // warn.
380
+ const late = row.expires_at != null && row.expires_at <= nowMs;
381
+ const newKind = late ? 'committed_post_expiry' : 'committed';
382
+
383
+ // IMPORTANT: replace the estimated amount with the actual cost
384
+ // on commit. The reservation's amount_usd reflects the upper
385
+ // bound; the actual cost may be smaller (cheaper model) or,
386
+ // in late-commit cases, may approximate the work that already
387
+ // ran. After this UPDATE, the SUM(... committed/committed_post_expiry)
388
+ // returns the real spend.
389
+ updateAmountAndState.run(newKind, amount, nowMs, txId);
390
+
391
+ // Update room.spent_usd to reflect the (now corrected) actual
392
+ // totals — kept in sync for status()'s `spentUsd`.
393
+ const totals = this._stmts.totalsThisCycle.get(nowMs + 1, row.room_id);
394
+ const committedTotal = Number(totals?.committed_total ?? 0);
395
+ this._stmts.setSpentUsd.run(committedTotal, row.room_id);
396
+
397
+ const room = this._stmts.getRoom.get(row.room_id);
398
+ const cap = Number(room?.monthly_cap_usd ?? 0);
399
+ const finalRemaining = cap - (committedTotal + Number(totals?.reserved_total ?? 0));
400
+
401
+ if (late) {
402
+ return {
403
+ ok: true,
404
+ warned: 'COMMIT_AFTER_EXPIRY',
405
+ finalRemaining,
406
+ };
407
+ }
408
+ return { ok: true, committed: true, finalRemaining };
409
+ });
410
+ return commitTxn.immediate();
411
+ }
412
+
413
+ // ── Release ───────────────────────────────────────────────────────
414
+ /**
415
+ * @returns {ReleaseResult}
416
+ */
417
+ release(txId) {
418
+ const releaseTxn = this.db.transaction(() => {
419
+ const row = this._stmts.getTx.get(txId);
420
+ if (!row) return { ok: false, error: 'NOT_FOUND' };
421
+ if (row.kind !== 'reserved') {
422
+ return { ok: false, error: 'ALREADY_FINALIZED' };
423
+ }
424
+ this._stmts.flipTxState.run('released', this.clock(), txId);
425
+ return { ok: true, released: true };
426
+ });
427
+ return releaseTxn.immediate();
428
+ }
429
+
430
+ // ── Status ────────────────────────────────────────────────────────
431
+ /**
432
+ * @returns {RoomStatus | null}
433
+ */
434
+ status(roomId) {
435
+ const room = this._stmts.getRoom.get(roomId);
436
+ if (!room) return null;
437
+ const capUsd = Number(room.monthly_cap_usd);
438
+ const now = this.clock();
439
+ const totals = this._stmts.totalsThisCycle.get(now, roomId);
440
+ const committed = Number(totals?.committed_total ?? 0);
441
+ const reserved = Number(totals?.reserved_total ?? 0);
442
+ const count = this._stmts.txCountForRoom.get(roomId);
443
+ return {
444
+ roomId,
445
+ capUsd,
446
+ spentUsd: committed,
447
+ reservedUsd: reserved,
448
+ remainingUsd: capUsd - (committed + reserved),
449
+ txCount: Number(count?.n ?? 0),
450
+ lastResetAt: Number(room.last_reset_at),
451
+ };
452
+ }
453
+
454
+ listRooms() {
455
+ const rows = this._stmts.listRooms.all();
456
+ return rows.map((r) => {
457
+ const totals = this._stmts.totalsThisCycle.get(this.clock(), r.id);
458
+ const committed = Number(totals?.committed_total ?? 0);
459
+ const reserved = Number(totals?.reserved_total ?? 0);
460
+ const capUsd = Number(r.monthly_cap_usd);
461
+ return {
462
+ roomId: r.id,
463
+ capUsd,
464
+ spentUsd: committed,
465
+ reservedUsd: reserved,
466
+ remainingUsd: capUsd - (committed + reserved),
467
+ lastResetAt: Number(r.last_reset_at),
468
+ };
469
+ });
470
+ }
471
+
472
+ // ── Sweep ─────────────────────────────────────────────────────────
473
+ /**
474
+ * Sweep expired reservations to 'expired' state. Returns the number
475
+ * of rows updated. Driven by setInterval at the integration site.
476
+ */
477
+ sweepExpired(nowMs) {
478
+ const ts = nowMs == null ? this.clock() : Number(nowMs);
479
+ const result = this._stmts.sweepExpired.run(ts);
480
+ return Number(result.changes ?? 0);
481
+ }
482
+
483
+ // ── Test-only / introspection ────────────────────────────────────
484
+ /** Return raw transactions for a room. Used by tests + CLI status. */
485
+ listTransactions(roomId) {
486
+ return this._stmts.listTxForRoom.all(roomId);
487
+ }
488
+ }
489
+
490
+ // ── File-path helper (default location under .bizar/) ────────────────
491
+
492
+ import { homedir } from 'node:os';
493
+ import { join } from 'node:path';
494
+
495
+ /** Default DB path: $HOME/.bizar/cost-gate.db (or override via BIZAR_COST_GATE_DB). */
496
+ export function defaultDbPath() {
497
+ if (process.env.BIZAR_COST_GATE_DB && process.env.BIZAR_COST_GATE_DB.trim()) {
498
+ return process.env.BIZAR_COST_GATE_DB.trim();
499
+ }
500
+ return join(homedir(), '.bizar', 'cost-gate.db');
501
+ }
@@ -4,12 +4,12 @@
4
4
  * Tests for the `bizar dev-link` / `bizar dev-unlink` subcommands.
5
5
  * Uses Node's built-in node:test (no external test framework).
6
6
  *
7
- * Strategy: mock HOME (and XDG_CONFIG_HOME) so clineConfigDir() in
7
+ * Strategy: mock HOME (and XDG_CONFIG_HOME) so claudeConfigDir() in
8
8
  * cli/utils.mjs returns a path inside a tmpdir, and exercise the
9
9
  * create/remove symlink behavior against a controlled filesystem.
10
10
  *
11
11
  * Note: We mock HOME *before* importing dev-link.mjs because the module
12
- * imports clineConfigDir transitively from utils.mjs. The path is
12
+ * imports claudeConfigDir transitively from utils.mjs. The path is
13
13
  * resolved at call time, though, so the mock just needs to be in place
14
14
  * when the functions run.
15
15
  */
@@ -40,28 +40,28 @@ const ORIG_HOME = process.env.HOME;
40
40
  const ORIG_XDG = process.env.XDG_CONFIG_HOME;
41
41
 
42
42
  /**
43
- * Point HOME at a fresh tmpdir so the module's clineConfigDir()
44
- * resolves inside it (via the fallback `<HOME>/.cline`).
43
+ * Point HOME at a fresh tmpdir so the module's claudeConfigDir()
44
+ * resolves inside it (via the fallback `<HOME>/.claude`).
45
45
  * Returns the tmpdir path.
46
46
  *
47
47
  * Note: we deliberately do NOT set XDG_CONFIG_HOME here. The
48
- * clineConfigDir() helper treats a set XDG_CONFIG_HOME as the
49
- * direct parent (so `XDG_CONFIG_HOME=~/.config` → `~/.cline`,
48
+ * claudeConfigDir() helper treats a set XDG_CONFIG_HOME as the
49
+ * direct parent (so `XDG_CONFIG_HOME=~/.config` → `~/.claude`,
50
50
  * matching the standard layout). Setting it to a raw tmpdir would
51
- * produce `<tmpdir>/cline` instead of the expected
52
- * `<tmpdir>/.cline` and break path alignment with the test.
51
+ * produce `<tmpdir>/claude` instead of the expected
52
+ * `<tmpdir>/.claude` and break path alignment with the test.
53
53
  */
54
54
  function freshHome() {
55
55
  const home = mkdtempSync(join(tmpdir(), 'bizar-devlink-'));
56
56
  process.env.HOME = home;
57
- delete process.env.CLINE_DIR;
58
- delete process.env.BIZAR_LEGACY_CLINE_DIR;
57
+ delete process.env.CLAUDE_CONFIG_DIR;
58
+ delete process.env.BIZAR_LEGACY_CLAUDE_DIR;
59
59
  return home;
60
60
  }
61
61
 
62
62
  /** Path to the deployed plugin dir under the mocked HOME. */
63
63
  function pluginDest(home) {
64
- return join(home, '.cline', 'plugins', 'bizar');
64
+ return join(home, '.claude', 'plugins', 'bizar');
65
65
  }
66
66
 
67
67
  after(() => {