@polderlabs/bizar 3.23.0 → 4.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 (346) hide show
  1. package/README.md +72 -2
  2. package/bizar-dash/.bizar/activity.log +3 -0
  3. package/bizar-dash/.bizar/graph/.graphify_analysis.json +1540 -0
  4. package/bizar-dash/.bizar/graph/.graphify_labels.json +1 -0
  5. package/bizar-dash/.bizar/graph/GRAPH_REPORT.md +404 -0
  6. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/0661b816358db84dfdb7f10443db8a61152fd20b3fee950caf8fbf32920a1790.json +1 -0
  7. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/16da06d774142a6e5d74829ad982531286a6193ef798de8f593db029e123ec32.json +1 -0
  8. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/27e5697c01254c69c64c5a33896669073b40afb5ba88375102ae77fa5404136d.json +1 -0
  9. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/532997898027254aa4c0932243dc71d2f55888181232b65974961934997dc85b.json +1 -0
  10. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/84e3451a64c7f99f0cd6a88b0748d7426780486f53ab4935b7476b28c08f8293.json +1 -0
  11. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/88e5ea5f3e78fa69353fe9e6a8d1a05391d54605e25600cb125531eb5a6432ff.json +1 -0
  12. package/bizar-dash/.bizar/graph/cache/stat-index.json +1 -0
  13. package/bizar-dash/.bizar/graph/graph.html +307 -0
  14. package/bizar-dash/.bizar/graph/graph.json +40267 -0
  15. package/bizar-dash/.bizar/graph/manifest.json +762 -0
  16. package/bizar-dash/.graphifyignore +40 -0
  17. package/bizar-dash/.obsidian/README.md +14 -0
  18. package/bizar-dash/.obsidian/daily/2026-06-25.md +9 -0
  19. package/bizar-dash/.obsidian/vault.json +7 -0
  20. package/bizar-dash/.od-skills/web-prototype-e1429c1737/SKILL.md +103 -0
  21. package/bizar-dash/.od-skills/web-prototype-e1429c1737/assets/template.html +338 -0
  22. package/bizar-dash/.od-skills/web-prototype-e1429c1737/example.html +81 -0
  23. package/bizar-dash/.od-skills/web-prototype-e1429c1737/open-design.json +172 -0
  24. package/bizar-dash/.od-skills/web-prototype-e1429c1737/references/checklist.md +44 -0
  25. package/bizar-dash/.od-skills/web-prototype-e1429c1737/references/layouts.md +247 -0
  26. package/bizar-dash/CHANGELOG.md +474 -0
  27. package/bizar-dash/DESIGN.md +136 -0
  28. package/bizar-dash/dist/assets/main-B3RgW6FS.js +331 -0
  29. package/bizar-dash/dist/assets/main-B3RgW6FS.js.map +1 -0
  30. package/bizar-dash/dist/assets/main-DlJ8wgLR.css +1 -0
  31. package/bizar-dash/dist/assets/mobile-CsZQAswA.css +1 -0
  32. package/bizar-dash/dist/assets/mobile-DbxIw8BG.js +2 -0
  33. package/bizar-dash/dist/assets/mobile-DbxIw8BG.js.map +1 -0
  34. package/bizar-dash/dist/assets/mobile-Dvq2d53Y.js +354 -0
  35. package/bizar-dash/dist/assets/mobile-Dvq2d53Y.js.map +1 -0
  36. package/bizar-dash/dist/index.html +40 -0
  37. package/bizar-dash/dist/mobile.html +22 -0
  38. package/bizar-dash/plans/debug-plan/comments.json +1 -0
  39. package/bizar-dash/plans/debug-plan/meta.json +10 -0
  40. package/bizar-dash/plans/debug-plan/plan.json +174 -0
  41. package/bizar-dash/scripts/smoke-bg-retry.mjs +246 -0
  42. package/bizar-dash/src/cli/dashboard-ports.mjs +488 -0
  43. package/bizar-dash/src/cli.mjs +522 -0
  44. package/bizar-dash/src/server/activity-log.mjs +174 -0
  45. package/bizar-dash/src/server/agents-store.mjs +465 -0
  46. package/bizar-dash/src/server/api.mjs +138 -0
  47. package/bizar-dash/src/server/artifact-template.html +810 -0
  48. package/bizar-dash/src/server/artifacts-store.mjs +733 -0
  49. package/bizar-dash/src/server/auth.mjs +381 -0
  50. package/bizar-dash/src/server/background-store.mjs +447 -0
  51. package/bizar-dash/src/server/bg-poller.mjs +305 -0
  52. package/bizar-dash/src/server/bg-retry.mjs +574 -0
  53. package/bizar-dash/src/server/browser.mjs +40 -0
  54. package/bizar-dash/src/server/diagnostics-store.mjs +148 -0
  55. package/bizar-dash/src/server/dialog-poller.mjs +105 -0
  56. package/bizar-dash/src/server/dialog-store.mjs +177 -0
  57. package/bizar-dash/src/server/glyphs/mdx-compiler.mjs +583 -0
  58. package/bizar-dash/src/server/lib/path-safe.mjs +283 -0
  59. package/bizar-dash/src/server/memory-git.mjs +249 -0
  60. package/bizar-dash/src/server/memory-schema.mjs +145 -0
  61. package/bizar-dash/src/server/memory-secrets.mjs +84 -0
  62. package/bizar-dash/src/server/memory-store.mjs +424 -0
  63. package/bizar-dash/src/server/mod-security.mjs +398 -0
  64. package/bizar-dash/src/server/mods-loader.mjs +1067 -0
  65. package/bizar-dash/src/server/notifications-store.mjs +243 -0
  66. package/bizar-dash/src/server/obsidian-store.mjs +318 -0
  67. package/bizar-dash/src/server/opencode-runner.mjs +279 -0
  68. package/bizar-dash/src/server/pair-store.mjs +138 -0
  69. package/bizar-dash/src/server/projects-store.mjs +364 -0
  70. package/bizar-dash/src/server/providers-store.mjs +789 -0
  71. package/bizar-dash/src/server/routes/_shared.mjs +415 -0
  72. package/bizar-dash/src/server/routes/activity.mjs +110 -0
  73. package/bizar-dash/src/server/routes/agents.mjs +134 -0
  74. package/bizar-dash/src/server/routes/artifacts.mjs +279 -0
  75. package/bizar-dash/src/server/routes/auth.mjs +69 -0
  76. package/bizar-dash/src/server/routes/background.mjs +165 -0
  77. package/bizar-dash/src/server/routes/chat.mjs +485 -0
  78. package/bizar-dash/src/server/routes/config.mjs +129 -0
  79. package/bizar-dash/src/server/routes/diagnostics.mjs +50 -0
  80. package/bizar-dash/src/server/routes/dialogs.mjs +86 -0
  81. package/bizar-dash/src/server/routes/fs.mjs +429 -0
  82. package/bizar-dash/src/server/routes/history.mjs +78 -0
  83. package/bizar-dash/src/server/routes/memory.mjs +499 -0
  84. package/bizar-dash/src/server/routes/misc.mjs +89 -0
  85. package/bizar-dash/src/server/routes/mods.mjs +359 -0
  86. package/bizar-dash/src/server/routes/notifications.mjs +54 -0
  87. package/bizar-dash/src/server/routes/obsidian.mjs +239 -0
  88. package/bizar-dash/src/server/routes/opencode-sessions.mjs +55 -0
  89. package/bizar-dash/src/server/routes/overview.mjs +91 -0
  90. package/bizar-dash/src/server/routes/pair.mjs +67 -0
  91. package/bizar-dash/src/server/routes/projects.mjs +175 -0
  92. package/bizar-dash/src/server/routes/providers.mjs +47 -0
  93. package/bizar-dash/src/server/routes/schedules.mjs +104 -0
  94. package/bizar-dash/src/server/routes/settings.mjs +51 -0
  95. package/bizar-dash/src/server/routes/skills.mjs +76 -0
  96. package/bizar-dash/src/server/routes/tasks.mjs +468 -0
  97. package/bizar-dash/src/server/routes/themes.mjs +51 -0
  98. package/bizar-dash/src/server/routes-v2/auth.mjs +59 -0
  99. package/bizar-dash/src/server/routes-v2/events.mjs +107 -0
  100. package/bizar-dash/src/server/routes-v2/health.mjs +21 -0
  101. package/bizar-dash/src/server/routes-v2/index.mjs +90 -0
  102. package/bizar-dash/src/server/routes-v2/sessions.mjs +111 -0
  103. package/bizar-dash/src/server/schedules-runner.mjs +369 -0
  104. package/bizar-dash/src/server/schedules-store.mjs +268 -0
  105. package/bizar-dash/src/server/search-store.mjs +220 -0
  106. package/bizar-dash/src/server/serve-info.mjs +684 -0
  107. package/bizar-dash/src/server/server.mjs +796 -0
  108. package/bizar-dash/src/server/settings-store.mjs +45 -0
  109. package/bizar-dash/src/server/skills-store.mjs +300 -0
  110. package/bizar-dash/src/server/state.mjs +437 -0
  111. package/bizar-dash/src/server/tailscale-store.mjs +113 -0
  112. package/bizar-dash/src/server/task-delegator.mjs +824 -0
  113. package/bizar-dash/src/server/tasks-store.mjs +508 -0
  114. package/bizar-dash/src/server/tui.mjs +923 -0
  115. package/bizar-dash/src/server/update-store.mjs +168 -0
  116. package/bizar-dash/src/server/v2-auth-file.mjs +99 -0
  117. package/bizar-dash/src/server/v2-event-bus.mjs +128 -0
  118. package/bizar-dash/src/server/watcher.mjs +81 -0
  119. package/bizar-dash/src/server/yaml.mjs +238 -0
  120. package/bizar-dash/src/web/App.tsx +718 -0
  121. package/bizar-dash/src/web/MobileApp.tsx +408 -0
  122. package/bizar-dash/src/web/components/ArtifactCreateDialog.tsx +95 -0
  123. package/bizar-dash/src/web/components/ArtifactListDialog.tsx +55 -0
  124. package/bizar-dash/src/web/components/ArtifactViewer.tsx +143 -0
  125. package/bizar-dash/src/web/components/AuditDialog.tsx +79 -0
  126. package/bizar-dash/src/web/components/BgStatusBadge.tsx +32 -0
  127. package/bizar-dash/src/web/components/Button.tsx +56 -0
  128. package/bizar-dash/src/web/components/CanvasContextMenu.tsx +68 -0
  129. package/bizar-dash/src/web/components/Card.tsx +40 -0
  130. package/bizar-dash/src/web/components/CollapsibleSection.tsx +72 -0
  131. package/bizar-dash/src/web/components/CommandDialog.tsx +66 -0
  132. package/bizar-dash/src/web/components/EmptyState.tsx +30 -0
  133. package/bizar-dash/src/web/components/FileBrowser.tsx +633 -0
  134. package/bizar-dash/src/web/components/HelpDialog.tsx +55 -0
  135. package/bizar-dash/src/web/components/KillConfirmDialog.tsx +88 -0
  136. package/bizar-dash/src/web/components/Modal.tsx +215 -0
  137. package/bizar-dash/src/web/components/Notifications.tsx +241 -0
  138. package/bizar-dash/src/web/components/SearchModal.tsx +224 -0
  139. package/bizar-dash/src/web/components/Sidebar.tsx +66 -0
  140. package/bizar-dash/src/web/components/Spinner.tsx +19 -0
  141. package/bizar-dash/src/web/components/StatusBadge.tsx +25 -0
  142. package/bizar-dash/src/web/components/Tag.tsx +28 -0
  143. package/bizar-dash/src/web/components/Toast.tsx +150 -0
  144. package/bizar-dash/src/web/components/Topbar.tsx +368 -0
  145. package/bizar-dash/src/web/components/VisualPlanDialog.tsx +58 -0
  146. package/bizar-dash/src/web/components/chat/AgentChip.tsx +68 -0
  147. package/bizar-dash/src/web/components/chat/ChatBubble.tsx +60 -0
  148. package/bizar-dash/src/web/components/chat/ChatThread.tsx +88 -0
  149. package/bizar-dash/src/web/components/chat/ChatTopBar.tsx +50 -0
  150. package/bizar-dash/src/web/components/chat/Composer.tsx +164 -0
  151. package/bizar-dash/src/web/components/chat/ConfirmModal.tsx +54 -0
  152. package/bizar-dash/src/web/components/chat/EmptyState.tsx +21 -0
  153. package/bizar-dash/src/web/components/chat/FirstRunGreeting.tsx +18 -0
  154. package/bizar-dash/src/web/components/chat/FloatingComposer.tsx +32 -0
  155. package/bizar-dash/src/web/components/chat/InfoPanel.tsx +119 -0
  156. package/bizar-dash/src/web/components/chat/LoadingSkeleton.tsx +19 -0
  157. package/bizar-dash/src/web/components/chat/MessageBubble.tsx +60 -0
  158. package/bizar-dash/src/web/components/chat/SessionList.tsx +153 -0
  159. package/bizar-dash/src/web/components/chat/StreamingIndicator.tsx +9 -0
  160. package/bizar-dash/src/web/components/chat/SuggestionCards.tsx +55 -0
  161. package/bizar-dash/src/web/components/chat/WelcomeScreen.tsx +36 -0
  162. package/bizar-dash/src/web/components/chat/index.ts +20 -0
  163. package/bizar-dash/src/web/components/chat/useAutoGrowTextarea.ts +18 -0
  164. package/bizar-dash/src/web/components/chat/useChat.ts +219 -0
  165. package/bizar-dash/src/web/components/chat/useSlashCommands.ts +47 -0
  166. package/bizar-dash/src/web/index.html +37 -0
  167. package/bizar-dash/src/web/lib/api.ts +193 -0
  168. package/bizar-dash/src/web/lib/markdown.tsx +59 -0
  169. package/bizar-dash/src/web/lib/types.ts +668 -0
  170. package/bizar-dash/src/web/lib/utils.ts +114 -0
  171. package/bizar-dash/src/web/lib/ws.ts +176 -0
  172. package/bizar-dash/src/web/main.tsx +34 -0
  173. package/bizar-dash/src/web/mobile/MobileApp.tsx +278 -0
  174. package/bizar-dash/src/web/mobile/MobileBottomNav.tsx +38 -0
  175. package/bizar-dash/src/web/mobile/MobileTopbar.tsx +115 -0
  176. package/bizar-dash/src/web/mobile/components/MobileBottomSheet.tsx +182 -0
  177. package/bizar-dash/src/web/mobile/components/MobileListItem.tsx +64 -0
  178. package/bizar-dash/src/web/mobile/components/MobileModal.tsx +123 -0
  179. package/bizar-dash/src/web/mobile/views/MobileActivity.tsx +273 -0
  180. package/bizar-dash/src/web/mobile/views/MobileAgents.tsx +374 -0
  181. package/bizar-dash/src/web/mobile/views/MobileArtifactCanvas.tsx +439 -0
  182. package/bizar-dash/src/web/mobile/views/MobileArtifacts.tsx +143 -0
  183. package/bizar-dash/src/web/mobile/views/MobileChat.tsx +180 -0
  184. package/bizar-dash/src/web/mobile/views/MobileConfig.tsx +175 -0
  185. package/bizar-dash/src/web/mobile/views/MobileHistory.tsx +191 -0
  186. package/bizar-dash/src/web/mobile/views/MobileMods.tsx +149 -0
  187. package/bizar-dash/src/web/mobile/views/MobileMore.tsx +121 -0
  188. package/bizar-dash/src/web/mobile/views/MobileNotifications.tsx +137 -0
  189. package/bizar-dash/src/web/mobile/views/MobilePlans.tsx +26 -0
  190. package/bizar-dash/src/web/mobile/views/MobileSchedules.tsx +685 -0
  191. package/bizar-dash/src/web/mobile/views/MobileSearchModal.tsx +172 -0
  192. package/bizar-dash/src/web/mobile/views/MobileSettings.tsx +388 -0
  193. package/bizar-dash/src/web/mobile/views/MobileSkills.tsx +153 -0
  194. package/bizar-dash/src/web/mobile/views/MobileTasks.tsx +564 -0
  195. package/bizar-dash/src/web/mobile.html +20 -0
  196. package/bizar-dash/src/web/mobile.tsx +13 -0
  197. package/bizar-dash/src/web/styles/chat.css +198 -0
  198. package/bizar-dash/src/web/styles/glyphs.css +960 -0
  199. package/bizar-dash/src/web/styles/main.css +8855 -0
  200. package/bizar-dash/src/web/styles/mobile-chat.css +5 -0
  201. package/bizar-dash/src/web/styles/mobile.css +1960 -0
  202. package/bizar-dash/src/web/views/Activity.tsx +1203 -0
  203. package/bizar-dash/src/web/views/Agents.tsx +701 -0
  204. package/bizar-dash/src/web/views/Artifacts.tsx +1480 -0
  205. package/bizar-dash/src/web/views/BackgroundAgents.tsx +450 -0
  206. package/bizar-dash/src/web/views/Chat.tsx +190 -0
  207. package/bizar-dash/src/web/views/Config.tsx +1603 -0
  208. package/bizar-dash/src/web/views/History.tsx +335 -0
  209. package/bizar-dash/src/web/views/ModView.tsx +207 -0
  210. package/bizar-dash/src/web/views/Mods.tsx +693 -0
  211. package/bizar-dash/src/web/views/Overview.tsx +812 -0
  212. package/bizar-dash/src/web/views/Providers.tsx +302 -0
  213. package/bizar-dash/src/web/views/Schedules.tsx +802 -0
  214. package/bizar-dash/src/web/views/Settings.tsx +1787 -0
  215. package/bizar-dash/src/web/views/Skills.tsx +431 -0
  216. package/bizar-dash/src/web/views/Tasks.tsx +1523 -0
  217. package/bizar-dash/src/web/views/glyphs/GlyphRenderer.tsx +613 -0
  218. package/bizar-dash/src/web/views/glyphs/components.tsx +1098 -0
  219. package/bizar-dash/templates/mod/FORMAT.md +76 -0
  220. package/bizar-dash/templates/mod/hello-mod/README.md +19 -0
  221. package/bizar-dash/templates/mod/hello-mod/agents/greeter.md +8 -0
  222. package/bizar-dash/templates/mod/hello-mod/commands/hello.md +6 -0
  223. package/bizar-dash/templates/mod/hello-mod/mod.json +20 -0
  224. package/bizar-dash/templates/mod/hello-mod/routes/ping.mjs +9 -0
  225. package/bizar-dash/templates/mod/hello-mod/views/HelloView.tsx +10 -0
  226. package/bizar-dash/tests/dashboard-ports.test.mjs +138 -0
  227. package/bizar-dash/tests/graphify-mod-spawn.node.test.mjs +90 -0
  228. package/bizar-dash/tests/memory-git.test.mjs +138 -0
  229. package/bizar-dash/tests/memory-schema.test.mjs +198 -0
  230. package/bizar-dash/tests/memory-secrets.test.mjs +121 -0
  231. package/bizar-dash/tests/memory-store.test.mjs +390 -0
  232. package/bizar-dash/tests/memory-sync.test.mjs +141 -0
  233. package/bizar-dash/tests/mod-instructions.node.test.mjs +188 -0
  234. package/bizar-dash/tests/mod-security.test.mjs +273 -0
  235. package/bizar-dash/tests/mod-upgrade.node.test.mjs +357 -0
  236. package/bizar-dash/tests/no-agent-browser.node.test.mjs +98 -0
  237. package/bizar-dash/tests/obsidian-back-compat.test.mjs +199 -0
  238. package/bizar-dash/tests/opencode-runner.test.mjs +172 -0
  239. package/bizar-dash/tests/path-safe.test.mjs +108 -0
  240. package/bizar-dash/tests/providers-store-backup-keys.node.test.mjs +333 -0
  241. package/bizar-dash/tests/smoke-v2.mjs +212 -0
  242. package/bizar-dash/tests/strip-thinking.test.mjs +175 -0
  243. package/bizar-dash/tests/submit-feedback.test.mjs +353 -0
  244. package/bizar-dash/tests/tmux-wrap.test.mjs +145 -0
  245. package/bizar-dash/tests/yaml.test.mjs +128 -0
  246. package/bizar-dash/tsconfig.json +23 -0
  247. package/bizar-dash/vite.config.ts +27 -0
  248. package/cli/atomic.mjs +73 -0
  249. package/cli/bin.mjs +43 -46
  250. package/cli/copy.mjs +3 -0
  251. package/cli/dev-link.mjs +17 -1
  252. package/cli/init.mjs +135 -1
  253. package/cli/install.mjs +10 -23
  254. package/cli/memory-constants.mjs +59 -0
  255. package/cli/memory.mjs +757 -0
  256. package/cli/service.mjs +5 -6
  257. package/config/skills/obsidian/SKILL.md +213 -65
  258. package/install.sh +48 -18
  259. package/package.json +49 -14
  260. package/packages/sdk/LICENSE +21 -0
  261. package/packages/sdk/README.md +80 -0
  262. package/packages/sdk/src/client.ts +183 -0
  263. package/packages/sdk/src/errors.ts +120 -0
  264. package/packages/sdk/src/events.ts +153 -0
  265. package/packages/sdk/src/index.ts +63 -0
  266. package/packages/sdk/src/types.ts +176 -0
  267. package/packages/sdk/src/version.ts +4 -0
  268. package/packages/sdk/tests/client.test.ts +217 -0
  269. package/packages/sdk/tests/errors.test.ts +108 -0
  270. package/packages/sdk/tests/events.test.ts +139 -0
  271. package/packages/sdk/tests/fixtures/fetch-mock.ts +152 -0
  272. package/packages/sdk/tests/fixtures/sse-mock.ts +30 -0
  273. package/packages/sdk/tsconfig.json +25 -0
  274. package/packages/sdk/vitest.config.ts +9 -0
  275. package/plugins/bizar/LICENSE +21 -0
  276. package/plugins/bizar/README.md +448 -0
  277. package/plugins/bizar/dist/index.js +29901 -0
  278. package/plugins/bizar/index.ts +1484 -0
  279. package/plugins/bizar/scripts/check-forbidden-imports.sh +33 -0
  280. package/plugins/bizar/src/background-state.ts +551 -0
  281. package/plugins/bizar/src/background.ts +1250 -0
  282. package/plugins/bizar/src/commands-impl.ts +464 -0
  283. package/plugins/bizar/src/commands.ts +1127 -0
  284. package/plugins/bizar/src/dashboard-client.ts +233 -0
  285. package/plugins/bizar/src/event-stream.ts +606 -0
  286. package/plugins/bizar/src/fingerprint.ts +120 -0
  287. package/plugins/bizar/src/handoff.ts +79 -0
  288. package/plugins/bizar/src/http-client.ts +467 -0
  289. package/plugins/bizar/src/key-rotation.ts +218 -0
  290. package/plugins/bizar/src/logger.ts +144 -0
  291. package/plugins/bizar/src/loop.ts +176 -0
  292. package/plugins/bizar/src/opencode-runner.ts +390 -0
  293. package/plugins/bizar/src/options.ts +421 -0
  294. package/plugins/bizar/src/plan-fs.ts +323 -0
  295. package/plugins/bizar/src/reasoning-clean.ts +454 -0
  296. package/plugins/bizar/src/report.ts +178 -0
  297. package/plugins/bizar/src/research-prompt.ts +35 -0
  298. package/plugins/bizar/src/serve-info.ts +228 -0
  299. package/plugins/bizar/src/serve.ts +496 -0
  300. package/plugins/bizar/src/settings.ts +349 -0
  301. package/plugins/bizar/src/state.ts +298 -0
  302. package/plugins/bizar/src/tools/bg-collect.ts +104 -0
  303. package/plugins/bizar/src/tools/bg-get-comments.ts +239 -0
  304. package/plugins/bizar/src/tools/bg-kill.ts +87 -0
  305. package/plugins/bizar/src/tools/bg-spawn.ts +401 -0
  306. package/plugins/bizar/src/tools/bg-status.ts +99 -0
  307. package/plugins/bizar/src/tools/plan-action.ts +767 -0
  308. package/plugins/bizar/src/tools/read-glyph-feedback.ts +170 -0
  309. package/plugins/bizar/src/tools/wait-for-feedback.ts +402 -0
  310. package/plugins/bizar/tests/attach-handler-bug.test.ts +169 -0
  311. package/plugins/bizar/tests/background-state.test.ts +277 -0
  312. package/plugins/bizar/tests/background.test.ts +402 -0
  313. package/plugins/bizar/tests/block.test.ts +195 -0
  314. package/plugins/bizar/tests/canonical-key-order.test.ts +75 -0
  315. package/plugins/bizar/tests/commands-impl.test.ts +442 -0
  316. package/plugins/bizar/tests/commands.test.ts +548 -0
  317. package/plugins/bizar/tests/config.test.ts +122 -0
  318. package/plugins/bizar/tests/dashboard-client.test.ts +159 -0
  319. package/plugins/bizar/tests/dispose.test.ts +336 -0
  320. package/plugins/bizar/tests/event-stream.test.ts +409 -0
  321. package/plugins/bizar/tests/event.test.ts +262 -0
  322. package/plugins/bizar/tests/fingerprint.test.ts +162 -0
  323. package/plugins/bizar/tests/http-client.test.ts +404 -0
  324. package/plugins/bizar/tests/init-helpers.test.ts +203 -0
  325. package/plugins/bizar/tests/integration/slash-command.test.ts +348 -0
  326. package/plugins/bizar/tests/integration/tool-routing.test.ts +314 -0
  327. package/plugins/bizar/tests/key-rotation.test.ts +396 -0
  328. package/plugins/bizar/tests/loop.test.ts +397 -0
  329. package/plugins/bizar/tests/options.test.ts +276 -0
  330. package/plugins/bizar/tests/reasoning-clean.test.ts +422 -0
  331. package/plugins/bizar/tests/serve.test.ts +339 -0
  332. package/plugins/bizar/tests/settings.test.ts +351 -0
  333. package/plugins/bizar/tests/stall-think.test.ts +750 -0
  334. package/plugins/bizar/tests/state.test.ts +276 -0
  335. package/plugins/bizar/tests/tools/bg-collect.test.ts +337 -0
  336. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +485 -0
  337. package/plugins/bizar/tests/tools/bg-kill.test.ts +235 -0
  338. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +147 -0
  339. package/plugins/bizar/tests/tools/bg-spawn.test.ts +311 -0
  340. package/plugins/bizar/tests/tools/bg-status.test.ts +217 -0
  341. package/plugins/bizar/tests/tools/opencode-runner.test.ts +115 -0
  342. package/plugins/bizar/tests/tools/plan-action.test.ts +599 -0
  343. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +253 -0
  344. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +390 -0
  345. package/plugins/bizar/tests/update-deadlock.test.ts +145 -0
  346. package/plugins/bizar/tsconfig.json +29 -0
@@ -0,0 +1,168 @@
1
+ /**
2
+ * src/server/update-store.mjs
3
+ *
4
+ * v3.5.3 — Read installed package versions, check npm for latest,
5
+ * and apply updates for the three core bizarre packages.
6
+ */
7
+ import { execSync, spawn } from 'node:child_process';
8
+ import { createRequire } from 'node:module';
9
+
10
+ const require = createRequire(import.meta.url);
11
+
12
+ const PACKAGES = [
13
+ { id: 'bizar', name: '@polderlabs/bizar' },
14
+ { id: 'bizar-dash', name: '@polderlabs/bizar-dash' },
15
+ { id: 'bizar-plugin', name: '@polderlabs/bizar-plugin' },
16
+ ];
17
+
18
+ export const updateStore = {
19
+ /**
20
+ * Get currently installed versions (read from each package's package.json).
21
+ * Returns null for any package that's not installed locally.
22
+ */
23
+ current() {
24
+ const out = {};
25
+ for (const p of PACKAGES) {
26
+ try {
27
+ out[p.id] = require(`${p.name}/package.json`).version;
28
+ } catch {
29
+ out[p.id] = null;
30
+ }
31
+ }
32
+ return out;
33
+ },
34
+
35
+ /**
36
+ * Check npm registry for latest published versions.
37
+ * Uses `npm view <pkg> version` — works without auth.
38
+ * Returns null for any package that errors (e.g., offline).
39
+ */
40
+ async latest() {
41
+ const out = {};
42
+ for (const p of PACKAGES) {
43
+ try {
44
+ const ver = execSync(`npm view ${p.name} version`, {
45
+ encoding: 'utf8',
46
+ timeout: 15000,
47
+ }).trim();
48
+ out[p.id] = ver;
49
+ } catch {
50
+ out[p.id] = null;
51
+ }
52
+ }
53
+ return out;
54
+ },
55
+
56
+ /**
57
+ * Determine if updates are available.
58
+ */
59
+ hasUpdates(current, latest) {
60
+ if (!current || !latest) return false;
61
+ return PACKAGES.some((p) => {
62
+ if (!current[p.id] || !latest[p.id]) return false;
63
+ return latest[p.id] !== current[p.id];
64
+ });
65
+ },
66
+
67
+ /**
68
+ * Run the update. Installs the specified packages at @latest.
69
+ * Streams progress via the broadcast callback.
70
+ */
71
+ async apply({ packages, broadcast }) {
72
+ const targets = PACKAGES.filter((p) => packages.includes(p.id));
73
+ const results = {};
74
+
75
+ for (const p of targets) {
76
+ broadcast?.({ type: 'update:progress', pkg: p.id, status: 'installing' });
77
+ try {
78
+ const output = execSync(
79
+ `npm install -g ${p.name}@latest --ignore-scripts`,
80
+ {
81
+ encoding: 'utf8',
82
+ timeout: 180000,
83
+ },
84
+ );
85
+ results[p.id] = { ok: true, output: output.slice(-500) };
86
+ broadcast?.({ type: 'update:progress', pkg: p.id, status: 'done' });
87
+ } catch (err) {
88
+ results[p.id] = { ok: false, error: err.message };
89
+ broadcast?.({ type: 'update:progress', pkg: p.id, status: 'error', error: err.message });
90
+ }
91
+ }
92
+
93
+ return results;
94
+ },
95
+
96
+ /**
97
+ * Apply updates for specified packages with live progress via broadcast.
98
+ * Streams events:
99
+ * { type: 'update:progress', pkg, status: 'starting' }
100
+ * { type: 'update:progress', pkg, status: 'installing' }
101
+ * { type: 'update:progress', pkg, status: 'done', newVersion }
102
+ * { type: 'update:progress', pkg, status: 'error', error }
103
+ * { type: 'update:complete', results, requiresRestart: true }
104
+ */
105
+ async applyWithProgress({ packages, broadcast }) {
106
+ const results = {};
107
+ let allOk = true;
108
+
109
+ for (const pkg of packages) {
110
+ const pkgDef = PACKAGES.find((p) => p.id === pkg);
111
+ if (!pkgDef) continue;
112
+
113
+ broadcast?.({ type: 'update:progress', pkg, status: 'starting' });
114
+
115
+ try {
116
+ broadcast?.({ type: 'update:progress', pkg, status: 'installing' });
117
+
118
+ // Use spawn so we can stream stdout/stderr
119
+ const child = spawn('npm', ['install', '-g', `${pkgDef.name}@latest`, '--ignore-scripts'], {
120
+ stdio: ['ignore', 'pipe', 'pipe'],
121
+ });
122
+
123
+ // Stream stdout/stderr to broadcast for live log display
124
+ child.stdout.on('data', (data) => {
125
+ const line = data.toString().trim();
126
+ if (line) broadcast?.({ type: 'update:log', pkg, line });
127
+ });
128
+ child.stderr.on('data', (data) => {
129
+ const line = data.toString().trim();
130
+ if (line) broadcast?.({ type: 'update:log', pkg, line });
131
+ });
132
+
133
+ const exitCode = await new Promise((resolve) => {
134
+ child.on('close', resolve);
135
+ });
136
+
137
+ if (exitCode !== 0) {
138
+ allOk = false;
139
+ results[pkg] = { ok: false, error: `npm exited with code ${exitCode}` };
140
+ broadcast?.({ type: 'update:progress', pkg, status: 'error', error: `exit ${exitCode}` });
141
+ continue;
142
+ }
143
+
144
+ // Get the new version
145
+ const newVersion = this.getInstalledVersion(pkg);
146
+ results[pkg] = { ok: true, newVersion };
147
+ broadcast?.({ type: 'update:progress', pkg, status: 'done', newVersion });
148
+ } catch (err) {
149
+ allOk = false;
150
+ results[pkg] = { ok: false, error: err.message };
151
+ broadcast?.({ type: 'update:progress', pkg, status: 'error', error: err.message });
152
+ }
153
+ }
154
+
155
+ broadcast?.({ type: 'update:complete', results, requiresRestart: true, allOk });
156
+ return { results, requiresRestart: true };
157
+ },
158
+
159
+ getInstalledVersion(pkgId) {
160
+ const pkgDef = PACKAGES.find((p) => p.id === pkgId);
161
+ if (!pkgDef) return null;
162
+ try {
163
+ return require(`${pkgDef.name}/package.json`).version;
164
+ } catch {
165
+ return null;
166
+ }
167
+ },
168
+ };
@@ -0,0 +1,99 @@
1
+ /**
2
+ * src/server/v2-auth-file.mjs
3
+ *
4
+ * v0.7.0-alpha.1 — Manages the dashboard's persistent password file.
5
+ *
6
+ * On first start: generate a 32-byte random password (base64), write to
7
+ * `~/.cache/bizarharness/dash-auth.json` with mode 0600.
8
+ *
9
+ * On subsequent starts: read the existing file and reuse the password.
10
+ *
11
+ * The plugin reads this same file to authenticate (or accepts
12
+ * `BIZAR_DASHBOARD_PASSWORD` env var override).
13
+ *
14
+ * Discovery paths (mirrors serve-info.mjs pattern):
15
+ * - ~/.cache/bizarharness/dash-auth.json (default)
16
+ * - ~/.cache/bizar/dash-auth.json (legacy, fallback)
17
+ */
18
+
19
+ import { randomBytes } from 'node:crypto';
20
+ import { writeFileSync, readFileSync, existsSync, mkdirSync, chmodSync, renameSync } from 'node:fs';
21
+ import { dirname, join } from 'node:path';
22
+ import { homedir } from 'node:os';
23
+
24
+ const HOME = homedir();
25
+ const DEFAULT_DIR = join(HOME, '.cache', 'bizarharness');
26
+ const DEFAULT_FILE = join(DEFAULT_DIR, 'dash-auth.json');
27
+ const LEGACY_FILE = join(HOME, '.cache', 'bizar', 'dash-auth.json');
28
+
29
+ export const V2_DEFAULT_PORT = 4098;
30
+
31
+ /**
32
+ * Load or create the dashboard auth record.
33
+ *
34
+ * @param {object} opts
35
+ * @param {string} [opts.file=DEFAULT_FILE] - explicit path
36
+ * @param {number} [opts.port=V2_DEFAULT_PORT] - port to record in auth file
37
+ * @returns {{ password: string, port: number, baseUrl: string, file: string, createdAt: number }}
38
+ */
39
+ export function loadOrCreateAuth({ file = DEFAULT_FILE, port = V2_DEFAULT_PORT } = {}) {
40
+ // Prefer legacy file if it exists and default doesn't (migration).
41
+ const candidates = [file, LEGACY_FILE];
42
+ for (const candidate of candidates) {
43
+ if (existsSync(candidate)) {
44
+ try {
45
+ const raw = readFileSync(candidate, 'utf8');
46
+ const parsed = JSON.parse(raw);
47
+ if (typeof parsed.password === 'string' && parsed.password.length >= 16) {
48
+ // Reuse the persisted PASSWORD (idempotent auth), but always
49
+ // use the CURRENT port — the persisted port may be wrong
50
+ // (from an earlier bug or a different listen port).
51
+ const result = {
52
+ password: parsed.password,
53
+ port,
54
+ baseUrl: `http://127.0.0.1:${port}`,
55
+ file: candidate,
56
+ createdAt: typeof parsed.createdAt === 'number' ? parsed.createdAt : 0,
57
+ };
58
+ // Re-write the file to update the port (atomic). The persisted
59
+ // password and createdAt are preserved.
60
+ if (typeof parsed.port !== 'number' || parsed.port !== port) {
61
+ try {
62
+ writeAuthFile(candidate, result);
63
+ } catch {
64
+ // non-fatal — return the in-memory record even if rewrite fails
65
+ }
66
+ }
67
+ return result;
68
+ }
69
+ } catch {
70
+ // fall through to regeneration
71
+ }
72
+ }
73
+ }
74
+
75
+ // Generate a new password.
76
+ const password = randomBytes(24).toString('base64');
77
+ const createdAt = Date.now();
78
+ const record = { password, port, baseUrl: `http://127.0.0.1:${port}`, createdAt };
79
+
80
+ writeAuthFile(file, record);
81
+
82
+ return { ...record, file };
83
+ }
84
+
85
+ /**
86
+ * Atomically write the auth file with mode 0600.
87
+ */
88
+ function writeAuthFile(file, record) {
89
+ mkdirSync(dirname(file), { recursive: true });
90
+ const tmpFile = `${file}.tmp`;
91
+ writeFileSync(tmpFile, JSON.stringify(record, null, 2), { mode: 0o600 });
92
+ chmodSync(tmpFile, 0o600);
93
+ renameSync(tmpFile, file);
94
+ try {
95
+ chmodSync(file, 0o600);
96
+ } catch {
97
+ // non-fatal
98
+ }
99
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * src/server/v2-event-bus.mjs
3
+ *
4
+ * v0.7.0-alpha.1 — In-memory event bus for the v2 SSE protocol.
5
+ *
6
+ * Buffers the last N events for late subscribers (replay via `?since=`).
7
+ * New subscribers get the buffer + live events.
8
+ *
9
+ * Replaces the file-based serve.json bridge for plugin→dashboard
10
+ * communication (the file bridge remains as fallback for v1 consumers).
11
+ */
12
+
13
+ import { EventEmitter } from 'node:events';
14
+
15
+ const BUFFER_LIMIT = 100;
16
+
17
+ export class V2EventBus {
18
+ constructor({ bufferLimit = BUFFER_LIMIT, logger = console } = {}) {
19
+ this.bufferLimit = bufferLimit;
20
+ this.logger = logger;
21
+ this.emitter = new EventEmitter();
22
+ this.emitter.setMaxListeners(0); // unlimited subscribers
23
+ this.buffer = []; // [{ seq, type, properties, publishedAt }]
24
+ this.seq = 0;
25
+ }
26
+
27
+ /**
28
+ * Publish an event. Returns the assigned sequence number.
29
+ *
30
+ * @param {{ type: string, properties: object }} event
31
+ * @returns {number} sequence number
32
+ */
33
+ publish(event) {
34
+ if (!event || typeof event !== 'object' || typeof event.type !== 'string') {
35
+ throw new TypeError('V2EventBus.publish: event must have a string `type` field');
36
+ }
37
+ this.seq += 1;
38
+ const record = {
39
+ seq: this.seq,
40
+ type: event.type,
41
+ properties: event.properties ?? {},
42
+ publishedAt: Date.now(),
43
+ };
44
+ this.buffer.push(record);
45
+ if (this.buffer.length > this.bufferLimit) {
46
+ this.buffer.shift();
47
+ }
48
+ this.emitter.emit('event', record);
49
+ return record.seq;
50
+ }
51
+
52
+ /**
53
+ * Subscribe to live events.
54
+ *
55
+ * @param {object} opts
56
+ * @param {number} [opts.since] - replay events with seq > since (from buffer)
57
+ * @param {AbortSignal} [opts.signal] - abort signal to close subscription
58
+ * @returns {{ events: AsyncIterable, close: () => void }}
59
+ */
60
+ subscribe({ since, signal } = {}) {
61
+ const replay = typeof since === 'number'
62
+ ? this.buffer.filter((r) => r.seq > since)
63
+ : [];
64
+ const queue = [...replay];
65
+ const liveListeners = [];
66
+ let closed = false;
67
+
68
+ const onAbort = () => close();
69
+ if (signal) {
70
+ if (signal.aborted) {
71
+ // already aborted
72
+ return { events: emptyAsyncIterable(), close: () => {} };
73
+ }
74
+ signal.addEventListener('abort', onAbort, { once: true });
75
+ }
76
+
77
+ const onEvent = (record) => {
78
+ if (!closed) queue.push(record);
79
+ };
80
+ this.emitter.on('event', onEvent);
81
+ liveListeners.push(() => this.emitter.off('event', onEvent));
82
+
83
+ const close = () => {
84
+ if (closed) return;
85
+ closed = true;
86
+ for (const off of liveListeners) off();
87
+ if (signal) signal.removeEventListener('abort', onAbort);
88
+ };
89
+
90
+ return {
91
+ events: drainQueue(queue, close),
92
+ close,
93
+ };
94
+ }
95
+
96
+ /** Total events published since bus start. */
97
+ size() {
98
+ return this.seq;
99
+ }
100
+
101
+ /** Number of buffered events currently held for replay. */
102
+ bufferSize() {
103
+ return this.buffer.length;
104
+ }
105
+ }
106
+
107
+ async function* drainQueue(queue, onEnd) {
108
+ try {
109
+ while (queue.length > 0) {
110
+ yield queue.shift();
111
+ }
112
+ // After replay, switch to live: block until queue has items or close()
113
+ while (true) {
114
+ if (queue.length > 0) {
115
+ yield queue.shift();
116
+ continue;
117
+ }
118
+ // wait briefly then check again
119
+ await new Promise((resolve) => setTimeout(resolve, 50));
120
+ }
121
+ } finally {
122
+ if (onEnd) onEnd();
123
+ }
124
+ }
125
+
126
+ async function* emptyAsyncIterable() {
127
+ // no-op
128
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * cli/dashboard/watcher.mjs
3
+ *
4
+ * chokidar-backed file watcher. Translates low-level fs events into the
5
+ * shape the dashboard's WebSocket layer expects.
6
+ *
7
+ * The watcher ignores initial add events (the UI doesn't need a "you just
8
+ * started, here are 200 files that already existed" flood on connect).
9
+ */
10
+ import chokidar from 'chokidar';
11
+
12
+ /**
13
+ * @param {object} opts
14
+ * @param {string[]} opts.paths - files or directories to watch
15
+ * @param {(event: 'add'|'change'|'unlink', path: string) => void} opts.onChange
16
+ * @param {object} [opts.options] - extra chokidar options
17
+ */
18
+ export function createWatcher({ paths, onChange, options = {} }) {
19
+ if (!Array.isArray(paths) || paths.length === 0) {
20
+ throw new Error('createWatcher requires a non-empty paths array');
21
+ }
22
+ if (typeof onChange !== 'function') {
23
+ throw new Error('createWatcher requires an onChange callback');
24
+ }
25
+
26
+ const watcher = chokidar.watch(paths, {
27
+ ignoreInitial: true,
28
+ persistent: true,
29
+ awaitWriteFinish: { stabilityThreshold: 100, pollInterval: 50 },
30
+ // Ignore: any path segment named `node_modules` (anywhere), and any
31
+ // file/dir whose IMMEDIATE basename starts with `.` (covers .DS_Store,
32
+ // .swp, .bak, etc.). We must NOT walk the whole path — the watched
33
+ // root `~/.config/opencode/agents` contains the segment `.config`
34
+ // which would otherwise match and silently disable the watch.
35
+ ignored: (p) => {
36
+ const s = String(p);
37
+ const parts = s.split(/[\\/]/);
38
+ // Walk all segments — `node_modules` is fine to match anywhere.
39
+ if (parts.includes('node_modules')) return true;
40
+ // Last segment is the basename — check that ONLY, so `.config`
41
+ // in parent dirs doesn't disqualify the watched root.
42
+ const basename = parts[parts.length - 1] || '';
43
+ return basename.startsWith('.');
44
+ },
45
+ ...options,
46
+ });
47
+
48
+ const safe = (event, p) => {
49
+ try {
50
+ onChange(event, p);
51
+ } catch (err) {
52
+ // A faulty onChange must not crash the watcher
53
+ console.error('[dashboard watcher] onChange error:', err);
54
+ }
55
+ };
56
+
57
+ watcher.on('add', (p) => safe('add', p));
58
+ watcher.on('change', (p) => safe('change', p));
59
+ watcher.on('unlink', (p) => safe('unlink', p));
60
+ watcher.on('error', (err) => {
61
+ console.error('[dashboard watcher] chokidar error:', err);
62
+ });
63
+
64
+ return {
65
+ /** @returns {chokidar.FSWatcher} */
66
+ start() {
67
+ return watcher;
68
+ },
69
+ async stop() {
70
+ try {
71
+ await watcher.close();
72
+ } catch {
73
+ /* ignore */
74
+ }
75
+ },
76
+ /** Force a synthetic broadcast — useful after a self-mutation. */
77
+ poke(event = 'change', path = '<synthetic>') {
78
+ safe(event, path);
79
+ },
80
+ };
81
+ }