borgmcp 1.1.14 → 2.0.1
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/CONTRIBUTING.md +15 -0
- package/LICENSE +201 -33
- package/NOTICE +2 -0
- package/README.md +86 -37
- package/SECURITY.md +7 -0
- package/dist/agent-runtime.d.ts.map +1 -0
- package/dist/agent-runtime.js +63 -1
- package/dist/agent-runtime.js.map +1 -0
- package/dist/assimilate-cmd.d.ts +96 -17
- package/dist/assimilate-cmd.d.ts.map +1 -0
- package/dist/assimilate-cmd.js +1396 -48
- package/dist/assimilate-cmd.js.map +1 -0
- package/dist/assimilate-deps.d.ts.map +1 -0
- package/dist/assimilate-deps.js +384 -3
- package/dist/assimilate-deps.js.map +1 -0
- package/dist/assimilate-guard.d.ts +5 -7
- package/dist/assimilate-guard.d.ts.map +1 -0
- package/dist/assimilate-guard.js +60 -2
- package/dist/assimilate-guard.js.map +1 -0
- package/dist/assimilate-welcome.d.ts +1 -1
- package/dist/assimilate-welcome.d.ts.map +1 -0
- package/dist/assimilate-welcome.js +32 -2
- package/dist/assimilate-welcome.js.map +1 -0
- package/dist/auth-env.d.ts +7 -50
- package/dist/auth-env.d.ts.map +1 -0
- package/dist/auth-env.js +22 -1
- package/dist/auth-env.js.map +1 -0
- package/dist/backends/launch-all-pastelist.d.ts.map +1 -0
- package/dist/backends/launch-all-pastelist.js +11 -4
- package/dist/backends/launch-all-pastelist.js.map +1 -0
- package/dist/backends/launch-all-tmux.d.ts.map +1 -0
- package/dist/backends/launch-all-tmux.js +49 -1
- package/dist/backends/launch-all-tmux.js.map +1 -0
- package/dist/backends/launch-all-windows.d.ts.map +1 -0
- package/dist/backends/launch-all-windows.js +86 -12
- package/dist/backends/launch-all-windows.js.map +1 -0
- package/dist/bare-launch-menu.d.ts.map +1 -0
- package/dist/bare-launch-menu.js +83 -6
- package/dist/bare-launch-menu.js.map +1 -0
- package/dist/claude-launch-args.d.ts.map +1 -0
- package/dist/claude-launch-args.js +34 -1
- package/dist/claude-launch-args.js.map +1 -0
- package/dist/claude.d.ts.map +1 -0
- package/dist/claude.js +486 -14
- package/dist/claude.js.map +1 -0
- package/dist/cleanup-cmd.d.ts +5 -5
- package/dist/cleanup-cmd.d.ts.map +1 -0
- package/dist/cleanup-cmd.js +453 -14
- package/dist/cleanup-cmd.js.map +1 -0
- package/dist/clear-rewake-core.d.ts.map +1 -0
- package/dist/clear-rewake-core.js +23 -2
- package/dist/clear-rewake-core.js.map +1 -0
- package/dist/clear-rewake.d.ts.map +1 -0
- package/dist/clear-rewake.js +19 -1
- package/dist/clear-rewake.js.map +1 -0
- package/dist/cli-help.d.ts +5 -0
- package/dist/cli-help.d.ts.map +1 -0
- package/dist/cli-help.js +104 -56
- package/dist/cli-help.js.map +1 -0
- package/dist/cli-platform.d.ts.map +1 -0
- package/dist/cli-platform.js +106 -4
- package/dist/cli-platform.js.map +1 -0
- package/dist/cli-tool-approval.d.ts +84 -0
- package/dist/cli-tool-approval.d.ts.map +1 -0
- package/dist/cli-tool-approval.js +583 -0
- package/dist/cli-tool-approval.js.map +1 -0
- package/dist/codex-app-server.d.ts.map +1 -0
- package/dist/codex-app-server.js +228 -4
- package/dist/codex-app-server.js.map +1 -0
- package/dist/codex-app-wake.d.ts.map +1 -0
- package/dist/codex-app-wake.js +432 -2
- package/dist/codex-app-wake.js.map +1 -0
- package/dist/codex-launch.d.ts.map +1 -0
- package/dist/codex-launch.js +102 -2
- package/dist/codex-launch.js.map +1 -0
- package/dist/codex-remote.d.ts +6 -1
- package/dist/codex-remote.d.ts.map +1 -0
- package/dist/codex-remote.js +394 -1
- package/dist/codex-remote.js.map +1 -0
- package/dist/codex-wake-resolve.d.ts.map +1 -0
- package/dist/codex-wake-resolve.js +127 -1
- package/dist/codex-wake-resolve.js.map +1 -0
- package/dist/config-utils.d.ts +2 -2
- package/dist/config-utils.d.ts.map +1 -0
- package/dist/config-utils.js +766 -3
- package/dist/config-utils.js.map +1 -0
- package/dist/config.d.ts +98 -61
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +426 -1
- package/dist/config.js.map +1 -0
- package/dist/console-prefix.d.ts.map +1 -0
- package/dist/console-prefix.js +96 -1
- package/dist/console-prefix.js.map +1 -0
- package/dist/cube-name.d.ts.map +1 -0
- package/dist/cube-name.js +67 -1
- package/dist/cube-name.js.map +1 -0
- package/dist/cubes.d.ts +126 -18
- package/dist/cubes.d.ts.map +1 -0
- package/dist/cubes.js +412 -4
- package/dist/cubes.js.map +1 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +71 -1
- package/dist/debug.js.map +1 -0
- package/dist/direct-log.d.ts.map +1 -0
- package/dist/direct-log.js +11 -1
- package/dist/direct-log.js.map +1 -0
- package/dist/docs-sections.d.ts +11 -10
- package/dist/docs-sections.d.ts.map +1 -0
- package/dist/docs-sections.js +113 -3
- package/dist/docs-sections.js.map +1 -0
- package/dist/drone-lifecycle.d.ts +5 -21
- package/dist/drone-lifecycle.d.ts.map +1 -0
- package/dist/drone-lifecycle.js +57 -8
- package/dist/drone-lifecycle.js.map +1 -0
- package/dist/drone-management.d.ts +29 -0
- package/dist/drone-management.d.ts.map +1 -0
- package/dist/drone-management.js +109 -0
- package/dist/drone-management.js.map +1 -0
- package/dist/ensure-mcp-config.d.ts.map +1 -0
- package/dist/ensure-mcp-config.js +36 -1
- package/dist/ensure-mcp-config.js.map +1 -0
- package/dist/evict-drone.d.ts +10 -2
- package/dist/evict-drone.d.ts.map +1 -0
- package/dist/evict-drone.js +60 -1
- package/dist/evict-drone.js.map +1 -0
- package/dist/gc-orphan-inboxes.d.ts.map +1 -0
- package/dist/gc-orphan-inboxes.js +177 -1
- package/dist/gc-orphan-inboxes.js.map +1 -0
- package/dist/inbox-monitor.d.ts +1 -1
- package/dist/inbox-monitor.d.ts.map +1 -0
- package/dist/inbox-monitor.js +856 -3
- package/dist/inbox-monitor.js.map +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1034 -37
- package/dist/index.js.map +1 -0
- package/dist/launch-all-cmd.d.ts.map +1 -0
- package/dist/launch-all-cmd.js +377 -37
- package/dist/launch-all-cmd.js.map +1 -0
- package/dist/launch-all-command.d.ts.map +1 -0
- package/dist/launch-all-command.js +24 -1
- package/dist/launch-all-command.js.map +1 -0
- package/dist/launch-all-deps.d.ts +3 -8
- package/dist/launch-all-deps.d.ts.map +1 -0
- package/dist/launch-all-deps.js +99 -1
- package/dist/launch-all-deps.js.map +1 -0
- package/dist/launch-all-discovery.d.ts +1 -0
- package/dist/launch-all-discovery.d.ts.map +1 -0
- package/dist/launch-all-discovery.js +90 -4
- package/dist/launch-all-discovery.js.map +1 -0
- package/dist/launch-all-locks.d.ts.map +1 -0
- package/dist/launch-all-locks.js +54 -1
- package/dist/launch-all-locks.js.map +1 -0
- package/dist/launch-gate.d.ts +2 -2
- package/dist/launch-gate.d.ts.map +1 -0
- package/dist/launch-gate.js +73 -1
- package/dist/launch-gate.js.map +1 -0
- package/dist/lifecycle-log-guard.d.ts.map +1 -0
- package/dist/lifecycle-log-guard.js +93 -2
- package/dist/lifecycle-log-guard.js.map +1 -0
- package/dist/list-roles-render.d.ts.map +1 -0
- package/dist/list-roles-render.js +40 -6
- package/dist/list-roles-render.js.map +1 -0
- package/dist/local-log-routing.d.ts +19 -0
- package/dist/local-log-routing.d.ts.map +1 -0
- package/dist/local-log-routing.js +67 -0
- package/dist/local-log-routing.js.map +1 -0
- package/dist/local-manage-tool-result.d.ts +8 -0
- package/dist/local-manage-tool-result.d.ts.map +1 -0
- package/dist/local-manage-tool-result.js +10 -0
- package/dist/local-manage-tool-result.js.map +1 -0
- package/dist/local-server-cursor.d.ts +34 -0
- package/dist/local-server-cursor.d.ts.map +1 -0
- package/dist/local-server-cursor.js +151 -0
- package/dist/local-server-cursor.js.map +1 -0
- package/dist/log-audit.d.ts.map +1 -0
- package/dist/log-audit.js +194 -3
- package/dist/log-audit.js.map +1 -0
- package/dist/log-stream.d.ts +31 -18
- package/dist/log-stream.d.ts.map +1 -0
- package/dist/log-stream.js +1214 -12
- package/dist/log-stream.js.map +1 -0
- package/dist/model-presets.d.ts.map +1 -0
- package/dist/model-presets.js +19 -1
- package/dist/model-presets.js.map +1 -0
- package/dist/name-validator.d.ts.map +1 -0
- package/dist/name-validator.js +22 -1
- package/dist/name-validator.js.map +1 -0
- package/dist/opencode-drone.d.ts.map +1 -0
- package/dist/opencode-drone.js +438 -4
- package/dist/opencode-drone.js.map +1 -0
- package/dist/opencode-plugin.d.ts +1 -1
- package/dist/opencode-plugin.d.ts.map +1 -0
- package/dist/opencode-plugin.js +29 -4
- package/dist/opencode-plugin.js.map +1 -0
- package/dist/parse-assimilate-args.d.ts +1 -1
- package/dist/parse-assimilate-args.d.ts.map +1 -0
- package/dist/parse-assimilate-args.js +125 -1
- package/dist/parse-assimilate-args.js.map +1 -0
- package/dist/parse-launch-all-args.d.ts.map +1 -0
- package/dist/parse-launch-all-args.js +70 -1
- package/dist/parse-launch-all-args.js.map +1 -0
- package/dist/postinstall-banner.d.ts.map +1 -0
- package/dist/postinstall-banner.js +27 -2
- package/dist/postinstall-banner.js.map +1 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +32 -5
- package/dist/postinstall.js.map +1 -0
- package/dist/readiness-probe.d.ts.map +1 -0
- package/dist/readiness-probe.js +9 -1
- package/dist/readiness-probe.js.map +1 -0
- package/dist/regen-format.d.ts.map +1 -0
- package/dist/regen-format.js +545 -13
- package/dist/regen-format.js.map +1 -0
- package/dist/regen.d.ts.map +1 -0
- package/dist/regen.js +141 -5
- package/dist/regen.js.map +1 -0
- package/dist/remote-client.d.ts +65 -175
- package/dist/remote-client.d.ts.map +1 -0
- package/dist/remote-client.js +942 -1
- package/dist/remote-client.js.map +1 -0
- package/dist/reset-local-seat-cmd.d.ts +50 -0
- package/dist/reset-local-seat-cmd.d.ts.map +1 -0
- package/dist/reset-local-seat-cmd.js +169 -0
- package/dist/reset-local-seat-cmd.js.map +1 -0
- package/dist/role-match.d.ts.map +1 -0
- package/dist/role-match.js +23 -1
- package/dist/role-match.js.map +1 -0
- package/dist/role-resolver.d.ts.map +1 -0
- package/dist/role-resolver.js +60 -1
- package/dist/role-resolver.js.map +1 -0
- package/dist/roster-render.d.ts.map +1 -0
- package/dist/roster-render.js +121 -3
- package/dist/roster-render.js.map +1 -0
- package/dist/seat-probe.d.ts +32 -13
- package/dist/seat-probe.d.ts.map +1 -0
- package/dist/seat-probe.js +78 -1
- package/dist/seat-probe.js.map +1 -0
- package/dist/seat-store.d.ts +76 -0
- package/dist/seat-store.d.ts.map +1 -0
- package/dist/seat-store.js +309 -0
- package/dist/seat-store.js.map +1 -0
- package/dist/seats.d.ts +303 -0
- package/dist/seats.d.ts.map +1 -0
- package/dist/seats.js +551 -0
- package/dist/seats.js.map +1 -0
- package/dist/self-path.d.ts +27 -0
- package/dist/self-path.d.ts.map +1 -0
- package/dist/self-path.js +43 -0
- package/dist/self-path.js.map +1 -0
- package/dist/server-endpoint.d.ts +9 -0
- package/dist/server-endpoint.d.ts.map +1 -0
- package/dist/server-endpoint.js +38 -0
- package/dist/server-endpoint.js.map +1 -0
- package/dist/server-errors.d.ts +50 -0
- package/dist/server-errors.d.ts.map +1 -0
- package/dist/server-errors.js +79 -0
- package/dist/server-errors.js.map +1 -0
- package/dist/server-handshake.d.ts +197 -0
- package/dist/server-handshake.d.ts.map +1 -0
- package/dist/server-handshake.js +505 -0
- package/dist/server-handshake.js.map +1 -0
- package/dist/server-response.d.ts +3 -0
- package/dist/server-response.d.ts.map +1 -0
- package/dist/server-response.js +67 -0
- package/dist/server-response.js.map +1 -0
- package/dist/server-trust.d.ts +14 -0
- package/dist/server-trust.d.ts.map +1 -0
- package/dist/server-trust.js +225 -0
- package/dist/server-trust.js.map +1 -0
- package/dist/setup-confirm.d.ts +3 -3
- package/dist/setup-confirm.d.ts.map +1 -0
- package/dist/setup-confirm.js +126 -2
- package/dist/setup-confirm.js.map +1 -0
- package/dist/setup.d.ts +5 -3
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +169 -46
- package/dist/setup.js.map +1 -0
- package/dist/shell-escape.d.ts.map +1 -0
- package/dist/shell-escape.js +22 -1
- package/dist/shell-escape.js.map +1 -0
- package/dist/spawn.d.ts +2 -2
- package/dist/spawn.d.ts.map +1 -0
- package/dist/spawn.js +29 -10
- package/dist/spawn.js.map +1 -0
- package/dist/startup-services.d.ts +0 -1
- package/dist/startup-services.d.ts.map +1 -0
- package/dist/startup-services.js +26 -1
- package/dist/startup-services.js.map +1 -0
- package/dist/stream-owner.d.ts +6 -2
- package/dist/stream-owner.d.ts.map +1 -0
- package/dist/stream-owner.js +547 -2
- package/dist/stream-owner.js.map +1 -0
- package/dist/stream-status.d.ts +1 -1
- package/dist/stream-status.d.ts.map +1 -0
- package/dist/stream-status.js +268 -3
- package/dist/stream-status.js.map +1 -0
- package/dist/sync-roles-render.d.ts.map +1 -0
- package/dist/sync-roles-render.js +118 -3
- package/dist/sync-roles-render.js.map +1 -0
- package/dist/sync.d.ts +1 -1
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +286 -22
- package/dist/sync.js.map +1 -0
- package/dist/terminal-title.d.ts.map +1 -0
- package/dist/terminal-title.js +68 -1
- package/dist/terminal-title.js.map +1 -0
- package/dist/token-store.d.ts +17 -111
- package/dist/token-store.d.ts.map +1 -0
- package/dist/token-store.js +81 -1
- package/dist/token-store.js.map +1 -0
- package/dist/tool-manifest.d.ts +4 -8
- package/dist/tool-manifest.d.ts.map +1 -0
- package/dist/tool-manifest.js +554 -1
- package/dist/tool-manifest.js.map +1 -0
- package/dist/tool-scope.d.ts +8 -12
- package/dist/tool-scope.d.ts.map +1 -0
- package/dist/tool-scope.js +97 -1
- package/dist/tool-scope.js.map +1 -0
- package/dist/types.d.ts +1 -5
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/unknown-subcommand.d.ts +1 -1
- package/dist/unknown-subcommand.d.ts.map +1 -0
- package/dist/unknown-subcommand.js +37 -1
- package/dist/unknown-subcommand.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +78 -2
- package/dist/version.js.map +1 -0
- package/dist/working-repo.d.ts.map +1 -0
- package/dist/working-repo.js +81 -1
- package/dist/working-repo.js.map +1 -0
- package/dist/worktree-lifecycle.d.ts.map +1 -0
- package/dist/worktree-lifecycle.js +205 -2
- package/dist/worktree-lifecycle.js.map +1 -0
- package/docs/EXTRACTION_PROVENANCE.md +40 -0
- package/docs/LOCAL_SERVER.md +103 -0
- package/docs/RELEASING.md +120 -0
- package/package.json +52 -34
- package/src/agent-runtime.ts +69 -0
- package/src/assimilate-cmd.ts +1864 -0
- package/src/assimilate-deps.ts +444 -0
- package/src/assimilate-guard.ts +84 -0
- package/src/assimilate-welcome.ts +39 -0
- package/src/auth-env.ts +21 -0
- package/src/backends/launch-all-pastelist.ts +18 -0
- package/src/backends/launch-all-tmux.ts +75 -0
- package/src/backends/launch-all-windows.ts +110 -0
- package/src/bare-launch-menu.ts +148 -0
- package/src/claude-launch-args.ts +35 -0
- package/src/claude.ts +561 -0
- package/src/cleanup-cmd.ts +581 -0
- package/src/clear-rewake-core.ts +34 -0
- package/src/clear-rewake.ts +18 -0
- package/src/cli-help.ts +116 -0
- package/src/cli-platform.ts +127 -0
- package/src/cli-tool-approval.ts +716 -0
- package/src/codex-app-server.ts +238 -0
- package/src/codex-app-wake.ts +512 -0
- package/src/codex-launch.ts +140 -0
- package/src/codex-remote.ts +500 -0
- package/src/codex-wake-resolve.ts +155 -0
- package/src/config-utils.ts +811 -0
- package/src/config.ts +595 -0
- package/src/console-prefix.ts +99 -0
- package/src/cube-name.ts +69 -0
- package/src/cubes.ts +583 -0
- package/src/debug.ts +73 -0
- package/src/direct-log.ts +9 -0
- package/src/docs-sections.ts +129 -0
- package/src/drone-lifecycle.ts +62 -0
- package/src/drone-management.ts +162 -0
- package/src/ensure-mcp-config.ts +54 -0
- package/src/evict-drone.ts +82 -0
- package/src/gc-orphan-inboxes.ts +229 -0
- package/src/inbox-monitor.ts +1005 -0
- package/src/index.ts +1201 -0
- package/src/launch-all-cmd.ts +450 -0
- package/src/launch-all-command.ts +30 -0
- package/src/launch-all-deps.ts +188 -0
- package/src/launch-all-discovery.ts +118 -0
- package/src/launch-all-locks.ts +74 -0
- package/src/launch-gate.ts +80 -0
- package/src/lifecycle-log-guard.ts +144 -0
- package/src/list-roles-render.ts +52 -0
- package/src/local-log-routing.ts +106 -0
- package/src/local-manage-tool-result.ts +10 -0
- package/src/local-server-cursor.ts +188 -0
- package/src/log-audit.ts +207 -0
- package/src/log-stream.ts +1505 -0
- package/src/model-presets.ts +22 -0
- package/src/name-validator.ts +23 -0
- package/src/opencode-drone.ts +528 -0
- package/src/opencode-plugin.ts +38 -0
- package/src/parse-assimilate-args.ts +125 -0
- package/src/parse-launch-all-args.ts +100 -0
- package/src/postinstall-banner.ts +37 -0
- package/src/postinstall.ts +36 -0
- package/src/readiness-probe.ts +12 -0
- package/src/regen-format.ts +651 -0
- package/src/regen.ts +150 -0
- package/src/remote-client.ts +1379 -0
- package/src/reset-local-seat-cmd.ts +227 -0
- package/src/role-match.ts +29 -0
- package/src/role-resolver.ts +93 -0
- package/src/roster-render.ts +196 -0
- package/src/seat-probe.ts +115 -0
- package/src/seat-store.ts +333 -0
- package/src/seats.ts +741 -0
- package/src/self-path.ts +51 -0
- package/src/server-endpoint.ts +38 -0
- package/src/server-errors.ts +93 -0
- package/src/server-handshake.ts +783 -0
- package/src/server-response.ts +76 -0
- package/src/server-trust.ts +245 -0
- package/src/setup-confirm.ts +171 -0
- package/src/setup.ts +186 -0
- package/src/shell-escape.ts +22 -0
- package/src/spawn.ts +31 -0
- package/src/startup-services.ts +36 -0
- package/src/stream-owner.ts +686 -0
- package/src/stream-status.ts +337 -0
- package/src/sync-roles-render.ts +163 -0
- package/src/sync.ts +363 -0
- package/src/terminal-title.ts +76 -0
- package/src/token-store.ts +102 -0
- package/src/tool-manifest.ts +610 -0
- package/src/tool-scope.ts +110 -0
- package/src/types.ts +5 -0
- package/src/unknown-subcommand.ts +35 -0
- package/src/version.ts +82 -0
- package/src/working-repo.ts +99 -0
- package/src/worktree-lifecycle.ts +254 -0
- package/dist/auth-recovery.d.ts +0 -33
- package/dist/auth-recovery.js +0 -1
- package/dist/auth.d.ts +0 -103
- package/dist/auth.js +0 -39
- package/dist/device-auth.d.ts +0 -75
- package/dist/device-auth.js +0 -1
- package/dist/drone-address.d.ts +0 -26
- package/dist/drone-address.js +0 -1
- package/dist/get-started.d.ts +0 -20
- package/dist/get-started.js +0 -2
- package/dist/health-beat.d.ts +0 -134
- package/dist/health-beat.js +0 -1
- package/dist/role-section.d.ts +0 -110
- package/dist/role-section.js +0 -8
- package/dist/setup-action.d.ts +0 -20
- package/dist/setup-action.js +0 -1
- package/dist/stale-version-check.d.ts +0 -40
- package/dist/stale-version-check.js +0 -1
- package/dist/subscription-retry.d.ts +0 -40
- package/dist/subscription-retry.js +0 -1
- package/dist/templates.d.ts +0 -107
- package/dist/templates.js +0 -359
- package/dist/token-crypto.d.ts +0 -50
- package/dist/token-crypto.js +0 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual, X509Certificate } from 'node:crypto';
|
|
2
|
+
import { constants } from 'node:fs';
|
|
3
|
+
import { open } from 'node:fs/promises';
|
|
4
|
+
import { request as httpsRequest } from 'node:https';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { join, resolve } from 'node:path';
|
|
7
|
+
import { Readable } from 'node:stream';
|
|
8
|
+
import { BorgServerTrustError } from './server-errors.js';
|
|
9
|
+
// CR5 TLS LATTICE: OpenSSL/Node TLS certificate-verification error codes. A raw
|
|
10
|
+
// CA / cert-chain / SAN failure from the pinned transport is a potential MITM and
|
|
11
|
+
// MUST be a TERMINAL trust-mismatch verdict — never a transient 'restart' blip.
|
|
12
|
+
// Connection refusal / reset / timeout are NOT in here: those stay raw transport
|
|
13
|
+
// errors so the seat probe classifies them as `unreachable` (genuinely transient).
|
|
14
|
+
const TLS_TRUST_ERROR_CODES = new Set([
|
|
15
|
+
'DEPTH_ZERO_SELF_SIGNED_CERT',
|
|
16
|
+
'SELF_SIGNED_CERT_IN_CHAIN',
|
|
17
|
+
'UNABLE_TO_GET_ISSUER_CERT',
|
|
18
|
+
'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
|
|
19
|
+
'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
|
|
20
|
+
'CERT_UNTRUSTED',
|
|
21
|
+
'CERT_CHAIN_TOO_LONG',
|
|
22
|
+
'HOSTNAME_MISMATCH',
|
|
23
|
+
'ERR_TLS_CERT_ALTNAME_INVALID',
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* True iff `code` is a PINNED-TRANSPORT certificate-verification failure (bad CA,
|
|
27
|
+
* unverifiable chain, self-signed leaf, expired/not-yet-valid cert, or a SAN /
|
|
28
|
+
* hostname mismatch). These are terminal trust-mismatch — a restart never fixes a
|
|
29
|
+
* wrong cert. `CERT_*` covers the OpenSSL verify family (CERT_HAS_EXPIRED,
|
|
30
|
+
* CERT_NOT_YET_VALID, CERT_REVOKED, …); `ERR_TLS_CERT*` covers Node's SAN check.
|
|
31
|
+
*/
|
|
32
|
+
function isPinnedTransportTrustFailure(code) {
|
|
33
|
+
if (!code)
|
|
34
|
+
return false;
|
|
35
|
+
return (code.startsWith('CERT_') ||
|
|
36
|
+
code.startsWith('ERR_TLS_CERT') ||
|
|
37
|
+
TLS_TRUST_ERROR_CODES.has(code));
|
|
38
|
+
}
|
|
39
|
+
const trustCache = new Map();
|
|
40
|
+
function serverDataDirectory() {
|
|
41
|
+
return resolve(process.env.BORG_SERVER_DATA_DIR ?? join(homedir(), '.borg', 'server'));
|
|
42
|
+
}
|
|
43
|
+
async function readTrustFile(path) {
|
|
44
|
+
let handle;
|
|
45
|
+
try {
|
|
46
|
+
handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error.code === 'ENOENT') {
|
|
50
|
+
throw new Error('Borg server trust files were not found');
|
|
51
|
+
}
|
|
52
|
+
throw new Error('Borg server trust files could not be opened safely');
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const metadata = await handle.stat();
|
|
56
|
+
if (!metadata.isFile() || (metadata.mode & 0o077) !== 0) {
|
|
57
|
+
throw new Error('Borg server trust files must be private regular files');
|
|
58
|
+
}
|
|
59
|
+
if (typeof process.getuid === 'function' && metadata.uid !== process.getuid()) {
|
|
60
|
+
throw new Error('Borg server trust files must be owned by the current user');
|
|
61
|
+
}
|
|
62
|
+
return await handle.readFile('utf8');
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
await handle.close();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function decodeTrustConfig(value) {
|
|
69
|
+
let parsed;
|
|
70
|
+
try {
|
|
71
|
+
parsed = JSON.parse(value);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
throw new Error('Borg server trust metadata is invalid');
|
|
75
|
+
}
|
|
76
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
77
|
+
throw new Error('Borg server trust metadata is invalid');
|
|
78
|
+
}
|
|
79
|
+
const fingerprint = parsed.ca_spki_sha256;
|
|
80
|
+
if (typeof fingerprint !== 'string' || !/^[a-f0-9]{64}$/i.test(fingerprint)) {
|
|
81
|
+
throw new Error('Borg server trust metadata is missing a valid CA identity');
|
|
82
|
+
}
|
|
83
|
+
return { ca_spki_sha256: fingerprint.toLowerCase() };
|
|
84
|
+
}
|
|
85
|
+
function verifyCaIdentity(certificate, expected) {
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
parsed = new X509Certificate(certificate);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
throw new Error('Borg server CA certificate is invalid');
|
|
92
|
+
}
|
|
93
|
+
if (!parsed.ca)
|
|
94
|
+
throw new Error('Borg server trust anchor is not a CA certificate');
|
|
95
|
+
const actual = createHash('sha256')
|
|
96
|
+
.update(parsed.publicKey.export({ type: 'spki', format: 'der' }))
|
|
97
|
+
.digest();
|
|
98
|
+
const expectedBytes = Buffer.from(expected, 'hex');
|
|
99
|
+
if (expectedBytes.length !== actual.length || !timingSafeEqual(actual, expectedBytes)) {
|
|
100
|
+
throw new Error('Borg server CA certificate does not match its pinned identity');
|
|
101
|
+
}
|
|
102
|
+
return `spki-sha256:${actual.toString('hex')}`;
|
|
103
|
+
}
|
|
104
|
+
function responseHeaders(rawHeaders) {
|
|
105
|
+
const headers = new Headers();
|
|
106
|
+
for (let index = 0; index < rawHeaders.length; index += 2) {
|
|
107
|
+
const name = rawHeaders[index];
|
|
108
|
+
const value = rawHeaders[index + 1];
|
|
109
|
+
if (name !== undefined && value !== undefined)
|
|
110
|
+
headers.append(name, value);
|
|
111
|
+
}
|
|
112
|
+
return headers;
|
|
113
|
+
}
|
|
114
|
+
function requestBody(value) {
|
|
115
|
+
if (value === null || value === undefined)
|
|
116
|
+
return undefined;
|
|
117
|
+
if (typeof value === 'string')
|
|
118
|
+
return value;
|
|
119
|
+
if (value instanceof Uint8Array)
|
|
120
|
+
return value;
|
|
121
|
+
if (value instanceof ArrayBuffer)
|
|
122
|
+
return new Uint8Array(value);
|
|
123
|
+
throw new Error('Borg server transport received an unsupported request body');
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Minimal fetch-compatible HTTPS transport bound to one origin and one
|
|
127
|
+
* explicit local CA. Node's global fetch cannot consume the server-owned CA,
|
|
128
|
+
* and disabling certificate validation would collapse the authority boundary.
|
|
129
|
+
*/
|
|
130
|
+
export function createPinnedServerFetch(origin, caCertificate) {
|
|
131
|
+
const authority = new URL(origin);
|
|
132
|
+
if (authority.protocol !== 'https:' || authority.origin !== origin) {
|
|
133
|
+
throw new Error('Borg server trust requires a canonical HTTPS origin');
|
|
134
|
+
}
|
|
135
|
+
return (async (input, init = {}) => {
|
|
136
|
+
const url = input instanceof Request ? new URL(input.url) : new URL(input.toString());
|
|
137
|
+
if (url.origin !== authority.origin || url.protocol !== 'https:') {
|
|
138
|
+
throw new Error('Borg server transport refused a cross-authority request');
|
|
139
|
+
}
|
|
140
|
+
if (input instanceof Request) {
|
|
141
|
+
throw new Error('Borg server transport requires an explicit URL and request options');
|
|
142
|
+
}
|
|
143
|
+
if (init.signal?.aborted)
|
|
144
|
+
throw new DOMException('This operation was aborted', 'AbortError');
|
|
145
|
+
const body = requestBody(init.body);
|
|
146
|
+
const headers = new Headers(init.headers);
|
|
147
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
148
|
+
const request = httpsRequest({
|
|
149
|
+
protocol: 'https:',
|
|
150
|
+
hostname: url.hostname.replace(/^\[(.*)\]$/, '$1'),
|
|
151
|
+
port: url.port || 443,
|
|
152
|
+
path: `${url.pathname}${url.search}`,
|
|
153
|
+
method: init.method ?? 'GET',
|
|
154
|
+
headers: Object.fromEntries(headers.entries()),
|
|
155
|
+
ca: caCertificate,
|
|
156
|
+
rejectUnauthorized: true,
|
|
157
|
+
minVersion: 'TLSv1.3',
|
|
158
|
+
}, (incoming) => {
|
|
159
|
+
const status = incoming.statusCode ?? 500;
|
|
160
|
+
if (init.redirect === 'error' && status >= 300 && status < 400) {
|
|
161
|
+
incoming.resume();
|
|
162
|
+
rejectPromise(new Error('Borg server redirect refused'));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const noBody = init.method === 'HEAD' || status === 204 || status === 304;
|
|
166
|
+
const stream = noBody
|
|
167
|
+
? null
|
|
168
|
+
: Readable.toWeb(incoming);
|
|
169
|
+
if (noBody)
|
|
170
|
+
incoming.resume();
|
|
171
|
+
resolvePromise(new Response(stream, {
|
|
172
|
+
status,
|
|
173
|
+
statusText: incoming.statusMessage,
|
|
174
|
+
headers: responseHeaders(incoming.rawHeaders),
|
|
175
|
+
}));
|
|
176
|
+
});
|
|
177
|
+
const abort = () => {
|
|
178
|
+
request.destroy(new DOMException('This operation was aborted', 'AbortError'));
|
|
179
|
+
};
|
|
180
|
+
init.signal?.addEventListener('abort', abort, { once: true });
|
|
181
|
+
request.once('close', () => init.signal?.removeEventListener('abort', abort));
|
|
182
|
+
request.once('error', (error) => {
|
|
183
|
+
// CR5: a pinned-transport CERT/CA/SAN verification failure is TERMINAL trust
|
|
184
|
+
// — type it as BorgServerTrustError so the seat probe returns `trust-mismatch`
|
|
185
|
+
// (never `indeterminate` → "restart"). Connection refusal/reset/timeout carry
|
|
186
|
+
// a transport errno (or an AbortError) and are rethrown RAW so the probe
|
|
187
|
+
// classifies them as `unreachable`.
|
|
188
|
+
const code = error.code;
|
|
189
|
+
if (isPinnedTransportTrustFailure(code)) {
|
|
190
|
+
rejectPromise(new BorgServerTrustError(`Borg server presented a certificate that failed pinned verification (${code})`));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
rejectPromise(error);
|
|
194
|
+
});
|
|
195
|
+
if (body !== undefined)
|
|
196
|
+
request.write(body);
|
|
197
|
+
request.end();
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
export async function loadBorgServerTrust(origin, dataDirectory = serverDataDirectory()) {
|
|
202
|
+
const key = `${dataDirectory}\0${origin}`;
|
|
203
|
+
let pending = trustCache.get(key);
|
|
204
|
+
if (!pending) {
|
|
205
|
+
pending = (async () => {
|
|
206
|
+
const [certificate, configText] = await Promise.all([
|
|
207
|
+
readTrustFile(join(dataDirectory, 'ca.crt')),
|
|
208
|
+
readTrustFile(join(dataDirectory, 'server.json')),
|
|
209
|
+
]);
|
|
210
|
+
const config = decodeTrustConfig(configText);
|
|
211
|
+
const identity = verifyCaIdentity(certificate, config.ca_spki_sha256);
|
|
212
|
+
return {
|
|
213
|
+
identity,
|
|
214
|
+
fetchImpl: createPinnedServerFetch(origin, certificate),
|
|
215
|
+
};
|
|
216
|
+
})();
|
|
217
|
+
trustCache.set(key, pending);
|
|
218
|
+
pending.catch(() => trustCache.delete(key));
|
|
219
|
+
}
|
|
220
|
+
return pending;
|
|
221
|
+
}
|
|
222
|
+
export function __clearServerTrustCacheForTest() {
|
|
223
|
+
trustCache.clear();
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=server-trust.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-trust.js","sourceRoot":"","sources":["../src/server-trust.ts"],"names":[],"mappings":"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"}
|
package/dist/setup-confirm.d.ts
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
*
|
|
13
13
|
* SECURITY (SR-light, gh#818 221c43df): the disclosure lists file PATHS +
|
|
14
14
|
* at most the PUBLIC `BORG_API_URL` — there is NO token/secret in the
|
|
15
|
-
* written config to echo.
|
|
16
|
-
*
|
|
15
|
+
* written config to echo. Local credentials live in the local 0600-permission
|
|
16
|
+
* seat store, and the written config never contains a token or secret.
|
|
17
17
|
*/
|
|
18
18
|
export interface ConfigMutationTarget {
|
|
19
19
|
/** Human-readable config file path (tilde form). */
|
|
@@ -77,7 +77,7 @@ export declare function parseYesFlag(argv: string[]): boolean;
|
|
|
77
77
|
*
|
|
78
78
|
* The disclosure + confirm prompt exists to obtain informed consent for the
|
|
79
79
|
* config writes Step-1 performs (gh#818). On a pure refresh — the normal
|
|
80
|
-
*
|
|
80
|
+
* setup re-run where every DETECTED agent CLI already has the full
|
|
81
81
|
* borg setup (MCP server registered AND every hook write already applied) —
|
|
82
82
|
* there is no mutation to consent to, so the prompt is redundant and skipped.
|
|
83
83
|
*
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-confirm.d.ts","sourceRoot":"","sources":["../src/setup-confirm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,oBAAoB,EAAE,CA6BzB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,oBAAoB,EAAE,GAC9B,MAAM,CAUR;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;AAElD,MAAM,WAAW,yBAAyB;IACxC,sCAAsC;IACtC,KAAK,EAAE,OAAO,CAAC;IACf,sCAAsC;IACtC,GAAG,EAAE,OAAO,CAAC;IACb;;;;OAIG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,eAAe,CAAC,CAK1B;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAEpD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAMV"}
|
package/dist/setup-confirm.js
CHANGED
|
@@ -1,2 +1,126 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* gh#818 P3 — disclose + confirm the `borg setup` global-config mutation.
|
|
3
|
+
*
|
|
4
|
+
* Step-1 of the setup wizard writes the user's GLOBAL agent config
|
|
5
|
+
* (registers the borg MCP server + hooks). Before gh#818 this happened
|
|
6
|
+
* silently on first run. This module adds informed-consent disclosure:
|
|
7
|
+
* it lists WHICH files will be written (well-known `os.homedir()` paths)
|
|
8
|
+
* and asks to continue before the first mutation.
|
|
9
|
+
*
|
|
10
|
+
* Pure / dep-injected (mirrors `resolveCliChoice` + `setup-action.ts`) so
|
|
11
|
+
* the decision is unit-testable without spawning a prompt or touching argv.
|
|
12
|
+
*
|
|
13
|
+
* SECURITY (SR-light, gh#818 221c43df): the disclosure lists file PATHS +
|
|
14
|
+
* at most the PUBLIC `BORG_API_URL` — there is NO token/secret in the
|
|
15
|
+
* written config to echo. Local credentials live in the local 0600-permission
|
|
16
|
+
* seat store, and the written config never contains a token or secret.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* The set of global config files Step-1 writes, scoped to the detected
|
|
20
|
+
* agent CLIs. Paths mirror `config-utils.ts`:
|
|
21
|
+
* Claude Code: ~/.claude.json (MCP server) + ~/.claude/settings.json (hook)
|
|
22
|
+
* Codex: ~/.codex/config.toml (MCP server) + ~/.codex/hooks.json (hooks)
|
|
23
|
+
* OpenCode: ~/.config/opencode/opencode.json (MCP server)
|
|
24
|
+
*/
|
|
25
|
+
export function configMutationTargets(deps) {
|
|
26
|
+
const targets = [];
|
|
27
|
+
if (deps.claude) {
|
|
28
|
+
targets.push({
|
|
29
|
+
file: '~/.claude.json',
|
|
30
|
+
change: 'registers the borg MCP server',
|
|
31
|
+
});
|
|
32
|
+
targets.push({
|
|
33
|
+
file: '~/.claude/settings.json',
|
|
34
|
+
change: 'adds a UserPromptSubmit hook',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
if (deps.codex) {
|
|
38
|
+
targets.push({
|
|
39
|
+
file: '~/.codex/config.toml',
|
|
40
|
+
change: 'registers the borg MCP server',
|
|
41
|
+
});
|
|
42
|
+
targets.push({
|
|
43
|
+
file: '~/.codex/hooks.json',
|
|
44
|
+
change: 'adds SessionStart + UserPromptSubmit hooks',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (deps.opencode) {
|
|
48
|
+
targets.push({
|
|
49
|
+
file: '~/.config/opencode/opencode.json',
|
|
50
|
+
change: 'registers the borg MCP server (with BORG_SESSION activation)',
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return targets;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Disclosure text: the files Step-1 will write + an undo note. Pure so SR
|
|
57
|
+
* can pin "lists paths only, no secret". Lists the public `BORG_API_URL`
|
|
58
|
+
* only by reference (the MCP-server registration env), never a credential.
|
|
59
|
+
*/
|
|
60
|
+
export function formatConfigMutationDisclosure(targets) {
|
|
61
|
+
const lines = [];
|
|
62
|
+
lines.push('borg setup will register the borg MCP server in your agent config:');
|
|
63
|
+
for (const t of targets) {
|
|
64
|
+
lines.push(` • ${t.file} (${t.change})`);
|
|
65
|
+
}
|
|
66
|
+
lines.push('These changes are additive and reversible — remove the "borg" entries to undo.');
|
|
67
|
+
return lines.join('\n');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Decide whether to proceed with the Step-1 config mutation.
|
|
71
|
+
*
|
|
72
|
+
* The six CR-binding build-gate items (gh#818, 3b3e85a5) live here:
|
|
73
|
+
* 1. (THE load-bearing headless no-regress) non-TTY → 'proceed' WITHOUT
|
|
74
|
+
* prompting. We return before touching `confirm`, so a non-TTY run
|
|
75
|
+
* (CI / pipe / headless) never reads stdin → no hang.
|
|
76
|
+
* 2. `--yes`/`-y` → 'proceed' without prompting (scripted-but-TTY +
|
|
77
|
+
* explicit non-interactive). No collision with --no-browser/--device.
|
|
78
|
+
* 3. TTY + interactive → ask; decline → 'abort' (the caller exits BEFORE
|
|
79
|
+
* any write).
|
|
80
|
+
* 6. This dep-injected shape IS the testable seam.
|
|
81
|
+
*/
|
|
82
|
+
export async function confirmConfigMutation(deps) {
|
|
83
|
+
if (!deps.isTTY)
|
|
84
|
+
return 'proceed'; // item 1 — never block on stdin
|
|
85
|
+
if (deps.yes)
|
|
86
|
+
return 'proceed'; // item 2 — explicit bypass
|
|
87
|
+
const ok = await deps.confirm(); // item 3 — interactive consent
|
|
88
|
+
return ok ? 'proceed' : 'abort';
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Scan argv for the `--yes` / `-y` bypass. Kept separate so the flag set
|
|
92
|
+
* is pinned in tests (item 2 — no collision with the existing
|
|
93
|
+
* --no-browser/--device scan in setup.ts).
|
|
94
|
+
*/
|
|
95
|
+
export function parseYesFlag(argv) {
|
|
96
|
+
return argv.includes('--yes') || argv.includes('-y');
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* gh#844 — whether Step-1 has ANY config mutation worth disclosing.
|
|
100
|
+
*
|
|
101
|
+
* The disclosure + confirm prompt exists to obtain informed consent for the
|
|
102
|
+
* config writes Step-1 performs (gh#818). On a pure refresh — the normal
|
|
103
|
+
* setup re-run where every DETECTED agent CLI already has the full
|
|
104
|
+
* borg setup (MCP server registered AND every hook write already applied) —
|
|
105
|
+
* there is no mutation to consent to, so the prompt is redundant and skipped.
|
|
106
|
+
*
|
|
107
|
+
* CRITICAL (gh#844 SR finding 8d9c732e): the gate must cover the FULL disclosed
|
|
108
|
+
* mutation set — MCP registration AND every hook write (claude UserPromptSubmit
|
|
109
|
+
* + the legacy SessionStart removal; codex SessionStart + UserPromptSubmit) —
|
|
110
|
+
* not MCP registration alone. Otherwise an MCP-configured user with a pending
|
|
111
|
+
* hook write (e.g. a pre-gh#673 upgrader whose legacy global hook must be
|
|
112
|
+
* removed) would have settings.json mutated with consent silently skipped.
|
|
113
|
+
* Caller derives `claudeHookPending`/`codexHookPending` from the SAME peeks
|
|
114
|
+
* that gate the individual writers, so the gate and the writers cannot drift.
|
|
115
|
+
*
|
|
116
|
+
* Scoped to DETECTED CLIs: a claude-only user is never gated on codex config
|
|
117
|
+
* state (and vice-versa). A naive `!isMcpServerConfigured() ||
|
|
118
|
+
* !isCodexMcpServerConfigured()` gate would mis-fire for single-CLI users —
|
|
119
|
+
* the absent CLI's config is unconfigured, so the OR would always be true.
|
|
120
|
+
*/
|
|
121
|
+
export function setupMutationPending(deps) {
|
|
122
|
+
return ((deps.claude && (!deps.claudeMcpConfigured || deps.claudeHookPending)) ||
|
|
123
|
+
(deps.codex && (!deps.codexMcpConfigured || deps.codexHookPending)) ||
|
|
124
|
+
(deps.opencode && !deps.opencodeMcpConfigured));
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=setup-confirm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-confirm.js","sourceRoot":"","sources":["../src/setup-confirm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAIrC;IACC,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,gBAAgB;YACtB,MAAM,EAAE,+BAA+B;SACxC,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,yBAAyB;YAC/B,MAAM,EAAE,8BAA8B;SACvC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,sBAAsB;YAC5B,MAAM,EAAE,+BAA+B;SACxC,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,qBAAqB;YAC3B,MAAM,EAAE,4CAA4C;SACrD,CAAC,CAAC;IACL,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,kCAAkC;YACxC,MAAM,EAAE,8DAA8D;SACvE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAC5C,OAA+B;IAE/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;IACjF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7C,CAAC;IACD,KAAK,CAAC,IAAI,CACR,gFAAgF,CACjF,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAiBD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAA+B;IAE/B,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC,CAAC,gCAAgC;IACnE,IAAI,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC,CAAC,2BAA2B;IAC3D,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,+BAA+B;IAChE,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,oBAAoB,CAAC,IASpC;IACC,OAAO,CACL,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACtE,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACnE,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAC/C,CAAC;AACJ,CAAC"}
|
package/dist/setup.d.ts
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
* Borg MCP Setup Wizard
|
|
4
4
|
*
|
|
5
5
|
* Interactive setup flow:
|
|
6
|
-
* 1. Configure
|
|
7
|
-
* 2.
|
|
8
|
-
*
|
|
6
|
+
* 1. Configure agent CLI MCP settings + orientation hooks
|
|
7
|
+
* 2. Print how to connect to a local self-hosted Borg server
|
|
8
|
+
*
|
|
9
|
+
* There is no cloud authority: setup offers/executes NO cloud auth, Google
|
|
10
|
+
* auth, subscription, or checkout.
|
|
9
11
|
*/
|
|
10
12
|
export {};
|
|
11
13
|
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
|