@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.
- package/README.md +72 -2
- 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 +249 -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 +424 -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 +499 -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 +1603 -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-git.test.mjs +138 -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/bin.mjs +43 -46
- package/cli/copy.mjs +3 -0
- package/cli/dev-link.mjs +17 -1
- package/cli/init.mjs +135 -1
- package/cli/install.mjs +10 -23
- package/cli/memory-constants.mjs +59 -0
- package/cli/memory.mjs +757 -0
- package/cli/service.mjs +5 -6
- package/config/skills/obsidian/SKILL.md +213 -65
- package/install.sh +48 -18
- 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 +1484 -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 +1127 -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/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 +548 -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,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options — plugin option validation, clamping, and secret-dir refusal.
|
|
3
|
+
*
|
|
4
|
+
* Spec requirements satisfied here:
|
|
5
|
+
* - §6.1 — plugin option shape (defaults listed below).
|
|
6
|
+
* - §6.2 — clamping rules. The plugin NEVER throws on bad config.
|
|
7
|
+
* - §6.3 — threshold/window constraint (`loopThresholdBlock <= loopWindowSize + 2`).
|
|
8
|
+
* - §6.4 — secret-directory refusal. The plugin refuses to start if `logDir`
|
|
9
|
+
* or `stateDir` resolves inside `~/.ssh/`, `~/.gnupg/`, `~/.aws/`, or
|
|
10
|
+
* `~/.kube/`. Matching uses the spec's exact algorithm: `path.resolve`
|
|
11
|
+
* on both sides, then test equality OR `startsWith(resolved + path.sep)`.
|
|
12
|
+
* The `+ path.sep` is critical — without it, `~/.ssh-foo` would falsely
|
|
13
|
+
* match the `~/.ssh` prefix.
|
|
14
|
+
* - §6.5 — environment-variable overrides (`BIZAR_DISABLE`,
|
|
15
|
+
* `BIZAR_DISABLE_LOOP`, `BIZAR_DISABLE_LOG`, `BIZAR_LOG_LEVEL`,
|
|
16
|
+
* `BIZAR_SERVE_PORT`, `BIZAR_MAX_CONCURRENT_INSTANCES`,
|
|
17
|
+
* `BIZAR_SERVE_DISABLE`, `BIZAR_BACKGROUND_TOOL_CALL_CAP`,
|
|
18
|
+
* `BIZAR_BACKGROUND_SKIP_PERMISSIONS`,
|
|
19
|
+
* `BIZAR_STALL_TIMEOUT_MS`, `BIZAR_THINKING_LOOP_TIMEOUT_MS`,
|
|
20
|
+
* `BIZAR_MAX_INTERVENTIONS`). Env vars are read once at init;
|
|
21
|
+
* mid-session changes are ignored.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import path from "node:path";
|
|
25
|
+
import os from "node:os";
|
|
26
|
+
|
|
27
|
+
/** Raw plugin options as they appear in `opencode.json` (before clamping). */
|
|
28
|
+
export interface RawOptions {
|
|
29
|
+
loopThresholdWarn?: unknown;
|
|
30
|
+
loopThresholdEscalate?: unknown;
|
|
31
|
+
loopThresholdBlock?: unknown;
|
|
32
|
+
loopWindowSize?: unknown;
|
|
33
|
+
logDir?: unknown;
|
|
34
|
+
stateDir?: unknown;
|
|
35
|
+
logRotationBytes?: unknown;
|
|
36
|
+
servePort?: unknown;
|
|
37
|
+
maxConcurrentInstances?: unknown;
|
|
38
|
+
serveDisabled?: unknown;
|
|
39
|
+
backgroundToolCallCap?: unknown;
|
|
40
|
+
backgroundSkipPermissions?: unknown;
|
|
41
|
+
httpTimeoutMs?: unknown;
|
|
42
|
+
// v0.3.0 — stall and thinking-loop protection
|
|
43
|
+
backgroundStallTimeoutMs?: unknown;
|
|
44
|
+
backgroundThinkingLoopTimeoutMs?: unknown;
|
|
45
|
+
backgroundMaxInterventions?: unknown;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Normalized options — the output of `normalizeOptions`. Every field has a
|
|
50
|
+
* safe, valid value. The loop guard and logger consume this shape.
|
|
51
|
+
*/
|
|
52
|
+
export interface NormalizedOptions {
|
|
53
|
+
loopThresholdWarn: number;
|
|
54
|
+
loopThresholdEscalate: number;
|
|
55
|
+
loopThresholdBlock: number;
|
|
56
|
+
loopWindowSize: number;
|
|
57
|
+
logDir: string;
|
|
58
|
+
stateDir: string;
|
|
59
|
+
logRotationBytes: number;
|
|
60
|
+
servePort: number;
|
|
61
|
+
maxConcurrentInstances: number;
|
|
62
|
+
serveDisabled: boolean;
|
|
63
|
+
backgroundToolCallCap: number;
|
|
64
|
+
backgroundSkipPermissions: boolean;
|
|
65
|
+
httpTimeoutMs: number;
|
|
66
|
+
// v0.3.0 — stall and thinking-loop protection
|
|
67
|
+
/** ms without any SSE event before a non-terminal instance is aborted as stalled (default 180000 = 3 min, range [10000, 600000]). */
|
|
68
|
+
backgroundStallTimeoutMs: number;
|
|
69
|
+
/** ms without any tool/text part before a `running` instance is flagged as a thinking loop (default 300000 = 5 min, range [30000, 900000]). */
|
|
70
|
+
backgroundThinkingLoopTimeoutMs: number;
|
|
71
|
+
/** max number of research interventions sent before forcing an abort (default 1, range [1, 3]). */
|
|
72
|
+
backgroundMaxInterventions: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Environment-variable override flags. */
|
|
76
|
+
export interface EnvFlags {
|
|
77
|
+
disable: boolean;
|
|
78
|
+
disableLoop: boolean;
|
|
79
|
+
disableLog: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Default values per spec §6.1 / §8. */
|
|
83
|
+
export const DEFAULT_OPTIONS: NormalizedOptions = {
|
|
84
|
+
loopThresholdWarn: 5,
|
|
85
|
+
loopThresholdEscalate: 8,
|
|
86
|
+
loopThresholdBlock: 12,
|
|
87
|
+
loopWindowSize: 10,
|
|
88
|
+
logDir: "~/.cache/bizar/logs",
|
|
89
|
+
stateDir: "~/.cache/bizar",
|
|
90
|
+
logRotationBytes: 10_485_760, // 10 MB
|
|
91
|
+
servePort: 0, // 0 = random OS-assigned port (§1.1)
|
|
92
|
+
maxConcurrentInstances: 8, // §8
|
|
93
|
+
serveDisabled: false, // §8
|
|
94
|
+
backgroundToolCallCap: 500, // §8 / §6.2
|
|
95
|
+
backgroundSkipPermissions: false, // §8 / §6.4
|
|
96
|
+
httpTimeoutMs: 30_000, // §2.3 / §8
|
|
97
|
+
// v0.3.0 — stall and thinking-loop protection
|
|
98
|
+
backgroundStallTimeoutMs: 180_000, // 3 min
|
|
99
|
+
backgroundThinkingLoopTimeoutMs: 300_000, // 5 min
|
|
100
|
+
backgroundMaxInterventions: 1,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const SECRET_DIRS: readonly string[] = [
|
|
104
|
+
"~/.ssh",
|
|
105
|
+
"~/.gnupg",
|
|
106
|
+
"~/.aws",
|
|
107
|
+
"~/.kube",
|
|
108
|
+
] as const;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Expand a leading `~` to the user's home directory. The spec's default
|
|
112
|
+
* paths use `~/.cache/bizar`; we honor that.
|
|
113
|
+
*/
|
|
114
|
+
export function expandHome(p: string): string {
|
|
115
|
+
if (p === "~") return os.homedir();
|
|
116
|
+
if (p.startsWith("~/") || p.startsWith("~\\")) {
|
|
117
|
+
return path.join(os.homedir(), p.slice(2));
|
|
118
|
+
}
|
|
119
|
+
return p;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Spec §6.4 matching algorithm. Returns the secret-dir kind that `target`
|
|
124
|
+
* matches (e.g. `~/.ssh`), or `null` if `target` is safe.
|
|
125
|
+
*
|
|
126
|
+
* resolvedTarget === resolvedSecret → equal
|
|
127
|
+
* resolvedTarget.startsWith(resolvedSecret + sep) → strict descendant
|
|
128
|
+
*/
|
|
129
|
+
export function findSecretDirMatch(target: string): string | null {
|
|
130
|
+
const resolvedTarget = path.resolve(expandHome(target));
|
|
131
|
+
for (const secret of SECRET_DIRS) {
|
|
132
|
+
const resolvedSecret = path.resolve(expandHome(secret));
|
|
133
|
+
if (resolvedTarget === resolvedSecret) return secret;
|
|
134
|
+
if (resolvedTarget.startsWith(resolvedSecret + path.sep)) return secret;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Coerce an unknown value to a finite integer, or return `undefined`. */
|
|
140
|
+
function toFiniteInt(value: unknown): number | undefined {
|
|
141
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
142
|
+
return Math.floor(value);
|
|
143
|
+
}
|
|
144
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
145
|
+
const n = Number(value);
|
|
146
|
+
if (Number.isFinite(n)) return Math.floor(n);
|
|
147
|
+
}
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Coerce to a string path; return `undefined` if the value is not a string. */
|
|
152
|
+
function toStringPath(value: unknown): string | undefined {
|
|
153
|
+
if (typeof value === "string" && value !== "") return value;
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Apply the clamping rules from spec §6.2. Returns the normalized options
|
|
159
|
+
* and a list of "clamp notes" — human-readable strings describing each
|
|
160
|
+
* non-default normalization applied. The caller is expected to log these
|
|
161
|
+
* via `client.app.log` at warn level (spec §6.2: "After clamping, log a
|
|
162
|
+
* `client.app.log` warning if any non-default normalization was applied").
|
|
163
|
+
*/
|
|
164
|
+
export function normalizeOptions(raw: RawOptions | undefined): {
|
|
165
|
+
options: NormalizedOptions;
|
|
166
|
+
notes: string[];
|
|
167
|
+
} {
|
|
168
|
+
const notes: string[] = [];
|
|
169
|
+
const r = raw ?? {};
|
|
170
|
+
|
|
171
|
+
// --- Numeric thresholds (§6.2) ---
|
|
172
|
+
const rawWarn = toFiniteInt(r.loopThresholdWarn);
|
|
173
|
+
const rawEscalate = toFiniteInt(r.loopThresholdEscalate);
|
|
174
|
+
const rawBlock = toFiniteInt(r.loopThresholdBlock);
|
|
175
|
+
|
|
176
|
+
let warn = rawWarn !== undefined ? Math.max(1, rawWarn) : DEFAULT_OPTIONS.loopThresholdWarn;
|
|
177
|
+
let escalate = rawEscalate !== undefined ? Math.max(1, rawEscalate) : DEFAULT_OPTIONS.loopThresholdEscalate;
|
|
178
|
+
let block = rawBlock !== undefined ? Math.max(1, rawBlock) : DEFAULT_OPTIONS.loopThresholdBlock;
|
|
179
|
+
|
|
180
|
+
if (rawWarn !== undefined && rawWarn < 1) {
|
|
181
|
+
notes.push(`loopThresholdWarn ${rawWarn} clamped to 1`);
|
|
182
|
+
} else if (rawWarn === undefined) {
|
|
183
|
+
notes.push(`loopThresholdWarn defaulted to ${warn}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// --- Ordering: warn < escalate < block (§6.2) ---
|
|
187
|
+
if (warn >= escalate) {
|
|
188
|
+
const newEscalate = warn + 1;
|
|
189
|
+
notes.push(`loopThresholdEscalate adjusted from ${escalate} to ${newEscalate} (must be > loopThresholdWarn)`);
|
|
190
|
+
escalate = newEscalate;
|
|
191
|
+
}
|
|
192
|
+
if (escalate >= block) {
|
|
193
|
+
const newBlock = escalate + 1;
|
|
194
|
+
notes.push(`loopThresholdBlock adjusted from ${block} to ${newBlock} (must be > loopThresholdEscalate)`);
|
|
195
|
+
block = newBlock;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// --- Window size (§6.2: clamped to [3, 50]) ---
|
|
199
|
+
const rawWindow = toFiniteInt(r.loopWindowSize);
|
|
200
|
+
let window: number;
|
|
201
|
+
if (rawWindow === undefined) {
|
|
202
|
+
window = DEFAULT_OPTIONS.loopWindowSize;
|
|
203
|
+
} else if (rawWindow < 3) {
|
|
204
|
+
window = 3;
|
|
205
|
+
notes.push(`loopWindowSize ${rawWindow} clamped to 3 (minimum)`);
|
|
206
|
+
} else if (rawWindow > 50) {
|
|
207
|
+
window = 50;
|
|
208
|
+
notes.push(`loopWindowSize ${rawWindow} clamped to 50 (maximum)`);
|
|
209
|
+
} else {
|
|
210
|
+
window = rawWindow;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// --- Threshold/window constraint (§6.3) ---
|
|
214
|
+
if (block > window + 2) {
|
|
215
|
+
const newBlock = window + 2;
|
|
216
|
+
notes.push(
|
|
217
|
+
`loopThresholdBlock ${block} adjusted to ${newBlock} (must be <= loopWindowSize + 2)`,
|
|
218
|
+
);
|
|
219
|
+
block = newBlock;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// --- logRotationBytes (§6.2: minimum 1024) ---
|
|
223
|
+
const rawBytes = toFiniteInt(r.logRotationBytes);
|
|
224
|
+
let bytes: number;
|
|
225
|
+
if (rawBytes === undefined) {
|
|
226
|
+
bytes = DEFAULT_OPTIONS.logRotationBytes;
|
|
227
|
+
} else if (rawBytes < 1024) {
|
|
228
|
+
bytes = 1024;
|
|
229
|
+
notes.push(`logRotationBytes ${rawBytes} clamped to 1024 (minimum)`);
|
|
230
|
+
} else {
|
|
231
|
+
bytes = rawBytes;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// --- Background agent options (§6.5 / §8) ---
|
|
235
|
+
// servePort: default 0 (random); env BIZAR_SERVE_PORT overrides
|
|
236
|
+
const rawServePort = toFiniteInt(r.servePort);
|
|
237
|
+
const envServePort = toFiniteInt(process.env.BIZAR_SERVE_PORT);
|
|
238
|
+
const servePort = rawServePort !== undefined
|
|
239
|
+
? (rawServePort < 0 ? (notes.push(`servePort ${rawServePort} clamped to 0 (minimum)`), 0) : rawServePort)
|
|
240
|
+
: envServePort !== undefined
|
|
241
|
+
? envServePort
|
|
242
|
+
: DEFAULT_OPTIONS.servePort;
|
|
243
|
+
|
|
244
|
+
// maxConcurrentInstances: default 8, max 32 (§6.5)
|
|
245
|
+
const rawMaxInstances = toFiniteInt(r.maxConcurrentInstances);
|
|
246
|
+
const envMaxInstances = toFiniteInt(process.env.BIZAR_MAX_CONCURRENT_INSTANCES);
|
|
247
|
+
let maxConcurrentInstances: number;
|
|
248
|
+
if (rawMaxInstances !== undefined) {
|
|
249
|
+
maxConcurrentInstances = Math.min(Math.max(1, rawMaxInstances), 32);
|
|
250
|
+
if (rawMaxInstances !== maxConcurrentInstances) {
|
|
251
|
+
notes.push(`maxConcurrentInstances ${rawMaxInstances} clamped to ${maxConcurrentInstances} (range [1, 32])`);
|
|
252
|
+
}
|
|
253
|
+
} else if (envMaxInstances !== undefined) {
|
|
254
|
+
maxConcurrentInstances = Math.min(Math.max(1, envMaxInstances), 32);
|
|
255
|
+
if (envMaxInstances !== maxConcurrentInstances) {
|
|
256
|
+
notes.push(`maxConcurrentInstances ${envMaxInstances} (env) clamped to ${maxConcurrentInstances} (range [1, 32])`);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
maxConcurrentInstances = DEFAULT_OPTIONS.maxConcurrentInstances;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// serveDisabled: default false; env BIZAR_SERVE_DISABLE=1 sets true (§8)
|
|
263
|
+
const serveDisabled = process.env.BIZAR_SERVE_DISABLE === "1"
|
|
264
|
+
? true
|
|
265
|
+
: (r.serveDisabled === true || r.serveDisabled === "true");
|
|
266
|
+
|
|
267
|
+
// backgroundToolCallCap: default 500, max 5000 (§6.5)
|
|
268
|
+
const rawToolCap = toFiniteInt(r.backgroundToolCallCap);
|
|
269
|
+
const envToolCap = toFiniteInt(process.env.BIZAR_BACKGROUND_TOOL_CALL_CAP);
|
|
270
|
+
let backgroundToolCallCap: number;
|
|
271
|
+
if (rawToolCap !== undefined) {
|
|
272
|
+
backgroundToolCallCap = Math.min(Math.max(1, rawToolCap), 5000);
|
|
273
|
+
if (rawToolCap !== backgroundToolCallCap) {
|
|
274
|
+
notes.push(`backgroundToolCallCap ${rawToolCap} clamped to ${backgroundToolCallCap} (range [1, 5000])`);
|
|
275
|
+
}
|
|
276
|
+
} else if (envToolCap !== undefined) {
|
|
277
|
+
backgroundToolCallCap = Math.min(Math.max(1, envToolCap), 5000);
|
|
278
|
+
if (envToolCap !== backgroundToolCallCap) {
|
|
279
|
+
notes.push(`backgroundToolCallCap ${envToolCap} (env) clamped to ${backgroundToolCallCap} (range [1, 5000])`);
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
backgroundToolCallCap = DEFAULT_OPTIONS.backgroundToolCallCap;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// backgroundSkipPermissions: default false; env BIZAR_BACKGROUND_SKIP_PERMISSIONS=1 sets true (§6.4)
|
|
286
|
+
const backgroundSkipPermissions = process.env.BIZAR_BACKGROUND_SKIP_PERMISSIONS === "1"
|
|
287
|
+
? true
|
|
288
|
+
: (r.backgroundSkipPermissions === true || r.backgroundSkipPermissions === "true");
|
|
289
|
+
|
|
290
|
+
// httpTimeoutMs: default 30000, range [5000, 120000] (§2.3)
|
|
291
|
+
const rawHttpTimeout = toFiniteInt(r.httpTimeoutMs);
|
|
292
|
+
const envHttpTimeout = toFiniteInt(process.env.BIZAR_HTTP_TIMEOUT_MS);
|
|
293
|
+
let httpTimeoutMs: number;
|
|
294
|
+
if (rawHttpTimeout !== undefined) {
|
|
295
|
+
httpTimeoutMs = Math.min(Math.max(5000, rawHttpTimeout), 120_000);
|
|
296
|
+
if (rawHttpTimeout !== httpTimeoutMs) {
|
|
297
|
+
notes.push(`httpTimeoutMs ${rawHttpTimeout} clamped to ${httpTimeoutMs} (range [5000, 120000])`);
|
|
298
|
+
}
|
|
299
|
+
} else if (envHttpTimeout !== undefined) {
|
|
300
|
+
httpTimeoutMs = Math.min(Math.max(5000, envHttpTimeout), 120_000);
|
|
301
|
+
if (envHttpTimeout !== httpTimeoutMs) {
|
|
302
|
+
notes.push(`httpTimeoutMs ${envHttpTimeout} (env) clamped to ${httpTimeoutMs} (range [5000, 120000])`);
|
|
303
|
+
}
|
|
304
|
+
} else {
|
|
305
|
+
httpTimeoutMs = DEFAULT_OPTIONS.httpTimeoutMs;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// --- v0.3.0 stall and thinking-loop protection -------------------------
|
|
309
|
+
|
|
310
|
+
// backgroundStallTimeoutMs: default 180000, range [10000, 600000] (10s..10min)
|
|
311
|
+
const rawStallTimeout = toFiniteInt(r.backgroundStallTimeoutMs);
|
|
312
|
+
const envStallTimeout = toFiniteInt(process.env.BIZAR_STALL_TIMEOUT_MS);
|
|
313
|
+
let backgroundStallTimeoutMs: number;
|
|
314
|
+
if (rawStallTimeout !== undefined) {
|
|
315
|
+
backgroundStallTimeoutMs = Math.min(Math.max(10_000, rawStallTimeout), 600_000);
|
|
316
|
+
if (rawStallTimeout !== backgroundStallTimeoutMs) {
|
|
317
|
+
notes.push(`backgroundStallTimeoutMs ${rawStallTimeout} clamped to ${backgroundStallTimeoutMs} (range [10000, 600000])`);
|
|
318
|
+
}
|
|
319
|
+
} else if (envStallTimeout !== undefined) {
|
|
320
|
+
backgroundStallTimeoutMs = Math.min(Math.max(10_000, envStallTimeout), 600_000);
|
|
321
|
+
if (envStallTimeout !== backgroundStallTimeoutMs) {
|
|
322
|
+
notes.push(`backgroundStallTimeoutMs ${envStallTimeout} (env) clamped to ${backgroundStallTimeoutMs} (range [10000, 600000])`);
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
backgroundStallTimeoutMs = DEFAULT_OPTIONS.backgroundStallTimeoutMs;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// backgroundThinkingLoopTimeoutMs: default 300000, range [30000, 900000] (30s..15min)
|
|
329
|
+
const rawThinkingTimeout = toFiniteInt(r.backgroundThinkingLoopTimeoutMs);
|
|
330
|
+
const envThinkingTimeout = toFiniteInt(process.env.BIZAR_THINKING_LOOP_TIMEOUT_MS);
|
|
331
|
+
let backgroundThinkingLoopTimeoutMs: number;
|
|
332
|
+
if (rawThinkingTimeout !== undefined) {
|
|
333
|
+
backgroundThinkingLoopTimeoutMs = Math.min(Math.max(30_000, rawThinkingTimeout), 900_000);
|
|
334
|
+
if (rawThinkingTimeout !== backgroundThinkingLoopTimeoutMs) {
|
|
335
|
+
notes.push(`backgroundThinkingLoopTimeoutMs ${rawThinkingTimeout} clamped to ${backgroundThinkingLoopTimeoutMs} (range [30000, 900000])`);
|
|
336
|
+
}
|
|
337
|
+
} else if (envThinkingTimeout !== undefined) {
|
|
338
|
+
backgroundThinkingLoopTimeoutMs = Math.min(Math.max(30_000, envThinkingTimeout), 900_000);
|
|
339
|
+
if (envThinkingTimeout !== backgroundThinkingLoopTimeoutMs) {
|
|
340
|
+
notes.push(`backgroundThinkingLoopTimeoutMs ${envThinkingTimeout} (env) clamped to ${backgroundThinkingLoopTimeoutMs} (range [30000, 900000])`);
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
backgroundThinkingLoopTimeoutMs = DEFAULT_OPTIONS.backgroundThinkingLoopTimeoutMs;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// backgroundMaxInterventions: default 1, range [1, 3]
|
|
347
|
+
const rawMaxInterventions = toFiniteInt(r.backgroundMaxInterventions);
|
|
348
|
+
const envMaxInterventions = toFiniteInt(process.env.BIZAR_MAX_INTERVENTIONS);
|
|
349
|
+
let backgroundMaxInterventions: number;
|
|
350
|
+
if (rawMaxInterventions !== undefined) {
|
|
351
|
+
backgroundMaxInterventions = Math.min(Math.max(1, rawMaxInterventions), 3);
|
|
352
|
+
if (rawMaxInterventions !== backgroundMaxInterventions) {
|
|
353
|
+
notes.push(`backgroundMaxInterventions ${rawMaxInterventions} clamped to ${backgroundMaxInterventions} (range [1, 3])`);
|
|
354
|
+
}
|
|
355
|
+
} else if (envMaxInterventions !== undefined) {
|
|
356
|
+
backgroundMaxInterventions = Math.min(Math.max(1, envMaxInterventions), 3);
|
|
357
|
+
if (envMaxInterventions !== backgroundMaxInterventions) {
|
|
358
|
+
notes.push(`backgroundMaxInterventions ${envMaxInterventions} (env) clamped to ${backgroundMaxInterventions} (range [1, 3])`);
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
backgroundMaxInterventions = DEFAULT_OPTIONS.backgroundMaxInterventions;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// --- Paths (§6.1 defaults) ---
|
|
365
|
+
const logDir = toStringPath(r.logDir) ?? DEFAULT_OPTIONS.logDir;
|
|
366
|
+
const stateDir = toStringPath(r.stateDir) ?? DEFAULT_OPTIONS.stateDir;
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
options: {
|
|
370
|
+
loopThresholdWarn: warn,
|
|
371
|
+
loopThresholdEscalate: escalate,
|
|
372
|
+
loopThresholdBlock: block,
|
|
373
|
+
loopWindowSize: window,
|
|
374
|
+
logDir,
|
|
375
|
+
stateDir,
|
|
376
|
+
logRotationBytes: bytes,
|
|
377
|
+
servePort,
|
|
378
|
+
maxConcurrentInstances,
|
|
379
|
+
serveDisabled,
|
|
380
|
+
backgroundToolCallCap,
|
|
381
|
+
backgroundSkipPermissions,
|
|
382
|
+
httpTimeoutMs,
|
|
383
|
+
backgroundStallTimeoutMs,
|
|
384
|
+
backgroundThinkingLoopTimeoutMs,
|
|
385
|
+
backgroundMaxInterventions,
|
|
386
|
+
},
|
|
387
|
+
notes,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Read environment-variable override flags per spec §6.5. Read once at
|
|
393
|
+
* plugin init. Mid-session changes are ignored.
|
|
394
|
+
*/
|
|
395
|
+
export function readEnvFlags(): EnvFlags {
|
|
396
|
+
return {
|
|
397
|
+
disable: process.env.BIZAR_DISABLE === "1",
|
|
398
|
+
disableLoop: process.env.BIZAR_DISABLE_LOOP === "1",
|
|
399
|
+
disableLog: process.env.BIZAR_DISABLE_LOG === "1",
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Spec §6.4: refuse to start if `logDir` or `stateDir` is inside a secret
|
|
405
|
+
* directory. Returns the offending path and the matched secret kind, or
|
|
406
|
+
* `null` if both paths are safe.
|
|
407
|
+
*/
|
|
408
|
+
export function findOffendingPath(options: NormalizedOptions): {
|
|
409
|
+
path: string;
|
|
410
|
+
kind: string;
|
|
411
|
+
} | null {
|
|
412
|
+
const logMatch = findSecretDirMatch(options.logDir);
|
|
413
|
+
if (logMatch !== null) {
|
|
414
|
+
return { path: path.resolve(expandHome(options.logDir)), kind: logMatch };
|
|
415
|
+
}
|
|
416
|
+
const stateMatch = findSecretDirMatch(options.stateDir);
|
|
417
|
+
if (stateMatch !== null) {
|
|
418
|
+
return { path: path.resolve(expandHome(options.stateDir)), kind: stateMatch };
|
|
419
|
+
}
|
|
420
|
+
return null;
|
|
421
|
+
}
|