@polderlabs/bizar 3.23.1 → 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,279 @@
1
+ /**
2
+ * bizar-dash/src/server/opencode-runner.mjs
3
+ *
4
+ * v3.11.1 — Node child_process version of the opencode-runner.
5
+ *
6
+ * The plugin uses Bun.spawn (see plugins/bizar/src/opencode-runner.ts);
7
+ * the dashboard runs under Node and uses child_process.spawn. This
8
+ * module keeps the two implementations in sync — same surface, same
9
+ * log-format parsing, same exit semantics.
10
+ *
11
+ * See plugins/bizar/src/opencode-runner.ts for the design rationale
12
+ * and the structured-log wire format we parse.
13
+ */
14
+ import { spawn } from 'node:child_process';
15
+ import { createWriteStream, mkdirSync, existsSync } from 'node:fs';
16
+ import { dirname } from 'node:path';
17
+
18
+ /**
19
+ * @typedef {'starting'|'running'|'done'|'failed'|'killed'} AgentState
20
+ *
21
+ * @typedef {Object} AgentStatus
22
+ * @property {AgentState} state
23
+ * @property {string} [sessionId]
24
+ * @property {number} processId
25
+ * @property {number} startedAt
26
+ * @property {number} [endedAt]
27
+ * @property {number} [exitCode]
28
+ * @property {string} [error]
29
+ *
30
+ * @typedef {Object} SpawnAgentOptions
31
+ * @property {string} prompt
32
+ * @property {string} agent
33
+ * @property {{ providerID: string, modelID: string }} [model]
34
+ * @property {string} worktree
35
+ * @property {string} logPath
36
+ * @property {string} [title]
37
+ * @property {Object<string,string>} [env]
38
+ * @property {number} [sessionIdTimeoutMs]
39
+ *
40
+ * @typedef {Object} SpawnAgentResult
41
+ * @property {boolean} ok
42
+ * @property {string} [sessionId]
43
+ * @property {number} [processId]
44
+ * @property {string} [error]
45
+ */
46
+
47
+ /** @type {Map<number, { status: AgentStatus, proc: import('node:child_process').ChildProcess, onExit: Function[], spawnResolvers: Function[] }>} */
48
+ const agents = new Map();
49
+
50
+ /**
51
+ * Spawn a single `opencode run` process. Resolves once the opencode
52
+ * child has reported its session id in the structured log stream
53
+ * (or once the process exits before that).
54
+ *
55
+ * @param {SpawnAgentOptions} opts
56
+ * @returns {Promise<SpawnAgentResult>}
57
+ */
58
+ export function spawnAgent(opts) {
59
+ // 1. Pre-flight: log dir must exist.
60
+ const logDir = dirname(opts.logPath);
61
+ if (!existsSync(logDir)) {
62
+ try {
63
+ mkdirSync(logDir, { recursive: true });
64
+ } catch (err) {
65
+ return Promise.resolve({
66
+ ok: false,
67
+ error: `cannot create log dir ${logDir}: ${err.message}`,
68
+ });
69
+ }
70
+ }
71
+
72
+ // 2. Build argv.
73
+ const args = [
74
+ 'run',
75
+ '--dir', opts.worktree,
76
+ '--print-logs',
77
+ '--log-level', 'INFO',
78
+ '--title', opts.title || `bgr:${opts.agent}:${Date.now()}`,
79
+ ];
80
+ if (opts.model) {
81
+ args.push('--model', `${opts.model.providerID}/${opts.model.modelID}`);
82
+ }
83
+ args.push('--', opts.prompt);
84
+
85
+ // 3. Spawn the process.
86
+ let proc;
87
+ try {
88
+ proc = spawn('opencode', args, {
89
+ stdio: ['ignore', 'pipe', 'pipe'],
90
+ env: { ...process.env, ...(opts.env || {}) },
91
+ });
92
+ } catch (err) {
93
+ return Promise.resolve({
94
+ ok: false,
95
+ error: `failed to spawn opencode run: ${err.message}`,
96
+ });
97
+ }
98
+
99
+ // 4. Track the agent.
100
+ const rec = {
101
+ status: { state: 'starting', processId: proc.pid, startedAt: Date.now() },
102
+ proc,
103
+ onExit: [],
104
+ spawnResolvers: [],
105
+ };
106
+ agents.set(proc.pid, rec);
107
+
108
+ // 5. Pipe stdout+stderr to the log file.
109
+ const logStream = createWriteStream(opts.logPath, { flags: 'a' });
110
+ const sessionIdRegex = /message=created id=(ses_[A-Za-z0-9_]+)/;
111
+ let sessionId;
112
+
113
+ const resolveSpawnIfReady = (forceError) => {
114
+ const resolvers = rec.spawnResolvers.splice(0);
115
+ if (resolvers.length === 0) return;
116
+ if (forceError) {
117
+ for (const r of resolvers) r({ ok: false, processId: proc.pid, error: forceError });
118
+ return;
119
+ }
120
+ if (sessionId) {
121
+ rec.status.state = 'running';
122
+ for (const r of resolvers) r({ ok: true, sessionId, processId: proc.pid });
123
+ }
124
+ };
125
+
126
+ // 6. Stream readers — line-buffered by splitting on newlines. We
127
+ // append a [stdout]/[stderr] prefix for human readability.
128
+ const attachLineReader = (stream, label) => {
129
+ let buf = '';
130
+ stream.setEncoding('utf8');
131
+ stream.on('data', (chunk) => {
132
+ const text = typeof chunk === 'string' ? chunk : chunk.toString('utf8');
133
+ logStream.write(`[${label}] ${text}`);
134
+ if (label === 'stderr' && !sessionId) {
135
+ buf += text;
136
+ const m = buf.match(sessionIdRegex);
137
+ if (m && m[1]) {
138
+ sessionId = m[1];
139
+ rec.status.sessionId = sessionId;
140
+ resolveSpawnIfReady();
141
+ }
142
+ }
143
+ });
144
+ stream.on('end', () => {
145
+ // Final flush attempt.
146
+ if (label === 'stderr' && !sessionId && buf) {
147
+ const m = buf.match(sessionIdRegex);
148
+ if (m && m[1]) {
149
+ sessionId = m[1];
150
+ rec.status.sessionId = sessionId;
151
+ resolveSpawnIfReady();
152
+ }
153
+ }
154
+ });
155
+ stream.on('error', (err) => {
156
+ logStream.write(`[${label}] <stream error: ${err.message}>\n`);
157
+ });
158
+ };
159
+
160
+ if (proc.stdout) attachLineReader(proc.stdout, 'stdout');
161
+ if (proc.stderr) attachLineReader(proc.stderr, 'stderr');
162
+
163
+ // 7. Exit handler.
164
+ proc.on('exit', (exitCode, signal) => {
165
+ rec.status.exitCode = exitCode ?? undefined;
166
+ rec.status.endedAt = Date.now();
167
+ if (rec.status.state !== 'killed') {
168
+ if (signal) {
169
+ rec.status.state = 'killed';
170
+ } else if (exitCode === 0) {
171
+ rec.status.state = 'done';
172
+ } else {
173
+ rec.status.state = 'failed';
174
+ rec.status.error = rec.status.error || `opencode run exited with code ${exitCode}`;
175
+ }
176
+ }
177
+ if (!sessionId) {
178
+ resolveSpawnIfReady(rec.status.error || 'opencode run exited before reporting session id');
179
+ }
180
+ const cbs = rec.onExit.splice(0);
181
+ for (const cb of cbs) {
182
+ try { cb({ ...rec.status }); } catch { /* ignore */ }
183
+ }
184
+ try { logStream.end(); } catch { /* ignore */ }
185
+ });
186
+ proc.on('error', (err) => {
187
+ rec.status.error = err.message;
188
+ rec.status.endedAt = Date.now();
189
+ rec.status.state = 'failed';
190
+ if (!sessionId) resolveSpawnIfReady(err.message);
191
+ const cbs = rec.onExit.splice(0);
192
+ for (const cb of cbs) try { cb({ ...rec.status }); } catch { /* ignore */ }
193
+ });
194
+
195
+ // 8. Race against a timeout.
196
+ const sessionIdTimeoutMs = opts.sessionIdTimeoutMs ?? 10_000;
197
+ return new Promise((resolve) => {
198
+ rec.spawnResolvers.push(resolve);
199
+ setTimeout(() => {
200
+ if (!sessionId) {
201
+ resolveSpawnIfReady(
202
+ `opencode run did not report a session id within ${sessionIdTimeoutMs}ms`,
203
+ );
204
+ }
205
+ }, sessionIdTimeoutMs);
206
+ });
207
+ }
208
+
209
+ /**
210
+ * Snapshot the current status of an agent.
211
+ * @param {number} processId
212
+ * @returns {AgentStatus | null}
213
+ */
214
+ export function getStatus(processId) {
215
+ const rec = agents.get(processId);
216
+ if (!rec) return null;
217
+ return { ...rec.status };
218
+ }
219
+
220
+ /**
221
+ * Subscribe to the exit event. Callback fires exactly once when
222
+ * the process exits.
223
+ * @param {number} processId
224
+ * @param {(status: AgentStatus) => void} cb
225
+ * @returns {() => void} unsubscribe
226
+ */
227
+ export function onExit(processId, cb) {
228
+ const rec = agents.get(processId);
229
+ if (!rec) return () => undefined;
230
+ rec.onExit.push(cb);
231
+ if (rec.status.endedAt !== undefined) {
232
+ queueMicrotask(() => {
233
+ try { cb({ ...rec.status }); } catch { /* ignore */ }
234
+ });
235
+ }
236
+ return () => {
237
+ const i = rec.onExit.indexOf(cb);
238
+ if (i >= 0) rec.onExit.splice(i, 1);
239
+ };
240
+ }
241
+
242
+ /**
243
+ * Kill the agent. Sends SIGTERM, waits up to 5s, then SIGKILL.
244
+ * @param {number} processId
245
+ * @param {'SIGTERM'|'SIGKILL'} [signal]
246
+ * @returns {{ ok: boolean, error?: string }}
247
+ */
248
+ export function killAgent(processId, signal = 'SIGTERM') {
249
+ const rec = agents.get(processId);
250
+ if (!rec) return { ok: true, error: 'no such process tracked' };
251
+ if (rec.status.endedAt !== undefined) {
252
+ return { ok: true, error: 'process already exited' };
253
+ }
254
+ rec.status.state = 'killed';
255
+ try {
256
+ rec.proc.kill(signal);
257
+ } catch (err) {
258
+ return { ok: false, error: `kill(${signal}) failed: ${err.message}` };
259
+ }
260
+ setTimeout(() => {
261
+ if (rec.status.endedAt === undefined) {
262
+ try { rec.proc.kill('SIGKILL'); } catch { /* ignore */ }
263
+ }
264
+ }, 5_000);
265
+ return { ok: true };
266
+ }
267
+
268
+ /**
269
+ * List every tracked agent.
270
+ * @returns {AgentStatus[]}
271
+ */
272
+ export function list() {
273
+ return Array.from(agents.values()).map((r) => ({ ...r.status }));
274
+ }
275
+
276
+ /** For tests: clear the in-memory registry. */
277
+ export function _resetForTests() {
278
+ agents.clear();
279
+ }
@@ -0,0 +1,138 @@
1
+ /**
2
+ * src/server/pair-store.mjs
3
+ *
4
+ * v3.5.2 — Pairing token store for the Bizar Companion mobile app.
5
+ *
6
+ * Generates short-lived bearer tokens that the dashboard issues when a user
7
+ * taps "Pair Device" in the Settings view (or runs the TUI / pair CLI).
8
+ * The companion app scans a QR code containing:
9
+ *
10
+ * bizar://pair?url=<publicUrl>&token=<token>
11
+ *
12
+ * …then calls `GET /api/pair/verify` with the token. On success the
13
+ * companion stores the URL + token in expo-secure-store and uses it as a
14
+ * Bearer header for all subsequent API + WebSocket calls.
15
+ *
16
+ * Tokens are stored in memory only — a server restart invalidates all
17
+ * outstanding tokens. The TTL is 5 minutes, which is enough for the user
18
+ * to open the app, scan, and verify.
19
+ */
20
+ import { randomBytes } from 'node:crypto';
21
+ import { existsSync, readFileSync } from 'node:fs';
22
+ import { join } from 'node:path';
23
+ import { homedir } from 'node:os';
24
+
25
+ /** @typedef {{ token: string, expiresAt: number, publicUrl: string }} PairToken */
26
+
27
+ /** @type {Map<string, PairToken>} */
28
+ const tokens = new Map();
29
+
30
+ const DEFAULT_TTL_MS = 5 * 60 * 1000; // 5 minutes
31
+
32
+ function gc() {
33
+ const now = Date.now();
34
+ for (const [tok, entry] of tokens) {
35
+ if (entry.expiresAt <= now) tokens.delete(tok);
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Mint a fresh pairing token bound to a public URL.
41
+ * @param {string} publicUrl - URL the companion app should hit (https://... or http://localhost:...)
42
+ * @param {number} [ttlMs] - milliseconds until expiry
43
+ * @returns {PairToken & { qrPayload: string }}
44
+ */
45
+ export function mint(publicUrl, ttlMs = DEFAULT_TTL_MS) {
46
+ gc();
47
+ const token = `pair_${randomBytes(24).toString('base64url')}`;
48
+ const expiresAt = Date.now() + ttlMs;
49
+ const entry = { token, expiresAt, publicUrl };
50
+ tokens.set(token, entry);
51
+ return {
52
+ ...entry,
53
+ qrPayload: `bizar://pair?url=${encodeURIComponent(publicUrl)}&token=${encodeURIComponent(token)}`,
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Verify a Bearer token. Returns the entry on success, null on failure.
59
+ * @param {string | null | undefined} token
60
+ * @returns {PairToken | null}
61
+ */
62
+ export function verify(token) {
63
+ if (!token || typeof token !== 'string') return null;
64
+ const entry = tokens.get(token);
65
+ if (!entry) return null;
66
+ if (entry.expiresAt <= Date.now()) {
67
+ tokens.delete(token);
68
+ return null;
69
+ }
70
+ return entry;
71
+ }
72
+
73
+ /**
74
+ * Express middleware: if the request carries a valid Bearer pair token,
75
+ * set `req.pairToken` and `req.pairEntry`. Does NOT block unauthenticated
76
+ * requests — the dashboard itself doesn't require auth; this middleware
77
+ * just enriches the request so other handlers can recognize paired clients.
78
+ */
79
+ export function pairTokenMiddleware(req, _res, next) {
80
+ const auth = req.headers.authorization;
81
+ if (!auth || !auth.startsWith('Bearer ')) {
82
+ req.pairToken = null;
83
+ req.pairEntry = null;
84
+ return next();
85
+ }
86
+ const token = auth.slice(7).trim();
87
+ const entry = verify(token);
88
+ req.pairToken = entry ? token : null;
89
+ req.pairEntry = entry;
90
+ next();
91
+ }
92
+
93
+ /**
94
+ * Detect the URL the companion app should hit. Preference order:
95
+ * 1. Tailscale MagicDNS hostname from `tailscale.json` (if enabled)
96
+ * 2. The Host header from the current request (so localhost works in dev)
97
+ * 3. localhost on the configured port
98
+ *
99
+ * @param {import('express').Request} req
100
+ * @param {number} port
101
+ * @returns {string}
102
+ */
103
+ export function detectPublicUrl(req, port) {
104
+ // 1. Tailscale config (best for phone-over-WiFi)
105
+ try {
106
+ const cfgPath = join(homedir(), '.config', 'bizar', 'tailscale.json');
107
+ if (existsSync(cfgPath)) {
108
+ const cfg = JSON.parse(readFileSync(cfgPath, 'utf8'));
109
+ if (cfg?.enabled && cfg?.hostname) {
110
+ const proto = cfg.https === false ? 'http' : 'https';
111
+ return `${proto}://${cfg.hostname}`;
112
+ }
113
+ }
114
+ } catch {
115
+ /* fall through */
116
+ }
117
+
118
+ // 2. Host header from the current request
119
+ const host = (req?.headers?.host || '').toString().trim();
120
+ if (host && /^[A-Za-z0-9.:[\]-]+$/.test(host) && !host.startsWith('127.0.0.1') && !host.startsWith('localhost')) {
121
+ const rawProto = (req?.headers?.['x-forwarded-proto'] || req?.protocol || 'http').toString().split(',')[0].trim().toLowerCase();
122
+ const proto = rawProto === 'https' ? 'https' : 'http';
123
+ return `${proto}://${host}`;
124
+ }
125
+
126
+ // 3. localhost fallback
127
+ return `http://localhost:${port}`;
128
+ }
129
+
130
+ export const pairStore = {
131
+ mint,
132
+ verify,
133
+ detectPublicUrl,
134
+ middleware: pairTokenMiddleware,
135
+ /** For tests / introspection only. */
136
+ _size: () => tokens.size,
137
+ _clear: () => tokens.clear(),
138
+ };