bosun 0.42.5 → 0.43.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/.env.example +36 -51
- package/README.md +19 -3
- package/agent/agent-custom-tools.mjs +138 -26
- package/agent/agent-endpoint.mjs +1 -2
- package/agent/agent-event-bus.mjs +33 -2
- package/agent/agent-hooks.mjs +1 -1
- package/agent/agent-launcher.mjs +6210 -0
- package/agent/agent-pool.mjs +7 -4018
- package/agent/agent-prompt-catalog.mjs +5 -6
- package/agent/agent-prompts.mjs +62 -6
- package/agent/agent-sdk.mjs +130 -0
- package/agent/agent-supervisor.mjs +30 -6
- package/agent/auth/_shared.mjs +129 -0
- package/agent/auth/anthropic-api-key.mjs +13 -0
- package/agent/auth/azure-openai.mjs +17 -0
- package/agent/auth/cerebras.mjs +14 -0
- package/agent/auth/chatgpt-codex-subscription.mjs +15 -0
- package/agent/auth/claude-subscription.mjs +15 -0
- package/agent/auth/copilot-oauth.mjs +13 -0
- package/agent/auth/deepinfra.mjs +14 -0
- package/agent/auth/fireworks.mjs +14 -0
- package/agent/auth/gemini-api-key.mjs +14 -0
- package/agent/auth/groq.mjs +14 -0
- package/agent/auth/index.mjs +85 -0
- package/agent/auth/nebius.mjs +14 -0
- package/agent/auth/ollama.mjs +14 -0
- package/agent/auth/openai-api-key.mjs +13 -0
- package/agent/auth/openai-compatible.mjs +15 -0
- package/agent/auth/openrouter.mjs +14 -0
- package/agent/auth/perplexity.mjs +14 -0
- package/agent/auth/sambanova.mjs +14 -0
- package/agent/auth/together.mjs +14 -0
- package/agent/auth/xai.mjs +14 -0
- package/agent/autofix-prompts.mjs +2 -2
- package/agent/autofix.mjs +2 -2
- package/agent/bosun-skills.mjs +215 -86
- package/agent/fleet-coordinator.mjs +161 -32
- package/agent/harness/agent-loop.mjs +26 -0
- package/agent/harness/event-contract.mjs +125 -0
- package/agent/harness/followup-queue.mjs +33 -0
- package/agent/harness/message-normalizer.mjs +43 -0
- package/agent/harness/module-boundaries.md +73 -0
- package/agent/harness/run-contract.mjs +122 -0
- package/agent/harness/runtime-config.mjs +132 -0
- package/agent/harness/session-state.mjs +80 -0
- package/agent/harness/steering-queue.mjs +35 -0
- package/agent/harness/tool-runner.mjs +95 -0
- package/agent/harness/turn-runner.mjs +135 -0
- package/agent/harness-agent-service.mjs +852 -0
- package/agent/harness-executor-config.mjs +384 -0
- package/agent/hook-library.mjs +141 -2
- package/agent/hook-profiles.mjs +15 -2
- package/agent/internal-harness-control-plane.mjs +672 -0
- package/agent/internal-harness-profile.mjs +519 -0
- package/agent/internal-harness-runtime.mjs +1219 -0
- package/agent/lineage-graph.mjs +141 -0
- package/agent/primary-agent.mjs +602 -706
- package/agent/provider-auth-manager.mjs +830 -0
- package/agent/provider-auth-state.mjs +440 -0
- package/agent/provider-capabilities.mjs +116 -0
- package/agent/provider-kernel.mjs +596 -0
- package/agent/provider-message-transform.mjs +583 -0
- package/agent/provider-model-catalog.mjs +163 -0
- package/agent/provider-registry.mjs +657 -0
- package/agent/provider-runtime-discovery.mjs +147 -0
- package/agent/provider-session.mjs +767 -0
- package/agent/providers/_shared.mjs +397 -0
- package/agent/providers/anthropic-messages.mjs +64 -0
- package/agent/providers/azure-openai-responses.mjs +69 -0
- package/agent/providers/cerebras.mjs +66 -0
- package/agent/providers/claude-subscription-shim.mjs +68 -0
- package/agent/providers/copilot-oauth.mjs +66 -0
- package/agent/providers/deepinfra.mjs +66 -0
- package/agent/providers/fireworks.mjs +66 -0
- package/agent/providers/gemini-generate-content.mjs +66 -0
- package/agent/providers/groq.mjs +66 -0
- package/agent/providers/index.mjs +208 -0
- package/agent/providers/nebius.mjs +66 -0
- package/agent/providers/ollama.mjs +66 -0
- package/agent/providers/openai-codex-subscription.mjs +75 -0
- package/agent/providers/openai-compatible.mjs +65 -0
- package/agent/providers/openai-responses.mjs +67 -0
- package/agent/providers/openrouter.mjs +66 -0
- package/agent/providers/perplexity.mjs +66 -0
- package/agent/providers/provider-contract.mjs +138 -0
- package/agent/providers/provider-errors.mjs +63 -0
- package/agent/providers/provider-model-pricing.mjs +246 -0
- package/agent/providers/provider-stream-normalizer.mjs +7 -0
- package/agent/providers/provider-usage-normalizer.mjs +48 -0
- package/agent/providers/sambanova.mjs +66 -0
- package/agent/providers/together.mjs +66 -0
- package/agent/providers/xai.mjs +66 -0
- package/agent/query-engine.mjs +260 -0
- package/agent/retry-queue.mjs +1 -0
- package/agent/review-agent.mjs +1 -1
- package/agent/session-contract.mjs +127 -0
- package/agent/session-manager.mjs +1859 -0
- package/agent/session-replay.mjs +617 -0
- package/agent/session-snapshot-store.mjs +379 -0
- package/agent/skills/agent-coordination.md +6 -0
- package/agent/skills/background-task-execution.md +6 -0
- package/agent/skills/bosun-agent-api.md +6 -0
- package/agent/skills/code-quality-anti-patterns.md +7 -0
- package/agent/skills/commit-conventions.md +6 -0
- package/agent/skills/custom-tool-creation.md +6 -0
- package/agent/skills/error-recovery.md +6 -0
- package/agent/skills/pr-workflow.md +6 -0
- package/agent/skills/tdd-pattern.md +6 -0
- package/agent/subagent-contract.mjs +104 -0
- package/agent/subagent-control.mjs +633 -0
- package/agent/subagent-pool.mjs +260 -0
- package/agent/thread-contract.mjs +88 -0
- package/agent/thread-registry.mjs +552 -0
- package/agent/tool-approval-manager.mjs +259 -0
- package/agent/tool-builtin-catalog.mjs +855 -0
- package/agent/tool-contract.mjs +101 -0
- package/agent/tool-event-contract.mjs +99 -0
- package/agent/tool-execution-ledger.mjs +32 -0
- package/agent/tool-network-policy.mjs +86 -0
- package/agent/tool-orchestrator.mjs +382 -0
- package/agent/tool-output-truncation.mjs +70 -0
- package/agent/tool-registry.mjs +200 -0
- package/agent/tool-retry-policy.mjs +57 -0
- package/agent/tool-runtime-context.mjs +220 -0
- package/bench/harness-load-bench.mjs +281 -0
- package/bench/harness-parity-bench.mjs +214 -0
- package/bench/swebench/bosun-swebench.mjs +21 -6
- package/bosun-tui.mjs +59 -13
- package/bosun.config.example.json +55 -2
- package/bosun.schema.json +598 -5
- package/cli.mjs +656 -160
- package/config/config-doctor.mjs +80 -26
- package/config/config-editor.mjs +417 -0
- package/config/config.mjs +489 -144
- package/config/repo-config.mjs +125 -49
- package/config/repo-root.mjs +33 -1
- package/desktop/main.mjs +554 -115
- package/desktop/package.json +1 -1
- package/git/diff-stats.mjs +7 -5
- package/git/git-editor-fix.mjs +2 -42
- package/github/github-app-auth.mjs +6 -0
- package/github/github-oauth-portal.mjs +20 -0
- package/infra/anomaly-detector.mjs +122 -22
- package/infra/approval-projection-store.mjs +75 -0
- package/infra/config-reload-bus.mjs +33 -0
- package/infra/container-runner.mjs +37 -4
- package/infra/error-detector.mjs +110 -35
- package/infra/event-schema.mjs +353 -0
- package/infra/guardrails.mjs +383 -0
- package/infra/heartbeat-monitor.mjs +432 -0
- package/infra/library-manager.mjs +367 -19
- package/infra/live-event-projector.mjs +197 -0
- package/infra/maintenance.mjs +202 -51
- package/infra/monitor.mjs +1749 -2027
- package/infra/preflight.mjs +107 -6
- package/infra/presence.mjs +33 -9
- package/infra/projection-contract.mjs +27 -0
- package/infra/provider-usage-ledger.mjs +73 -0
- package/infra/replay-reader.mjs +140 -0
- package/infra/runtime-accumulator.mjs +303 -8
- package/infra/runtime-metrics.mjs +156 -0
- package/infra/session-projection-store.mjs +169 -0
- package/infra/session-telemetry-runtime.mjs +580 -0
- package/infra/session-telemetry.mjs +338 -0
- package/infra/session-tracker.mjs +1613 -228
- package/infra/startup-service.mjs +0 -2
- package/infra/storage-janitor.mjs +1046 -0
- package/infra/subagent-projection-store.mjs +89 -0
- package/infra/test-runtime.mjs +53 -20
- package/infra/trace-export.mjs +103 -0
- package/infra/tui-bridge.mjs +607 -5
- package/infra/update-check.mjs +7 -8
- package/infra/windows-hidden-child-processes.mjs +99 -0
- package/infra/worktree-recovery-state.mjs +20 -7
- package/kanban/kanban-adapter.mjs +702 -310
- package/kanban/repo-mirror-projection-store.mjs +871 -0
- package/lib/agent-configuration-guide.mjs +280 -0
- package/lib/hot-path-runtime.mjs +1061 -0
- package/lib/integrations-registry.mjs +294 -0
- package/lib/log-tail.mjs +101 -0
- package/lib/logger.mjs +21 -25
- package/lib/mojibake-repair.mjs +40 -0
- package/lib/repo-map.mjs +137 -24
- package/lib/request-json-api.mjs +59 -0
- package/lib/safe-box.mjs +56 -0
- package/lib/session-insights.mjs +3 -1
- package/lib/skill-markdown-safety.mjs +394 -0
- package/lib/state-ledger-sqlite.mjs +4462 -0
- package/lib/vault-keychain.mjs +259 -0
- package/lib/vault.mjs +374 -0
- package/lib/workflow-flowchart-utils.mjs +326 -0
- package/monitor-tail-sanitizer.mjs +1 -2
- package/native/bosun-telemetry/Cargo.toml +9 -0
- package/native/bosun-telemetry/src/export.rs +151 -0
- package/native/bosun-telemetry/src/main.rs +76 -0
- package/native/bosun-telemetry/src/metrics.rs +114 -0
- package/native/bosun-telemetry/src/session_telemetry.rs +178 -0
- package/native/bosun-unified-exec/Cargo.lock +107 -0
- package/native/bosun-unified-exec/Cargo.toml +8 -0
- package/native/bosun-unified-exec/src/async_watcher.rs +145 -0
- package/native/bosun-unified-exec/src/head_tail_buffer.rs +241 -0
- package/native/bosun-unified-exec/src/main.rs +86 -0
- package/native/bosun-unified-exec/src/process_manager.rs +308 -0
- package/native/bosun-unified-exec/src/tool_orchestrator.rs +187 -0
- package/package.json +230 -59
- package/postinstall.mjs +182 -13
- package/server/bosun-mcp-server.mjs +348 -10
- package/server/routes/harness-agent-bridge.mjs +128 -0
- package/server/routes/harness-approvals.mjs +290 -0
- package/server/routes/harness-events.mjs +469 -0
- package/server/routes/harness-providers.mjs +385 -0
- package/server/routes/harness-sessions.mjs +2230 -0
- package/server/routes/harness-subagents.mjs +138 -0
- package/server/routes/harness-surface-payload.mjs +74 -0
- package/server/setup-web-server.mjs +468 -39
- package/server/ui-server.mjs +13041 -4418
- package/setup.mjs +206 -298
- package/shared-workspaces.json +1 -1
- package/shell/anthropic-native-adapter.mjs +1218 -0
- package/shell/auth-resolver.mjs +247 -0
- package/shell/claude-shell.mjs +85 -2
- package/shell/codex-config-file.mjs +9 -0
- package/shell/codex-config.mjs +192 -249
- package/shell/codex-model-profiles.mjs +76 -12
- package/shell/codex-sdk-import.mjs +7 -0
- package/shell/codex-shell.mjs +708 -170
- package/shell/context-compaction.mjs +898 -0
- package/shell/copilot-shell.mjs +359 -109
- package/shell/gemini-native-adapter.mjs +411 -0
- package/shell/gemini-shell.mjs +121 -13
- package/shell/mcp-client.mjs +401 -0
- package/shell/mcp-registry.mjs +72 -0
- package/shell/message-pruner.mjs +248 -0
- package/shell/openai-native-adapter.mjs +1975 -0
- package/shell/opencode-providers.mjs +16 -531
- package/shell/opencode-shell.mjs +180 -9
- package/shell/provider-transform.mjs +386 -0
- package/shell/pwsh-runtime.mjs +9 -2
- package/shell/retry-fetch.mjs +244 -0
- package/shell/session-resume.mjs +97 -0
- package/shell/session-store.mjs +215 -0
- package/shell/shell-adapter-registry.mjs +346 -0
- package/shell/shell-session-compat.mjs +442 -0
- package/shell/smooth-stream.mjs +233 -0
- package/shell/stop-condition.mjs +238 -0
- package/shell/tool-call-repair.mjs +345 -0
- package/shell/tool-executor.mjs +571 -0
- package/task/pipeline.mjs +3 -1
- package/task/task-assessment.mjs +312 -6
- package/task/task-claims.mjs +312 -48
- package/task/task-cli.mjs +90 -14
- package/task/task-complexity.mjs +6 -6
- package/task/task-context.mjs +37 -0
- package/task/task-debt-ledger.mjs +110 -0
- package/task/task-executor.mjs +1104 -119
- package/task/task-replanner.mjs +553 -0
- package/task/task-simulate-cli.mjs +1481 -0
- package/task/task-store.mjs +996 -68
- package/telegram/executor-health-region-cache.mjs +75 -0
- package/telegram/get-telegram-chat-id.mjs +0 -0
- package/telegram/harness-api-client.mjs +124 -0
- package/telegram/sticky-menu-state.mjs +384 -0
- package/telegram/telegram-bot.mjs +548 -865
- package/telegram/telegram-sentinel.mjs +25 -14
- package/telegram/telegram-surface-runtime.mjs +53 -0
- package/tools/generate-demo-defaults.mjs +23 -4
- package/tools/harness-hotpath-bench.mjs +246 -0
- package/tools/import-check.mjs +279 -234
- package/tools/install-git-hooks.mjs +96 -20
- package/tools/native-rust.mjs +124 -0
- package/tools/packed-cli-smoke.mjs +147 -0
- package/tools/prepublish-check.mjs +53 -1
- package/tools/run-workflow-guaranteed-suite.mjs +56 -0
- package/tools/site-serve.mjs +112 -0
- package/tools/sync-demo-ui.mjs +188 -0
- package/tools/syntax-check.mjs +32 -28
- package/tools/test-kanban-enhancement.mjs +7 -7
- package/tools/test-shared-state-integration.mjs +5 -19
- package/tools/vite-windows-realpath-shim.mjs +274 -0
- package/tools/vitest-esbuild-shim.mjs +45 -0
- package/tools/vitest-full-suite.mjs +310 -0
- package/tools/vitest-runner.mjs +505 -11
- package/tools/workflow-orphan-worktree-recovery.mjs +24 -7
- package/tui/CommandPalette.js +87 -0
- package/tui/app.mjs +463 -37
- package/tui/components/status-header.mjs +43 -1
- package/tui/lib/command-palette.mjs +191 -0
- package/tui/lib/connection-target.mjs +577 -0
- package/tui/lib/header-config.mjs +0 -2
- package/tui/lib/navigation.mjs +8 -3
- package/tui/lib/ws-bridge.mjs +141 -51
- package/tui/screens/agents-screen-helpers.mjs +87 -3
- package/tui/screens/agents.mjs +1074 -202
- package/tui/screens/connection-setup.mjs +363 -0
- package/tui/screens/harness-approvals.mjs +7 -0
- package/tui/screens/harness-sessions.mjs +109 -0
- package/tui/screens/harness-subagents.mjs +18 -0
- package/tui/screens/harness-telemetry.mjs +67 -0
- package/tui/screens/logs.mjs +325 -0
- package/tui/screens/settings-screen-helpers.mjs +75 -0
- package/tui/screens/settings.mjs +397 -0
- package/tui/screens/status.mjs +130 -5
- package/tui/screens/telemetry-screen-helpers.mjs +158 -0
- package/tui/screens/telemetry.mjs +246 -0
- package/tui/screens/workflows.mjs +984 -0
- package/ui/app.js +746 -189
- package/ui/app.monolith.js +2 -3
- package/ui/assets/toastui-editor-all.min.js +24 -0
- package/ui/components/agent-selector.js +706 -49
- package/ui/components/charts.js +16 -12
- package/ui/components/chat-view.js +536 -35
- package/ui/components/commit-graph.js +648 -0
- package/ui/components/context-menu.js +89 -0
- package/ui/components/diff-viewer.js +169 -53
- package/ui/components/forms.js +13 -2
- package/ui/components/kanban-board.js +541 -92
- package/ui/components/session-list.js +303 -66
- package/ui/components/shared.js +9 -1
- package/ui/components/task-markdown.js +272 -0
- package/ui/components/workspace-executor-settings.js +142 -0
- package/ui/components/workspace-switcher.js +35 -79
- package/ui/demo-defaults.js +17278 -7297
- package/ui/demo.html +7058 -5338
- package/ui/index.html +189 -112
- package/ui/modules/agent-events.js +309 -36
- package/ui/modules/api.js +236 -13
- package/ui/modules/chat-turn-groups.js +101 -0
- package/ui/modules/harness-client.js +56 -0
- package/ui/modules/icon-utils.js +9 -1
- package/ui/modules/icons.js +26 -2
- package/ui/modules/repo-area-contention.js +97 -0
- package/ui/modules/router.js +2 -0
- package/ui/modules/session-api.js +158 -14
- package/ui/modules/session-insights-worker.js +28 -0
- package/ui/modules/session-insights.js +173 -4
- package/ui/modules/session-surface.js +221 -0
- package/ui/modules/settings-schema.js +148 -27
- package/ui/modules/state.js +122 -13
- package/ui/modules/streaming.js +196 -60
- package/ui/modules/structured-values.js +47 -0
- package/ui/modules/task-hierarchy.js +374 -0
- package/ui/modules/worktree-recovery.js +10 -1
- package/ui/setup.html +3327 -2538
- package/ui/styles/components.css +983 -99
- package/ui/styles/kanban.css +229 -0
- package/ui/styles/layout.css +578 -106
- package/ui/styles/toastui-editor-dark.css +1 -0
- package/ui/styles/toastui-editor-viewer.css +6 -0
- package/ui/styles/toastui-editor.css +6 -0
- package/ui/styles/variables.css +14 -2
- package/ui/styles/workspace-switcher.css +22 -0
- package/ui/styles.css +20 -5
- package/ui/tabs/agents.js +1222 -86
- package/ui/tabs/chat.js +588 -146
- package/ui/tabs/context-compression-lab.js +962 -0
- package/ui/tabs/control.js +347 -61
- package/ui/tabs/dashboard.js +372 -105
- package/ui/tabs/guardrails.js +1140 -0
- package/ui/tabs/infra.js +91 -12
- package/ui/tabs/integrations.js +388 -0
- package/ui/tabs/library.js +161 -21
- package/ui/tabs/logs.js +410 -52
- package/ui/tabs/manual-flows.js +268 -52
- package/ui/tabs/settings.js +2117 -105
- package/ui/tabs/tasks.js +2851 -303
- package/ui/tabs/telemetry.js +246 -8
- package/ui/tabs/workflow-canvas-utils.mjs +172 -15
- package/ui/tabs/workflows.js +2632 -348
- package/ui/tui/App.js +127 -119
- package/ui/tui/HelpScreen.js +201 -0
- package/ui/tui/SettingsScreen.js +388 -0
- package/ui/tui/TasksScreen.js +30 -7
- package/ui/tui/TelemetryScreen.js +155 -0
- package/ui/tui/WorkflowsScreen.js +350 -0
- package/ui/tui/config-events.js +13 -0
- package/ui/tui/constants.js +1 -1
- package/ui/tui/logs-screen-helpers.js +292 -0
- package/ui/tui/tasks-screen-helpers.js +52 -0
- package/ui/tui/telemetry-helpers.js +158 -0
- package/ui/tui/useWorkflows.js +126 -6
- package/ui/tui/workflows-screen-helpers.js +220 -0
- package/ui/vendor/preact-jsx-runtime.js +5 -0
- package/utils.mjs +2 -2
- package/voice/vision-session-state.mjs +257 -0
- package/voice/voice-action-dispatcher.mjs +57 -12
- package/voice/voice-agents-sdk.mjs +1 -1
- package/voice/voice-auth-manager.mjs +102 -123
- package/voice/voice-tool-definitions.mjs +7 -7
- package/voice/voice-tools.mjs +837 -101
- package/workflow/action-approval.mjs +415 -0
- package/workflow/approval-queue.mjs +1254 -0
- package/workflow/credential-store.mjs +553 -0
- package/workflow/cron-scheduler.mjs +512 -0
- package/workflow/declarative-workflows.mjs +21 -2
- package/workflow/delegation-runtime.mjs +557 -0
- package/workflow/execution-ledger.mjs +1317 -33
- package/workflow/harness-approval-node.mjs +237 -0
- package/workflow/harness-output-contract.mjs +86 -0
- package/workflow/harness-session-node.mjs +160 -0
- package/workflow/harness-subagent-node.mjs +483 -0
- package/workflow/harness-tool-node.mjs +176 -0
- package/workflow/heavy-runner-pool.mjs +546 -0
- package/workflow/manual-flows.mjs +969 -28
- package/workflow/mcp-discovery-proxy.mjs +363 -143
- package/workflow/mcp-registry.mjs +507 -65
- package/workflow/meeting-workflow-service.mjs +24 -12
- package/workflow/pipeline-workflows.mjs +44 -2
- package/workflow/pipeline.mjs +72 -28
- package/workflow/project-detection.mjs +31 -6
- package/workflow/research-evidence-sidecar.mjs +1246 -0
- package/workflow/run-evaluator.mjs +2155 -0
- package/workflow/workflow-cli.mjs +229 -2
- package/workflow/workflow-contract.mjs +130 -2
- package/workflow/workflow-engine.mjs +5636 -331
- package/workflow/workflow-migration.mjs +0 -1
- package/workflow/workflow-nodes/actions.mjs +15526 -0
- package/workflow/workflow-nodes/agent.mjs +1863 -0
- package/workflow/workflow-nodes/conditions.mjs +307 -0
- package/workflow/workflow-nodes/definitions.mjs +210 -29
- package/workflow/workflow-nodes/flow.mjs +749 -0
- package/workflow/workflow-nodes/loop.mjs +449 -0
- package/workflow/workflow-nodes/meetings.mjs +456 -0
- package/workflow/workflow-nodes/notifications.mjs +169 -0
- package/workflow/workflow-nodes/transforms.mjs +83 -30
- package/workflow/workflow-nodes/triggers.mjs +1405 -0
- package/workflow/workflow-nodes/validation.mjs +722 -0
- package/workflow/workflow-nodes.mjs +43 -14965
- package/workflow/workflow-serializer.mjs +294 -0
- package/workflow/workflow-templates.mjs +304 -9
- package/workflow-templates/_helpers.mjs +1 -3
- package/workflow-templates/agents.mjs +235 -27
- package/workflow-templates/bosun-native.mjs +3 -1
- package/workflow-templates/code-quality.mjs +1 -1
- package/workflow-templates/continuation-loop.mjs +21 -5
- package/workflow-templates/coverage.mjs +6 -2
- package/workflow-templates/github.mjs +2565 -177
- package/workflow-templates/reliability.mjs +463 -35
- package/workflow-templates/research-evidence.mjs +389 -0
- package/workflow-templates/security.mjs +75 -62
- package/workflow-templates/sub-workflows.mjs +11 -3
- package/workflow-templates/task-batch.mjs +102 -20
- package/workflow-templates/task-lifecycle.mjs +333 -298
- package/workspace/command-diagnostics.mjs +111 -0
- package/workspace/context-cache.mjs +1308 -124
- package/workspace/context-indexer.mjs +915 -9
- package/workspace/context-injector.mjs +144 -0
- package/workspace/execution-journal.mjs +255 -0
- package/workspace/scope-locks.mjs +481 -0
- package/workspace/shared-knowledge.mjs +496 -91
- package/workspace/shared-state-manager.mjs +344 -1
- package/workspace/shared-workspace-cli.mjs +0 -0
- package/workspace/shared-workspace-registry.mjs +2 -2
- package/workspace/skillbook-store.mjs +681 -0
- package/workspace/workspace-manager.mjs +14 -8
- package/workspace/workspace-monitor.mjs +4 -4
- package/workspace/worktree-manager.mjs +146 -55
- package/workspace/worktree-setup.mjs +822 -0
- package/agent/rotate-agent-logs.sh +0 -134
- package/git/sdk-conflict-resolver.mjs +0 -971
- package/infra/sync-engine.mjs +0 -1160
- package/kanban/ve-kanban.mjs +0 -664
- package/kanban/ve-kanban.ps1 +0 -1365
- package/kanban/ve-kanban.sh +0 -18
- package/kanban/ve-orchestrator.mjs +0 -340
- package/kanban/ve-orchestrator.ps1 +0 -6762
- package/kanban/ve-orchestrator.sh +0 -18
- package/kanban/vibe-kanban-wrapper.mjs +0 -41
- package/kanban/vk-error-resolver.mjs +0 -474
- package/kanban/vk-log-stream.mjs +0 -932
- package/task/task-archiver.mjs +0 -813
- package/tools/publish.mjs +0 -239
- package/ui/components/chat-view.js.bak +0 -1
- package/ui/tabs/infra.js.bak +0 -1
package/.env.example
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# Max characters of matched built-in/local skills injected into an agent task prompt.
|
|
2
|
+
# Skills are only injected when task title/description/labels match skill tags.
|
|
3
|
+
BOSUN_SKILLS_MAX_CHARS=4000
|
|
1
4
|
# ─── Bosun — Environment Configuration ───────────────────────────────
|
|
2
5
|
# Copy this file to .env and fill in your values.
|
|
3
6
|
# Or run: bosun --setup
|
|
@@ -350,12 +353,8 @@ VOICE_DELEGATE_EXECUTOR=codex-sdk
|
|
|
350
353
|
# FAILOVER_DISABLE_AFTER=3
|
|
351
354
|
|
|
352
355
|
# ─── Internal Executor ───────────────────────────────────────────────────────
|
|
353
|
-
# Controls whether tasks are executed locally via agent-pool
|
|
354
|
-
#
|
|
355
|
-
# "vk" — all tasks via VK executor (default, existing behavior)
|
|
356
|
-
# "internal" — all tasks via local agent-pool (bypass wrapper orchestrator script)
|
|
357
|
-
# "hybrid" — both VK and internal run simultaneously for overflow
|
|
358
|
-
# EXECUTOR_MODE=vk
|
|
356
|
+
# Controls whether tasks are executed locally via agent-pool.
|
|
357
|
+
# EXECUTOR_MODE=internal
|
|
359
358
|
# Max concurrent agent slots for internal executor (default: 3)
|
|
360
359
|
# INTERNAL_EXECUTOR_PARALLEL=3
|
|
361
360
|
# INTERNAL_EXECUTOR_BASE_BRANCH_PARALLEL=0
|
|
@@ -381,6 +380,12 @@ VOICE_DELEGATE_EXECUTOR=codex-sdk
|
|
|
381
380
|
# INTERNAL_EXECUTOR_REVIEW_TIMEOUT_MS=300000
|
|
382
381
|
# Experimental autonomous backlog replenishment (disabled by default)
|
|
383
382
|
# INTERNAL_EXECUTOR_REPLENISH_ENABLED=false
|
|
383
|
+
# Enable deterministic internal harness compile/activate control-plane support
|
|
384
|
+
# BOSUN_HARNESS_ENABLED=false
|
|
385
|
+
# Path to harness profile source (JSON or markdown fenced JSON)
|
|
386
|
+
# BOSUN_HARNESS_SOURCE=.bosun/harness/internal-harness.md
|
|
387
|
+
# Validation mode: off | report | enforce
|
|
388
|
+
# BOSUN_HARNESS_VALIDATION_MODE=report
|
|
384
389
|
# Minimum follow-up tasks to generate per completed task (1-2)
|
|
385
390
|
# INTERNAL_EXECUTOR_REPLENISH_MIN_NEW_TASKS=1
|
|
386
391
|
# Maximum follow-up tasks to generate per completed task (1-3)
|
|
@@ -495,9 +500,9 @@ VOICE_DELEGATE_EXECUTOR=codex-sdk
|
|
|
495
500
|
# ─── Kanban Backend ──────────────────────────────────────────────────────────
|
|
496
501
|
# Task-board backend:
|
|
497
502
|
# internal - local task-store source of truth (recommended primary)
|
|
498
|
-
# vk - Vibe-Kanban (secondary adapter)
|
|
499
503
|
# github - GitHub Issues
|
|
500
504
|
# jira - Jira Issues
|
|
505
|
+
# gnap - GNAP projection backend (off by default)
|
|
501
506
|
# KANBAN_BACKEND=internal
|
|
502
507
|
# Sync behavior:
|
|
503
508
|
# internal-primary - internal task-store remains source-of-truth (recommended)
|
|
@@ -598,6 +603,20 @@ VOICE_DELEGATE_EXECUTOR=codex-sdk
|
|
|
598
603
|
# Optional JSON custom field to store full shared state payload
|
|
599
604
|
# JIRA_CUSTOM_FIELD_SHARED_STATE=customfield_10048
|
|
600
605
|
|
|
606
|
+
# GNAP backend (KANBAN_BACKEND=gnap)
|
|
607
|
+
# Master toggle for GNAP integration. Must be enabled before selecting gnap.
|
|
608
|
+
# GNAP_ENABLED=false
|
|
609
|
+
# Path to the repo or clone that will host GNAP projection data
|
|
610
|
+
# GNAP_REPO_PATH=
|
|
611
|
+
# Synchronization mode. Bosun currently supports projection-only GNAP wiring.
|
|
612
|
+
# GNAP_SYNC_MODE=projection
|
|
613
|
+
# Where to store GNAP run metadata: git|local
|
|
614
|
+
# GNAP_RUN_STORAGE=git
|
|
615
|
+
# Where to store GNAP message projections: off|git|local
|
|
616
|
+
# GNAP_MESSAGE_STORAGE=off
|
|
617
|
+
# Optional sanitized roadmap export for shared visibility
|
|
618
|
+
# GNAP_PUBLIC_ROADMAP_ENABLED=false
|
|
619
|
+
|
|
601
620
|
# ─── Sandbox Policy ──────────────────────────────────────────────────────────
|
|
602
621
|
# Controls agent sandbox isolation when using Codex SDK.
|
|
603
622
|
# Options:
|
|
@@ -661,37 +680,6 @@ VOICE_DELEGATE_EXECUTOR=codex-sdk
|
|
|
661
680
|
# Stop auto-restarts after this many instant failures in a row (default: 3)
|
|
662
681
|
# BOSUN_DAEMON_MAX_INSTANT_RESTARTS=3
|
|
663
682
|
|
|
664
|
-
# ─── Vibe-Kanban ──────────────────────────────────────────────────────────────
|
|
665
|
-
# Base URL for the Vibe-Kanban API (default: http://127.0.0.1:54089)
|
|
666
|
-
VK_BASE_URL=http://127.0.0.1:54089
|
|
667
|
-
# Alternate endpoint URL for VK (overrides VK_BASE_URL if set)
|
|
668
|
-
# VK_ENDPOINT_URL=http://127.0.0.1:54089
|
|
669
|
-
# Port for vibe-kanban API (default: 54089)
|
|
670
|
-
VK_RECOVERY_PORT=54089
|
|
671
|
-
# Host for VK recovery (default: 0.0.0.0)
|
|
672
|
-
# VK_RECOVERY_HOST=0.0.0.0
|
|
673
|
-
# VK_HOST=0.0.0.0
|
|
674
|
-
# Public URL shown in Telegram links (optional)
|
|
675
|
-
# VK_PUBLIC_URL=https://kanban.yoursite.com
|
|
676
|
-
# VK_WEB_URL=https://kanban.yoursite.com
|
|
677
|
-
# VK HTTP timeout/retry controls (used by ve-kanban.ps1)
|
|
678
|
-
# VK_HTTP_TIMEOUT_SEC=45
|
|
679
|
-
# VK_HTTP_RETRIES=2
|
|
680
|
-
# VK_HTTP_RETRY_DELAY_MS=1500
|
|
681
|
-
# Set to true to prevent the monitor from spawning vibe-kanban automatically
|
|
682
|
-
# VK_NO_SPAWN=false
|
|
683
|
-
# Cooldown minutes between VK recovery attempts (default: 10)
|
|
684
|
-
# VK_RECOVERY_COOLDOWN_MIN=10
|
|
685
|
-
# VK health check interval in ms (default: 60000)
|
|
686
|
-
# VK_ENSURE_INTERVAL=60000
|
|
687
|
-
# VK project name (auto-detected)
|
|
688
|
-
# VK_PROJECT_NAME=my-project
|
|
689
|
-
# Explicit VK project/repo IDs (auto-detected if empty)
|
|
690
|
-
# VK_PROJECT_ID=
|
|
691
|
-
# VK_REPO_ID=
|
|
692
|
-
# Override task URL template (optional)
|
|
693
|
-
# VK_TASK_URL_TEMPLATE=https://kanban.yoursite.com/projects/{projectId}/tasks/{taskId}
|
|
694
|
-
|
|
695
683
|
# ─── Shared Workspace Registry ───────────────────────────────────────────────
|
|
696
684
|
# Optional registry path for shared workspace leasing
|
|
697
685
|
# VE_SHARED_WORKSPACE_REGISTRY=.cache/bosun/shared-workspaces.json
|
|
@@ -713,13 +701,8 @@ VK_RECOVERY_PORT=54089
|
|
|
713
701
|
# GITHUB_TOKEN=
|
|
714
702
|
# GH_TOKEN=
|
|
715
703
|
# GITHUB_PAT=
|
|
716
|
-
# Owner/repo for gh CLI in ve-kanban
|
|
717
|
-
# GH_OWNER=virtengine
|
|
718
|
-
# GH_REPO=virtengine
|
|
719
704
|
# Target branch for PR checks/merge (default: origin/main)
|
|
720
|
-
#
|
|
721
|
-
# Default upstream/base branch for bosun tasks (overrides VK_TARGET_BRANCH)
|
|
722
|
-
# BOSUN_TASK_UPSTREAM=origin/ve/bosun-generic
|
|
705
|
+
# BOSUN_TASK_UPSTREAM=origin/main
|
|
723
706
|
|
|
724
707
|
# ─── Codex / AI Provider ─────────────────────────────────────────────────────
|
|
725
708
|
# The Codex SDK uses OpenAI-compatible configuration that has been setup in ~/.codex/config.toml -
|
|
@@ -1024,7 +1007,7 @@ COPILOT_CLOUD_DISABLED=true
|
|
|
1024
1007
|
|
|
1025
1008
|
# ─── Task Planner ─────────────────────────────────────────────────────────────
|
|
1026
1009
|
# How to plan new tasks when backlog is empty:
|
|
1027
|
-
# "kanban" - (default) create a
|
|
1010
|
+
# "kanban" - (default) create a planning task for an agent to refine
|
|
1028
1011
|
# "codex-sdk" - run Codex SDK directly to generate tasks
|
|
1029
1012
|
# "disabled" - do nothing, wait for manual task creation
|
|
1030
1013
|
# TASK_PLANNER_MODE=kanban
|
|
@@ -1056,6 +1039,8 @@ COPILOT_CLOUD_DISABLED=true
|
|
|
1056
1039
|
# WORKFLOW_RECOVERY_BACKOFF_MAX_MS=60000
|
|
1057
1040
|
# Random jitter ratio (0.0-0.9) applied to backoff to prevent retry storms.
|
|
1058
1041
|
# WORKFLOW_RECOVERY_BACKOFF_JITTER_RATIO=0.2
|
|
1042
|
+
# Delay startup interrupted-run replay so the UI/API can become responsive first.
|
|
1043
|
+
# WORKFLOW_STARTUP_HISTORY_RECOVERY_DELAY_MS=120000
|
|
1059
1044
|
|
|
1060
1045
|
# ─── GitHub Issue Reconciler ─────────────────────────────────────────────────
|
|
1061
1046
|
# Periodically reconciles open GitHub issues against open/merged PRs.
|
|
@@ -1135,12 +1120,15 @@ COPILOT_CLOUD_DISABLED=true
|
|
|
1135
1120
|
# Repository root (auto-detected from git; setup writes this)
|
|
1136
1121
|
# REPO_ROOT=/path/to/repo
|
|
1137
1122
|
# Watch path to trigger restarts (default: script path)
|
|
1138
|
-
# WATCH_PATH=/path/to/
|
|
1123
|
+
# WATCH_PATH=/path/to/orchestrator.sh
|
|
1139
1124
|
# Monitor source hot-reload watcher. Default: enabled in devmode, disabled otherwise.
|
|
1140
1125
|
# Set to true to force-enable monitor source hot-restart, false to force-disable.
|
|
1141
1126
|
# SELF_RESTART_WATCH_ENABLED=true
|
|
1142
|
-
#
|
|
1143
|
-
#
|
|
1127
|
+
# Quiet period after the last source-file change before self-restart is allowed.
|
|
1128
|
+
# Default: 180000 (3 minutes)
|
|
1129
|
+
# SELF_RESTART_QUIET_MS=180000
|
|
1130
|
+
# Status file path (default: .cache/orchestrator-status.json)
|
|
1131
|
+
# STATUS_FILE=.cache/orchestrator-status.json
|
|
1144
1132
|
# Log directory (default: ./logs)
|
|
1145
1133
|
# LOG_DIR=./logs
|
|
1146
1134
|
# Max total log folder size in MB. Oldest logs are deleted when exceeded. 0 = unlimited.
|
|
@@ -1161,8 +1149,6 @@ COPILOT_CLOUD_DISABLED=true
|
|
|
1161
1149
|
# AGENT_WORK_LOGGING_ENABLED=true
|
|
1162
1150
|
# Enable/disable live stream analyzer (default: true)
|
|
1163
1151
|
# AGENT_WORK_ANALYZER_ENABLED=true
|
|
1164
|
-
# Enrich missing task metadata from VK for agent work logs (default: true)
|
|
1165
|
-
# AGENT_WORK_LOGGING_ENRICH_VK=true
|
|
1166
1152
|
# Task metadata cache (auto-managed): .cache/agent-work-logs/task-metadata.json
|
|
1167
1153
|
# Log directory (default: .cache/agent-work-logs)
|
|
1168
1154
|
# AGENT_WORK_LOG_DIR=.cache/agent-work-logs
|
|
@@ -1183,4 +1169,3 @@ COPILOT_CLOUD_DISABLED=true
|
|
|
1183
1169
|
|
|
1184
1170
|
# OpenTelemetry tracing (optional)
|
|
1185
1171
|
# BOSUN_OTEL_ENDPOINT=http://localhost:4318/v1/traces
|
|
1186
|
-
|
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ Open `https://localhost:3080` to start the setup wizard.
|
|
|
65
65
|
|
|
66
66
|
Requires:
|
|
67
67
|
|
|
68
|
-
- Node.js
|
|
68
|
+
- Node.js 22.13+
|
|
69
69
|
- Git
|
|
70
70
|
- Bash (for `.sh` wrappers) or PowerShell 7+ (for `.ps1` wrappers)
|
|
71
71
|
- GitHub CLI (`gh`) recommended
|
|
@@ -108,7 +108,7 @@ Fallback admin auth (secondary path) is available and stores only Argon2id hash
|
|
|
108
108
|
- Persists workflow runs to disk and auto-resumes on restart
|
|
109
109
|
- Monitors runs and recovers from stalled or broken states
|
|
110
110
|
- Provides Telegram control and a Mini App dashboard
|
|
111
|
-
- Integrates with GitHub
|
|
111
|
+
- Integrates with GitHub and Jira boards
|
|
112
112
|
|
|
113
113
|
## Autonomous Engineer Workflow Capabilities
|
|
114
114
|
|
|
@@ -162,6 +162,20 @@ Key places to start:
|
|
|
162
162
|
- `docs/agent-logging-quickstart.md` - agent work logging quickstart
|
|
163
163
|
- `docs/agent-work-logging-design.md` - logging design and event model
|
|
164
164
|
|
|
165
|
+
## Troubleshooting
|
|
166
|
+
|
|
167
|
+
### Preflight warns about an interactive git editor
|
|
168
|
+
|
|
169
|
+
If preflight reports an interactive git editor such as `code --wait`, `vim`, or `nano`, Bosun can deadlock while Git waits for an editor session to close.
|
|
170
|
+
|
|
171
|
+
Run this from the repo root to switch the local repo config to a non-interactive editor:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
node git-editor-fix.mjs
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Preflight checks both `GIT_EDITOR` and `git config --get core.editor`. No warning is shown when `core.editor` is already non-interactive, for example `:`.
|
|
178
|
+
|
|
165
179
|
---
|
|
166
180
|
|
|
167
181
|
## CI/CD and quality gates
|
|
@@ -228,7 +242,7 @@ npm run hooks:install
|
|
|
228
242
|
- `server/` — setup server, Mini App backend, and API endpoints
|
|
229
243
|
- `ui/` — Mini App frontend assets and operator dashboard modules
|
|
230
244
|
- `telegram/` — Telegram bot, sentinel, and channel integrations
|
|
231
|
-
- `github/` and `kanban/` — GitHub auth/webhooks and
|
|
245
|
+
- `github/` and `kanban/` — GitHub auth/webhooks and kanban adapters
|
|
232
246
|
- `workspace/` — shared workspace registry, context indexing, and worktree lifecycle
|
|
233
247
|
- `shell/` and `agent/` — executor integrations, prompts, hooks, and fleet coordination
|
|
234
248
|
- `site/` — marketing site and generated docs website assets
|
|
@@ -251,3 +265,5 @@ If you find this project useful or would like to stay up to date with new releas
|
|
|
251
265
|
## License
|
|
252
266
|
|
|
253
267
|
Apache-2.0
|
|
268
|
+
|
|
269
|
+
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
rmSync,
|
|
48
48
|
writeFileSync,
|
|
49
49
|
} from "node:fs";
|
|
50
|
-
import { copyFile
|
|
50
|
+
import { copyFile } from "node:fs/promises";
|
|
51
51
|
import { homedir } from "node:os";
|
|
52
52
|
import { basename, dirname, extname, resolve } from "node:path";
|
|
53
53
|
import { fileURLToPath } from "node:url";
|
|
@@ -212,7 +212,10 @@ function safeReadIndex(storeDir) {
|
|
|
212
212
|
if (!existsSync(idx)) return [];
|
|
213
213
|
try {
|
|
214
214
|
const parsed = JSON.parse(readFileSync(idx, "utf8"));
|
|
215
|
-
|
|
215
|
+
if (!Array.isArray(parsed)) return [];
|
|
216
|
+
return parsed
|
|
217
|
+
.map((entry) => sanitizeIndexEntry(entry))
|
|
218
|
+
.filter(Boolean);
|
|
216
219
|
} catch {
|
|
217
220
|
return [];
|
|
218
221
|
}
|
|
@@ -243,6 +246,77 @@ function scriptPath(storeDir, id, lang) {
|
|
|
243
246
|
return resolve(storeDir, `${id}.${lang}`);
|
|
244
247
|
}
|
|
245
248
|
|
|
249
|
+
function isPlainObject(value) {
|
|
250
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function normalizeStringList(values, { lowercase = true } = {}) {
|
|
254
|
+
if (!Array.isArray(values)) return [];
|
|
255
|
+
const normalized = values
|
|
256
|
+
.map((value) => String(value ?? "").trim())
|
|
257
|
+
.filter(Boolean)
|
|
258
|
+
.map((value) => (lowercase ? value.toLowerCase() : value));
|
|
259
|
+
return Array.from(new Set(normalized));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function normalizeUsageCount(value) {
|
|
263
|
+
const numeric = Number(value);
|
|
264
|
+
return Number.isFinite(numeric) && numeric >= 0 ? numeric : 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function normalizeToolId(toolId) {
|
|
268
|
+
if (typeof toolId !== "string") return null;
|
|
269
|
+
const trimmed = toolId.trim();
|
|
270
|
+
if (!trimmed) return null;
|
|
271
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,59}$/.test(trimmed)) return null;
|
|
272
|
+
return trimmed;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function sanitizeIndexEntry(raw) {
|
|
276
|
+
if (!isPlainObject(raw)) return null;
|
|
277
|
+
|
|
278
|
+
const id = normalizeToolId(raw.id);
|
|
279
|
+
const lang = VALID_LANGS.includes(raw.lang) ? raw.lang : null;
|
|
280
|
+
if (!id || !lang) return null;
|
|
281
|
+
|
|
282
|
+
const category = TOOL_CATEGORIES.includes(raw.category)
|
|
283
|
+
? raw.category
|
|
284
|
+
: "utility";
|
|
285
|
+
const skills = normalizeStringList(raw.skills, { lowercase: false });
|
|
286
|
+
const agents = normalizeStringList(raw.agents, { lowercase: false });
|
|
287
|
+
const templates = normalizeStringList(raw.templates, { lowercase: false });
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
...raw,
|
|
291
|
+
id,
|
|
292
|
+
title: typeof raw.title === "string" && raw.title.trim() ? raw.title : id,
|
|
293
|
+
description: typeof raw.description === "string" ? raw.description : "",
|
|
294
|
+
tags: normalizeStringList(raw.tags),
|
|
295
|
+
category,
|
|
296
|
+
lang,
|
|
297
|
+
createdBy: typeof raw.createdBy === "string" && raw.createdBy.trim()
|
|
298
|
+
? raw.createdBy
|
|
299
|
+
: "agent",
|
|
300
|
+
createdAt: typeof raw.createdAt === "string" && raw.createdAt.trim()
|
|
301
|
+
? raw.createdAt
|
|
302
|
+
: nowISO(),
|
|
303
|
+
updatedAt: typeof raw.updatedAt === "string" && raw.updatedAt.trim()
|
|
304
|
+
? raw.updatedAt
|
|
305
|
+
: nowISO(),
|
|
306
|
+
usageCount: normalizeUsageCount(raw.usageCount),
|
|
307
|
+
...(typeof raw.lastUsed === "string" && raw.lastUsed.trim()
|
|
308
|
+
? { lastUsed: raw.lastUsed }
|
|
309
|
+
: {}),
|
|
310
|
+
...(skills.length > 0 ? { skills } : {}),
|
|
311
|
+
...(agents.length > 0 ? { agents } : {}),
|
|
312
|
+
...(templates.length > 0 ? { templates } : {}),
|
|
313
|
+
...(raw.autoInject ? { autoInject: true } : {}),
|
|
314
|
+
...(typeof raw.version === "string" && raw.version.trim()
|
|
315
|
+
? { version: raw.version }
|
|
316
|
+
: {}),
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
246
320
|
// ── Types ─────────────────────────────────────────────────────────────────────
|
|
247
321
|
|
|
248
322
|
/**
|
|
@@ -302,6 +376,9 @@ export function listCustomTools(rootDir, opts = {}) {
|
|
|
302
376
|
includeBuiltins = true,
|
|
303
377
|
} = opts;
|
|
304
378
|
|
|
379
|
+
const requestedTags = normalizeStringList(tags);
|
|
380
|
+
const searchQuery = typeof search === "string" ? search.trim().toLowerCase() : "";
|
|
381
|
+
|
|
305
382
|
let entries = [];
|
|
306
383
|
|
|
307
384
|
// Workspace tools
|
|
@@ -339,23 +416,24 @@ export function listCustomTools(rootDir, opts = {}) {
|
|
|
339
416
|
if (category) {
|
|
340
417
|
entries = entries.filter((e) => e.category === category);
|
|
341
418
|
}
|
|
342
|
-
if (
|
|
419
|
+
if (requestedTags.length > 0) {
|
|
343
420
|
entries = entries.filter((e) =>
|
|
344
|
-
|
|
421
|
+
requestedTags.some((t) => (e.tags || []).includes(t)),
|
|
345
422
|
);
|
|
346
423
|
}
|
|
347
|
-
if (
|
|
348
|
-
const q = search.toLowerCase();
|
|
424
|
+
if (searchQuery) {
|
|
349
425
|
entries = entries.filter(
|
|
350
426
|
(e) =>
|
|
351
|
-
e.id.includes(
|
|
352
|
-
e.title.toLowerCase().includes(
|
|
353
|
-
e.description.toLowerCase().includes(
|
|
354
|
-
(e.tags || []).some((t) => t.includes(
|
|
427
|
+
e.id.toLowerCase().includes(searchQuery) ||
|
|
428
|
+
e.title.toLowerCase().includes(searchQuery) ||
|
|
429
|
+
e.description.toLowerCase().includes(searchQuery) ||
|
|
430
|
+
(e.tags || []).some((t) => t.toLowerCase().includes(searchQuery)),
|
|
355
431
|
);
|
|
356
432
|
}
|
|
357
433
|
|
|
358
|
-
return entries.sort(
|
|
434
|
+
return entries.sort(
|
|
435
|
+
(a, b) => normalizeUsageCount(b.usageCount) - normalizeUsageCount(a.usageCount),
|
|
436
|
+
);
|
|
359
437
|
}
|
|
360
438
|
|
|
361
439
|
/**
|
|
@@ -366,11 +444,14 @@ export function listCustomTools(rootDir, opts = {}) {
|
|
|
366
444
|
* @returns {{ entry: CustomToolEntry, script: string }|null}
|
|
367
445
|
*/
|
|
368
446
|
export function getCustomTool(rootDir, toolId) {
|
|
447
|
+
const normalizedToolId = normalizeToolId(toolId);
|
|
448
|
+
if (!normalizedToolId) return null;
|
|
449
|
+
|
|
369
450
|
// Workspace-scoped takes precedence, then global, then builtin
|
|
370
451
|
for (const isGlobal of [false, true]) {
|
|
371
452
|
const storeDir = getToolStore(rootDir, { global: isGlobal });
|
|
372
453
|
const index = safeReadIndex(storeDir);
|
|
373
|
-
const entry = index.find((e) => e.id ===
|
|
454
|
+
const entry = index.find((e) => e.id === normalizedToolId);
|
|
374
455
|
if (!entry) continue;
|
|
375
456
|
|
|
376
457
|
const sPath = scriptPath(storeDir, entry.id, entry.lang);
|
|
@@ -383,7 +464,7 @@ export function getCustomTool(rootDir, toolId) {
|
|
|
383
464
|
}
|
|
384
465
|
|
|
385
466
|
// Fall back to built-in tools shipped with bosun
|
|
386
|
-
const builtinDef = BUILTIN_TOOLS.find((b) => b.id ===
|
|
467
|
+
const builtinDef = BUILTIN_TOOLS.find((b) => b.id === normalizedToolId);
|
|
387
468
|
if (builtinDef) {
|
|
388
469
|
const sPath = resolve(BUILTIN_TOOLS_DIR, `${builtinDef.id}.${builtinDef.lang}`);
|
|
389
470
|
if (existsSync(sPath)) {
|
|
@@ -414,6 +495,10 @@ export function getCustomTool(rootDir, toolId) {
|
|
|
414
495
|
* @returns {CustomToolEntry}
|
|
415
496
|
*/
|
|
416
497
|
export function registerCustomTool(rootDir, def) {
|
|
498
|
+
if (!isPlainObject(def)) {
|
|
499
|
+
throw new TypeError("registerCustomTool: definition object is required");
|
|
500
|
+
}
|
|
501
|
+
|
|
417
502
|
const {
|
|
418
503
|
title,
|
|
419
504
|
description,
|
|
@@ -449,19 +534,29 @@ export function registerCustomTool(rootDir, def) {
|
|
|
449
534
|
);
|
|
450
535
|
}
|
|
451
536
|
|
|
537
|
+
const explicitId = def.id == null ? null : normalizeToolId(def.id);
|
|
538
|
+
if (def.id != null && !explicitId) {
|
|
539
|
+
throw new TypeError(
|
|
540
|
+
"registerCustomTool: id must match /^[A-Za-z0-9][A-Za-z0-9_-]{0,59}$/ and must not contain path separators",
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
|
|
452
544
|
const storeDir = getToolStore(rootDir, { global: isGlobal });
|
|
453
545
|
const index = safeReadIndex(storeDir);
|
|
454
546
|
|
|
455
|
-
const id =
|
|
547
|
+
const id = explicitId || slugify(title) || `tool-${Date.now()}`;
|
|
456
548
|
const existingIdx = index.findIndex((e) => e.id === id);
|
|
457
549
|
const now = nowISO();
|
|
550
|
+
const normalizedSkills = normalizeStringList(skills, { lowercase: false });
|
|
551
|
+
const normalizedAgents = normalizeStringList(agents, { lowercase: false });
|
|
552
|
+
const normalizedTemplates = normalizeStringList(templates, { lowercase: false });
|
|
458
553
|
|
|
459
554
|
/** @type {CustomToolEntry} */
|
|
460
555
|
const entry = {
|
|
461
556
|
id,
|
|
462
557
|
title,
|
|
463
558
|
description: description || "",
|
|
464
|
-
tags:
|
|
559
|
+
tags: normalizeStringList(tags),
|
|
465
560
|
category,
|
|
466
561
|
lang,
|
|
467
562
|
createdBy,
|
|
@@ -474,9 +569,9 @@ export function registerCustomTool(rootDir, def) {
|
|
|
474
569
|
: {}),
|
|
475
570
|
scope: isGlobal ? "global" : "workspace",
|
|
476
571
|
// Affinity metadata (persisted for future skill/agent matching)
|
|
477
|
-
...(
|
|
478
|
-
...(
|
|
479
|
-
...(
|
|
572
|
+
...(normalizedSkills.length > 0 ? { skills: normalizedSkills } : {}),
|
|
573
|
+
...(normalizedAgents.length > 0 ? { agents: normalizedAgents } : {}),
|
|
574
|
+
...(normalizedTemplates.length > 0 ? { templates: normalizedTemplates } : {}),
|
|
480
575
|
...(autoInject ? { autoInject } : {}),
|
|
481
576
|
...(version ? { version } : {}),
|
|
482
577
|
};
|
|
@@ -518,6 +613,10 @@ export async function invokeCustomTool(rootDir, toolId, args = [], opts = {}) {
|
|
|
518
613
|
throw new Error(`invokeCustomTool: tool "${toolId}" not found`);
|
|
519
614
|
}
|
|
520
615
|
|
|
616
|
+
const cliArgs = Array.isArray(args)
|
|
617
|
+
? args.map((arg) => String(arg))
|
|
618
|
+
: [String(args)];
|
|
619
|
+
|
|
521
620
|
const { entry } = result;
|
|
522
621
|
let sPath;
|
|
523
622
|
if (entry.scope === "builtin") {
|
|
@@ -536,15 +635,15 @@ export async function invokeCustomTool(rootDir, toolId, args = [], opts = {}) {
|
|
|
536
635
|
switch (entry.lang) {
|
|
537
636
|
case "mjs":
|
|
538
637
|
cmd = process.execPath; // use same node binary
|
|
539
|
-
cmdArgs = [sPath, ...
|
|
638
|
+
cmdArgs = [sPath, ...cliArgs];
|
|
540
639
|
break;
|
|
541
640
|
case "sh":
|
|
542
641
|
cmd = process.platform === "win32" ? "bash" : "/bin/sh";
|
|
543
|
-
cmdArgs = [sPath, ...
|
|
642
|
+
cmdArgs = [sPath, ...cliArgs];
|
|
544
643
|
break;
|
|
545
644
|
case "py":
|
|
546
|
-
cmd = "python3";
|
|
547
|
-
cmdArgs = [sPath, ...
|
|
645
|
+
cmd = process.platform === "win32" ? "python" : "python3";
|
|
646
|
+
cmdArgs = [sPath, ...cliArgs];
|
|
548
647
|
break;
|
|
549
648
|
default:
|
|
550
649
|
throw new Error(`invokeCustomTool: unsupported lang "${entry.lang}"`);
|
|
@@ -601,10 +700,13 @@ export async function invokeCustomTool(rootDir, toolId, args = [], opts = {}) {
|
|
|
601
700
|
* @returns {Promise<void>}
|
|
602
701
|
*/
|
|
603
702
|
export async function recordToolUsage(rootDir, toolId) {
|
|
703
|
+
const normalizedToolId = normalizeToolId(toolId);
|
|
704
|
+
if (!normalizedToolId) return;
|
|
705
|
+
|
|
604
706
|
for (const isGlobal of [false, true]) {
|
|
605
707
|
const storeDir = getToolStore(rootDir, { global: isGlobal });
|
|
606
708
|
const index = safeReadIndex(storeDir);
|
|
607
|
-
const idx = index.findIndex((e) => e.id ===
|
|
709
|
+
const idx = index.findIndex((e) => e.id === normalizedToolId);
|
|
608
710
|
if (idx < 0) continue;
|
|
609
711
|
index[idx].usageCount = (index[idx].usageCount ?? 0) + 1;
|
|
610
712
|
index[idx].lastUsed = nowISO();
|
|
@@ -622,9 +724,12 @@ export async function recordToolUsage(rootDir, toolId) {
|
|
|
622
724
|
* @returns {boolean} true if the tool was found and removed
|
|
623
725
|
*/
|
|
624
726
|
export function deleteCustomTool(rootDir, toolId, { global: isGlobal = false } = {}) {
|
|
727
|
+
const normalizedToolId = normalizeToolId(toolId);
|
|
728
|
+
if (!normalizedToolId) return false;
|
|
729
|
+
|
|
625
730
|
const storeDir = getToolStore(rootDir, { global: isGlobal });
|
|
626
731
|
const index = safeReadIndex(storeDir);
|
|
627
|
-
const idx = index.findIndex((e) => e.id ===
|
|
732
|
+
const idx = index.findIndex((e) => e.id === normalizedToolId);
|
|
628
733
|
if (idx < 0) return false;
|
|
629
734
|
|
|
630
735
|
const entry = index[idx];
|
|
@@ -651,9 +756,14 @@ export function deleteCustomTool(rootDir, toolId, { global: isGlobal = false } =
|
|
|
651
756
|
* @returns {Promise<CustomToolEntry>} the entry as it now exists in global scope
|
|
652
757
|
*/
|
|
653
758
|
export async function promoteToGlobal(rootDir, toolId) {
|
|
759
|
+
const normalizedToolId = normalizeToolId(toolId);
|
|
760
|
+
if (!normalizedToolId) {
|
|
761
|
+
throw new Error(`promoteToGlobal: workspace tool "${toolId}" not found`);
|
|
762
|
+
}
|
|
763
|
+
|
|
654
764
|
const wsStore = getToolStore(rootDir, { global: false });
|
|
655
765
|
const wsIndex = safeReadIndex(wsStore);
|
|
656
|
-
const wsEntry = wsIndex.find((e) => e.id ===
|
|
766
|
+
const wsEntry = wsIndex.find((e) => e.id === normalizedToolId);
|
|
657
767
|
if (!wsEntry) {
|
|
658
768
|
throw new Error(
|
|
659
769
|
`promoteToGlobal: workspace tool "${toolId}" not found`,
|
|
@@ -676,7 +786,7 @@ export async function promoteToGlobal(rootDir, toolId) {
|
|
|
676
786
|
|
|
677
787
|
// Upsert in global index
|
|
678
788
|
const globalEntry = { ...wsEntry, scope: "global", updatedAt: nowISO() };
|
|
679
|
-
const existingIdx = globalIndex.findIndex((e) => e.id ===
|
|
789
|
+
const existingIdx = globalIndex.findIndex((e) => e.id === normalizedToolId);
|
|
680
790
|
if (existingIdx >= 0) {
|
|
681
791
|
globalIndex[existingIdx] = globalEntry;
|
|
682
792
|
} else {
|
|
@@ -722,6 +832,8 @@ export function getToolsPromptBlock(rootDir, opts = {}) {
|
|
|
722
832
|
template,
|
|
723
833
|
limit,
|
|
724
834
|
includeBuiltins,
|
|
835
|
+
category,
|
|
836
|
+
tags,
|
|
725
837
|
});
|
|
726
838
|
const affinityIds = new Set(affinityTools.map((t) => t.id));
|
|
727
839
|
const remaining = listCustomTools(rootDir, { category, tags, includeBuiltins })
|
package/agent/agent-endpoint.mjs
CHANGED
|
@@ -201,8 +201,7 @@ function isLikelyBosunCommandLine(commandLine) {
|
|
|
201
201
|
normalized.includes("/bosun/") &&
|
|
202
202
|
(normalized.includes("monitor.mjs") ||
|
|
203
203
|
normalized.includes("cli.mjs") ||
|
|
204
|
-
normalized.includes("agent-endpoint.mjs")
|
|
205
|
-
normalized.includes("ve-orchestrator"))
|
|
204
|
+
normalized.includes("agent-endpoint.mjs"))
|
|
206
205
|
) {
|
|
207
206
|
return true;
|
|
208
207
|
}
|
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
* createAgentEventBus(options) → AgentEventBus instance
|
|
19
19
|
* AgentEventBus class
|
|
20
20
|
* AGENT_EVENT — Frozen enum of all event types
|
|
21
|
+
*
|
|
22
|
+
* Canonical architecture note:
|
|
23
|
+
* This bus is the canonical runtime ingress for live agent events into the
|
|
24
|
+
* observability spine. Surfaces may subscribe or rebroadcast, but canonical
|
|
25
|
+
* event normalization and harness telemetry recording must remain centralized
|
|
26
|
+
* here plus `infra/session-telemetry.mjs`.
|
|
21
27
|
*/
|
|
22
28
|
|
|
23
29
|
import {
|
|
@@ -26,6 +32,12 @@ import {
|
|
|
26
32
|
snapshotRetryQueue,
|
|
27
33
|
} from "./retry-queue.mjs";
|
|
28
34
|
import { addSpanEvent, recordAgentError, recordIntervention } from "../infra/tracing.mjs";
|
|
35
|
+
import {
|
|
36
|
+
getHarnessTelemetrySummary,
|
|
37
|
+
listHarnessTelemetryEvents,
|
|
38
|
+
recordHarnessTelemetryEvent,
|
|
39
|
+
} from "../infra/session-telemetry.mjs";
|
|
40
|
+
import { normalizeCanonicalBusEvent } from "../infra/event-schema.mjs";
|
|
29
41
|
|
|
30
42
|
const TAG = "[agent-event-bus]";
|
|
31
43
|
|
|
@@ -147,6 +159,7 @@ export class AgentEventBus {
|
|
|
147
159
|
: (typeof globalThis.__bosun_setRetryQueueData === "function"
|
|
148
160
|
? globalThis.__bosun_setRetryQueueData
|
|
149
161
|
: null);
|
|
162
|
+
this._configDir = options.configDir || process.cwd();
|
|
150
163
|
|
|
151
164
|
/** @type {Array<{type: string, taskId: string, payload: object, ts: number}>} ring buffer */
|
|
152
165
|
this._eventLog = [];
|
|
@@ -259,6 +272,7 @@ export class AgentEventBus {
|
|
|
259
272
|
if (this._eventLog.length > this._maxEventLogSize) {
|
|
260
273
|
this._eventLog.shift();
|
|
261
274
|
}
|
|
275
|
+
this._recordCanonicalEvent(event);
|
|
262
276
|
|
|
263
277
|
// ── WS broadcast
|
|
264
278
|
if (!opts.skipBroadcast) {
|
|
@@ -589,6 +603,7 @@ export class AgentEventBus {
|
|
|
589
603
|
*/
|
|
590
604
|
getStatus() {
|
|
591
605
|
const retryQueue = snapshotRetryQueue(this._retryQueueState);
|
|
606
|
+
const observability = getHarnessTelemetrySummary({ configDir: this._configDir });
|
|
592
607
|
return {
|
|
593
608
|
started: this._started,
|
|
594
609
|
eventLogSize: this._eventLog.length,
|
|
@@ -599,6 +614,10 @@ export class AgentEventBus {
|
|
|
599
614
|
retryQueue,
|
|
600
615
|
liveness: this.getAgentLiveness(),
|
|
601
616
|
errorPatterns: this.getErrorPatternSummary(),
|
|
617
|
+
observability: {
|
|
618
|
+
eventCount: Number(observability?.eventCount || 0),
|
|
619
|
+
lastEventAt: observability?.lastEventAt || null,
|
|
620
|
+
},
|
|
602
621
|
};
|
|
603
622
|
}
|
|
604
623
|
|
|
@@ -606,6 +625,13 @@ export class AgentEventBus {
|
|
|
606
625
|
return snapshotRetryQueue(this._retryQueueState);
|
|
607
626
|
}
|
|
608
627
|
|
|
628
|
+
getCanonicalEventLog(filter = {}) {
|
|
629
|
+
return listHarnessTelemetryEvents({
|
|
630
|
+
...filter,
|
|
631
|
+
source: filter.source || "agent-event-bus",
|
|
632
|
+
}, { configDir: this._configDir });
|
|
633
|
+
}
|
|
634
|
+
|
|
609
635
|
clearRetryQueueTask(taskId, reason = "manual") {
|
|
610
636
|
const id = String(taskId || "").trim();
|
|
611
637
|
if (!id) return;
|
|
@@ -637,6 +663,13 @@ export class AgentEventBus {
|
|
|
637
663
|
}
|
|
638
664
|
}
|
|
639
665
|
|
|
666
|
+
_recordCanonicalEvent(event) {
|
|
667
|
+
recordHarnessTelemetryEvent(
|
|
668
|
+
normalizeCanonicalBusEvent(event),
|
|
669
|
+
{ configDir: this._configDir },
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
|
|
640
673
|
_updateRetryQueue(action, meta = {}) {
|
|
641
674
|
this._retryQueueState = reduceRetryQueue(this._retryQueueState, action);
|
|
642
675
|
const snapshot = snapshotRetryQueue(this._retryQueueState);
|
|
@@ -1100,5 +1133,3 @@ export class AgentEventBus {
|
|
|
1100
1133
|
export function createAgentEventBus(options) {
|
|
1101
1134
|
return new AgentEventBus(options);
|
|
1102
1135
|
}
|
|
1103
|
-
|
|
1104
|
-
|
package/agent/agent-hooks.mjs
CHANGED
|
@@ -643,7 +643,7 @@ export function registerBuiltinHooks(options = {}) {
|
|
|
643
643
|
|
|
644
644
|
// ── PrePush: agent preflight quality gate ──
|
|
645
645
|
if (!skipPrePush) {
|
|
646
|
-
const preflightScript = "node preflight.mjs";
|
|
646
|
+
const preflightScript = "node infra/preflight.mjs";
|
|
647
647
|
|
|
648
648
|
registerHook("PrePush", {
|
|
649
649
|
id: "builtin-prepush-preflight",
|