@polderlabs/bizar 3.23.1 → 4.2.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.
- package/README.md +83 -16
- package/bizar-dash/.bizar/activity.log +3 -0
- package/bizar-dash/.bizar/graph/.graphify_analysis.json +1540 -0
- package/bizar-dash/.bizar/graph/.graphify_labels.json +1 -0
- package/bizar-dash/.bizar/graph/GRAPH_REPORT.md +404 -0
- package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/0661b816358db84dfdb7f10443db8a61152fd20b3fee950caf8fbf32920a1790.json +1 -0
- package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/16da06d774142a6e5d74829ad982531286a6193ef798de8f593db029e123ec32.json +1 -0
- package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/27e5697c01254c69c64c5a33896669073b40afb5ba88375102ae77fa5404136d.json +1 -0
- package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/532997898027254aa4c0932243dc71d2f55888181232b65974961934997dc85b.json +1 -0
- package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/84e3451a64c7f99f0cd6a88b0748d7426780486f53ab4935b7476b28c08f8293.json +1 -0
- package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/88e5ea5f3e78fa69353fe9e6a8d1a05391d54605e25600cb125531eb5a6432ff.json +1 -0
- package/bizar-dash/.bizar/graph/cache/stat-index.json +1 -0
- package/bizar-dash/.bizar/graph/graph.html +307 -0
- package/bizar-dash/.bizar/graph/graph.json +40267 -0
- package/bizar-dash/.bizar/graph/manifest.json +762 -0
- package/bizar-dash/.graphifyignore +40 -0
- package/bizar-dash/.obsidian/README.md +14 -0
- package/bizar-dash/.obsidian/daily/2026-06-25.md +9 -0
- package/bizar-dash/.obsidian/vault.json +7 -0
- package/bizar-dash/.od-skills/web-prototype-e1429c1737/SKILL.md +103 -0
- package/bizar-dash/.od-skills/web-prototype-e1429c1737/assets/template.html +338 -0
- package/bizar-dash/.od-skills/web-prototype-e1429c1737/example.html +81 -0
- package/bizar-dash/.od-skills/web-prototype-e1429c1737/open-design.json +172 -0
- package/bizar-dash/.od-skills/web-prototype-e1429c1737/references/checklist.md +44 -0
- package/bizar-dash/.od-skills/web-prototype-e1429c1737/references/layouts.md +247 -0
- package/bizar-dash/CHANGELOG.md +474 -0
- package/bizar-dash/DESIGN.md +136 -0
- package/bizar-dash/dist/assets/main-B3RgW6FS.js +331 -0
- package/bizar-dash/dist/assets/main-B3RgW6FS.js.map +1 -0
- package/bizar-dash/dist/assets/main-DlJ8wgLR.css +1 -0
- package/bizar-dash/dist/assets/mobile-CsZQAswA.css +1 -0
- package/bizar-dash/dist/assets/mobile-DbxIw8BG.js +2 -0
- package/bizar-dash/dist/assets/mobile-DbxIw8BG.js.map +1 -0
- package/bizar-dash/dist/assets/mobile-Dvq2d53Y.js +354 -0
- package/bizar-dash/dist/assets/mobile-Dvq2d53Y.js.map +1 -0
- package/bizar-dash/dist/index.html +40 -0
- package/bizar-dash/dist/mobile.html +22 -0
- package/bizar-dash/plans/debug-plan/comments.json +1 -0
- package/bizar-dash/plans/debug-plan/meta.json +10 -0
- package/bizar-dash/plans/debug-plan/plan.json +174 -0
- package/bizar-dash/scripts/smoke-bg-retry.mjs +246 -0
- package/bizar-dash/src/cli/dashboard-ports.mjs +488 -0
- package/bizar-dash/src/cli.mjs +522 -0
- package/bizar-dash/src/server/activity-log.mjs +174 -0
- package/bizar-dash/src/server/agents-store.mjs +465 -0
- package/bizar-dash/src/server/api.mjs +138 -0
- package/bizar-dash/src/server/artifact-template.html +810 -0
- package/bizar-dash/src/server/artifacts-store.mjs +733 -0
- package/bizar-dash/src/server/auth.mjs +381 -0
- package/bizar-dash/src/server/background-store.mjs +447 -0
- package/bizar-dash/src/server/bg-poller.mjs +305 -0
- package/bizar-dash/src/server/bg-retry.mjs +574 -0
- package/bizar-dash/src/server/browser.mjs +40 -0
- package/bizar-dash/src/server/diagnostics-store.mjs +148 -0
- package/bizar-dash/src/server/dialog-poller.mjs +105 -0
- package/bizar-dash/src/server/dialog-store.mjs +177 -0
- package/bizar-dash/src/server/glyphs/mdx-compiler.mjs +583 -0
- package/bizar-dash/src/server/lib/path-safe.mjs +283 -0
- package/bizar-dash/src/server/memory-git.mjs +329 -0
- package/bizar-dash/src/server/memory-lightrag.mjs +767 -0
- package/bizar-dash/src/server/memory-schema.mjs +145 -0
- package/bizar-dash/src/server/memory-secrets.mjs +84 -0
- package/bizar-dash/src/server/memory-store.mjs +471 -0
- package/bizar-dash/src/server/mod-security.mjs +398 -0
- package/bizar-dash/src/server/mods-loader.mjs +1067 -0
- package/bizar-dash/src/server/notifications-store.mjs +243 -0
- package/bizar-dash/src/server/obsidian-store.mjs +318 -0
- package/bizar-dash/src/server/opencode-runner.mjs +279 -0
- package/bizar-dash/src/server/pair-store.mjs +138 -0
- package/bizar-dash/src/server/projects-store.mjs +364 -0
- package/bizar-dash/src/server/providers-store.mjs +789 -0
- package/bizar-dash/src/server/routes/_shared.mjs +415 -0
- package/bizar-dash/src/server/routes/activity.mjs +110 -0
- package/bizar-dash/src/server/routes/agents.mjs +134 -0
- package/bizar-dash/src/server/routes/artifacts.mjs +279 -0
- package/bizar-dash/src/server/routes/auth.mjs +69 -0
- package/bizar-dash/src/server/routes/background.mjs +165 -0
- package/bizar-dash/src/server/routes/chat.mjs +485 -0
- package/bizar-dash/src/server/routes/config.mjs +129 -0
- package/bizar-dash/src/server/routes/diagnostics.mjs +50 -0
- package/bizar-dash/src/server/routes/dialogs.mjs +86 -0
- package/bizar-dash/src/server/routes/fs.mjs +429 -0
- package/bizar-dash/src/server/routes/history.mjs +78 -0
- package/bizar-dash/src/server/routes/memory.mjs +658 -0
- package/bizar-dash/src/server/routes/misc.mjs +89 -0
- package/bizar-dash/src/server/routes/mods.mjs +359 -0
- package/bizar-dash/src/server/routes/notifications.mjs +54 -0
- package/bizar-dash/src/server/routes/obsidian.mjs +239 -0
- package/bizar-dash/src/server/routes/opencode-sessions.mjs +55 -0
- package/bizar-dash/src/server/routes/overview.mjs +91 -0
- package/bizar-dash/src/server/routes/pair.mjs +67 -0
- package/bizar-dash/src/server/routes/projects.mjs +175 -0
- package/bizar-dash/src/server/routes/providers.mjs +47 -0
- package/bizar-dash/src/server/routes/schedules.mjs +104 -0
- package/bizar-dash/src/server/routes/settings.mjs +51 -0
- package/bizar-dash/src/server/routes/skills.mjs +76 -0
- package/bizar-dash/src/server/routes/tasks.mjs +468 -0
- package/bizar-dash/src/server/routes/themes.mjs +51 -0
- package/bizar-dash/src/server/routes-v2/auth.mjs +59 -0
- package/bizar-dash/src/server/routes-v2/events.mjs +107 -0
- package/bizar-dash/src/server/routes-v2/health.mjs +21 -0
- package/bizar-dash/src/server/routes-v2/index.mjs +90 -0
- package/bizar-dash/src/server/routes-v2/sessions.mjs +111 -0
- package/bizar-dash/src/server/schedules-runner.mjs +369 -0
- package/bizar-dash/src/server/schedules-store.mjs +268 -0
- package/bizar-dash/src/server/search-store.mjs +220 -0
- package/bizar-dash/src/server/serve-info.mjs +684 -0
- package/bizar-dash/src/server/server.mjs +796 -0
- package/bizar-dash/src/server/settings-store.mjs +45 -0
- package/bizar-dash/src/server/skills-store.mjs +300 -0
- package/bizar-dash/src/server/state.mjs +437 -0
- package/bizar-dash/src/server/tailscale-store.mjs +113 -0
- package/bizar-dash/src/server/task-delegator.mjs +824 -0
- package/bizar-dash/src/server/tasks-store.mjs +508 -0
- package/bizar-dash/src/server/tui.mjs +923 -0
- package/bizar-dash/src/server/update-store.mjs +168 -0
- package/bizar-dash/src/server/v2-auth-file.mjs +99 -0
- package/bizar-dash/src/server/v2-event-bus.mjs +128 -0
- package/bizar-dash/src/server/watcher.mjs +81 -0
- package/bizar-dash/src/server/yaml.mjs +238 -0
- package/bizar-dash/src/web/App.tsx +718 -0
- package/bizar-dash/src/web/MobileApp.tsx +408 -0
- package/bizar-dash/src/web/components/ArtifactCreateDialog.tsx +95 -0
- package/bizar-dash/src/web/components/ArtifactListDialog.tsx +55 -0
- package/bizar-dash/src/web/components/ArtifactViewer.tsx +143 -0
- package/bizar-dash/src/web/components/AuditDialog.tsx +79 -0
- package/bizar-dash/src/web/components/BgStatusBadge.tsx +32 -0
- package/bizar-dash/src/web/components/Button.tsx +56 -0
- package/bizar-dash/src/web/components/CanvasContextMenu.tsx +68 -0
- package/bizar-dash/src/web/components/Card.tsx +40 -0
- package/bizar-dash/src/web/components/CollapsibleSection.tsx +72 -0
- package/bizar-dash/src/web/components/CommandDialog.tsx +66 -0
- package/bizar-dash/src/web/components/EmptyState.tsx +30 -0
- package/bizar-dash/src/web/components/FileBrowser.tsx +633 -0
- package/bizar-dash/src/web/components/HelpDialog.tsx +55 -0
- package/bizar-dash/src/web/components/KillConfirmDialog.tsx +88 -0
- package/bizar-dash/src/web/components/Modal.tsx +215 -0
- package/bizar-dash/src/web/components/Notifications.tsx +241 -0
- package/bizar-dash/src/web/components/SearchModal.tsx +224 -0
- package/bizar-dash/src/web/components/Sidebar.tsx +66 -0
- package/bizar-dash/src/web/components/Spinner.tsx +19 -0
- package/bizar-dash/src/web/components/StatusBadge.tsx +25 -0
- package/bizar-dash/src/web/components/Tag.tsx +28 -0
- package/bizar-dash/src/web/components/Toast.tsx +150 -0
- package/bizar-dash/src/web/components/Topbar.tsx +368 -0
- package/bizar-dash/src/web/components/VisualPlanDialog.tsx +58 -0
- package/bizar-dash/src/web/components/chat/AgentChip.tsx +68 -0
- package/bizar-dash/src/web/components/chat/ChatBubble.tsx +60 -0
- package/bizar-dash/src/web/components/chat/ChatThread.tsx +88 -0
- package/bizar-dash/src/web/components/chat/ChatTopBar.tsx +50 -0
- package/bizar-dash/src/web/components/chat/Composer.tsx +164 -0
- package/bizar-dash/src/web/components/chat/ConfirmModal.tsx +54 -0
- package/bizar-dash/src/web/components/chat/EmptyState.tsx +21 -0
- package/bizar-dash/src/web/components/chat/FirstRunGreeting.tsx +18 -0
- package/bizar-dash/src/web/components/chat/FloatingComposer.tsx +32 -0
- package/bizar-dash/src/web/components/chat/InfoPanel.tsx +119 -0
- package/bizar-dash/src/web/components/chat/LoadingSkeleton.tsx +19 -0
- package/bizar-dash/src/web/components/chat/MessageBubble.tsx +60 -0
- package/bizar-dash/src/web/components/chat/SessionList.tsx +153 -0
- package/bizar-dash/src/web/components/chat/StreamingIndicator.tsx +9 -0
- package/bizar-dash/src/web/components/chat/SuggestionCards.tsx +55 -0
- package/bizar-dash/src/web/components/chat/WelcomeScreen.tsx +36 -0
- package/bizar-dash/src/web/components/chat/index.ts +20 -0
- package/bizar-dash/src/web/components/chat/useAutoGrowTextarea.ts +18 -0
- package/bizar-dash/src/web/components/chat/useChat.ts +219 -0
- package/bizar-dash/src/web/components/chat/useSlashCommands.ts +47 -0
- package/bizar-dash/src/web/index.html +37 -0
- package/bizar-dash/src/web/lib/api.ts +193 -0
- package/bizar-dash/src/web/lib/markdown.tsx +59 -0
- package/bizar-dash/src/web/lib/types.ts +668 -0
- package/bizar-dash/src/web/lib/utils.ts +114 -0
- package/bizar-dash/src/web/lib/ws.ts +176 -0
- package/bizar-dash/src/web/main.tsx +34 -0
- package/bizar-dash/src/web/mobile/MobileApp.tsx +278 -0
- package/bizar-dash/src/web/mobile/MobileBottomNav.tsx +38 -0
- package/bizar-dash/src/web/mobile/MobileTopbar.tsx +115 -0
- package/bizar-dash/src/web/mobile/components/MobileBottomSheet.tsx +182 -0
- package/bizar-dash/src/web/mobile/components/MobileListItem.tsx +64 -0
- package/bizar-dash/src/web/mobile/components/MobileModal.tsx +123 -0
- package/bizar-dash/src/web/mobile/views/MobileActivity.tsx +273 -0
- package/bizar-dash/src/web/mobile/views/MobileAgents.tsx +374 -0
- package/bizar-dash/src/web/mobile/views/MobileArtifactCanvas.tsx +439 -0
- package/bizar-dash/src/web/mobile/views/MobileArtifacts.tsx +143 -0
- package/bizar-dash/src/web/mobile/views/MobileChat.tsx +180 -0
- package/bizar-dash/src/web/mobile/views/MobileConfig.tsx +175 -0
- package/bizar-dash/src/web/mobile/views/MobileHistory.tsx +191 -0
- package/bizar-dash/src/web/mobile/views/MobileMods.tsx +149 -0
- package/bizar-dash/src/web/mobile/views/MobileMore.tsx +121 -0
- package/bizar-dash/src/web/mobile/views/MobileNotifications.tsx +137 -0
- package/bizar-dash/src/web/mobile/views/MobilePlans.tsx +26 -0
- package/bizar-dash/src/web/mobile/views/MobileSchedules.tsx +685 -0
- package/bizar-dash/src/web/mobile/views/MobileSearchModal.tsx +172 -0
- package/bizar-dash/src/web/mobile/views/MobileSettings.tsx +388 -0
- package/bizar-dash/src/web/mobile/views/MobileSkills.tsx +153 -0
- package/bizar-dash/src/web/mobile/views/MobileTasks.tsx +564 -0
- package/bizar-dash/src/web/mobile.html +20 -0
- package/bizar-dash/src/web/mobile.tsx +13 -0
- package/bizar-dash/src/web/styles/chat.css +198 -0
- package/bizar-dash/src/web/styles/glyphs.css +960 -0
- package/bizar-dash/src/web/styles/main.css +8855 -0
- package/bizar-dash/src/web/styles/mobile-chat.css +5 -0
- package/bizar-dash/src/web/styles/mobile.css +1960 -0
- package/bizar-dash/src/web/views/Activity.tsx +1203 -0
- package/bizar-dash/src/web/views/Agents.tsx +701 -0
- package/bizar-dash/src/web/views/Artifacts.tsx +1480 -0
- package/bizar-dash/src/web/views/BackgroundAgents.tsx +450 -0
- package/bizar-dash/src/web/views/Chat.tsx +190 -0
- package/bizar-dash/src/web/views/Config.tsx +2063 -0
- package/bizar-dash/src/web/views/History.tsx +335 -0
- package/bizar-dash/src/web/views/ModView.tsx +207 -0
- package/bizar-dash/src/web/views/Mods.tsx +693 -0
- package/bizar-dash/src/web/views/Overview.tsx +812 -0
- package/bizar-dash/src/web/views/Providers.tsx +302 -0
- package/bizar-dash/src/web/views/Schedules.tsx +802 -0
- package/bizar-dash/src/web/views/Settings.tsx +1787 -0
- package/bizar-dash/src/web/views/Skills.tsx +431 -0
- package/bizar-dash/src/web/views/Tasks.tsx +1523 -0
- package/bizar-dash/src/web/views/glyphs/GlyphRenderer.tsx +613 -0
- package/bizar-dash/src/web/views/glyphs/components.tsx +1098 -0
- package/bizar-dash/templates/mod/FORMAT.md +76 -0
- package/bizar-dash/templates/mod/hello-mod/README.md +19 -0
- package/bizar-dash/templates/mod/hello-mod/agents/greeter.md +8 -0
- package/bizar-dash/templates/mod/hello-mod/commands/hello.md +6 -0
- package/bizar-dash/templates/mod/hello-mod/mod.json +20 -0
- package/bizar-dash/templates/mod/hello-mod/routes/ping.mjs +9 -0
- package/bizar-dash/templates/mod/hello-mod/views/HelloView.tsx +10 -0
- package/bizar-dash/tests/dashboard-ports.test.mjs +138 -0
- package/bizar-dash/tests/graphify-mod-spawn.node.test.mjs +90 -0
- package/bizar-dash/tests/memory-cli.test.mjs +542 -0
- package/bizar-dash/tests/memory-config.test.mjs +422 -0
- package/bizar-dash/tests/memory-git.test.mjs +246 -0
- package/bizar-dash/tests/memory-lightrag.test.mjs +153 -0
- package/bizar-dash/tests/memory-protocol-drift.test.mjs +45 -0
- package/bizar-dash/tests/memory-schema.test.mjs +198 -0
- package/bizar-dash/tests/memory-secrets.test.mjs +121 -0
- package/bizar-dash/tests/memory-store.test.mjs +390 -0
- package/bizar-dash/tests/memory-sync.test.mjs +141 -0
- package/bizar-dash/tests/mod-instructions.node.test.mjs +188 -0
- package/bizar-dash/tests/mod-security.test.mjs +273 -0
- package/bizar-dash/tests/mod-upgrade.node.test.mjs +357 -0
- package/bizar-dash/tests/no-agent-browser.node.test.mjs +98 -0
- package/bizar-dash/tests/obsidian-back-compat.test.mjs +199 -0
- package/bizar-dash/tests/opencode-runner.test.mjs +172 -0
- package/bizar-dash/tests/path-safe.test.mjs +108 -0
- package/bizar-dash/tests/providers-store-backup-keys.node.test.mjs +333 -0
- package/bizar-dash/tests/smoke-v2.mjs +212 -0
- package/bizar-dash/tests/strip-thinking.test.mjs +175 -0
- package/bizar-dash/tests/submit-feedback.test.mjs +353 -0
- package/bizar-dash/tests/tmux-wrap.test.mjs +145 -0
- package/bizar-dash/tests/yaml.test.mjs +128 -0
- package/bizar-dash/tsconfig.json +23 -0
- package/bizar-dash/vite.config.ts +27 -0
- package/cli/atomic.mjs +73 -0
- package/cli/banner.mjs +1 -1
- package/cli/bin.mjs +44 -47
- package/cli/bootstrap.mjs +1 -1
- package/cli/copy.mjs +25 -16
- package/cli/dev-link.mjs +17 -1
- package/cli/doctor.mjs +4 -4
- package/cli/doctor.test.mjs +2 -2
- package/cli/init.mjs +135 -1
- package/cli/install.mjs +31 -39
- package/cli/memory-constants.mjs +59 -0
- package/cli/memory.mjs +1436 -0
- package/cli/service.mjs +5 -6
- package/cli/utils.mjs +6 -3
- package/config/AGENTS.md +7 -7
- package/config/agents/_shared/AGENT_BASELINE.md +59 -61
- package/config/opencode.json +13 -38
- package/config/skills/memory-protocol/SKILL.md +105 -0
- package/config/skills/obsidian/SKILL.md +270 -65
- package/install.sh +59 -19
- package/package.json +49 -14
- package/packages/sdk/LICENSE +21 -0
- package/packages/sdk/README.md +80 -0
- package/packages/sdk/src/client.ts +183 -0
- package/packages/sdk/src/errors.ts +120 -0
- package/packages/sdk/src/events.ts +153 -0
- package/packages/sdk/src/index.ts +63 -0
- package/packages/sdk/src/types.ts +176 -0
- package/packages/sdk/src/version.ts +4 -0
- package/packages/sdk/tests/client.test.ts +217 -0
- package/packages/sdk/tests/errors.test.ts +108 -0
- package/packages/sdk/tests/events.test.ts +139 -0
- package/packages/sdk/tests/fixtures/fetch-mock.ts +152 -0
- package/packages/sdk/tests/fixtures/sse-mock.ts +30 -0
- package/packages/sdk/tsconfig.json +25 -0
- package/packages/sdk/vitest.config.ts +9 -0
- package/plugins/bizar/LICENSE +21 -0
- package/plugins/bizar/README.md +448 -0
- package/plugins/bizar/dist/index.js +29901 -0
- package/plugins/bizar/index.ts +1491 -0
- package/plugins/bizar/scripts/check-forbidden-imports.sh +33 -0
- package/plugins/bizar/src/background-state.ts +551 -0
- package/plugins/bizar/src/background.ts +1250 -0
- package/plugins/bizar/src/commands-impl.ts +464 -0
- package/plugins/bizar/src/commands.ts +1168 -0
- package/plugins/bizar/src/dashboard-client.ts +233 -0
- package/plugins/bizar/src/event-stream.ts +606 -0
- package/plugins/bizar/src/fingerprint.ts +120 -0
- package/plugins/bizar/src/handoff.ts +79 -0
- package/plugins/bizar/src/http-client.ts +467 -0
- package/plugins/bizar/src/key-rotation.ts +218 -0
- package/plugins/bizar/src/logger.ts +144 -0
- package/plugins/bizar/src/loop.ts +176 -0
- package/plugins/bizar/src/opencode-runner.ts +390 -0
- package/plugins/bizar/src/options.ts +421 -0
- package/plugins/bizar/src/plan-fs.ts +323 -0
- package/plugins/bizar/src/reasoning-clean.ts +454 -0
- package/plugins/bizar/src/report.ts +178 -0
- package/plugins/bizar/src/research-prompt.ts +35 -0
- package/plugins/bizar/src/serve-info.ts +228 -0
- package/plugins/bizar/src/serve.ts +496 -0
- package/plugins/bizar/src/settings.ts +349 -0
- package/plugins/bizar/src/state.ts +298 -0
- package/plugins/bizar/src/tools/bg-collect.ts +104 -0
- package/plugins/bizar/src/tools/bg-get-comments.ts +239 -0
- package/plugins/bizar/src/tools/bg-kill.ts +87 -0
- package/plugins/bizar/src/tools/bg-spawn.ts +401 -0
- package/plugins/bizar/src/tools/bg-status.ts +99 -0
- package/plugins/bizar/src/tools/open-kb.ts +191 -0
- package/plugins/bizar/src/tools/plan-action.ts +767 -0
- package/plugins/bizar/src/tools/read-glyph-feedback.ts +170 -0
- package/plugins/bizar/src/tools/wait-for-feedback.ts +402 -0
- package/plugins/bizar/tests/attach-handler-bug.test.ts +169 -0
- package/plugins/bizar/tests/background-state.test.ts +277 -0
- package/plugins/bizar/tests/background.test.ts +402 -0
- package/plugins/bizar/tests/block.test.ts +195 -0
- package/plugins/bizar/tests/canonical-key-order.test.ts +75 -0
- package/plugins/bizar/tests/commands-impl.test.ts +442 -0
- package/plugins/bizar/tests/commands.test.ts +584 -0
- package/plugins/bizar/tests/config.test.ts +122 -0
- package/plugins/bizar/tests/dashboard-client.test.ts +159 -0
- package/plugins/bizar/tests/dispose.test.ts +336 -0
- package/plugins/bizar/tests/event-stream.test.ts +409 -0
- package/plugins/bizar/tests/event.test.ts +262 -0
- package/plugins/bizar/tests/fingerprint.test.ts +162 -0
- package/plugins/bizar/tests/http-client.test.ts +404 -0
- package/plugins/bizar/tests/init-helpers.test.ts +203 -0
- package/plugins/bizar/tests/integration/slash-command.test.ts +348 -0
- package/plugins/bizar/tests/integration/tool-routing.test.ts +314 -0
- package/plugins/bizar/tests/key-rotation.test.ts +396 -0
- package/plugins/bizar/tests/loop.test.ts +397 -0
- package/plugins/bizar/tests/options.test.ts +276 -0
- package/plugins/bizar/tests/reasoning-clean.test.ts +422 -0
- package/plugins/bizar/tests/serve.test.ts +339 -0
- package/plugins/bizar/tests/settings.test.ts +351 -0
- package/plugins/bizar/tests/stall-think.test.ts +750 -0
- package/plugins/bizar/tests/state.test.ts +276 -0
- package/plugins/bizar/tests/tools/bg-collect.test.ts +337 -0
- package/plugins/bizar/tests/tools/bg-get-comments.test.ts +485 -0
- package/plugins/bizar/tests/tools/bg-kill.test.ts +235 -0
- package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +147 -0
- package/plugins/bizar/tests/tools/bg-spawn.test.ts +311 -0
- package/plugins/bizar/tests/tools/bg-status.test.ts +217 -0
- package/plugins/bizar/tests/tools/opencode-runner.test.ts +115 -0
- package/plugins/bizar/tests/tools/plan-action.test.ts +599 -0
- package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +253 -0
- package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +390 -0
- package/plugins/bizar/tests/update-deadlock.test.ts +145 -0
- package/plugins/bizar/tsconfig.json +29 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DrB0rk / BizarHarness contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @polderlabs/bizar-sdk
|
|
2
|
+
|
|
3
|
+
Typed SDK for the BizarHarness plugin ↔ dashboard communication protocol.
|
|
4
|
+
|
|
5
|
+
This package is the **shared types + client library** used by both:
|
|
6
|
+
- The Bizar opencode plugin (`@polderlabs/bizar-plugin`) — publishes events to the dashboard.
|
|
7
|
+
- The Bizar dashboard (`@polderlabs/bizar-dash`) — exposes REST + SSE endpoints and consumes events.
|
|
8
|
+
|
|
9
|
+
It replaces the legacy file-based `serve.json` bridge with a typed HTTP + SSE protocol sourced from an OpenAPI 3.1 spec.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @polderlabs/bizar-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { createBizarClient, SDK_VERSION } from "@polderlabs/bizar-sdk";
|
|
21
|
+
|
|
22
|
+
const client = createBizarClient({
|
|
23
|
+
baseUrl: process.env.BIZAR_DASHBOARD_URL ?? "http://127.0.0.1:4098",
|
|
24
|
+
password: process.env.BIZAR_DASHBOARD_PASSWORD ?? readPasswordFromAuthFile(),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// REST — resource-grouped methods
|
|
28
|
+
const sessions = await client.sessions.list({ status: "running" });
|
|
29
|
+
const session = await client.sessions.create({
|
|
30
|
+
agent: "mimir",
|
|
31
|
+
prompt: "Research the latest opencode serve API.",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// SSE — async iterable
|
|
35
|
+
const sub = await client.events.subscribe();
|
|
36
|
+
for await (const event of sub.stream) {
|
|
37
|
+
// event.type is a discriminated string: "session.created" | "session.updated" | …
|
|
38
|
+
// event.properties is the typed payload
|
|
39
|
+
console.log(event.type, event.properties);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Errors are returned by default (not thrown). Discriminated by `name`.
|
|
43
|
+
const result = await client.sessions.get({ sessionId: "ses_xyz" });
|
|
44
|
+
if ("name" in result && result.name === "DashboardError") {
|
|
45
|
+
console.error("dashboard error:", result.data);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Architecture
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
┌────────────────────────────┐
|
|
53
|
+
│ opencode + Bizar plugin │
|
|
54
|
+
│ (publishes events) │
|
|
55
|
+
└──────────────┬─────────────┘
|
|
56
|
+
│ HTTP + SSE
|
|
57
|
+
│ (this SDK)
|
|
58
|
+
┌──────────────▼─────────────┐
|
|
59
|
+
│ Bizar dashboard server │
|
|
60
|
+
│ (subscribes, exposes UI) │
|
|
61
|
+
└────────────────────────────┘
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Transport
|
|
65
|
+
|
|
66
|
+
- **REST (JSON)** for request/response CRUD operations.
|
|
67
|
+
- **SSE (`text/event-stream`)** for live events — single endpoint at `GET /event`.
|
|
68
|
+
- **No WebSocket** anywhere in the protocol.
|
|
69
|
+
|
|
70
|
+
## Auth
|
|
71
|
+
|
|
72
|
+
HTTP basic with the dashboard-generated password. The dashboard writes the password to `~/.cache/bizarharness/dash-auth.json` (mode 0600) on first start. The plugin reads this file or accepts `BIZAR_DASHBOARD_PASSWORD` env var override.
|
|
73
|
+
|
|
74
|
+
## Source of Truth
|
|
75
|
+
|
|
76
|
+
The API surface is defined in [OPENAPI_SPEC.yaml](../../.bizar/research/OPENAPI_SPEC.yaml). TypeScript types in `src/types.ts` are hand-written to match the spec exactly. In v0.7.1, types will be auto-generated via `@hey-api/openapi-ts` from that spec.
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BizarHarness SDK client factory.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the opencode SDK pattern: a single `createBizarClient(config)`
|
|
5
|
+
* call returns a typed client with resource-grouped methods. The client
|
|
6
|
+
* handles auth header injection, response unwrapping, and error mapping
|
|
7
|
+
* via the discriminated BizarError union.
|
|
8
|
+
*
|
|
9
|
+
* Reference: https://opencode.ai/docs/sdk/ (createOpencodeClient).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
apiErrorFrom,
|
|
14
|
+
connectionErrorFrom,
|
|
15
|
+
dashboardErrorFrom,
|
|
16
|
+
type BizarError,
|
|
17
|
+
} from "./errors.js";
|
|
18
|
+
import { subscribeEvents, type EventSubscription } from "./events.js";
|
|
19
|
+
import type {
|
|
20
|
+
DashboardEvent,
|
|
21
|
+
Health,
|
|
22
|
+
Plan,
|
|
23
|
+
Project,
|
|
24
|
+
Session,
|
|
25
|
+
SessionCreate,
|
|
26
|
+
SessionListQuery,
|
|
27
|
+
} from "./types.js";
|
|
28
|
+
|
|
29
|
+
export interface BizarClientConfig {
|
|
30
|
+
baseUrl: string;
|
|
31
|
+
password: string;
|
|
32
|
+
/** Injectable fetch for testing. Defaults to global `fetch`. */
|
|
33
|
+
fetch?: typeof fetch;
|
|
34
|
+
/** When true, errors are thrown. Default false (return BizarError). */
|
|
35
|
+
throwOnError?: boolean;
|
|
36
|
+
/** Extra headers to attach to every request. */
|
|
37
|
+
headers?: Record<string, string>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface SessionsResource {
|
|
41
|
+
list(query?: SessionListQuery): Promise<Session[] | BizarError>;
|
|
42
|
+
get(input: { sessionId: string }): Promise<Session | BizarError>;
|
|
43
|
+
create(input: SessionCreate): Promise<Session | BizarError>;
|
|
44
|
+
abort(input: { sessionId: string }): Promise<null | BizarError>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ProjectsResource {
|
|
48
|
+
list(): Promise<Project[] | BizarError>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface PlansResource {
|
|
52
|
+
list(): Promise<Plan[] | BizarError>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface EventsResource {
|
|
56
|
+
subscribe(opts?: { signal?: AbortSignal; since?: number }): Promise<EventSubscription>;
|
|
57
|
+
publish(event: DashboardEvent): Promise<null | BizarError>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface HealthResource {
|
|
61
|
+
check(): Promise<Health | BizarError>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface BizarClient {
|
|
65
|
+
sessions: SessionsResource;
|
|
66
|
+
projects: ProjectsResource;
|
|
67
|
+
plans: PlansResource;
|
|
68
|
+
events: EventsResource;
|
|
69
|
+
health: HealthResource;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function createBizarClient(config: BizarClientConfig): BizarClient {
|
|
73
|
+
const fetchImpl = config.fetch ?? fetch;
|
|
74
|
+
const authHeader = makeAuthHeader(config.password);
|
|
75
|
+
const baseHeaders: Record<string, string> = {
|
|
76
|
+
Authorization: authHeader,
|
|
77
|
+
Accept: "application/json",
|
|
78
|
+
...(config.headers ?? {}),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
async function request<T>(
|
|
82
|
+
method: string,
|
|
83
|
+
path: string,
|
|
84
|
+
init?: { body?: unknown; query?: Record<string, string | number | undefined> },
|
|
85
|
+
): Promise<T | BizarError> {
|
|
86
|
+
const url = new URL(path, config.baseUrl);
|
|
87
|
+
if (init?.query) {
|
|
88
|
+
for (const [k, v] of Object.entries(init.query)) {
|
|
89
|
+
if (v !== undefined) url.searchParams.set(k, String(v));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const headers: Record<string, string> = { ...baseHeaders };
|
|
94
|
+
let body: string | undefined;
|
|
95
|
+
if (init?.body !== undefined) {
|
|
96
|
+
headers["Content-Type"] = "application/json";
|
|
97
|
+
body = JSON.stringify(init.body);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let response: Response;
|
|
101
|
+
try {
|
|
102
|
+
response = await fetchImpl(url.toString(), {
|
|
103
|
+
method,
|
|
104
|
+
headers,
|
|
105
|
+
body,
|
|
106
|
+
});
|
|
107
|
+
} catch (err) {
|
|
108
|
+
const error = connectionErrorFrom(err);
|
|
109
|
+
if (config.throwOnError) throw error;
|
|
110
|
+
return error;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (response.status === 204) {
|
|
114
|
+
return null as T;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const text = await response.text();
|
|
118
|
+
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
// 5xx and 429 → APIError (retryable); everything else → DashboardError.
|
|
121
|
+
const error =
|
|
122
|
+
response.status >= 500 || response.status === 429
|
|
123
|
+
? apiErrorFrom(response.status, text)
|
|
124
|
+
: dashboardErrorFrom(response.status, text);
|
|
125
|
+
if (config.throwOnError) throw error;
|
|
126
|
+
return error;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
return JSON.parse(text) as T;
|
|
131
|
+
} catch {
|
|
132
|
+
// Empty body or non-JSON; return null for caller to handle.
|
|
133
|
+
return null as T;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
sessions: {
|
|
139
|
+
list: (query) =>
|
|
140
|
+
request<Session[]>("GET", "/sessions", { query: query as Record<string, string | number | undefined> }),
|
|
141
|
+
get: ({ sessionId }) =>
|
|
142
|
+
request<Session>("GET", `/sessions/${encodeURIComponent(sessionId)}`),
|
|
143
|
+
create: (input) => request<Session>("POST", "/sessions", { body: input }),
|
|
144
|
+
abort: ({ sessionId }) =>
|
|
145
|
+
request<null>("DELETE", `/sessions/${encodeURIComponent(sessionId)}`),
|
|
146
|
+
},
|
|
147
|
+
projects: {
|
|
148
|
+
list: () => request<Project[]>("GET", "/projects"),
|
|
149
|
+
},
|
|
150
|
+
plans: {
|
|
151
|
+
list: () => request<Plan[]>("GET", "/plans"),
|
|
152
|
+
},
|
|
153
|
+
events: {
|
|
154
|
+
subscribe: (opts) => subscribeEvents(config.baseUrl, authHeader, opts, fetchImpl),
|
|
155
|
+
publish: (event) => request<null>("POST", "/event", { body: event }),
|
|
156
|
+
},
|
|
157
|
+
health: {
|
|
158
|
+
check: async () => {
|
|
159
|
+
const url = new URL("/health", config.baseUrl);
|
|
160
|
+
try {
|
|
161
|
+
const r = await fetchImpl(url.toString(), { method: "GET" });
|
|
162
|
+
if (!r.ok) return dashboardErrorFrom(r.status, await r.text());
|
|
163
|
+
return (await r.json()) as Health;
|
|
164
|
+
} catch (err) {
|
|
165
|
+
const e = connectionErrorFrom(err);
|
|
166
|
+
if (config.throwOnError) throw e;
|
|
167
|
+
return e;
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Build the `Authorization: Basic …` header value.
|
|
176
|
+
* Username is `opencode` per the opencode convention used by BizarHarness.
|
|
177
|
+
*/
|
|
178
|
+
function makeAuthHeader(password: string): string {
|
|
179
|
+
const credentials = `opencode:${password}`;
|
|
180
|
+
// Buffer.from is available in both Node (≥ 16) and Bun.
|
|
181
|
+
const encoded = Buffer.from(credentials, "utf-8").toString("base64");
|
|
182
|
+
return `Basic ${encoded}`;
|
|
183
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discriminated error model for the BizarHarness SDK.
|
|
3
|
+
*
|
|
4
|
+
* Errors are RETURNED (not thrown) by default, matching the opencode SDK
|
|
5
|
+
* pattern. Set `throwOnError: true` in the client config to opt into
|
|
6
|
+
* throwing.
|
|
7
|
+
*
|
|
8
|
+
* Discriminate via the `name` field:
|
|
9
|
+
*
|
|
10
|
+
* const result = await client.sessions.get({ sessionId });
|
|
11
|
+
* if (isBizarError(result)) {
|
|
12
|
+
* switch (result.name) {
|
|
13
|
+
* case "DashboardError": ...
|
|
14
|
+
* case "ConnectionError": ...
|
|
15
|
+
* case "APIError": ...
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export type PluginError = {
|
|
21
|
+
name: "PluginError";
|
|
22
|
+
data: {
|
|
23
|
+
code: string;
|
|
24
|
+
message: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type DashboardError = {
|
|
29
|
+
name: "DashboardError";
|
|
30
|
+
data: {
|
|
31
|
+
statusCode: number;
|
|
32
|
+
message: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type ConnectionError = {
|
|
37
|
+
name: "ConnectionError";
|
|
38
|
+
data: {
|
|
39
|
+
message: string;
|
|
40
|
+
cause?: unknown;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type APIError = {
|
|
45
|
+
name: "APIError";
|
|
46
|
+
data: {
|
|
47
|
+
statusCode: number;
|
|
48
|
+
isRetryable: boolean;
|
|
49
|
+
message: string;
|
|
50
|
+
responseBody?: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type BizarError = PluginError | DashboardError | ConnectionError | APIError;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Type guard: narrows `unknown` to `BizarError`.
|
|
58
|
+
*/
|
|
59
|
+
export function isBizarError(value: unknown): value is BizarError {
|
|
60
|
+
if (typeof value !== "object" || value === null) return false;
|
|
61
|
+
const v = value as { name?: unknown };
|
|
62
|
+
if (typeof v.name !== "string") return false;
|
|
63
|
+
return (
|
|
64
|
+
v.name === "PluginError" ||
|
|
65
|
+
v.name === "DashboardError" ||
|
|
66
|
+
v.name === "ConnectionError" ||
|
|
67
|
+
v.name === "APIError"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Convenience: build a ConnectionError from a thrown fetch failure.
|
|
73
|
+
*/
|
|
74
|
+
export function connectionErrorFrom(err: unknown): ConnectionError {
|
|
75
|
+
if (err instanceof Error) {
|
|
76
|
+
return {
|
|
77
|
+
name: "ConnectionError",
|
|
78
|
+
data: { message: err.message, cause: err },
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
name: "ConnectionError",
|
|
83
|
+
data: { message: String(err), cause: err },
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Convenience: build a DashboardError from a non-OK HTTP response.
|
|
89
|
+
*/
|
|
90
|
+
export function dashboardErrorFrom(status: number, body: string): DashboardError {
|
|
91
|
+
let message = `HTTP ${status}`;
|
|
92
|
+
try {
|
|
93
|
+
const parsed = JSON.parse(body) as { data?: { message?: string }; message?: string };
|
|
94
|
+
if (parsed.data?.message) message = parsed.data.message;
|
|
95
|
+
else if (parsed.message) message = parsed.message;
|
|
96
|
+
} catch {
|
|
97
|
+
// body wasn't JSON; fall back to status-only message
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
name: "DashboardError",
|
|
101
|
+
data: { statusCode: status, message },
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Convenience: build an APIError from a 5xx or specific 4xx response.
|
|
107
|
+
* 5xx and 429 are retryable.
|
|
108
|
+
*/
|
|
109
|
+
export function apiErrorFrom(status: number, body: string): APIError {
|
|
110
|
+
const isRetryable = status >= 500 || status === 429;
|
|
111
|
+
return {
|
|
112
|
+
name: "APIError",
|
|
113
|
+
data: {
|
|
114
|
+
statusCode: status,
|
|
115
|
+
isRetryable,
|
|
116
|
+
message: `Dashboard API returned ${status}`,
|
|
117
|
+
responseBody: body,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE event subscriber for the BizarHarness SDK.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the opencode-style SSE format:
|
|
5
|
+
*
|
|
6
|
+
* event: <type>
|
|
7
|
+
* data: {"type": "<type>", "properties": { ... }}
|
|
8
|
+
*
|
|
9
|
+
* Returns an async iterable + close handle.
|
|
10
|
+
*
|
|
11
|
+
* Reference: opencode SDK pattern (`for await (const event of events.stream)`).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { DashboardEvent } from "./types.js";
|
|
15
|
+
|
|
16
|
+
export interface EventSubscriptionOptions {
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
/** Replay events from this sequence number (buffered by dashboard). */
|
|
19
|
+
since?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface EventSubscription {
|
|
23
|
+
stream: AsyncIterable<DashboardEvent>;
|
|
24
|
+
close(): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Subscribe to dashboard events. The returned stream yields parsed
|
|
29
|
+
* `DashboardEvent` instances.
|
|
30
|
+
*
|
|
31
|
+
* If `signal` aborts, the underlying fetch is aborted and the stream ends.
|
|
32
|
+
*/
|
|
33
|
+
export async function subscribeEvents(
|
|
34
|
+
baseUrl: string,
|
|
35
|
+
authHeader: string,
|
|
36
|
+
opts: EventSubscriptionOptions = {},
|
|
37
|
+
fetchImpl: typeof fetch = fetch,
|
|
38
|
+
): Promise<EventSubscription> {
|
|
39
|
+
const url = new URL("/event", baseUrl);
|
|
40
|
+
if (typeof opts.since === "number") {
|
|
41
|
+
url.searchParams.set("since", String(opts.since));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const controller = new AbortController();
|
|
45
|
+
if (opts.signal) {
|
|
46
|
+
opts.signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const response = await fetchImpl(url.toString(), {
|
|
50
|
+
method: "GET",
|
|
51
|
+
headers: {
|
|
52
|
+
Authorization: authHeader,
|
|
53
|
+
Accept: "text/event-stream",
|
|
54
|
+
},
|
|
55
|
+
signal: controller.signal,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (!response.ok || !response.body) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`SSE subscribe failed: ${response.status} ${response.statusText}`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const stream = parseSseStream<DashboardEvent>(response.body, controller);
|
|
65
|
+
return {
|
|
66
|
+
stream,
|
|
67
|
+
close: () => controller.abort(),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Parse an SSE byte stream into a typed async iterable.
|
|
73
|
+
*
|
|
74
|
+
* Handles the opencode SSE format: lines starting with `event:` and `data:`.
|
|
75
|
+
* Lines beginning with `:` are comments (ignored). Empty lines delimit events.
|
|
76
|
+
*
|
|
77
|
+
* Yields parsed events as `{ type, properties, ... }` objects (the JSON
|
|
78
|
+
* decoded value of the `data:` line).
|
|
79
|
+
*/
|
|
80
|
+
export async function* parseSseStream<T extends { type: string }>(
|
|
81
|
+
body: ReadableStream<Uint8Array>,
|
|
82
|
+
controller: AbortController,
|
|
83
|
+
): AsyncIterable<T> {
|
|
84
|
+
const reader = body.getReader();
|
|
85
|
+
const decoder = new TextDecoder("utf-8");
|
|
86
|
+
let buffer = "";
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
while (true) {
|
|
90
|
+
const { done, value } = await reader.read();
|
|
91
|
+
if (done) break;
|
|
92
|
+
|
|
93
|
+
buffer += decoder.decode(value, { stream: true });
|
|
94
|
+
|
|
95
|
+
// SSE events are delimited by a blank line.
|
|
96
|
+
let boundary = buffer.indexOf("\n\n");
|
|
97
|
+
while (boundary !== -1) {
|
|
98
|
+
const raw = buffer.slice(0, boundary);
|
|
99
|
+
buffer = buffer.slice(boundary + 2);
|
|
100
|
+
const parsed = parseSseEvent(raw);
|
|
101
|
+
if (parsed !== null) {
|
|
102
|
+
yield parsed as T;
|
|
103
|
+
}
|
|
104
|
+
boundary = buffer.indexOf("\n\n");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Flush any trailing event without a blank line terminator.
|
|
109
|
+
if (buffer.trim().length > 0) {
|
|
110
|
+
const parsed = parseSseEvent(buffer);
|
|
111
|
+
if (parsed !== null) yield parsed as T;
|
|
112
|
+
}
|
|
113
|
+
} finally {
|
|
114
|
+
reader.releaseLock();
|
|
115
|
+
controller.abort();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function parseSseEvent(raw: string): unknown | null {
|
|
120
|
+
let eventType: string | null = null;
|
|
121
|
+
const dataLines: string[] = [];
|
|
122
|
+
|
|
123
|
+
for (const line of raw.split("\n")) {
|
|
124
|
+
if (line.length === 0) continue;
|
|
125
|
+
if (line.startsWith(":")) continue; // comment
|
|
126
|
+
const colonIdx = line.indexOf(":");
|
|
127
|
+
if (colonIdx === -1) continue;
|
|
128
|
+
const field = line.slice(0, colonIdx);
|
|
129
|
+
let value = line.slice(colonIdx + 1);
|
|
130
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
131
|
+
|
|
132
|
+
if (field === "event") {
|
|
133
|
+
eventType = value;
|
|
134
|
+
} else if (field === "data") {
|
|
135
|
+
dataLines.push(value);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (dataLines.length === 0) return null;
|
|
140
|
+
const data = dataLines.join("\n");
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const parsed = JSON.parse(data) as { type?: string; properties?: unknown };
|
|
144
|
+
// Prefer the SSE `event:` line; fall back to JSON's `type` field.
|
|
145
|
+
if (eventType && parsed.type !== eventType) {
|
|
146
|
+
return { ...parsed, type: eventType };
|
|
147
|
+
}
|
|
148
|
+
return parsed;
|
|
149
|
+
} catch {
|
|
150
|
+
// Malformed JSON — skip this event rather than crash the stream.
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for @polderlabs/bizar-sdk.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { createBizarClient } from "./client.js";
|
|
6
|
+
export type {
|
|
7
|
+
BizarClient,
|
|
8
|
+
BizarClientConfig,
|
|
9
|
+
SessionsResource,
|
|
10
|
+
ProjectsResource,
|
|
11
|
+
PlansResource,
|
|
12
|
+
EventsResource,
|
|
13
|
+
HealthResource,
|
|
14
|
+
} from "./client.js";
|
|
15
|
+
|
|
16
|
+
export type { EventSubscription, EventSubscriptionOptions } from "./events.js";
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
isBizarError,
|
|
20
|
+
connectionErrorFrom,
|
|
21
|
+
dashboardErrorFrom,
|
|
22
|
+
apiErrorFrom,
|
|
23
|
+
} from "./errors.js";
|
|
24
|
+
export type {
|
|
25
|
+
BizarError,
|
|
26
|
+
PluginError,
|
|
27
|
+
DashboardError,
|
|
28
|
+
ConnectionError,
|
|
29
|
+
APIError,
|
|
30
|
+
} from "./errors.js";
|
|
31
|
+
|
|
32
|
+
export type {
|
|
33
|
+
// Session
|
|
34
|
+
Session,
|
|
35
|
+
SessionStatus,
|
|
36
|
+
SessionCreate,
|
|
37
|
+
SessionListQuery,
|
|
38
|
+
// Project
|
|
39
|
+
Project,
|
|
40
|
+
// Plan
|
|
41
|
+
Plan,
|
|
42
|
+
PlanStatus,
|
|
43
|
+
// Part
|
|
44
|
+
Part,
|
|
45
|
+
TextPart,
|
|
46
|
+
ToolCallPart,
|
|
47
|
+
ToolResultPart,
|
|
48
|
+
ReasoningPart,
|
|
49
|
+
// Event
|
|
50
|
+
DashboardEvent,
|
|
51
|
+
DashboardConnectedEvent,
|
|
52
|
+
SessionCreatedEvent,
|
|
53
|
+
SessionUpdatedEvent,
|
|
54
|
+
SessionIdleEvent,
|
|
55
|
+
SessionErrorEvent,
|
|
56
|
+
MessagePartUpdatedEvent,
|
|
57
|
+
ToolExecutedEvent,
|
|
58
|
+
PlanUpdatedEvent,
|
|
59
|
+
// Health
|
|
60
|
+
Health,
|
|
61
|
+
} from "./types.js";
|
|
62
|
+
|
|
63
|
+
export { SDK_VERSION } from "./version.js";
|