@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,212 @@
1
+ /**
2
+ * Smoke test for the v2 plugin↔dashboard protocol.
3
+ *
4
+ * Spins up a minimal Express app with the v2 router, runs through:
5
+ * 1. GET /health (public, 200)
6
+ * 2. GET /api/v2/sessions without auth (401)
7
+ * 3. GET /api/v2/sessions with auth (200, [])
8
+ * 4. POST /api/v2/sessions with auth (201, session returned)
9
+ * 5. GET /api/v2/event without auth (401)
10
+ * 6. POST /api/v2/event + GET /api/v2/event (subscriber receives the published event)
11
+ * 7. GET /doc (200, OpenAPI YAML)
12
+ *
13
+ * Run with: node tests/smoke-v2.mjs
14
+ */
15
+
16
+ import express from 'express';
17
+ import { createServer } from 'node:http';
18
+ import { V2EventBus } from '../src/server/v2-event-bus.mjs';
19
+ import { loadOrCreateAuth } from '../src/server/v2-auth-file.mjs';
20
+ import { createV2Router } from '../src/server/routes-v2/index.mjs';
21
+ import { setTimeout as sleep } from 'node:timers/promises';
22
+
23
+ const tests = [];
24
+ let pass = 0;
25
+ let fail = 0;
26
+
27
+ function test(name, fn) {
28
+ tests.push({ name, fn });
29
+ }
30
+
31
+ async function main() {
32
+ // Setup
33
+ const v2Auth = loadOrCreateAuth({ port: 0 }); // 0 = ephemeral file path
34
+ const v2Bus = new V2EventBus({ logger: { log() {}, warn() {}, error() {} } });
35
+ const app = express();
36
+ app.use(express.json({ limit: '2mb' }));
37
+ app.use(
38
+ '/api/v2',
39
+ createV2Router({
40
+ eventBus: v2Bus,
41
+ getPassword: () => v2Auth.password,
42
+ version: '0.7.0-alpha.1',
43
+ startedAt: Date.now(),
44
+ }),
45
+ );
46
+ const server = createServer(app);
47
+ await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
48
+ const port = server.address().port;
49
+ const baseUrl = `http://127.0.0.1:${port}`;
50
+ const authHeader =
51
+ 'Basic ' + Buffer.from(`opencode:${v2Auth.password}`).toString('base64');
52
+
53
+ console.log(`\nSmoke test server listening on ${baseUrl}`);
54
+ console.log(`Auth: ${authHeader.slice(0, 32)}...\n`);
55
+
56
+ // 1. GET /health (public)
57
+ test('1. GET /health returns 200 (public)', async () => {
58
+ const r = await fetch(`${baseUrl}/api/v2/health`);
59
+ if (r.status !== 200) throw new Error(`status ${r.status}`);
60
+ const body = await r.json();
61
+ if (body.status !== 'ok') throw new Error(`body ${JSON.stringify(body)}`);
62
+ });
63
+
64
+ // 2. GET /api/v2/sessions without auth
65
+ test('2. GET /api/v2/sessions without auth returns 401', async () => {
66
+ const r = await fetch(`${baseUrl}/api/v2/sessions`);
67
+ if (r.status !== 401) throw new Error(`status ${r.status}`);
68
+ const body = await r.json();
69
+ if (body.name !== 'DashboardError') throw new Error(`body ${JSON.stringify(body)}`);
70
+ });
71
+
72
+ // 3. GET /api/v2/sessions with auth
73
+ test('3. GET /api/v2/sessions with auth returns 200 []', async () => {
74
+ const r = await fetch(`${baseUrl}/api/v2/sessions`, { headers: { Authorization: authHeader } });
75
+ if (r.status !== 200) throw new Error(`status ${r.status}`);
76
+ const body = await r.json();
77
+ if (!Array.isArray(body)) throw new Error(`not an array: ${JSON.stringify(body)}`);
78
+ });
79
+
80
+ // 4. POST /api/v2/sessions with auth
81
+ test('4. POST /api/v2/sessions with auth creates session and returns 201', async () => {
82
+ const r = await fetch(`${baseUrl}/api/v2/sessions`, {
83
+ method: 'POST',
84
+ headers: { Authorization: authHeader, 'Content-Type': 'application/json' },
85
+ body: JSON.stringify({ agent: 'mimir', prompt: 'hello' }),
86
+ });
87
+ if (r.status !== 201) throw new Error(`status ${r.status}`);
88
+ const body = await r.json();
89
+ if (!body.id?.startsWith('bgr_')) throw new Error(`bad id: ${body.id}`);
90
+ if (body.agent !== 'mimir') throw new Error(`bad agent: ${body.agent}`);
91
+ });
92
+
93
+ // 5. GET /api/v2/event without auth
94
+ test('5. GET /api/v2/event without auth returns 401', async () => {
95
+ const r = await fetch(`${baseUrl}/api/v2/event`, {
96
+ headers: { Accept: 'text/event-stream' },
97
+ });
98
+ if (r.status !== 401) throw new Error(`status ${r.status}`);
99
+ });
100
+
101
+ // 6. Subscribe + publish end-to-end
102
+ test('6. SSE subscriber receives published event end-to-end', async () => {
103
+ // Open subscriber
104
+ const subResponse = await fetch(`${baseUrl}/api/v2/event`, {
105
+ headers: { Authorization: authHeader, Accept: 'text/event-stream' },
106
+ });
107
+ if (subResponse.status !== 200) throw new Error(`sub status ${subResponse.status}`);
108
+ if (!subResponse.body) throw new Error('no response body');
109
+
110
+ const reader = subResponse.body.getReader();
111
+ const decoder = new TextDecoder();
112
+ let buf = '';
113
+
114
+ // Collect events in the background
115
+ const received = [];
116
+ const collectDone = (async () => {
117
+ try {
118
+ while (true) {
119
+ const { done, value } = await reader.read();
120
+ if (done) break;
121
+ buf += decoder.decode(value, { stream: true });
122
+ // Split on \n\n (SSE event boundary)
123
+ let idx = buf.indexOf('\n\n');
124
+ while (idx !== -1) {
125
+ const raw = buf.slice(0, idx);
126
+ buf = buf.slice(idx + 2);
127
+ // Parse "event: <type>\ndata: <json>"
128
+ const eventMatch = raw.match(/^event: (.+)$/m);
129
+ const dataMatch = raw.match(/^data: (.+)$/m);
130
+ if (eventMatch && dataMatch) {
131
+ received.push({ type: eventMatch[1], data: JSON.parse(dataMatch[1]) });
132
+ }
133
+ idx = buf.indexOf('\n\n');
134
+ }
135
+ }
136
+ } catch {
137
+ // stream closed
138
+ }
139
+ })();
140
+
141
+ // Wait briefly for the dashboard.connected event.
142
+ await sleep(150);
143
+
144
+ // Publish an event via POST.
145
+ const publishResponse = await fetch(`${baseUrl}/api/v2/event`, {
146
+ method: 'POST',
147
+ headers: { Authorization: authHeader, 'Content-Type': 'application/json' },
148
+ body: JSON.stringify({
149
+ type: 'session.created',
150
+ properties: { sessionId: 'ses_test_1', agent: 'thor' },
151
+ }),
152
+ });
153
+ if (publishResponse.status !== 204) {
154
+ throw new Error(`publish status ${publishResponse.status}`);
155
+ }
156
+
157
+ // Wait for the published event to arrive.
158
+ const start = Date.now();
159
+ while (Date.now() - start < 3000) {
160
+ if (received.some((e) => e.type === 'session.created')) break;
161
+ await sleep(50);
162
+ }
163
+
164
+ // Cleanup: cancel the subscriber.
165
+ try {
166
+ await reader.cancel();
167
+ } catch {
168
+ /* ignore */
169
+ }
170
+
171
+ if (!received.some((e) => e.type === 'dashboard.connected')) {
172
+ throw new Error('did not receive dashboard.connected');
173
+ }
174
+ if (!received.some((e) => e.type === 'session.created')) {
175
+ throw new Error('did not receive published session.created');
176
+ }
177
+ await collectDone.catch(() => {});
178
+ });
179
+
180
+ // 7. GET /doc
181
+ test('7. GET /doc returns OpenAPI YAML', async () => {
182
+ const r = await fetch(`${baseUrl}/api/v2/doc`);
183
+ if (r.status !== 200) throw new Error(`status ${r.status}`);
184
+ const ct = r.headers.get('content-type') || '';
185
+ if (!ct.includes('yaml')) throw new Error(`bad content-type: ${ct}`);
186
+ const text = await r.text();
187
+ if (!text.startsWith('openapi:')) throw new Error(`not YAML: ${text.slice(0, 80)}`);
188
+ });
189
+
190
+ // Run tests
191
+ for (const t of tests) {
192
+ try {
193
+ await t.fn();
194
+ console.log(` PASS ${t.name}`);
195
+ pass += 1;
196
+ } catch (err) {
197
+ console.log(` FAIL ${t.name}`);
198
+ console.log(` ${err.message}`);
199
+ fail += 1;
200
+ }
201
+ }
202
+
203
+ // Cleanup
204
+ await new Promise((resolve) => server.close(resolve));
205
+ console.log(`\n${pass} passed, ${fail} failed`);
206
+ process.exit(fail === 0 ? 0 : 1);
207
+ }
208
+
209
+ main().catch((err) => {
210
+ console.error('Smoke test crashed:', err);
211
+ process.exit(2);
212
+ });
@@ -0,0 +1,175 @@
1
+ /**
2
+ * tests/strip-thinking.test.mjs
3
+ *
4
+ * Unit tests for `stripThinkingTags` and `extractContentFromOpencodeMessage`
5
+ * in src/server/serve-info.mjs. The M3 model emits `<thinking>...</thinking>`
6
+ * inline in the assistant text; these tags must be stripped from any string
7
+ * that flows out of `extractContentFromOpencodeMessage` so that
8
+ * react-markdown (desktop + mobile chat) renders clean text.
9
+ *
10
+ * Run with: node --test tests/strip-thinking.test.mjs
11
+ */
12
+ import { test } from 'node:test';
13
+ import assert from 'node:assert/strict';
14
+
15
+ import {
16
+ stripThinkingTags,
17
+ extractContentFromOpencodeMessage,
18
+ } from '../src/server/serve-info.mjs';
19
+
20
+ test('stripThinkingTags: passes through plain text untouched', () => {
21
+ assert.equal(
22
+ stripThinkingTags('Hello, world.'),
23
+ 'Hello, world.'
24
+ );
25
+ });
26
+
27
+ test('stripThinkingTags: strips a single thinking block', () => {
28
+ const input = '<thinking>let me reason about this</thinking>Here is my answer.';
29
+ assert.equal(stripThinkingTags(input), 'Here is my answer.');
30
+ });
31
+
32
+ test('stripThinkingTags: strips multiline thinking blocks', () => {
33
+ const input = '<thinking>\nstep 1\nstep 2\nstep 3\n</thinking>\nFinal answer.';
34
+ assert.equal(stripThinkingTags(input), 'Final answer.');
35
+ });
36
+
37
+ test('stripThinkingTags: strips multiple thinking blocks', () => {
38
+ const input = '<thinking>a</thinking>foo<thinking>b</thinking>bar<thinking>c</thinking>baz';
39
+ assert.equal(stripThinkingTags(input), 'foobarbaz');
40
+ });
41
+
42
+ test('stripThinkingTags: strips THINKING block (uppercase, case-insensitive)', () => {
43
+ const input = '<THINKING>reasoning here</THINKING>visible output';
44
+ assert.equal(stripThinkingTags(input), 'visible output');
45
+ });
46
+
47
+ test('stripThinkingTags: strips MixedCase thinking block', () => {
48
+ const input = '<Thinking>x</Thinking>visible';
49
+ assert.equal(stripThinkingTags(input), 'visible');
50
+ });
51
+
52
+ test('stripThinkingTags: strips thinking tag with attributes', () => {
53
+ const input = '<thinking mode="deep" intensity="high">deep thought</thinking>answer';
54
+ assert.equal(stripThinkingTags(input), 'answer');
55
+ });
56
+
57
+ test('stripThinkingTags: strips self-closing thinking tag', () => {
58
+ const input = 'before<thinking/>after';
59
+ assert.equal(stripThinkingTags(input), 'beforeafter');
60
+ });
61
+
62
+ test('stripThinkingTags: strips self-closing thinking tag with attributes', () => {
63
+ const input = 'before<thinking mode="deep"/>after';
64
+ assert.equal(stripThinkingTags(input), 'beforeafter');
65
+ });
66
+
67
+ test('stripThinkingTags: strips stray closing tag with no opener', () => {
68
+ const input = 'before</thinking>after';
69
+ assert.equal(stripThinkingTags(input), 'beforeafter');
70
+ });
71
+
72
+ test('stripThinkingTags: returns empty string when content is only a thinking block', () => {
73
+ assert.equal(stripThinkingTags('<thinking>only this</thinking>'), '');
74
+ });
75
+
76
+ test('stripThinkingTags: returns empty string for empty input', () => {
77
+ assert.equal(stripThinkingTags(''), '');
78
+ });
79
+
80
+ test('stripThinkingTags: returns empty string for non-string input', () => {
81
+ assert.equal(stripThinkingTags(null), '');
82
+ assert.equal(stripThinkingTags(undefined), '');
83
+ assert.equal(stripThinkingTags(42), '');
84
+ assert.equal(stripThinkingTags({}), '');
85
+ });
86
+
87
+ test('stripThinkingTags: collapses 3+ newlines to 2 after stripping', () => {
88
+ const input = 'before<thinking>hidden</thinking>\n\n\n\n\nafter';
89
+ assert.equal(stripThinkingTags(input), 'before\n\nafter');
90
+ });
91
+
92
+ test('stripThinkingTags: collapses newlines left over after stripping a block', () => {
93
+ const input = '<thinking>hidden</thinking>\n\n\n\nvisible';
94
+ assert.equal(stripThinkingTags(input), 'visible');
95
+ });
96
+
97
+ test('stripThinkingTags: trims leading and trailing whitespace', () => {
98
+ assert.equal(stripThinkingTags(' hello '), 'hello');
99
+ });
100
+
101
+ test('stripThinkingTags: handles nested-looking but separate blocks', () => {
102
+ // Non-greedy match eats `<thinking>a<thinking>b</thinking>` first,
103
+ // then the stray-closer pass strips the remaining `</thinking>`.
104
+ const input = '<thinking>a<thinking>b</thinking>middle</thinking>visible';
105
+ assert.equal(stripThinkingTags(input), 'middlevisible');
106
+ });
107
+
108
+ test('extractContentFromOpencodeMessage: returns empty string for null/undefined', () => {
109
+ assert.equal(extractContentFromOpencodeMessage(null), '');
110
+ assert.equal(extractContentFromOpencodeMessage(undefined), '');
111
+ });
112
+
113
+ test('extractContentFromOpencodeMessage: strips thinking from msg.text', () => {
114
+ const msg = { text: '<thinking>reasoning</thinking>final answer' };
115
+ assert.equal(extractContentFromOpencodeMessage(msg), 'final answer');
116
+ });
117
+
118
+ test('extractContentFromOpencodeMessage: strips thinking from msg.content', () => {
119
+ const msg = { content: '<thinking>reasoning</thinking>final answer' };
120
+ assert.equal(extractContentFromOpencodeMessage(msg), 'final answer');
121
+ });
122
+
123
+ test('extractContentFromOpencodeMessage: strips thinking from each text part', () => {
124
+ const msg = {
125
+ parts: [
126
+ { type: 'text', text: '<thinking>step 1</thinking>first part' },
127
+ { type: 'text', text: '<thinking>step 2</thinking>second part' },
128
+ ],
129
+ };
130
+ assert.equal(
131
+ extractContentFromOpencodeMessage(msg),
132
+ 'first part\n\nsecond part'
133
+ );
134
+ });
135
+
136
+ test('extractContentFromOpencodeMessage: skips non-text parts', () => {
137
+ const msg = {
138
+ parts: [
139
+ { type: 'text', text: 'visible' },
140
+ { type: 'tool_use', id: 'x', name: 'bash', input: {} },
141
+ { type: 'text', text: '<thinking>hidden</thinking>also visible' },
142
+ ],
143
+ };
144
+ assert.equal(
145
+ extractContentFromOpencodeMessage(msg),
146
+ 'visible\n\nalso visible'
147
+ );
148
+ });
149
+
150
+ test('extractContentFromOpencodeMessage: returns empty for empty parts', () => {
151
+ assert.equal(extractContentFromOpencodeMessage({ parts: [] }), '');
152
+ assert.equal(extractContentFromOpencodeMessage({}), '');
153
+ });
154
+
155
+ test('extractContentFromOpencodeMessage: real-world M3 message shape', () => {
156
+ // Approximate shape of an interleaved-thinking assistant message
157
+ const msg = {
158
+ info: { id: 'm1', role: 'assistant', time: { created: 1000 } },
159
+ parts: [
160
+ {
161
+ type: 'reasoning',
162
+ text: '',
163
+ reasoning_details: [{ type: 'reasoning.text', text: 'internal' }],
164
+ },
165
+ {
166
+ type: 'text',
167
+ text: '<thinking>let me think</thinking>Here is my answer.\n\nIt covers A, B, C.',
168
+ },
169
+ ],
170
+ };
171
+ assert.equal(
172
+ extractContentFromOpencodeMessage(msg),
173
+ 'Here is my answer.\n\nIt covers A, B, C.'
174
+ );
175
+ });