@sayknow-cli/coding-agent 0.4.7 → 0.5.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/CHANGELOG.md +122 -0
- package/dist/types/capability/index.d.ts +10 -20
- package/dist/types/capability/types.d.ts +3 -0
- package/dist/types/cli/args.d.ts +0 -2
- package/dist/types/cli/read-cli.d.ts +1 -0
- package/dist/types/cli.d.ts +9 -1
- package/dist/types/commands/daemon.d.ts +2 -2
- package/dist/types/commands/deep-interview.d.ts +9 -0
- package/dist/types/commands/harness.d.ts +22 -0
- package/dist/types/commands/read.d.ts +6 -0
- package/dist/types/commands/sdk.d.ts +20 -2
- package/dist/types/config/keybindings.d.ts +34 -4
- package/dist/types/config/model-profile-contract.d.ts +40 -0
- package/dist/types/config/model-profiles.d.ts +2 -3
- package/dist/types/config/model-registry.d.ts +5 -0
- package/dist/types/config/provider-auth-health.d.ts +14 -0
- package/dist/types/config/provider-ranking.d.ts +59 -0
- package/dist/types/config/settings-schema.d.ts +156 -10
- package/dist/types/config/settings.d.ts +3 -0
- package/dist/types/edit/modes/patch.d.ts +13 -0
- package/dist/types/edit/path-mutation-lock.d.ts +15 -0
- package/dist/types/eval/py/executor.d.ts +1 -1
- package/dist/types/eval/py/runner-artifact.d.ts +8 -0
- package/dist/types/eval/py/tool-bridge.d.ts +1 -2
- package/dist/types/extensibility/extensions/types.d.ts +43 -2
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
- package/dist/types/main.d.ts +33 -2
- package/dist/types/memories/index.d.ts +2 -0
- package/dist/types/modes/acp/acp-agent.d.ts +22 -9
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/btw-panel.d.ts +1 -0
- package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
- package/dist/types/modes/components/queue-pane.d.ts +8 -0
- package/dist/types/modes/components/queued-message-selector.d.ts +6 -0
- package/dist/types/modes/components/read-tool-group.d.ts +4 -4
- package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
- package/dist/types/modes/components/session-observer-overlay.d.ts +4 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/tool-status-header.d.ts +4 -2
- package/dist/types/modes/components/welcome.d.ts +5 -0
- package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
- package/dist/types/modes/controllers/command-controller.d.ts +2 -0
- package/dist/types/modes/controllers/event-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +13 -2
- package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
- package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
- package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
- package/dist/types/modes/types.d.ts +6 -0
- package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
- package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
- package/dist/types/runtime/memory-domain.d.ts +9 -0
- package/dist/types/runtime/memory-guard-contract.d.ts +71 -0
- package/dist/types/runtime/memory-guard.d.ts +39 -0
- package/dist/types/runtime/memory-limit.d.ts +11 -0
- package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
- package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +1 -1
- package/dist/types/runtime-mcp/manager.d.ts +9 -1
- package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
- package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
- package/dist/types/runtime-mcp/redaction.d.ts +2 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
- package/dist/types/sdk/acp/final-text.d.ts +19 -0
- package/dist/types/sdk/acp/mcp.d.ts +23 -0
- package/dist/types/sdk/broker/broker.d.ts +2 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +13 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +9 -1
- package/dist/types/sdk/bus/config-commands.d.ts +2 -2
- package/dist/types/sdk/bus/config.d.ts +2 -0
- package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
- package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
- package/dist/types/sdk/bus/index.d.ts +52 -4
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +37 -0
- package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
- package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
- package/dist/types/sdk/bus/notification-service.d.ts +34 -0
- package/dist/types/sdk/bus/operator-runtime.d.ts +1 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +106 -0
- package/dist/types/sdk/bus/rate-limit-pool.d.ts +2 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +65 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +33 -9
- package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +286 -12
- package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
- package/dist/types/sdk/client/discovery.d.ts +2 -0
- package/dist/types/sdk/client/liveness.d.ts +7 -0
- package/dist/types/sdk/host/control/operations.d.ts +3 -2
- package/dist/types/sdk/host/host.d.ts +3 -1
- package/dist/types/sdk/host/query/handlers.d.ts +14 -0
- package/dist/types/sdk/index.d.ts +2 -0
- package/dist/types/sdk/lifecycle-session.d.ts +10 -1
- package/dist/types/sdk/prompt-status.d.ts +88 -0
- package/dist/types/sdk/session-directory.d.ts +1 -1
- package/dist/types/sdk/session.d.ts +7 -0
- package/dist/types/sdk/startup-capability.d.ts +9 -0
- package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
- package/dist/types/sdk/transport/index.d.ts +12 -0
- package/dist/types/sdk/transport/relay.d.ts +43 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
- package/dist/types/sdk/transport/socket.d.ts +7 -0
- package/dist/types/sdk/transport/stdio.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +83 -24
- package/dist/types/session/btw-contract.d.ts +16 -0
- package/dist/types/session/fallback-chain-controller.d.ts +18 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +70 -10
- package/dist/types/session/internal/managed-session-storage.d.ts +34 -12
- package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
- package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
- package/dist/types/session/session-manager.d.ts +89 -18
- package/dist/types/session/session-storage.d.ts +31 -0
- package/dist/types/session/streaming-output.d.ts +60 -5
- package/dist/types/setup/credential-import.d.ts +5 -1
- package/dist/types/setup/provider-onboarding.d.ts +2 -0
- package/dist/types/skc-runtime/deep-interview-runtime.d.ts +1 -1
- package/dist/types/skc-runtime/deep-interview-stage.d.ts +37 -0
- package/dist/types/skc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/skc-runtime/linux-proc.d.ts +22 -14
- package/dist/types/skc-runtime/memory-guard-owner-claims.d.ts +47 -0
- package/dist/types/skc-runtime/ralplan-runtime.d.ts +112 -1
- package/dist/types/skc-runtime/repository-binding.d.ts +63 -0
- package/dist/types/skc-runtime/state-runtime.d.ts +3 -1
- package/dist/types/skc-runtime/state-writer.d.ts +5 -1
- package/dist/types/skc-runtime/team-launch.d.ts +1 -1
- package/dist/types/skc-runtime/team-runtime.d.ts +9 -2
- package/dist/types/skc-runtime/team-store.d.ts +12 -0
- package/dist/types/skc-runtime/team-worker-memory-guard.d.ts +92 -0
- package/dist/types/skc-runtime/tmux-owner-isolation.d.ts +7 -0
- package/dist/types/skc-runtime/ultragoal-guard.d.ts +6 -5
- package/dist/types/skc-runtime/ultragoal-receipt-freshness.d.ts +28 -0
- package/dist/types/skc-runtime/ultragoal-runtime.d.ts +43 -5
- package/dist/types/skill-state/workflow-hud.d.ts +3 -0
- package/dist/types/ssh/utils.d.ts +1 -0
- package/dist/types/task/discovery.d.ts +3 -1
- package/dist/types/task/executor.d.ts +6 -0
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/task/provider-retry-status.d.ts +13 -0
- package/dist/types/task/receipt.d.ts +2 -0
- package/dist/types/task/types.d.ts +133 -0
- package/dist/types/task/ultragoal-redteam-activation.d.ts +33 -0
- package/dist/types/tools/browser/launch.d.ts +7 -0
- package/dist/types/tools/fetch.d.ts +22 -9
- package/dist/types/tools/image-gen.d.ts +63 -1
- package/dist/types/tools/index.d.ts +7 -1
- package/dist/types/tools/output-meta.d.ts +21 -1
- package/dist/types/tools/read-internals.d.ts +12 -0
- package/dist/types/tools/read.d.ts +45 -1
- package/dist/types/tools/resource-gc.d.ts +23 -0
- package/dist/types/tools/skill-discovery.d.ts +7 -0
- package/dist/types/tools/sqlite-reader.d.ts +7 -0
- package/dist/types/tools/tool-result.d.ts +7 -1
- package/dist/types/utils/prompt-suggestion.d.ts +33 -0
- package/dist/types/utils/shell-snapshot.d.ts +12 -0
- package/dist/types/web/insane/bridge.d.ts +1 -0
- package/dist/types/web/insane/url-guard.d.ts +17 -0
- package/package.json +8 -12
- package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
- package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
- package/scripts/capture-sticky-viewport-showcase.ts +292 -0
- package/scripts/compile-args.ts +0 -1
- package/scripts/dogfood-repository-binding.ts +209 -0
- package/scripts/generate-docs-index.ts +4 -1
- package/scripts/generate-sdk-operation-inventory.ts +9 -0
- package/scripts/run-test-manifest.ts +6 -4
- package/scripts/verify-skc-sdk-canonicalization.ts +122 -18
- package/scripts/verify-sticky-viewport-showcase.ts +611 -0
- package/src/capability/index.ts +58 -42
- package/src/capability/types.ts +3 -0
- package/src/cli/args.ts +16 -100
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/mcp-cli.ts +4 -21
- package/src/cli/notify-cli.ts +6 -38
- package/src/cli/read-cli.ts +2 -1
- package/src/cli/setup-cli.ts +10 -4
- package/src/cli.ts +133 -11
- package/src/commands/daemon.ts +22 -5
- package/src/commands/deep-interview.ts +26 -1
- package/src/commands/harness.ts +35 -12
- package/src/commands/read.ts +11 -2
- package/src/commands/sdk.ts +134 -17
- package/src/commands/team.ts +1 -1
- package/src/commit/agentic/index.ts +3 -3
- package/src/commit/map-reduce/index.ts +2 -2
- package/src/config/keybindings.ts +158 -25
- package/src/config/model-profile-contract.ts +174 -0
- package/src/config/model-profiles.ts +51 -10
- package/src/config/model-registry.ts +24 -4
- package/src/config/model-resolver.ts +2 -2
- package/src/config/provider-auth-health.ts +42 -0
- package/src/config/provider-ranking.ts +119 -0
- package/src/config/settings-schema.ts +157 -10
- package/src/config/settings.ts +254 -108
- package/src/coordinator-mcp/model-preset.ts +21 -74
- package/src/defaults/skc/skills/deep-interview/SKILL.md +147 -24
- package/src/defaults/skc/skills/ralplan/SKILL.md +91 -34
- package/src/defaults/skc/skills/team/SKILL.md +1 -1
- package/src/defaults/skc/skills/ultragoal/SKILL.md +68 -17
- package/src/discovery/ssh.ts +12 -1
- package/src/edit/index.ts +3 -6
- package/src/edit/modes/patch.ts +38 -1
- package/src/edit/modes/replace.ts +42 -0
- package/src/edit/path-mutation-lock.ts +112 -0
- package/src/eval/js/tool-bridge.ts +1 -1
- package/src/eval/py/executor.ts +37 -13
- package/src/eval/py/kernel.ts +1 -21
- package/src/eval/py/prelude.py +2 -2
- package/src/eval/py/runner-artifact.ts +84 -0
- package/src/eval/py/tool-bridge.ts +34 -18
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +42 -4
- package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
- package/src/extensibility/shared-events.ts +5 -0
- package/src/extensibility/skc-plugins/runtime-adapters.ts +2 -1
- package/src/hooks/native-skill-hook.ts +17 -4
- package/src/internal-urls/docs-index.generated.ts +17 -16
- package/src/internal-urls/local-protocol.ts +87 -25
- package/src/internal-urls/local-root-gc.ts +127 -0
- package/src/internal-urls/mcp-protocol.ts +73 -11
- package/src/main.ts +120 -42
- package/src/memories/index.ts +10 -0
- package/src/modes/DESIGN.md +52 -0
- package/src/modes/acp/acp-agent.ts +647 -83
- package/src/modes/acp/acp-event-mapper.ts +106 -12
- package/src/modes/acp/acp-mode.ts +39 -3
- package/src/modes/action-registry.ts +1 -1
- package/src/modes/components/assistant-message.ts +123 -22
- package/src/modes/components/btw-panel.ts +82 -16
- package/src/modes/components/irc-sidebar.ts +176 -62
- package/src/modes/components/model-selector.ts +61 -4
- package/src/modes/components/notifications-settings-editor.ts +1 -1
- package/src/modes/components/oauth-selector.ts +42 -12
- package/src/modes/components/plan-preview-overlay.ts +1 -1
- package/src/modes/components/queue-pane.ts +55 -9
- package/src/modes/components/queued-message-selector.ts +53 -10
- package/src/modes/components/read-tool-group.ts +82 -14
- package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
- package/src/modes/components/sayknow-pet-widget.ts +20 -8
- package/src/modes/components/session-observer-overlay.ts +187 -32
- package/src/modes/components/settings-selector.ts +60 -18
- package/src/modes/components/tool-execution.ts +138 -27
- package/src/modes/components/tool-status-header.ts +26 -8
- package/src/modes/components/welcome.ts +50 -23
- package/src/modes/controllers/btw-controller.ts +119 -36
- package/src/modes/controllers/command-controller.ts +101 -54
- package/src/modes/controllers/event-controller.ts +119 -27
- package/src/modes/controllers/extension-ui-controller.ts +23 -12
- package/src/modes/controllers/input-controller.ts +100 -8
- package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
- package/src/modes/controllers/selector-controller.ts +4 -1
- package/src/modes/interactive-mode.ts +201 -60
- package/src/modes/irc-observation-ledger.ts +71 -15
- package/src/modes/prompt-action-autocomplete.ts +32 -13
- package/src/modes/prompt-suggestion-controller.ts +96 -0
- package/src/modes/runtime-init.ts +20 -2
- package/src/modes/shared/agent-wire/command-dispatch.ts +3 -3
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
- package/src/modes/types.ts +6 -0
- package/src/modes/utils/hotkeys-markdown.ts +64 -36
- package/src/modes/utils/ui-helpers.ts +99 -4
- package/src/prompts/agent-fragments/restricted-bash.md +1 -1
- package/src/prompts/agents/architect.md +17 -3
- package/src/prompts/agents/critic.md +17 -2
- package/src/prompts/agents/executor.md +1 -1
- package/src/prompts/agents/planner.md +8 -1
- package/src/prompts/system/btw-user.md +3 -8
- package/src/prompts/system/prompt-suggestion-system.md +32 -0
- package/src/prompts/system/system-prompt.md +6 -3
- package/src/prompts/tools/cron.md +3 -1
- package/src/prompts/tools/read.md +4 -2
- package/src/prompts/tools/skill-discovery.md +1 -0
- package/src/runtime/memory-domain.ts +66 -0
- package/src/runtime/memory-guard-contract.ts +73 -0
- package/src/runtime/memory-guard.ts +292 -0
- package/src/runtime/memory-limit.ts +50 -0
- package/src/runtime-mcp/client.ts +41 -55
- package/src/runtime-mcp/content-limits.ts +71 -0
- package/src/runtime-mcp/discoverable-tool-metadata.ts +1 -1
- package/src/runtime-mcp/json-rpc.ts +28 -11
- package/src/runtime-mcp/manager.ts +77 -59
- package/src/runtime-mcp/oauth-flow.ts +0 -72
- package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
- package/src/runtime-mcp/redaction.ts +30 -0
- package/src/runtime-mcp/smithery-auth.ts +17 -2
- package/src/runtime-mcp/smithery-connect.ts +11 -1
- package/src/runtime-mcp/transports/http.ts +63 -22
- package/src/sdk/acp/adapter.ts +8 -1
- package/src/sdk/acp/final-text.ts +40 -0
- package/src/sdk/acp/mcp.ts +26 -0
- package/src/sdk/broker/broker.ts +34 -20
- package/src/sdk/broker/identity.ts +22 -12
- package/src/sdk/broker/lifecycle.ts +293 -43
- package/src/sdk/broker/session-index.ts +11 -1
- package/src/sdk/bus/chat-daemon-cli.ts +2 -2
- package/src/sdk/bus/chat-daemon-control.ts +22 -5
- package/src/sdk/bus/config-commands.ts +2 -2
- package/src/sdk/bus/config.ts +10 -2
- package/src/sdk/bus/control-drain-lease.ts +104 -0
- package/src/sdk/bus/conversation-store.ts +40 -6
- package/src/sdk/bus/daemon-paths.ts +2 -0
- package/src/sdk/bus/index.ts +793 -121
- package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
- package/src/sdk/bus/lifecycle-commands.ts +63 -10
- package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
- package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
- package/src/sdk/bus/notification-orchestration.ts +12 -0
- package/src/sdk/bus/notification-service.ts +87 -25
- package/src/sdk/bus/operator-runtime.ts +31 -5
- package/src/sdk/bus/prompt-reconciliation.ts +240 -0
- package/src/sdk/bus/rate-limit-pool.ts +8 -0
- package/src/sdk/bus/recent-activity.ts +90 -26
- package/src/sdk/bus/reconciliation-store.ts +224 -0
- package/src/sdk/bus/telegram-cli.ts +6 -13
- package/src/sdk/bus/telegram-daemon-cli.ts +8 -3
- package/src/sdk/bus/telegram-daemon-contract.ts +34 -9
- package/src/sdk/bus/telegram-daemon-control.ts +161 -40
- package/src/sdk/bus/telegram-daemon.ts +3649 -593
- package/src/sdk/bus/telegram-reference.ts +20 -2
- package/src/sdk/bus/topic-registry.ts +451 -12
- package/src/sdk/cli/session-cli.ts +15 -2
- package/src/sdk/client/discovery.ts +19 -3
- package/src/sdk/client/liveness.ts +49 -0
- package/src/sdk/host/control/dispatch.ts +8 -2
- package/src/sdk/host/control/operations.ts +3 -2
- package/src/sdk/host/host.ts +27 -9
- package/src/sdk/host/query/handlers.ts +125 -5
- package/src/sdk/index.ts +12 -0
- package/src/sdk/lifecycle-session.ts +19 -3
- package/src/sdk/mcp/server.ts +46 -18
- package/src/sdk/prompt-status.ts +97 -0
- package/src/sdk/protocol/operation-inventory.generated.json +145 -0
- package/src/sdk/protocol/operation-registry.ts +24 -4
- package/src/sdk/session-directory.ts +5 -1
- package/src/sdk/session.ts +69 -8
- package/src/sdk/startup-capability.ts +15 -1
- package/src/sdk/transport/auth-preface.ts +82 -0
- package/src/sdk/transport/index.ts +18 -0
- package/src/sdk/transport/relay.ts +252 -0
- package/src/sdk/transport/serve-cli.ts +105 -0
- package/src/sdk/transport/socket.ts +197 -0
- package/src/sdk/transport/stdio.ts +17 -0
- package/src/session/agent-session.ts +1112 -314
- package/src/session/blob-store.ts +25 -7
- package/src/session/btw-contract.ts +59 -0
- package/src/session/fallback-chain-controller.ts +47 -8
- package/src/session/internal/managed-session-scope.ts +1426 -259
- package/src/session/internal/managed-session-storage.ts +414 -238
- package/src/session/internal/native-publish-outcome.ts +271 -0
- package/src/session/memory-guard-checkpoint-participant.ts +131 -0
- package/src/session/session-manager.ts +2079 -469
- package/src/session/session-storage.ts +151 -11
- package/src/session/streaming-output.ts +262 -43
- package/src/setup/credential-import.ts +28 -3
- package/src/setup/provider-onboarding.ts +49 -5
- package/src/setup/provider-presets.json +2 -1
- package/src/skc-runtime/deep-interview-runtime.ts +303 -36
- package/src/skc-runtime/deep-interview-stage.ts +1016 -0
- package/src/skc-runtime/deep-interview-state.ts +8 -5
- package/src/skc-runtime/gc-render.ts +1 -0
- package/src/skc-runtime/gc-runtime.ts +11 -1
- package/src/skc-runtime/linux-proc.ts +70 -36
- package/src/skc-runtime/managed-owner-supervisor.ts +83 -4
- package/src/skc-runtime/memory-guard-owner-claims.ts +389 -0
- package/src/skc-runtime/ralplan-runtime.ts +1057 -75
- package/src/skc-runtime/repository-binding.ts +267 -0
- package/src/skc-runtime/session-state-sidecar.ts +25 -9
- package/src/skc-runtime/state-runtime.ts +50 -12
- package/src/skc-runtime/state-writer.ts +68 -56
- package/src/skc-runtime/team-launch.ts +34 -5
- package/src/skc-runtime/team-runtime.ts +41 -1
- package/src/skc-runtime/team-store.ts +32 -0
- package/src/skc-runtime/team-worker-memory-guard.ts +363 -0
- package/src/skc-runtime/team-workers.ts +1 -0
- package/src/skc-runtime/tmux-common.ts +13 -2
- package/src/skc-runtime/tmux-owner-isolation.ts +20 -1
- package/src/skc-runtime/tmux-sessions.ts +45 -6
- package/src/skc-runtime/ultragoal-guard.ts +93 -15
- package/src/skc-runtime/ultragoal-receipt-freshness.ts +123 -0
- package/src/skc-runtime/ultragoal-runtime.ts +469 -38
- package/src/skc-runtime/workflow-manifest.generated.json +195 -5
- package/src/skc-runtime/workflow-manifest.ts +67 -3
- package/src/skill-state/workflow-hud.ts +25 -2
- package/src/skill-state/workflow-mutation-guard.ts +104 -12
- package/src/slash-commands/builtin-registry.ts +1 -1
- package/src/ssh/utils.ts +14 -0
- package/src/task/discovery.ts +8 -2
- package/src/task/executor.ts +165 -47
- package/src/task/index.ts +123 -15
- package/src/task/provider-retry-status.ts +88 -0
- package/src/task/receipt.ts +3 -0
- package/src/task/render.ts +45 -26
- package/src/task/skc-command.ts +2 -2
- package/src/task/types.ts +55 -10
- package/src/task/ultragoal-redteam-activation.ts +75 -0
- package/src/tools/ask.ts +1 -1
- package/src/tools/ast-edit.ts +2 -2
- package/src/tools/bash-allowed-prefixes.ts +45 -1
- package/src/tools/bash-pty-selection.ts +2 -2
- package/src/tools/browser/launch.ts +41 -6
- package/src/tools/browser/screenshot-format.ts +6 -1
- package/src/tools/cron.ts +1 -1
- package/src/tools/fetch.ts +127 -154
- package/src/tools/image-gen.ts +476 -23
- package/src/tools/index.ts +7 -1
- package/src/tools/output-meta.ts +176 -9
- package/src/tools/path-utils.ts +5 -1
- package/src/tools/read-internals.ts +44 -0
- package/src/tools/read.ts +1544 -310
- package/src/tools/resource-gc.ts +665 -125
- package/src/tools/skill-discovery.ts +39 -3
- package/src/tools/sqlite-reader.ts +63 -5
- package/src/tools/subagent-render.ts +74 -16
- package/src/tools/subagent.ts +2 -0
- package/src/tools/tool-result.ts +14 -1
- package/src/utils/edit-mode.ts +2 -2
- package/src/utils/pasted-image-path.ts +15 -6
- package/src/utils/prompt-suggestion.ts +265 -0
- package/src/utils/shell-snapshot.ts +173 -63
- package/src/utils/sixel.ts +3 -3
- package/src/web/insane/bridge.ts +5 -1
- package/src/web/insane/url-guard.ts +140 -27
- package/src/web/scrapers/docs-rs.ts +30 -5
- package/src/web/scrapers/types.ts +19 -49
- package/src/web/scrapers/utils.ts +12 -26
- package/src/web/search/providers/codex.ts +1 -1
- package/src/workflow/workflow-intent-diff.ts +4 -1
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import * as url from "node:url";
|
|
9
|
-
import type
|
|
9
|
+
import { isCanonicalMCPOAuthBinding, resolveMCPOAuthResourceOrigin, type TSchema } from "@sayknow-cli/ai";
|
|
10
10
|
import { logger } from "@sayknow-cli/utils";
|
|
11
11
|
import type { SourceMeta } from "../capability/types";
|
|
12
12
|
import * as configValue from "../config/resolve-config-value";
|
|
13
13
|
import type { CustomTool } from "../extensibility/custom-tools/types";
|
|
14
|
-
import type { AuthStorage } from "../session/auth-storage";
|
|
14
|
+
import type { AuthStorage, OAuthCredential } from "../session/auth-storage";
|
|
15
15
|
import {
|
|
16
16
|
connectToServer,
|
|
17
17
|
disconnectServer,
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
unsubscribeFromResources,
|
|
28
28
|
} from "./client";
|
|
29
29
|
import { loadAllMCPConfigs, validateServerConfig } from "./config";
|
|
30
|
-
import { refreshMCPOAuthToken } from "./oauth-flow";
|
|
31
30
|
import type { MCPToolDetails } from "./tool-bridge";
|
|
32
31
|
import { DeferredMCPTool, MCPTool } from "./tool-bridge";
|
|
33
32
|
import type { MCPToolCache } from "./tool-cache";
|
|
@@ -69,17 +68,24 @@ type ConnectionTask = {
|
|
|
69
68
|
|
|
70
69
|
const STARTUP_TIMEOUT_MS = 250;
|
|
71
70
|
const STARTUP_TIMEOUT_GRACE_MS = 500;
|
|
71
|
+
/**
|
|
72
|
+
* Default ceiling on how long `discoverAndConnect` waits for a server batch to
|
|
73
|
+
* come up. Deliberately short: a config with a large `timeout` must not be able
|
|
74
|
+
* to hang ordinary startup. ACP lifecycle launches carry their own, larger
|
|
75
|
+
* budget derived from the readiness deadline (see `maxStartupTimeoutMs`).
|
|
76
|
+
*/
|
|
72
77
|
const MAX_STARTUP_TIMEOUT_MS = 1_750;
|
|
73
78
|
|
|
74
|
-
function resolveStartupTimeoutMs(configs: MCPServerConfig[]): number {
|
|
79
|
+
export function resolveStartupTimeoutMs(configs: MCPServerConfig[], maxStartupTimeoutMs?: number): number {
|
|
80
|
+
const ceiling =
|
|
81
|
+
typeof maxStartupTimeoutMs === "number" && Number.isFinite(maxStartupTimeoutMs) && maxStartupTimeoutMs > 0
|
|
82
|
+
? Math.max(STARTUP_TIMEOUT_MS, maxStartupTimeoutMs)
|
|
83
|
+
: MAX_STARTUP_TIMEOUT_MS;
|
|
75
84
|
const configuredTimeouts = configs
|
|
76
85
|
.map(config => config.timeout)
|
|
77
86
|
.filter((timeout): timeout is number => typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0);
|
|
78
87
|
if (configuredTimeouts.length === 0) return STARTUP_TIMEOUT_MS;
|
|
79
|
-
return Math.min(
|
|
80
|
-
MAX_STARTUP_TIMEOUT_MS,
|
|
81
|
-
Math.max(STARTUP_TIMEOUT_MS, Math.max(...configuredTimeouts) + STARTUP_TIMEOUT_GRACE_MS),
|
|
82
|
-
);
|
|
88
|
+
return Math.min(ceiling, Math.max(STARTUP_TIMEOUT_MS, Math.max(...configuredTimeouts) + STARTUP_TIMEOUT_GRACE_MS));
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
function trackPromise<T>(promise: Promise<T>): TrackedPromise<T> {
|
|
@@ -186,6 +192,13 @@ export interface MCPDiscoverOptions {
|
|
|
186
192
|
export interface MCPManagerOptions {
|
|
187
193
|
/** Restrict this instance to tools from an explicit MCP config. */
|
|
188
194
|
toolsOnly?: boolean;
|
|
195
|
+
/**
|
|
196
|
+
* Ceiling for the startup wait, in milliseconds. Only ACP lifecycle launches
|
|
197
|
+
* set this, so a slow ACP MCP handshake gets the readiness budget while every
|
|
198
|
+
* other consumer keeps the short default. Non-positive or non-finite values
|
|
199
|
+
* are ignored and the default applies.
|
|
200
|
+
*/
|
|
201
|
+
maxStartupTimeoutMs?: number;
|
|
189
202
|
}
|
|
190
203
|
|
|
191
204
|
/**
|
|
@@ -270,12 +283,15 @@ export class MCPManager {
|
|
|
270
283
|
);
|
|
271
284
|
}
|
|
272
285
|
|
|
286
|
+
readonly #maxStartupTimeoutMs: number | undefined;
|
|
287
|
+
|
|
273
288
|
constructor(
|
|
274
289
|
private cwd: string,
|
|
275
290
|
private toolCache: MCPToolCache | null = null,
|
|
276
291
|
options: MCPManagerOptions = {},
|
|
277
292
|
) {
|
|
278
293
|
this.#toolsOnly = options.toolsOnly === true;
|
|
294
|
+
this.#maxStartupTimeoutMs = options.maxStartupTimeoutMs;
|
|
279
295
|
}
|
|
280
296
|
|
|
281
297
|
isToolsOnly(): boolean {
|
|
@@ -634,7 +650,10 @@ export class MCPManager {
|
|
|
634
650
|
}
|
|
635
651
|
|
|
636
652
|
if (connectionTasks.length > 0) {
|
|
637
|
-
const startupTimeoutMs = resolveStartupTimeoutMs(
|
|
653
|
+
const startupTimeoutMs = resolveStartupTimeoutMs(
|
|
654
|
+
connectionTasks.map(task => task.config),
|
|
655
|
+
this.#maxStartupTimeoutMs,
|
|
656
|
+
);
|
|
638
657
|
const firstUnexpectedFailure = Promise.withResolvers<{ reason: unknown }>();
|
|
639
658
|
if (this.#toolsOnly) {
|
|
640
659
|
for (const task of connectionTasks) {
|
|
@@ -1469,64 +1488,63 @@ export class MCPManager {
|
|
|
1469
1488
|
let resolved: MCPServerConfig = { ...config };
|
|
1470
1489
|
|
|
1471
1490
|
const auth = config.auth;
|
|
1472
|
-
if (auth?.type === "oauth"
|
|
1491
|
+
if (auth?.type === "oauth") {
|
|
1492
|
+
if (!auth.credentialId || !this.#authStorage || (config.type !== "http" && config.type !== "sse")) {
|
|
1493
|
+
throw new MCPExpectedFailure();
|
|
1494
|
+
}
|
|
1473
1495
|
const credentialId = auth.credentialId;
|
|
1474
1496
|
let credential = this.#authStorage.get(credentialId);
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
}
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1497
|
+
const binding = credential?.type === "oauth" ? credential.mcpBinding : undefined;
|
|
1498
|
+
const endpointOrigin = resolveMCPOAuthResourceOrigin(config.url);
|
|
1499
|
+
if (
|
|
1500
|
+
credential?.type !== "oauth" ||
|
|
1501
|
+
!binding ||
|
|
1502
|
+
!isCanonicalMCPOAuthBinding(binding) ||
|
|
1503
|
+
binding.resourceOrigin !== endpointOrigin ||
|
|
1504
|
+
(auth.tokenUrl !== undefined && auth.tokenUrl !== binding.tokenEndpoint)
|
|
1505
|
+
) {
|
|
1506
|
+
throw new MCPExpectedFailure();
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
// Proactive refresh: 5-minute buffer before expiry
|
|
1510
|
+
// Force refresh: on 401/403 auth errors (revoked tokens, clock skew, missing expires)
|
|
1511
|
+
const REFRESH_BUFFER_MS = 5 * 60_000;
|
|
1512
|
+
const shouldRefresh =
|
|
1513
|
+
forceRefresh || (credential.expires && Date.now() >= credential.expires - REFRESH_BUFFER_MS);
|
|
1514
|
+
if (shouldRefresh && credential.refresh) {
|
|
1515
|
+
let refreshedCredential: OAuthCredential | undefined;
|
|
1516
|
+
try {
|
|
1517
|
+
refreshedCredential = await this.#authStorage.forceRefreshOAuthCredential(credentialId, credential, {
|
|
1518
|
+
clientId: auth.clientId,
|
|
1519
|
+
clientSecret: auth.clientSecret,
|
|
1520
|
+
});
|
|
1521
|
+
} catch {
|
|
1522
|
+
if (forceRefresh) throw new MCPExpectedFailure();
|
|
1523
|
+
if (this.#toolsOnly) {
|
|
1524
|
+
logger.debug("MCP OAuth refresh failed");
|
|
1525
|
+
} else {
|
|
1526
|
+
logger.warn("MCP OAuth refresh failed, using existing token");
|
|
1505
1527
|
}
|
|
1506
1528
|
}
|
|
1507
1529
|
if (refreshedCredential) {
|
|
1508
|
-
|
|
1530
|
+
const refreshedBinding = refreshedCredential.mcpBinding;
|
|
1531
|
+
if (
|
|
1532
|
+
!refreshedBinding ||
|
|
1533
|
+
refreshedBinding.resourceOrigin !== binding.resourceOrigin ||
|
|
1534
|
+
refreshedBinding.tokenEndpoint !== binding.tokenEndpoint
|
|
1535
|
+
) {
|
|
1536
|
+
throw new MCPExpectedFailure();
|
|
1537
|
+
}
|
|
1509
1538
|
credential = refreshedCredential;
|
|
1510
1539
|
}
|
|
1511
|
-
|
|
1512
|
-
if (resolved.type === "http" || resolved.type === "sse") {
|
|
1513
|
-
resolved = {
|
|
1514
|
-
...resolved,
|
|
1515
|
-
headers: {
|
|
1516
|
-
...resolved.headers,
|
|
1517
|
-
Authorization: `Bearer ${credential.access}`,
|
|
1518
|
-
},
|
|
1519
|
-
};
|
|
1520
|
-
} else {
|
|
1521
|
-
resolved = {
|
|
1522
|
-
...resolved,
|
|
1523
|
-
env: {
|
|
1524
|
-
...resolved.env,
|
|
1525
|
-
OAUTH_ACCESS_TOKEN: credential.access,
|
|
1526
|
-
},
|
|
1527
|
-
};
|
|
1528
|
-
}
|
|
1529
1540
|
}
|
|
1541
|
+
resolved = {
|
|
1542
|
+
...config,
|
|
1543
|
+
headers: {
|
|
1544
|
+
...config.headers,
|
|
1545
|
+
Authorization: `Bearer ${credential.access}`,
|
|
1546
|
+
},
|
|
1547
|
+
};
|
|
1530
1548
|
}
|
|
1531
1549
|
if (this.#toolsOnly && resolved.type === "stdio") {
|
|
1532
1550
|
resolved = { ...resolved, noInheritEnv: true };
|
|
@@ -8,29 +8,10 @@
|
|
|
8
8
|
import type { OAuthCallbackFlowOptions } from "@sayknow-cli/ai/utils/oauth/callback-server";
|
|
9
9
|
import { OAuthCallbackFlow } from "@sayknow-cli/ai/utils/oauth/callback-server";
|
|
10
10
|
import type { OAuthController, OAuthCredentials } from "@sayknow-cli/ai/utils/oauth/types";
|
|
11
|
-
import { MCPExpectedFailure } from "./types";
|
|
12
11
|
|
|
13
12
|
const DEFAULT_PORT = 3000;
|
|
14
13
|
const CALLBACK_PATH = "/callback";
|
|
15
14
|
const CALLBACK_BIND_HOSTNAME = "127.0.0.1";
|
|
16
|
-
type RefreshTokenResponse = {
|
|
17
|
-
access_token: string;
|
|
18
|
-
refresh_token?: string;
|
|
19
|
-
expires_in?: number;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function isRefreshTokenResponse(value: unknown): value is RefreshTokenResponse {
|
|
23
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
24
|
-
const payload = value as Record<string, unknown>;
|
|
25
|
-
return (
|
|
26
|
-
typeof payload.access_token === "string" &&
|
|
27
|
-
payload.access_token.length > 0 &&
|
|
28
|
-
(payload.refresh_token === undefined || typeof payload.refresh_token === "string") &&
|
|
29
|
-
(payload.expires_in === undefined ||
|
|
30
|
-
(typeof payload.expires_in === "number" && Number.isFinite(payload.expires_in) && payload.expires_in >= 0))
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
15
|
function isLoopbackHostname(hostname: string): boolean {
|
|
35
16
|
return hostname === "localhost" || hostname === "127.0.0.1";
|
|
36
17
|
}
|
|
@@ -384,56 +365,3 @@ export class MCPOAuthFlow extends OAuthCallbackFlow {
|
|
|
384
365
|
}
|
|
385
366
|
}
|
|
386
367
|
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Refresh an MCP OAuth token using the standard refresh_token grant.
|
|
390
|
-
* Returns updated credentials; preserves the old refresh token if the server doesn't rotate it.
|
|
391
|
-
*/
|
|
392
|
-
export async function refreshMCPOAuthToken(
|
|
393
|
-
tokenUrl: string,
|
|
394
|
-
refreshToken: string,
|
|
395
|
-
clientId?: string,
|
|
396
|
-
clientSecret?: string,
|
|
397
|
-
): Promise<OAuthCredentials> {
|
|
398
|
-
const params = new URLSearchParams({
|
|
399
|
-
grant_type: "refresh_token",
|
|
400
|
-
refresh_token: refreshToken,
|
|
401
|
-
});
|
|
402
|
-
if (clientId) params.set("client_id", clientId);
|
|
403
|
-
if (clientSecret) params.set("client_secret", clientSecret);
|
|
404
|
-
|
|
405
|
-
let response: Response;
|
|
406
|
-
try {
|
|
407
|
-
response = await fetch(tokenUrl, {
|
|
408
|
-
method: "POST",
|
|
409
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
410
|
-
body: params.toString(),
|
|
411
|
-
});
|
|
412
|
-
} catch (error) {
|
|
413
|
-
throw new MCPExpectedFailure(error);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (!response.ok) {
|
|
417
|
-
let text: string;
|
|
418
|
-
try {
|
|
419
|
-
text = await response.text();
|
|
420
|
-
} catch (error) {
|
|
421
|
-
throw new MCPExpectedFailure(error);
|
|
422
|
-
}
|
|
423
|
-
throw new MCPExpectedFailure(new Error(`MCP OAuth refresh failed: ${response.status} ${text}`));
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
let data: unknown;
|
|
427
|
-
try {
|
|
428
|
-
data = await response.json();
|
|
429
|
-
} catch {
|
|
430
|
-
throw new MCPExpectedFailure();
|
|
431
|
-
}
|
|
432
|
-
if (!isRefreshTokenResponse(data)) throw new MCPExpectedFailure();
|
|
433
|
-
const expiresIn = data.expires_in ?? 3600;
|
|
434
|
-
return {
|
|
435
|
-
access: data.access_token,
|
|
436
|
-
refresh: data.refresh_token ?? refreshToken,
|
|
437
|
-
expires: Date.now() + expiresIn * 1000,
|
|
438
|
-
};
|
|
439
|
-
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { type AddressResolver, guardedPublicFetch } from "../web/insane/url-guard";
|
|
2
|
+
import { cancelMCPStream } from "./content-limits";
|
|
3
|
+
import type { MCPHttpServerConfig, MCPSseServerConfig } from "./types";
|
|
4
|
+
|
|
5
|
+
const PLUGIN_MCP_PUBLIC_NETWORK_BOUNDARY: unique symbol = Symbol("plugin-mcp-public-network-boundary");
|
|
6
|
+
const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
|
|
7
|
+
const MAX_REDIRECTS = 20;
|
|
8
|
+
const REQUEST_BODY_HEADERS = [
|
|
9
|
+
"content-encoding",
|
|
10
|
+
"content-language",
|
|
11
|
+
"content-length",
|
|
12
|
+
"content-location",
|
|
13
|
+
"content-type",
|
|
14
|
+
] as const;
|
|
15
|
+
|
|
16
|
+
/** Mark an in-memory plugin-bundle remote MCP config for connection-bound public-network enforcement. */
|
|
17
|
+
export function bindPluginMcpToPublicNetwork<T extends MCPHttpServerConfig | MCPSseServerConfig>(config: T): T {
|
|
18
|
+
return Object.assign(config, { [PLUGIN_MCP_PUBLIC_NETWORK_BOUNDARY]: true });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The marker is an internal symbol, so persisted user MCP configs cannot opt into or forge this path. */
|
|
22
|
+
export function isPluginMcpPublicNetworkBound(config: MCPHttpServerConfig | MCPSseServerConfig): boolean {
|
|
23
|
+
return (
|
|
24
|
+
(config as MCPHttpServerConfig & { [PLUGIN_MCP_PUBLIC_NETWORK_BOUNDARY]?: boolean })[
|
|
25
|
+
PLUGIN_MCP_PUBLIC_NETWORK_BOUNDARY
|
|
26
|
+
] === true
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function blocked(reason: string): Error {
|
|
31
|
+
return new Error(`Plugin MCP network request blocked: ${reason}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseHttpsUrl(rawUrl: string): URL {
|
|
35
|
+
let url: URL;
|
|
36
|
+
try {
|
|
37
|
+
url = new URL(rawUrl);
|
|
38
|
+
} catch {
|
|
39
|
+
throw blocked("invalid URL");
|
|
40
|
+
}
|
|
41
|
+
if (url.protocol !== "https:") throw blocked("HTTPS is required");
|
|
42
|
+
return url;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function rewritesToGet(status: number, method: string): boolean {
|
|
46
|
+
return (
|
|
47
|
+
((status === 301 || status === 302) && method === "POST") ||
|
|
48
|
+
(status === 303 && method !== "GET" && method !== "HEAD")
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Fetch a plugin-bundle MCP request through a DNS-pinned public address. Every
|
|
54
|
+
* redirect is handled manually and revalidated before the next connection.
|
|
55
|
+
*/
|
|
56
|
+
export async function fetchPluginMcpRequest(
|
|
57
|
+
rawUrl: string,
|
|
58
|
+
init: BunFetchRequestInit,
|
|
59
|
+
options: { resolver?: AddressResolver; maxRedirects?: number } = {},
|
|
60
|
+
): Promise<Response> {
|
|
61
|
+
let currentUrl = parseHttpsUrl(rawUrl);
|
|
62
|
+
let currentInit: BunFetchRequestInit = { ...init };
|
|
63
|
+
const maxRedirects = options.maxRedirects ?? MAX_REDIRECTS;
|
|
64
|
+
|
|
65
|
+
for (let redirectCount = 0; ; redirectCount++) {
|
|
66
|
+
const dial = await guardedPublicFetch(currentUrl.toString(), currentInit, { resolver: options.resolver });
|
|
67
|
+
if (!dial.ok) throw blocked(dial.reason);
|
|
68
|
+
const { response, logicalUrl } = dial;
|
|
69
|
+
if (!REDIRECT_STATUSES.has(response.status)) return response;
|
|
70
|
+
|
|
71
|
+
const location = response.headers.get("location");
|
|
72
|
+
if (!location) return response;
|
|
73
|
+
if (redirectCount >= maxRedirects) {
|
|
74
|
+
cancelMCPStream(response.body);
|
|
75
|
+
throw blocked("redirect limit exceeded");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let nextUrl: URL;
|
|
79
|
+
try {
|
|
80
|
+
nextUrl = parseHttpsUrl(new URL(location, logicalUrl).toString());
|
|
81
|
+
} catch (error) {
|
|
82
|
+
cancelMCPStream(response.body);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
if (logicalUrl.origin !== nextUrl.origin) {
|
|
86
|
+
cancelMCPStream(response.body);
|
|
87
|
+
throw blocked("cross-origin redirects are not allowed");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const headers = new Headers(currentInit.headers);
|
|
91
|
+
const method = (currentInit.method ?? "GET").toUpperCase();
|
|
92
|
+
if (rewritesToGet(response.status, method)) {
|
|
93
|
+
for (const name of REQUEST_BODY_HEADERS) headers.delete(name);
|
|
94
|
+
currentInit = { ...currentInit, method: "GET", headers, body: undefined };
|
|
95
|
+
} else {
|
|
96
|
+
currentInit = { ...currentInit, headers };
|
|
97
|
+
}
|
|
98
|
+
currentUrl = nextUrl;
|
|
99
|
+
cancelMCPStream(response.body);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const REDACTED = "<redacted>";
|
|
2
|
+
const SENSITIVE_KEY_PATTERN = /(?:token|secret|key|credential|password|authorization|auth|bearer|cookie|session)/i;
|
|
3
|
+
|
|
4
|
+
export function redactMCPEndpoint(value: string | undefined): string | undefined {
|
|
5
|
+
if (!value) return value;
|
|
6
|
+
try {
|
|
7
|
+
const url = new URL(value);
|
|
8
|
+
if (url.username) url.username = REDACTED;
|
|
9
|
+
if (url.password) url.password = REDACTED;
|
|
10
|
+
if (url.pathname !== "/") url.pathname = `/${REDACTED}`;
|
|
11
|
+
for (const key of Array.from(url.searchParams.keys())) {
|
|
12
|
+
url.searchParams.set(key, REDACTED);
|
|
13
|
+
}
|
|
14
|
+
url.hash = "";
|
|
15
|
+
return url.toString();
|
|
16
|
+
} catch {
|
|
17
|
+
return REDACTED;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function redactMCPDiagnosticValue(value: unknown): unknown {
|
|
22
|
+
if (Array.isArray(value)) return value.map(redactMCPDiagnosticValue);
|
|
23
|
+
if (!value || typeof value !== "object") return value;
|
|
24
|
+
return Object.fromEntries(
|
|
25
|
+
Object.entries(value).map(([key, entry]) => [
|
|
26
|
+
key,
|
|
27
|
+
SENSITIVE_KEY_PATTERN.test(key) ? REDACTED : redactMCPDiagnosticValue(entry),
|
|
28
|
+
]),
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -2,9 +2,18 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { isEnoent, logger } from "@sayknow-cli/utils";
|
|
4
4
|
import { getAgentDir } from "@sayknow-cli/utils/dirs";
|
|
5
|
+
import { $credentialEnv } from "@sayknow-cli/utils/env";
|
|
5
6
|
|
|
6
7
|
const SMITHERY_AUTH_FILENAME = "smithery.json";
|
|
7
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Smithery web origin, from trusted environment sources only.
|
|
10
|
+
*
|
|
11
|
+
* This origin serves the CLI auth session and the verification URL the user is
|
|
12
|
+
* sent to, so whatever can set it can drive the login flow. `$env` merges the
|
|
13
|
+
* caller's `cwd/.env` into `process.env`, so reading it there would let
|
|
14
|
+
* repository content redirect that flow.
|
|
15
|
+
*/
|
|
16
|
+
const SMITHERY_URL = $credentialEnv("SMITHERY_URL") || "https://smithery.ai";
|
|
8
17
|
|
|
9
18
|
type SmitheryCliAuthSession = {
|
|
10
19
|
sessionId: string;
|
|
@@ -31,6 +40,11 @@ function normalizeApiKey(value: string | undefined): string | undefined {
|
|
|
31
40
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
32
41
|
}
|
|
33
42
|
|
|
43
|
+
/** Test seam: the Smithery origin and env API key as resolved from trusted env. */
|
|
44
|
+
export function resolveSmitheryEnvForTest(): { url: string; apiKey: string | undefined } {
|
|
45
|
+
return { url: SMITHERY_URL, apiKey: normalizeApiKey($credentialEnv("SMITHERY_API_KEY")) };
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
export function getSmitheryLoginUrl(): string {
|
|
35
49
|
return SMITHERY_URL;
|
|
36
50
|
}
|
|
@@ -62,7 +76,8 @@ export async function pollSmitheryCliAuthSession(
|
|
|
62
76
|
}
|
|
63
77
|
|
|
64
78
|
export async function getSmitheryApiKey(): Promise<string | undefined> {
|
|
65
|
-
|
|
79
|
+
// Trusted sources only: this key authenticates every Smithery API call.
|
|
80
|
+
const envKey = normalizeApiKey($credentialEnv("SMITHERY_API_KEY"));
|
|
66
81
|
if (envKey) return envKey;
|
|
67
82
|
|
|
68
83
|
const authPath = getSmitheryAuthPath();
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { $credentialEnv } from "@sayknow-cli/utils/env";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Smithery API base, from trusted environment sources only.
|
|
5
|
+
*
|
|
6
|
+
* Every request to this base carries `Authorization: Bearer <apiKey>` and the
|
|
7
|
+
* `/connect` routes return the connection records the agent consumes, so
|
|
8
|
+
* whatever can set it receives the key and supplies those records. `$env` merges
|
|
9
|
+
* the caller's `cwd/.env` into `process.env`.
|
|
10
|
+
*/
|
|
11
|
+
const SMITHERY_API_BASE_URL = ($credentialEnv("SMITHERY_API_URL") || "https://api.smithery.ai").replace(/\/+$/, "");
|
|
2
12
|
|
|
3
13
|
export class SmitheryConnectError extends Error {
|
|
4
14
|
status: number;
|