@theowlops/boombot 0.0.0-stage → 1.1.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 +69 -3
- package/dist/LICENSE +21 -0
- package/dist/bin/boombot.js +16 -0
- package/dist/cli/api-key.js +123 -0
- package/dist/cli/bin-bun.js +17 -0
- package/dist/cli/bin.js +34 -0
- package/dist/cli/cli/cli-error.js +61 -0
- package/dist/cli/cli/dispatch.js +138 -0
- package/dist/cli/cli/help.js +83 -0
- package/dist/cli/cli/parser.js +89 -0
- package/dist/cli/cli/registry.js +185 -0
- package/dist/cli/cli/spec.js +41 -0
- package/dist/cli/cli/suggest.js +125 -0
- package/dist/cli/cli/version.js +30 -0
- package/dist/cli/cli/vocabulary.js +87 -0
- package/dist/cli/commands/doctor.js +365 -0
- package/dist/cli/commands/gateway.js +290 -0
- package/dist/cli/commands/migrate.js +270 -0
- package/dist/cli/commands/plugin.js +97 -0
- package/dist/cli/commands/setup.js +230 -0
- package/dist/cli/config-file.js +133 -0
- package/dist/cli/master-key.js +78 -0
- package/dist/cli/open-browser.js +59 -0
- package/dist/cli/web-assets.js +58 -0
- package/dist/gateway/auth.js +46 -0
- package/dist/gateway/config-format.js +202 -0
- package/dist/gateway/config.js +427 -0
- package/dist/gateway/context.js +1 -0
- package/dist/gateway/env-file.js +129 -0
- package/dist/gateway/events.js +172 -0
- package/dist/gateway/guard/tagging.js +505 -0
- package/dist/gateway/handlers/index.js +66 -0
- package/dist/gateway/handlers/memory.js +54 -0
- package/dist/gateway/handlers/providers.js +73 -0
- package/dist/gateway/handlers/registry.js +39 -0
- package/dist/gateway/handlers/sessions.js +188 -0
- package/dist/gateway/handlers/system.js +12 -0
- package/dist/gateway/handlers/tasks.js +191 -0
- package/dist/gateway/handlers/turn.js +100 -0
- package/dist/gateway/index.js +126 -0
- package/dist/gateway/main.js +23 -0
- package/dist/gateway/server.js +354 -0
- package/dist/gateway/services/context-limits.js +75 -0
- package/dist/gateway/services/history-normalizer.js +42 -0
- package/dist/gateway/services/image-pipeline.js +56 -0
- package/dist/gateway/services/key-roulette-client.js +43 -0
- package/dist/gateway/services/llm-client.js +593 -0
- package/dist/gateway/services/llm-decoder.js +200 -0
- package/dist/gateway/services/local-fallback.js +135 -0
- package/dist/gateway/services/memory.js +511 -0
- package/dist/gateway/services/persistent-memory.js +196 -0
- package/dist/gateway/services/providers.js +44 -0
- package/dist/gateway/services/tasks.js +237 -0
- package/dist/gateway/services/verification.js +124 -0
- package/dist/gateway/services/vision-payload.js +48 -0
- package/dist/gateway/services.js +257 -0
- package/dist/gateway/session-snapshot.js +19 -0
- package/dist/gateway/sessions.js +701 -0
- package/dist/gateway/static.js +239 -0
- package/dist/gateway/turns/clarify-tool.js +57 -0
- package/dist/gateway/turns/cronjob-tool.js +96 -0
- package/dist/gateway/turns/deferred-tools.js +154 -0
- package/dist/gateway/turns/execute-code-tool.js +84 -0
- package/dist/gateway/turns/file-tool-defs.js +178 -0
- package/dist/gateway/turns/file-tool-ops.js +178 -0
- package/dist/gateway/turns/file-tool-scan.js +182 -0
- package/dist/gateway/turns/file-tool.js +302 -0
- package/dist/gateway/turns/index.js +416 -0
- package/dist/gateway/turns/jev-middleware.js +91 -0
- package/dist/gateway/turns/local-reply.js +156 -0
- package/dist/gateway/turns/mcp-client.js +643 -0
- package/dist/gateway/turns/memory-tool.js +171 -0
- package/dist/gateway/turns/middleware.js +96 -0
- package/dist/gateway/turns/python-core.js +397 -0
- package/dist/gateway/turns/routing/index.js +3 -0
- package/dist/gateway/turns/routing/intent-classifier.js +60 -0
- package/dist/gateway/turns/routing/planner-adapter.js +91 -0
- package/dist/gateway/turns/routing/types.js +1 -0
- package/dist/gateway/turns/runtime-deps.js +228 -0
- package/dist/gateway/turns/self-config-tool.js +277 -0
- package/dist/gateway/turns/service-types.js +11 -0
- package/dist/gateway/turns/service.js +820 -0
- package/dist/gateway/turns/session-adapter.js +158 -0
- package/dist/gateway/turns/session-tool.js +49 -0
- package/dist/gateway/turns/shell-tool.js +190 -0
- package/dist/gateway/turns/skill-tool.js +239 -0
- package/dist/gateway/turns/spillover.js +201 -0
- package/dist/gateway/turns/subagent-tool.js +140 -0
- package/dist/gateway/turns/system-prompt.js +121 -0
- package/dist/gateway/turns/tool-schema.js +90 -0
- package/dist/gateway/turns/turn-utils.js +58 -0
- package/dist/gateway/turns/vision-tool.js +120 -0
- package/dist/gateway/types.js +1 -0
- package/dist/native/win32-x64/boombot-native-host.exe +0 -0
- package/dist/node_modules/@boombot/channels/handlers.d.ts +9 -0
- package/dist/node_modules/@boombot/channels/handlers.js +109 -0
- package/dist/node_modules/@boombot/channels/index.d.ts +12 -0
- package/dist/node_modules/@boombot/channels/index.js +12 -0
- package/dist/node_modules/@boombot/channels/package.json +9 -0
- package/dist/node_modules/@boombot/channels/service.d.ts +62 -0
- package/dist/node_modules/@boombot/channels/service.js +608 -0
- package/dist/node_modules/@boombot/channels/tool.d.ts +10 -0
- package/dist/node_modules/@boombot/channels/tool.js +46 -0
- package/dist/node_modules/@boombot/channels/transports/common/dedup.d.ts +17 -0
- package/dist/node_modules/@boombot/channels/transports/common/dedup.js +42 -0
- package/dist/node_modules/@boombot/channels/transports/common/handoff.d.ts +19 -0
- package/dist/node_modules/@boombot/channels/transports/common/handoff.js +32 -0
- package/dist/node_modules/@boombot/channels/transports/common/index.d.ts +3 -0
- package/dist/node_modules/@boombot/channels/transports/common/index.js +3 -0
- package/dist/node_modules/@boombot/channels/transports/common/types.d.ts +99 -0
- package/dist/node_modules/@boombot/channels/transports/common/types.js +54 -0
- package/dist/node_modules/@boombot/channels/transports/common.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/common.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/dedup/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/dedup/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/dedup.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/dedup.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/discord/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/discord/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/discord/transport.d.ts +36 -0
- package/dist/node_modules/@boombot/channels/transports/discord/transport.js +199 -0
- package/dist/node_modules/@boombot/channels/transports/discord.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/discord.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/handoff.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/handoff.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/transport.d.ts +34 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/transport.js +180 -0
- package/dist/node_modules/@boombot/channels/transports/messenger.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/messenger.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/slack/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/slack/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/slack/transport.d.ts +35 -0
- package/dist/node_modules/@boombot/channels/transports/slack/transport.js +183 -0
- package/dist/node_modules/@boombot/channels/transports/slack.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/slack.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/streamer.d.ts +31 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/streamer.js +141 -0
- package/dist/node_modules/@boombot/channels/transports/streamer.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/streamer.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/transport.d.ts +75 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/transport.js +395 -0
- package/dist/node_modules/@boombot/channels/transports/telegram.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/telegram.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/transport.d.ts +27 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/transport.js +97 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.d.ts +38 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.js +189 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/index.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/index.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/oa.d.ts +28 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/oa.js +94 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/personal.d.ts +106 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/personal.js +171 -0
- package/dist/node_modules/@boombot/channels/transports/zalo-personal.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo-personal.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo.js +2 -0
- package/dist/node_modules/@boombot/core/agent-core/index.d.ts +12 -0
- package/dist/node_modules/@boombot/core/agent-core/index.js +12 -0
- package/dist/node_modules/@boombot/core/agent-core/middleware.d.ts +60 -0
- package/dist/node_modules/@boombot/core/agent-core/middleware.js +152 -0
- package/dist/node_modules/@boombot/core/agent-core/routing.d.ts +128 -0
- package/dist/node_modules/@boombot/core/agent-core/routing.js +437 -0
- package/dist/node_modules/@boombot/core/agent-core/runtime-deps.d.ts +88 -0
- package/dist/node_modules/@boombot/core/agent-core/runtime-deps.js +8 -0
- package/dist/node_modules/@boombot/core/agent-core/tool-errors.d.ts +44 -0
- package/dist/node_modules/@boombot/core/agent-core/tool-errors.js +60 -0
- package/dist/node_modules/@boombot/core/agent-core/turn-loop.d.ts +21 -0
- package/dist/node_modules/@boombot/core/agent-core/turn-loop.js +561 -0
- package/dist/node_modules/@boombot/core/agent-core/types.d.ts +189 -0
- package/dist/node_modules/@boombot/core/agent-core/types.js +7 -0
- package/dist/node_modules/@boombot/core/compaction/compactor.d.ts +19 -0
- package/dist/node_modules/@boombot/core/compaction/compactor.js +127 -0
- package/dist/node_modules/@boombot/core/compaction/estimator.d.ts +10 -0
- package/dist/node_modules/@boombot/core/compaction/estimator.js +48 -0
- package/dist/node_modules/@boombot/core/compaction/index.d.ts +3 -0
- package/dist/node_modules/@boombot/core/compaction/index.js +3 -0
- package/dist/node_modules/@boombot/core/compaction/types.d.ts +31 -0
- package/dist/node_modules/@boombot/core/compaction/types.js +7 -0
- package/dist/node_modules/@boombot/core/index.d.ts +9 -0
- package/dist/node_modules/@boombot/core/index.js +9 -0
- package/dist/node_modules/@boombot/core/jev/index.d.ts +2 -0
- package/dist/node_modules/@boombot/core/jev/index.js +2 -0
- package/dist/node_modules/@boombot/core/jev/jev.d.ts +30 -0
- package/dist/node_modules/@boombot/core/jev/jev.js +164 -0
- package/dist/node_modules/@boombot/core/jev/types.d.ts +22 -0
- package/dist/node_modules/@boombot/core/jev/types.js +1 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/budget.d.ts +63 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/budget.js +94 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.d.ts +152 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.js +318 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/index.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/index.js +12 -0
- package/dist/node_modules/@boombot/core/memory/curation.d.ts +86 -0
- package/dist/node_modules/@boombot/core/memory/curation.js +120 -0
- package/dist/node_modules/@boombot/core/memory/errors.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/errors.js +20 -0
- package/dist/node_modules/@boombot/core/memory/hybrid-search.d.ts +29 -0
- package/dist/node_modules/@boombot/core/memory/hybrid-search.js +52 -0
- package/dist/node_modules/@boombot/core/memory/index.d.ts +23 -0
- package/dist/node_modules/@boombot/core/memory/index.js +23 -0
- package/dist/node_modules/@boombot/core/memory/indexer.d.ts +47 -0
- package/dist/node_modules/@boombot/core/memory/indexer.js +138 -0
- package/dist/node_modules/@boombot/core/memory/lifecycle.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/lifecycle.js +66 -0
- package/dist/node_modules/@boombot/core/memory/provider.d.ts +84 -0
- package/dist/node_modules/@boombot/core/memory/provider.js +117 -0
- package/dist/node_modules/@boombot/core/memory/recall.d.ts +7 -0
- package/dist/node_modules/@boombot/core/memory/recall.js +111 -0
- package/dist/node_modules/@boombot/core/memory/scope-resolver.d.ts +27 -0
- package/dist/node_modules/@boombot/core/memory/scope-resolver.js +60 -0
- package/dist/node_modules/@boombot/core/memory/search.d.ts +37 -0
- package/dist/node_modules/@boombot/core/memory/search.js +158 -0
- package/dist/node_modules/@boombot/core/memory/store.d.ts +60 -0
- package/dist/node_modules/@boombot/core/memory/store.js +289 -0
- package/dist/node_modules/@boombot/core/memory/types.d.ts +121 -0
- package/dist/node_modules/@boombot/core/memory/types.js +21 -0
- package/dist/node_modules/@boombot/core/memory/vector-index.d.ts +34 -0
- package/dist/node_modules/@boombot/core/memory/vector-index.js +65 -0
- package/dist/node_modules/@boombot/core/package.json +9 -0
- package/dist/node_modules/@boombot/core/reflection/classifier.d.ts +13 -0
- package/dist/node_modules/@boombot/core/reflection/classifier.js +77 -0
- package/dist/node_modules/@boombot/core/reflection/index.d.ts +2 -0
- package/dist/node_modules/@boombot/core/reflection/index.js +2 -0
- package/dist/node_modules/@boombot/core/reflection/types.d.ts +13 -0
- package/dist/node_modules/@boombot/core/reflection/types.js +4 -0
- package/dist/node_modules/@boombot/core/research/config.d.ts +89 -0
- package/dist/node_modules/@boombot/core/research/config.js +206 -0
- package/dist/node_modules/@boombot/core/research/crawl.d.ts +36 -0
- package/dist/node_modules/@boombot/core/research/crawl.js +179 -0
- package/dist/node_modules/@boombot/core/research/factory.d.ts +26 -0
- package/dist/node_modules/@boombot/core/research/factory.js +46 -0
- package/dist/node_modules/@boombot/core/research/http.d.ts +87 -0
- package/dist/node_modules/@boombot/core/research/http.js +250 -0
- package/dist/node_modules/@boombot/core/research/index.d.ts +17 -0
- package/dist/node_modules/@boombot/core/research/index.js +10 -0
- package/dist/node_modules/@boombot/core/research/orchestrator.d.ts +113 -0
- package/dist/node_modules/@boombot/core/research/orchestrator.js +252 -0
- package/dist/node_modules/@boombot/core/research/parse/docx.d.ts +24 -0
- package/dist/node_modules/@boombot/core/research/parse/docx.js +183 -0
- package/dist/node_modules/@boombot/core/research/parse/guards.d.ts +89 -0
- package/dist/node_modules/@boombot/core/research/parse/guards.js +171 -0
- package/dist/node_modules/@boombot/core/research/parse/index.d.ts +68 -0
- package/dist/node_modules/@boombot/core/research/parse/index.js +219 -0
- package/dist/node_modules/@boombot/core/research/parse/pdf.d.ts +38 -0
- package/dist/node_modules/@boombot/core/research/parse/pdf.js +567 -0
- package/dist/node_modules/@boombot/core/research/providers/arxiv.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/arxiv.js +72 -0
- package/dist/node_modules/@boombot/core/research/providers/brave.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/brave.js +36 -0
- package/dist/node_modules/@boombot/core/research/providers/duckduckgo.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/duckduckgo.js +78 -0
- package/dist/node_modules/@boombot/core/research/providers/exa.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/exa.js +34 -0
- package/dist/node_modules/@boombot/core/research/providers/firecrawl.d.ts +16 -0
- package/dist/node_modules/@boombot/core/research/providers/firecrawl.js +47 -0
- package/dist/node_modules/@boombot/core/research/providers/index.d.ts +17 -0
- package/dist/node_modules/@boombot/core/research/providers/index.js +11 -0
- package/dist/node_modules/@boombot/core/research/providers/jina.d.ts +13 -0
- package/dist/node_modules/@boombot/core/research/providers/jina.js +114 -0
- package/dist/node_modules/@boombot/core/research/providers/openalex.d.ts +14 -0
- package/dist/node_modules/@boombot/core/research/providers/openalex.js +66 -0
- package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.js +56 -0
- package/dist/node_modules/@boombot/core/research/providers/tavily.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/tavily.js +35 -0
- package/dist/node_modules/@boombot/core/research/providers/wikipedia.d.ts +12 -0
- package/dist/node_modules/@boombot/core/research/providers/wikipedia.js +47 -0
- package/dist/node_modules/@boombot/core/research/tools.d.ts +27 -0
- package/dist/node_modules/@boombot/core/research/tools.js +251 -0
- package/dist/node_modules/@boombot/core/research/types.d.ts +133 -0
- package/dist/node_modules/@boombot/core/research/types.js +8 -0
- package/dist/node_modules/@boombot/core/research/wiring.d.ts +25 -0
- package/dist/node_modules/@boombot/core/research/wiring.js +51 -0
- package/dist/node_modules/@boombot/core/scheduler/cron.d.ts +34 -0
- package/dist/node_modules/@boombot/core/scheduler/cron.js +147 -0
- package/dist/node_modules/@boombot/core/scheduler/evaluator.d.ts +42 -0
- package/dist/node_modules/@boombot/core/scheduler/evaluator.js +148 -0
- package/dist/node_modules/@boombot/core/scheduler/index.d.ts +15 -0
- package/dist/node_modules/@boombot/core/scheduler/index.js +15 -0
- package/dist/node_modules/@boombot/core/scheduler/registry.d.ts +81 -0
- package/dist/node_modules/@boombot/core/scheduler/registry.js +263 -0
- package/dist/node_modules/@boombot/core/scheduler/runner.d.ts +59 -0
- package/dist/node_modules/@boombot/core/scheduler/runner.js +257 -0
- package/dist/node_modules/@boombot/core/scheduler/store.d.ts +150 -0
- package/dist/node_modules/@boombot/core/scheduler/store.js +526 -0
- package/dist/node_modules/@boombot/core/scheduler/timezone.d.ts +35 -0
- package/dist/node_modules/@boombot/core/scheduler/timezone.js +96 -0
- package/dist/node_modules/@boombot/core/scheduler/types.d.ts +157 -0
- package/dist/node_modules/@boombot/core/scheduler/types.js +89 -0
- package/dist/node_modules/@boombot/core/task-runner/index.d.ts +7 -0
- package/dist/node_modules/@boombot/core/task-runner/index.js +5 -0
- package/dist/node_modules/@boombot/core/task-runner/planner.d.ts +37 -0
- package/dist/node_modules/@boombot/core/task-runner/planner.js +154 -0
- package/dist/node_modules/@boombot/core/task-runner/runner.d.ts +8 -0
- package/dist/node_modules/@boombot/core/task-runner/runner.js +564 -0
- package/dist/node_modules/@boombot/core/task-runner/store.d.ts +28 -0
- package/dist/node_modules/@boombot/core/task-runner/store.js +126 -0
- package/dist/node_modules/@boombot/core/task-runner/types.d.ts +138 -0
- package/dist/node_modules/@boombot/core/task-runner/types.js +11 -0
- package/dist/node_modules/@boombot/core/workflow/dag.d.ts +16 -0
- package/dist/node_modules/@boombot/core/workflow/dag.js +109 -0
- package/dist/node_modules/@boombot/core/workflow/engine.d.ts +34 -0
- package/dist/node_modules/@boombot/core/workflow/engine.js +304 -0
- package/dist/node_modules/@boombot/core/workflow/index.d.ts +3 -0
- package/dist/node_modules/@boombot/core/workflow/index.js +3 -0
- package/dist/node_modules/@boombot/core/workflow/types.d.ts +98 -0
- package/dist/node_modules/@boombot/core/workflow/types.js +21 -0
- package/dist/node_modules/@boombot/cronjobs/handlers.d.ts +11 -0
- package/dist/node_modules/@boombot/cronjobs/handlers.js +174 -0
- package/dist/node_modules/@boombot/cronjobs/index.d.ts +2 -0
- package/dist/node_modules/@boombot/cronjobs/index.js +2 -0
- package/dist/node_modules/@boombot/cronjobs/package.json +9 -0
- package/dist/node_modules/@boombot/cronjobs/service.d.ts +53 -0
- package/dist/node_modules/@boombot/cronjobs/service.js +200 -0
- package/dist/node_modules/@boombot/plugins/index.d.ts +2 -0
- package/dist/node_modules/@boombot/plugins/index.js +2 -0
- package/dist/node_modules/@boombot/plugins/installer.d.ts +45 -0
- package/dist/node_modules/@boombot/plugins/installer.js +487 -0
- package/dist/node_modules/@boombot/plugins/manager.d.ts +23 -0
- package/dist/node_modules/@boombot/plugins/manager.js +243 -0
- package/dist/node_modules/@boombot/plugins/package.json +9 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.d.ts +125 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.js +76 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.d.ts +220 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.js +60 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.d.ts +33 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.js +25 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.d.ts +4349 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.js +563 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.d.ts +32 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.js +61 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.d.ts +13 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.js +16 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/events.d.ts +567 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/events.js +395 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/index.d.ts +20 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/index.js +13 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/types.d.ts +91 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/types.js +7 -0
- package/dist/node_modules/@boombot/protocol/index.d.ts +4 -0
- package/dist/node_modules/@boombot/protocol/index.js +3 -0
- package/dist/node_modules/@boombot/protocol/package.json +9 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.d.ts +41 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.js +17 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/index.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/index.js +10 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.d.ts +58 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.js +116 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.d.ts +25 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.js +1 -0
- package/dist/node_modules/@boombot/protocol/providers/cipher.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/cipher.js +52 -0
- package/dist/node_modules/@boombot/protocol/providers/index.d.ts +19 -0
- package/dist/node_modules/@boombot/protocol/providers/index.js +19 -0
- package/dist/node_modules/@boombot/protocol/providers/key-roulette.d.ts +79 -0
- package/dist/node_modules/@boombot/protocol/providers/key-roulette.js +81 -0
- package/dist/node_modules/@boombot/protocol/providers/probe.d.ts +29 -0
- package/dist/node_modules/@boombot/protocol/providers/probe.js +96 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.d.ts +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/custom.d.ts +22 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/custom.js +222 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.js +9 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/google.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/google.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/index.d.ts +31 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/index.js +56 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/local.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/local.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.js +9 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/types.d.ts +58 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/types.js +1 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/xai.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/xai.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/request-profile.d.ts +102 -0
- package/dist/node_modules/@boombot/protocol/providers/request-profile.js +118 -0
- package/dist/node_modules/@boombot/protocol/providers/service.d.ts +2 -0
- package/dist/node_modules/@boombot/protocol/providers/service.js +418 -0
- package/dist/node_modules/@boombot/protocol/providers/types.d.ts +141 -0
- package/dist/node_modules/@boombot/protocol/providers/types.js +16 -0
- package/dist/node_modules/@boombot/sandbox/fs-path.d.ts +13 -0
- package/dist/node_modules/@boombot/sandbox/fs-path.js +79 -0
- package/dist/node_modules/@boombot/sandbox/index.d.ts +13 -0
- package/dist/node_modules/@boombot/sandbox/index.js +13 -0
- package/dist/node_modules/@boombot/sandbox/native.d.ts +39 -0
- package/dist/node_modules/@boombot/sandbox/native.js +224 -0
- package/dist/node_modules/@boombot/sandbox/package.json +9 -0
- package/dist/node_modules/@boombot/sandbox/sandbox.d.ts +92 -0
- package/dist/node_modules/@boombot/sandbox/sandbox.js +229 -0
- package/dist/node_modules/@boombot/security/harness-guard/boundary.d.ts +22 -0
- package/dist/node_modules/@boombot/security/harness-guard/boundary.js +105 -0
- package/dist/node_modules/@boombot/security/harness-guard/gates.d.ts +90 -0
- package/dist/node_modules/@boombot/security/harness-guard/gates.js +791 -0
- package/dist/node_modules/@boombot/security/harness-guard/index.d.ts +23 -0
- package/dist/node_modules/@boombot/security/harness-guard/index.js +23 -0
- package/dist/node_modules/@boombot/security/harness-guard/policy.d.ts +20 -0
- package/dist/node_modules/@boombot/security/harness-guard/policy.js +70 -0
- package/dist/node_modules/@boombot/security/harness-guard/sanitizer.d.ts +53 -0
- package/dist/node_modules/@boombot/security/harness-guard/sanitizer.js +145 -0
- package/dist/node_modules/@boombot/security/harness-guard/types.d.ts +71 -0
- package/dist/node_modules/@boombot/security/harness-guard/types.js +10 -0
- package/dist/node_modules/@boombot/security/harness-guard/verifier.d.ts +59 -0
- package/dist/node_modules/@boombot/security/harness-guard/verifier.js +169 -0
- package/dist/node_modules/@boombot/security/index.d.ts +5 -0
- package/dist/node_modules/@boombot/security/index.js +9 -0
- package/dist/node_modules/@boombot/security/package.json +9 -0
- package/dist/node_modules/@boombot/security/policy/approval.d.ts +117 -0
- package/dist/node_modules/@boombot/security/policy/approval.js +223 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.d.ts +10 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.js +124 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.d.ts +25 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.js +70 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/gate.d.ts +38 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/gate.js +61 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.d.ts +12 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.js +234 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/index.d.ts +17 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/index.js +13 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/policy.d.ts +15 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/policy.js +39 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/types.d.ts +46 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/types.js +7 -0
- package/dist/node_modules/@boombot/security/security/approval.d.ts +63 -0
- package/dist/node_modules/@boombot/security/security/approval.js +140 -0
- package/dist/node_modules/@boombot/security/security/audit.d.ts +39 -0
- package/dist/node_modules/@boombot/security/security/audit.js +70 -0
- package/dist/node_modules/@boombot/security/security/index.d.ts +12 -0
- package/dist/node_modules/@boombot/security/security/index.js +12 -0
- package/dist/node_modules/@boombot/security/security/trust.d.ts +79 -0
- package/dist/node_modules/@boombot/security/security/trust.js +87 -0
- package/dist/package.json +5 -0
- package/dist/proto/agent_core.proto +56 -0
- package/dist/python/agent-core-python/pyproject.toml +40 -0
- package/dist/python/agent-core-python/src/boombot_agent/__init__.py +5 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/__init__.py +0 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2.py +54 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2_grpc.py +140 -0
- package/dist/python/agent-core-python/src/boombot_agent/rpc.py +265 -0
- package/dist/python/agent-core-python/src/boombot_agent/turn.py +577 -0
- package/dist/python/agent-core-python/src/boombot_ml/__init__.py +12 -0
- package/dist/python/agent-core-python/src/boombot_ml/embeddings.py +58 -0
- package/dist/python/agent-core-python/src/boombot_ml/training.py +156 -0
- package/dist/python/agent-core-python/uv.lock +2856 -0
- package/dist/web/assets/ChatView-BZrSD-64.js +262 -0
- package/dist/web/assets/ChatView-Cahbjez6.css +1 -0
- package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/web/assets/MemoryView-BJbXqqs7.css +1 -0
- package/dist/web/assets/MemoryView-BfMq_6CD.js +1 -0
- package/dist/web/assets/SchedulesView-B22QmPR-.js +1 -0
- package/dist/web/assets/SchedulesView-C6XK7A8a.css +1 -0
- package/dist/web/assets/SessionsView-C1dqdhxI.css +1 -0
- package/dist/web/assets/SessionsView-DS0-aH2a.js +1 -0
- package/dist/web/assets/TasksView-Dtasg4hd.css +1 -0
- package/dist/web/assets/TasksView-ey0FLsW8.js +2 -0
- package/dist/web/assets/Textarea-DN3Zybl1.js +1 -0
- package/dist/web/assets/Tooltip-Bn2cqFPz.css +1 -0
- package/dist/web/assets/Tooltip-MzV2Gqnc.js +1 -0
- package/dist/web/assets/browser-Bnt73-Ub.js +8 -0
- package/dist/web/assets/index-BL8bi7Yt.css +1 -0
- package/dist/web/assets/index-CuPR73Tn.js +73 -0
- package/dist/web/favicon.svg +4 -0
- package/dist/web/index.html +26 -0
- package/dist/web/logo.jpg +0 -0
- package/dist/web/logo.png +0 -0
- package/package.json +51 -4
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BoomBot config file: read/write/validate `~/.boombot/config.json`.
|
|
3
|
+
*
|
|
4
|
+
* Format matches the spec shared with the gateway (executor A): the gateway
|
|
5
|
+
* reads exactly these fields. Channel sections are optional. Secrets are
|
|
6
|
+
* stored in the file (permissions 0600 on POSIX — a no-op on Windows, see
|
|
7
|
+
* SECURITY.md §5) — API keys are stored as sha256
|
|
8
|
+
* hashes only; the raw key is printed once at generation time and never
|
|
9
|
+
* persisted or logged.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
12
|
+
import { chmodSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
13
|
+
import { homedir } from 'node:os';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
export class ConfigError extends Error {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'ConfigError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** `~/...` → absolute path using the current user's home directory. */
|
|
22
|
+
export function expandTilde(p) {
|
|
23
|
+
if (p === '~')
|
|
24
|
+
return homedir();
|
|
25
|
+
if (p.startsWith('~/') || p.startsWith('~\\'))
|
|
26
|
+
return path.join(homedir(), p.slice(2));
|
|
27
|
+
return p;
|
|
28
|
+
}
|
|
29
|
+
/** Safe profile names cannot escape `~/.boombot/profiles`. */
|
|
30
|
+
export function isValidProfileName(value) {
|
|
31
|
+
return /^[a-z0-9][a-z0-9_-]{0,63}$/u.test(value);
|
|
32
|
+
}
|
|
33
|
+
/** Config path: `$BOOMBOT_CONFIG`, a named profile, or the legacy default. */
|
|
34
|
+
export function resolveConfigPath() {
|
|
35
|
+
const fromEnv = process.env['BOOMBOT_CONFIG'];
|
|
36
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
37
|
+
return expandTilde(fromEnv);
|
|
38
|
+
const profile = process.env['BOOMBOT_PROFILE'];
|
|
39
|
+
if (profile !== undefined && profile !== '') {
|
|
40
|
+
if (!isValidProfileName(profile)) {
|
|
41
|
+
throw new ConfigError('BOOMBOT_PROFILE must match [a-z0-9][a-z0-9_-]{0,63}');
|
|
42
|
+
}
|
|
43
|
+
return path.join(homedir(), '.boombot', 'profiles', profile, 'config.json');
|
|
44
|
+
}
|
|
45
|
+
return path.join(homedir(), '.boombot', 'config.json');
|
|
46
|
+
}
|
|
47
|
+
/** Load config from disk. Returns `null` when the file does not exist. */
|
|
48
|
+
export function loadConfig(configPath = resolveConfigPath()) {
|
|
49
|
+
let raw;
|
|
50
|
+
try {
|
|
51
|
+
raw = readFileSync(configPath, 'utf8');
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
if (err.code === 'ENOENT')
|
|
55
|
+
return null;
|
|
56
|
+
throw new ConfigError(`cannot read config file ${configPath}: ${err.message}`);
|
|
57
|
+
}
|
|
58
|
+
let parsed;
|
|
59
|
+
try {
|
|
60
|
+
parsed = JSON.parse(raw);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
throw new ConfigError(`config file ${configPath} is not valid JSON: ${err.message}`);
|
|
64
|
+
}
|
|
65
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
66
|
+
throw new ConfigError(`config file ${configPath} must contain a JSON object`);
|
|
67
|
+
}
|
|
68
|
+
return parsed;
|
|
69
|
+
}
|
|
70
|
+
/** True when the config contains any secret material (tokens, key hash). */
|
|
71
|
+
export function configHasSecrets(config) {
|
|
72
|
+
return (config.apiKeyHash !== undefined ||
|
|
73
|
+
(config.telegram?.botToken ?? '') !== '' ||
|
|
74
|
+
(config.discord?.botToken ?? '') !== '' ||
|
|
75
|
+
(config.slack?.botToken ?? '') !== '' ||
|
|
76
|
+
(config.whatsapp?.accessToken ?? '') !== '');
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Write config to disk (creates parent dirs). When the config contains
|
|
80
|
+
* secrets the file is chmod'ed to 0600.
|
|
81
|
+
*
|
|
82
|
+
* POSIX-only: on Windows `chmodSync` cannot set ACLs (no-op), so the file
|
|
83
|
+
* is NOT actually protected there — `boombot doctor` reports WARN instead
|
|
84
|
+
* of PASS in that case. See SECURITY.md §5.
|
|
85
|
+
*/
|
|
86
|
+
export function saveConfig(config, configPath = resolveConfigPath(), flag = 'w') {
|
|
87
|
+
mkdirSync(path.dirname(configPath), { recursive: true });
|
|
88
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', {
|
|
89
|
+
encoding: 'utf8', flag, mode: configHasSecrets(config) ? 0o600 : 0o666,
|
|
90
|
+
});
|
|
91
|
+
if (configHasSecrets(config)) {
|
|
92
|
+
chmodSync(configPath, 0o600);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Basic validation; returns a list of human-readable problems (empty = valid). */
|
|
96
|
+
export function validateConfig(config) {
|
|
97
|
+
const problems = [];
|
|
98
|
+
if (typeof config.host !== 'string' || config.host.trim() === '') {
|
|
99
|
+
problems.push('host must be a non-empty string');
|
|
100
|
+
}
|
|
101
|
+
if (!Number.isInteger(config.port) || config.port < 1 || config.port > 65535) {
|
|
102
|
+
problems.push('port must be an integer between 1 and 65535');
|
|
103
|
+
}
|
|
104
|
+
if (typeof config.dataDir !== 'string' || config.dataDir.trim() === '') {
|
|
105
|
+
problems.push('dataDir must be a non-empty string');
|
|
106
|
+
}
|
|
107
|
+
if (config.apiKeyHash !== undefined && !/^[0-9a-f]{64}$/.test(config.apiKeyHash)) {
|
|
108
|
+
problems.push('apiKeyHash must be a sha256 hex string (64 lowercase hex chars)');
|
|
109
|
+
}
|
|
110
|
+
return problems;
|
|
111
|
+
}
|
|
112
|
+
/** Generate a fresh API key: 32 random bytes as hex; hash with sha256. */
|
|
113
|
+
/**
|
|
114
|
+
* sha256 hex digest of an API key — the only form ever persisted. The gateway
|
|
115
|
+
* computes the same digest in its `auth.ts`; this is the single owner of the
|
|
116
|
+
* recipe on the CLI side, so nothing else re-implements it and drifts.
|
|
117
|
+
*/
|
|
118
|
+
export function hashApiKey(apiKey) {
|
|
119
|
+
return createHash('sha256').update(apiKey, 'utf8').digest('hex');
|
|
120
|
+
}
|
|
121
|
+
export function generateApiKey() {
|
|
122
|
+
const apiKey = randomBytes(32).toString('hex');
|
|
123
|
+
return { apiKey, apiKeyHash: hashApiKey(apiKey) };
|
|
124
|
+
}
|
|
125
|
+
/** Current permission bits of a file (e.g. 0o600), or null when it cannot be stat'ed. */
|
|
126
|
+
export function fileModeBits(filePath) {
|
|
127
|
+
try {
|
|
128
|
+
return statSync(filePath).mode & 0o777;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Master key for provider API-key encryption (`@boombot/protocol`).
|
|
3
|
+
*
|
|
4
|
+
* The gateway refuses to boot without `BOOMBOT_MASTER_KEY` (its provider
|
|
5
|
+
* service stores keys AES-256-GCM encrypted). For the `npm i -g` golden path
|
|
6
|
+
* (`boombot setup` → `boombot gateway`) the wizard generates the key once and
|
|
7
|
+
* stores it at `~/.boombot/master.key` (next to the config file, mode 0600 on
|
|
8
|
+
* POSIX); `boombot gateway` loads it into the environment before booting the
|
|
9
|
+
* gateway in-process.
|
|
10
|
+
*
|
|
11
|
+
* The raw key is never printed or logged — only its presence is reported.
|
|
12
|
+
*/
|
|
13
|
+
import { randomBytes } from 'node:crypto';
|
|
14
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { resolveConfigPath } from "./config-file.js";
|
|
17
|
+
/**
|
|
18
|
+
* Default master-key path: `master.key` next to the config file
|
|
19
|
+
* (`~/.boombot/master.key` unless `$BOOMBOT_CONFIG` points elsewhere).
|
|
20
|
+
*/
|
|
21
|
+
export function resolveMasterKeyPath(configPath = resolveConfigPath()) {
|
|
22
|
+
return path.join(path.dirname(configPath), 'master.key');
|
|
23
|
+
}
|
|
24
|
+
/** Read the stored master key, or `null` when absent/empty/unreadable. */
|
|
25
|
+
export function loadMasterKey(keyPath = resolveMasterKeyPath()) {
|
|
26
|
+
let raw;
|
|
27
|
+
try {
|
|
28
|
+
raw = readFileSync(keyPath, 'utf8');
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const key = raw.trim();
|
|
34
|
+
return key === '' ? null : key;
|
|
35
|
+
}
|
|
36
|
+
/** True when a master key is available (file or environment). */
|
|
37
|
+
export function hasMasterKey(keyPath = resolveMasterKeyPath()) {
|
|
38
|
+
const fromEnv = process.env['BOOMBOT_MASTER_KEY'];
|
|
39
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
40
|
+
return true;
|
|
41
|
+
return existsSync(keyPath) && loadMasterKey(keyPath) !== null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Return the existing master key, generating and persisting a fresh one
|
|
45
|
+
* (0600 on POSIX; best-effort on Windows, see SECURITY.md §5) when absent.
|
|
46
|
+
*/
|
|
47
|
+
export function ensureMasterKey(keyPath = resolveMasterKeyPath()) {
|
|
48
|
+
const existing = loadMasterKey(keyPath);
|
|
49
|
+
if (existing !== null)
|
|
50
|
+
return existing;
|
|
51
|
+
const key = randomBytes(32).toString('hex');
|
|
52
|
+
mkdirSync(path.dirname(keyPath), { recursive: true });
|
|
53
|
+
writeFileSync(keyPath, `${key}\n`, { encoding: 'utf8', flag: 'wx', mode: 0o600 });
|
|
54
|
+
if (process.platform !== 'win32') {
|
|
55
|
+
chmodSync(keyPath, 0o600);
|
|
56
|
+
}
|
|
57
|
+
return key;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Make sure `BOOMBOT_MASTER_KEY` is set in this process before the gateway
|
|
61
|
+
* boots (the CLI runs the gateway in-process). Prefers an already-set env
|
|
62
|
+
* var; falls back to the stored key file.
|
|
63
|
+
*
|
|
64
|
+
* Throws a human-readable error when no key can be found — the caller
|
|
65
|
+
* (`boombot gateway`) surfaces it instead of the gateway's boot crash.
|
|
66
|
+
*/
|
|
67
|
+
export function ensureMasterKeyEnv(keyPath = resolveMasterKeyPath()) {
|
|
68
|
+
const fromEnv = process.env['BOOMBOT_MASTER_KEY'];
|
|
69
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
70
|
+
return;
|
|
71
|
+
const stored = loadMasterKey(keyPath);
|
|
72
|
+
if (stored === null) {
|
|
73
|
+
throw new Error('no master key found: the gateway needs BOOMBOT_MASTER_KEY to decrypt provider API keys.\n' +
|
|
74
|
+
`Run \`boombot setup\` to generate one (stored at ${keyPath}, mode 0600), ` +
|
|
75
|
+
'or set BOOMBOT_MASTER_KEY in the environment.');
|
|
76
|
+
}
|
|
77
|
+
process.env['BOOMBOT_MASTER_KEY'] = stored;
|
|
78
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Best-effort "open this URL in the user's browser".
|
|
3
|
+
*
|
|
4
|
+
* Used by `boombot gateway` after the server is listening. Platform-native:
|
|
5
|
+
* `open` (macOS), `cmd /c start` (Windows), `xdg-open` (Linux/others).
|
|
6
|
+
* Never throws and never blocks the CLI: headless machines, missing helpers
|
|
7
|
+
* or a denied spawn all degrade to "the URL was printed, open it yourself".
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
/** Opt-out env var (headless servers, CI): `BOOMBOT_NO_BROWSER=1`. */
|
|
11
|
+
export const NO_BROWSER_ENV = 'BOOMBOT_NO_BROWSER';
|
|
12
|
+
function browserCommand(url) {
|
|
13
|
+
if (process.env[NO_BROWSER_ENV] === '1')
|
|
14
|
+
return null;
|
|
15
|
+
switch (process.platform) {
|
|
16
|
+
case 'darwin':
|
|
17
|
+
return { cmd: 'open', args: [url] };
|
|
18
|
+
case 'win32':
|
|
19
|
+
// `start` needs a (possibly empty) window title as its first argument.
|
|
20
|
+
return { cmd: 'cmd', args: ['/c', 'start', '', url] };
|
|
21
|
+
default:
|
|
22
|
+
return { cmd: 'xdg-open', args: [url] };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Open `url` in the default browser. Resolves `true` when the OS accepted
|
|
27
|
+
* the request, `false` when there was nothing to try or it failed.
|
|
28
|
+
* Never rejects.
|
|
29
|
+
*/
|
|
30
|
+
export async function openBrowser(url) {
|
|
31
|
+
const target = browserCommand(url);
|
|
32
|
+
if (target === null)
|
|
33
|
+
return false;
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
let settled = false;
|
|
36
|
+
const done = (ok) => {
|
|
37
|
+
if (!settled) {
|
|
38
|
+
settled = true;
|
|
39
|
+
resolve(ok);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
let child;
|
|
43
|
+
try {
|
|
44
|
+
// No shell: the URL is passed as a single argv entry (injection-safe).
|
|
45
|
+
// Detached + unref'd: the browser outlives the CLI; the CLI never
|
|
46
|
+
// waits for it.
|
|
47
|
+
child = spawn(target.cmd, target.args, { detached: true, stdio: 'ignore' });
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
done(false);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
child.once('error', () => done(false));
|
|
54
|
+
child.unref();
|
|
55
|
+
// Don't wait for the browser to exit — a short grace period is enough
|
|
56
|
+
// to catch an immediate spawn failure (e.g. helper not installed).
|
|
57
|
+
setTimeout(() => done(true), 400);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locate the bundled web-UI assets (`dist/web/`) from the CLI.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the gateway's file-relative resolution (`static.ts`), so
|
|
5
|
+
* `boombot doctor` can report whether the UI the gateway would serve actually
|
|
6
|
+
* exists — without depending on `process.cwd()`.
|
|
7
|
+
*
|
|
8
|
+
* Layouts handled (first existing directory wins):
|
|
9
|
+
* - npm dist, bundled CLI: `dist/bin/boombot.js` → `dist/web/`
|
|
10
|
+
* - npm dist, per-file tsc: `dist/bin/commands/*.js` → `dist/web/`
|
|
11
|
+
* - monorepo dev: `apps/cli/src/commands/*` → `apps/web/dist/`
|
|
12
|
+
* - `BOOMBOT_WEB_ROOT` (when set): explicit operator override, authoritative —
|
|
13
|
+
* a missing path reports not-found instead of probing other locations.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, statSync } from 'node:fs';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
function moduleDir() {
|
|
19
|
+
return path.dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
}
|
|
21
|
+
/** `true` when `dir` looks like `<pkg>/dist/bin[/…]` (the npm dist layout). */
|
|
22
|
+
export function isDistLayoutDir(dir) {
|
|
23
|
+
const parts = dir.split(path.sep);
|
|
24
|
+
const distIndex = parts.lastIndexOf('dist');
|
|
25
|
+
return distIndex >= 0 && parts[distIndex + 1] === 'bin';
|
|
26
|
+
}
|
|
27
|
+
function isDirectory(p) {
|
|
28
|
+
try {
|
|
29
|
+
return existsSync(p) && statSync(p).isDirectory();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function resolveWebAssets() {
|
|
36
|
+
const dir = moduleDir();
|
|
37
|
+
const isDistLayout = isDistLayoutDir(dir);
|
|
38
|
+
const override = process.env['BOOMBOT_WEB_ROOT'];
|
|
39
|
+
if (override !== undefined && override.trim() !== '') {
|
|
40
|
+
// Authoritative: an explicit override never falls back to probing.
|
|
41
|
+
const resolved = path.resolve(override);
|
|
42
|
+
const found = isDirectory(resolved);
|
|
43
|
+
return { found, path: found ? resolved : null, isDistLayout };
|
|
44
|
+
}
|
|
45
|
+
const candidates = [
|
|
46
|
+
// dist/bin/boombot.js → dist/web ; dist/bin/commands/x.js → dist/web
|
|
47
|
+
path.resolve(dir, '..', 'web'),
|
|
48
|
+
path.resolve(dir, '..', '..', 'web'),
|
|
49
|
+
// apps/cli/src → apps/web/dist (monorepo dev, `vite build` output)
|
|
50
|
+
path.resolve(dir, '..', '..', '..', 'apps', 'web', 'dist'),
|
|
51
|
+
];
|
|
52
|
+
for (const candidate of candidates) {
|
|
53
|
+
if (isDirectory(candidate)) {
|
|
54
|
+
return { found: true, path: candidate, isDistLayout };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { found: false, path: null, isDistLayout };
|
|
58
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Bearer authentication for the gateway HTTP server.
|
|
4
|
+
*
|
|
5
|
+
* The operator's API key is never stored: `config.apiKeyHash` holds the
|
|
6
|
+
* SHA-256 hex digest (written once by the setup flow), and every request's
|
|
7
|
+
* `Authorization: Bearer <key>` is hashed and compared in constant time.
|
|
8
|
+
* Failing checks never reveal whether the key was missing, malformed, or
|
|
9
|
+
* wrong — all are 401.
|
|
10
|
+
*/
|
|
11
|
+
/** SHA-256 hex digest of a raw API key. The raw key itself is never persisted. */
|
|
12
|
+
export function hashApiKey(key) {
|
|
13
|
+
return createHash('sha256').update(key, 'utf8').digest('hex');
|
|
14
|
+
}
|
|
15
|
+
/** Extract the bearer token from `Authorization: Bearer <token>`. Undefined when absent or malformed. */
|
|
16
|
+
export function extractBearerToken(req) {
|
|
17
|
+
const header = req.headers.authorization;
|
|
18
|
+
if (typeof header !== 'string')
|
|
19
|
+
return undefined;
|
|
20
|
+
const [scheme, token] = header.split(' ');
|
|
21
|
+
if (scheme?.toLowerCase() !== 'bearer' || !token)
|
|
22
|
+
return undefined;
|
|
23
|
+
return token;
|
|
24
|
+
}
|
|
25
|
+
function safeEqualHex(a, b) {
|
|
26
|
+
const aBuf = Buffer.from(a, 'utf8');
|
|
27
|
+
const bBuf = Buffer.from(b, 'utf8');
|
|
28
|
+
// timingSafeEqual throws on length mismatch; lengths differ only when the
|
|
29
|
+
// stored hash is corrupt, which must fail closed anyway.
|
|
30
|
+
return aBuf.length === bBuf.length && timingSafeEqual(aBuf, bBuf);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check bearer auth for an incoming request. Fail-closed: when the gateway
|
|
34
|
+
* has no `apiKeyHash` configured, every check fails with AUTH_NOT_CONFIGURED.
|
|
35
|
+
* Callers translate a failed check into a 401 error envelope.
|
|
36
|
+
*/
|
|
37
|
+
export function checkAuth(req, config) {
|
|
38
|
+
if (!config.apiKeyHash) {
|
|
39
|
+
return { ok: false, code: 'AUTH_NOT_CONFIGURED', message: 'Gateway API key is not configured' };
|
|
40
|
+
}
|
|
41
|
+
const token = extractBearerToken(req);
|
|
42
|
+
if (!token || !safeEqualHex(hashApiKey(token), config.apiKeyHash)) {
|
|
43
|
+
return { ok: false, code: 'UNAUTHORIZED', message: 'Invalid or missing API key' };
|
|
44
|
+
}
|
|
45
|
+
return { ok: true };
|
|
46
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { extname, join } from 'node:path';
|
|
4
|
+
import { parse as parseYaml } from 'yaml';
|
|
5
|
+
/**
|
|
6
|
+
* Config file format.
|
|
7
|
+
*
|
|
8
|
+
* `config.yml` is the primary format because YAML allows **comments** — and a
|
|
9
|
+
* config file with a channel section where each field can be annotated
|
|
10
|
+
* (`# Slack: app-level token, starts with xapp-`) is something JSON cannot do.
|
|
11
|
+
* `config.json` is still read so old setups don't break.
|
|
12
|
+
*
|
|
13
|
+
* Format is chosen by FILE EXTENSION: `.json` goes through `JSON.parse` (keeps
|
|
14
|
+
* the old error message the tests assert on), every other extension goes to the
|
|
15
|
+
* YAML parser. YAML 1.2 is a superset of JSON, so JSON content read by the YAML
|
|
16
|
+
* parser still parses correctly — meaning a `$BOOMBOT_CONFIG` pointing at an
|
|
17
|
+
* odd path won't be misread.
|
|
18
|
+
*
|
|
19
|
+
* Why a separate module: `config.ts` owns the *schema* (which keys, which
|
|
20
|
+
* types), while this module owns the *format* (reading text into an object,
|
|
21
|
+
* and YAML coercion rules). Mixing both into one file means every format
|
|
22
|
+
* change touches the schema too.
|
|
23
|
+
*/
|
|
24
|
+
/** File probe order when `$BOOMBOT_CONFIG` is unset; first existing file wins. */
|
|
25
|
+
export const CONFIG_FILE_NAMES = ['config.yml', 'config.yaml', 'config.json'];
|
|
26
|
+
/** Default config directory: `~/.boombot`. */
|
|
27
|
+
export function defaultConfigDir(env = process.env) {
|
|
28
|
+
const profile = env['BOOMBOT_PROFILE'];
|
|
29
|
+
if (profile === undefined || profile === '')
|
|
30
|
+
return join(homedir(), '.boombot');
|
|
31
|
+
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/u.test(profile)) {
|
|
32
|
+
throw new Error('BOOMBOT_PROFILE must match [a-z0-9][a-z0-9_-]{0,63}');
|
|
33
|
+
}
|
|
34
|
+
return join(homedir(), '.boombot', 'profiles', profile);
|
|
35
|
+
}
|
|
36
|
+
/** Default WRITE path: `~/.boombot/config.yml`. */
|
|
37
|
+
export function defaultConfigPath(env = process.env) {
|
|
38
|
+
return join(defaultConfigDir(env), 'config.yml');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* READ path: `$BOOMBOT_CONFIG` when set, otherwise the first existing file in
|
|
42
|
+
* `CONFIG_FILE_NAMES`, otherwise the default write path (so error messages
|
|
43
|
+
* and the first write point at the same place).
|
|
44
|
+
*
|
|
45
|
+
* Deliberately does not hard-prefer `config.yml`: a running machine may have a
|
|
46
|
+
* legacy `config.json`, and forcing the user to rename the file before the
|
|
47
|
+
* gateway boots is the surest way to hand them a 401 they can't explain.
|
|
48
|
+
*/
|
|
49
|
+
export function resolveConfigFilePath(env = process.env) {
|
|
50
|
+
const explicit = env['BOOMBOT_CONFIG'];
|
|
51
|
+
if (explicit !== undefined && explicit !== '')
|
|
52
|
+
return explicit;
|
|
53
|
+
for (const name of CONFIG_FILE_NAMES) {
|
|
54
|
+
const candidate = join(defaultConfigDir(env), name);
|
|
55
|
+
if (existsSync(candidate))
|
|
56
|
+
return candidate;
|
|
57
|
+
}
|
|
58
|
+
return defaultConfigPath(env);
|
|
59
|
+
}
|
|
60
|
+
/** Describes a value's type for error messages; never prints the value (may be a secret). */
|
|
61
|
+
function describe(value) {
|
|
62
|
+
if (value === null)
|
|
63
|
+
return 'null';
|
|
64
|
+
if (Array.isArray(value))
|
|
65
|
+
return 'a list';
|
|
66
|
+
switch (typeof value) {
|
|
67
|
+
case 'object':
|
|
68
|
+
return 'a mapping';
|
|
69
|
+
case 'number':
|
|
70
|
+
return 'a number';
|
|
71
|
+
case 'boolean':
|
|
72
|
+
return 'a boolean';
|
|
73
|
+
default:
|
|
74
|
+
return `a ${typeof value}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Reads a config file into a raw object. A missing file yields `{}` (config is
|
|
79
|
+
* optional). A present-but-broken file throws — never return `{}` for a file
|
|
80
|
+
* that reads but is wrong, because then the gateway would run on defaults while
|
|
81
|
+
* the user believes their config was applied.
|
|
82
|
+
*/
|
|
83
|
+
export function readConfigObject(path) {
|
|
84
|
+
let raw;
|
|
85
|
+
try {
|
|
86
|
+
raw = readFileSync(path, 'utf8');
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error.code === 'ENOENT')
|
|
90
|
+
return {};
|
|
91
|
+
throw new Error(`Cannot read gateway config at ${path}: ${error.message}`);
|
|
92
|
+
}
|
|
93
|
+
const isJson = extname(path).toLowerCase() === '.json';
|
|
94
|
+
let parsed;
|
|
95
|
+
if (isJson) {
|
|
96
|
+
try {
|
|
97
|
+
parsed = JSON.parse(raw);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
throw new Error(`Gateway config at ${path} is not valid JSON`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
try {
|
|
105
|
+
parsed = parseYaml(raw, { version: '1.2' });
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new Error(`Gateway config at ${path} is not valid YAML: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
112
|
+
throw new Error(`Gateway config at ${path} must be a ${isJson ? 'JSON object' : 'YAML mapping'}`);
|
|
113
|
+
}
|
|
114
|
+
return parsed;
|
|
115
|
+
}
|
|
116
|
+
/** Channel fields that take a boolean; every other field is a string (or list of strings). */
|
|
117
|
+
const CHANNEL_BOOLEAN_FIELDS = new Set(['enabled']);
|
|
118
|
+
const CHANNEL_LIST_FIELDS = new Set(['allowlistChatIds']);
|
|
119
|
+
/**
|
|
120
|
+
* Every field `ChannelConnectionConfig` declares. Used to CATCH MISSPELLED
|
|
121
|
+
* NAMES: `botToke:` in YAML would be silently swallowed and surface as "channel
|
|
122
|
+
* not running" — the most time-expensive kind of bug to track down.
|
|
123
|
+
*
|
|
124
|
+
* This is a shared allowlist, not a per-channel schema: `telegram.accessToken`
|
|
125
|
+
* still passes. True per-channel validation needs a full schema; all that's
|
|
126
|
+
* needed here is catching typos.
|
|
127
|
+
*/
|
|
128
|
+
const KNOWN_CHANNEL_FIELDS = new Set([
|
|
129
|
+
'enabled',
|
|
130
|
+
'botToken',
|
|
131
|
+
'allowlistChatIds',
|
|
132
|
+
'guildId',
|
|
133
|
+
'publicKey',
|
|
134
|
+
'signingSecret',
|
|
135
|
+
'appToken',
|
|
136
|
+
'phoneNumberId',
|
|
137
|
+
'accessToken',
|
|
138
|
+
'verifyToken',
|
|
139
|
+
'bridgeUrl',
|
|
140
|
+
'oaToken',
|
|
141
|
+
'pageAccessToken',
|
|
142
|
+
'appSecret',
|
|
143
|
+
'appId',
|
|
144
|
+
'clientSecret',
|
|
145
|
+
]);
|
|
146
|
+
/**
|
|
147
|
+
* Coerces a scalar value to a string.
|
|
148
|
+
*
|
|
149
|
+
* YAML turns an unquoted `phoneNumberId: 1029384756` into a **number**. That's
|
|
150
|
+
* the most natural way to write it, so coerce to string instead of forcing the
|
|
151
|
+
* user to remember quoting — BUT only when the number survived intact. IDs past
|
|
152
|
+
* 2^53 lose digits going through JS's number type, and an ID wrong in its last
|
|
153
|
+
* few digits is the worst kind of bug in this file: the channel silently sends
|
|
154
|
+
* to the wrong place. In that case throw and tell the user to quote it, rather
|
|
155
|
+
* than guessing.
|
|
156
|
+
*/
|
|
157
|
+
function coerceScalarString(value, at) {
|
|
158
|
+
if (typeof value === 'string')
|
|
159
|
+
return value;
|
|
160
|
+
if (typeof value === 'number' && Number.isSafeInteger(value))
|
|
161
|
+
return String(value);
|
|
162
|
+
const hint = typeof value === 'number' ? ' — quote it to keep every digit' : '';
|
|
163
|
+
throw new Error(`Gateway config "${at}" must be a string (got ${describe(value)})${hint}`);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Normalizes a channel section: drops empty fields, coerces types, and rejects
|
|
167
|
+
* unknown fields.
|
|
168
|
+
*
|
|
169
|
+
* `configPath` is only used so error messages name the right file when multiple
|
|
170
|
+
* config sources exist (`.yml` next to `.json`).
|
|
171
|
+
*/
|
|
172
|
+
export function coerceChannelSection(kind, raw, configPath) {
|
|
173
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
|
174
|
+
throw new Error(`Gateway config at ${configPath}: "channels.${kind}" must be a mapping`);
|
|
175
|
+
}
|
|
176
|
+
const section = {};
|
|
177
|
+
for (const [field, value] of Object.entries(raw)) {
|
|
178
|
+
if (!KNOWN_CHANNEL_FIELDS.has(field)) {
|
|
179
|
+
throw new Error(`Gateway config at ${configPath}: unknown field "channels.${kind}.${field}"`);
|
|
180
|
+
}
|
|
181
|
+
// An empty `field:` in YAML yields null — treat as undeclared.
|
|
182
|
+
if (value === undefined || value === null)
|
|
183
|
+
continue;
|
|
184
|
+
const at = `channels.${kind}.${field}`;
|
|
185
|
+
if (CHANNEL_BOOLEAN_FIELDS.has(field)) {
|
|
186
|
+
if (typeof value !== 'boolean') {
|
|
187
|
+
throw new Error(`Gateway config "${at}" must be a boolean (got ${describe(value)})`);
|
|
188
|
+
}
|
|
189
|
+
section[field] = value;
|
|
190
|
+
}
|
|
191
|
+
else if (CHANNEL_LIST_FIELDS.has(field)) {
|
|
192
|
+
if (!Array.isArray(value)) {
|
|
193
|
+
throw new Error(`Gateway config "${at}" must be a list (got ${describe(value)})`);
|
|
194
|
+
}
|
|
195
|
+
section[field] = value.map((item) => coerceScalarString(item, `${at}[]`));
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
section[field] = coerceScalarString(value, at);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return section;
|
|
202
|
+
}
|