@oobe-protocol-labs/sap-mcp-server 0.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/.env.example +159 -0
- package/CHANGELOG.md +55 -0
- package/LICENSE +21 -0
- package/README.md +223 -0
- package/config.example.json +64 -0
- package/config.schema.json +370 -0
- package/config.secure-example.json +100 -0
- package/dist/adapters/index.d.ts +6 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +6 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/mcp/errors.d.ts +7 -0
- package/dist/adapters/mcp/errors.d.ts.map +1 -0
- package/dist/adapters/mcp/errors.js +10 -0
- package/dist/adapters/mcp/errors.js.map +1 -0
- package/dist/adapters/mcp/index.d.ts +8 -0
- package/dist/adapters/mcp/index.d.ts.map +1 -0
- package/dist/adapters/mcp/index.js +8 -0
- package/dist/adapters/mcp/index.js.map +1 -0
- package/dist/adapters/mcp/prompt-response.d.ts +13 -0
- package/dist/adapters/mcp/prompt-response.d.ts.map +1 -0
- package/dist/adapters/mcp/prompt-response.js +7 -0
- package/dist/adapters/mcp/prompt-response.js.map +1 -0
- package/dist/adapters/mcp/resource-response.d.ts +8 -0
- package/dist/adapters/mcp/resource-response.d.ts.map +1 -0
- package/dist/adapters/mcp/resource-response.js +7 -0
- package/dist/adapters/mcp/resource-response.js.map +1 -0
- package/dist/adapters/mcp/sdk-compat.d.ts +191 -0
- package/dist/adapters/mcp/sdk-compat.d.ts.map +1 -0
- package/dist/adapters/mcp/sdk-compat.js +606 -0
- package/dist/adapters/mcp/sdk-compat.js.map +1 -0
- package/dist/adapters/mcp/tool-response.d.ts +32 -0
- package/dist/adapters/mcp/tool-response.d.ts.map +1 -0
- package/dist/adapters/mcp/tool-response.js +27 -0
- package/dist/adapters/mcp/tool-response.js.map +1 -0
- package/dist/adapters/solana/commitment.d.ts +9 -0
- package/dist/adapters/solana/commitment.d.ts.map +1 -0
- package/dist/adapters/solana/commitment.js +14 -0
- package/dist/adapters/solana/commitment.js.map +1 -0
- package/dist/adapters/solana/connection.d.ts +10 -0
- package/dist/adapters/solana/connection.d.ts.map +1 -0
- package/dist/adapters/solana/connection.js +13 -0
- package/dist/adapters/solana/connection.js.map +1 -0
- package/dist/adapters/solana/index.d.ts +7 -0
- package/dist/adapters/solana/index.d.ts.map +1 -0
- package/dist/adapters/solana/index.js +7 -0
- package/dist/adapters/solana/index.js.map +1 -0
- package/dist/adapters/solana/public-key.d.ts +9 -0
- package/dist/adapters/solana/public-key.d.ts.map +1 -0
- package/dist/adapters/solana/public-key.js +11 -0
- package/dist/adapters/solana/public-key.js.map +1 -0
- package/dist/cli.d.ts +29 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +269 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/defaults.d.ts +28 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +28 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/env.d.ts +297 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +563 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +7 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/mcp-client-injection.d.ts +113 -0
- package/dist/config/mcp-client-injection.d.ts.map +1 -0
- package/dist/config/mcp-client-injection.js +453 -0
- package/dist/config/mcp-client-injection.js.map +1 -0
- package/dist/config/paths.d.ts +37 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +93 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/profiles.d.ts +85 -0
- package/dist/config/profiles.d.ts.map +1 -0
- package/dist/config/profiles.js +346 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/schema.d.ts +9 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +8 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/secure-config.d.ts +607 -0
- package/dist/config/secure-config.d.ts.map +1 -0
- package/dist/config/secure-config.js +526 -0
- package/dist/config/secure-config.js.map +1 -0
- package/dist/config/setup.d.ts +42 -0
- package/dist/config/setup.d.ts.map +1 -0
- package/dist/config/setup.js +173 -0
- package/dist/config/setup.js.map +1 -0
- package/dist/config/wizard.d.ts +15 -0
- package/dist/config/wizard.d.ts.map +1 -0
- package/dist/config/wizard.js +1176 -0
- package/dist/config/wizard.js.map +1 -0
- package/dist/config-cli.d.ts +21 -0
- package/dist/config-cli.d.ts.map +1 -0
- package/dist/config-cli.js +679 -0
- package/dist/config-cli.js.map +1 -0
- package/dist/core/constants.d.ts +78 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +78 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/errors.d.ts +188 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +337 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/guards.d.ts +41 -0
- package/dist/core/guards.d.ts.map +1 -0
- package/dist/core/guards.js +93 -0
- package/dist/core/guards.js.map +1 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +10 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +64 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +159 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/result.d.ts +49 -0
- package/dist/core/result.d.ts.map +1 -0
- package/dist/core/result.js +61 -0
- package/dist/core/result.js.map +1 -0
- package/dist/core/types.d.ts +147 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +8 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/payments/http-adapter.d.ts +76 -0
- package/dist/payments/http-adapter.d.ts.map +1 -0
- package/dist/payments/http-adapter.js +126 -0
- package/dist/payments/http-adapter.js.map +1 -0
- package/dist/payments/index.d.ts +12 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +9 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/payments/json-rpc.d.ts +49 -0
- package/dist/payments/json-rpc.d.ts.map +1 -0
- package/dist/payments/json-rpc.js +53 -0
- package/dist/payments/json-rpc.js.map +1 -0
- package/dist/payments/monetization-gate.d.ts +49 -0
- package/dist/payments/monetization-gate.d.ts.map +1 -0
- package/dist/payments/monetization-gate.js +398 -0
- package/dist/payments/monetization-gate.js.map +1 -0
- package/dist/payments/oobe-facilitator-server.d.ts +71 -0
- package/dist/payments/oobe-facilitator-server.d.ts.map +1 -0
- package/dist/payments/oobe-facilitator-server.js +409 -0
- package/dist/payments/oobe-facilitator-server.js.map +1 -0
- package/dist/payments/pay-sh-spec.d.ts +44 -0
- package/dist/payments/pay-sh-spec.d.ts.map +1 -0
- package/dist/payments/pay-sh-spec.js +218 -0
- package/dist/payments/pay-sh-spec.js.map +1 -0
- package/dist/payments/pricing.d.ts +60 -0
- package/dist/payments/pricing.d.ts.map +1 -0
- package/dist/payments/pricing.js +272 -0
- package/dist/payments/pricing.js.map +1 -0
- package/dist/payments/usage-ledger.d.ts +84 -0
- package/dist/payments/usage-ledger.d.ts.map +1 -0
- package/dist/payments/usage-ledger.js +126 -0
- package/dist/payments/usage-ledger.js.map +1 -0
- package/dist/policy/bento-policy-engine.d.ts +71 -0
- package/dist/policy/bento-policy-engine.d.ts.map +1 -0
- package/dist/policy/bento-policy-engine.js +218 -0
- package/dist/policy/bento-policy-engine.js.map +1 -0
- package/dist/policy/default-policies.d.ts +9 -0
- package/dist/policy/default-policies.d.ts.map +1 -0
- package/dist/policy/default-policies.js +69 -0
- package/dist/policy/default-policies.js.map +1 -0
- package/dist/policy/hybrid-policy-engine.d.ts +95 -0
- package/dist/policy/hybrid-policy-engine.d.ts.map +1 -0
- package/dist/policy/hybrid-policy-engine.js +297 -0
- package/dist/policy/hybrid-policy-engine.js.map +1 -0
- package/dist/policy/index.d.ts +10 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +10 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/local-policy-engine.d.ts +119 -0
- package/dist/policy/local-policy-engine.d.ts.map +1 -0
- package/dist/policy/local-policy-engine.js +318 -0
- package/dist/policy/local-policy-engine.js.map +1 -0
- package/dist/policy/permission-checks.d.ts +19 -0
- package/dist/policy/permission-checks.d.ts.map +1 -0
- package/dist/policy/permission-checks.js +60 -0
- package/dist/policy/permission-checks.js.map +1 -0
- package/dist/policy/policy-engine.d.ts +57 -0
- package/dist/policy/policy-engine.d.ts.map +1 -0
- package/dist/policy/policy-engine.js +162 -0
- package/dist/policy/policy-engine.js.map +1 -0
- package/dist/policy/policy-types.d.ts +46 -0
- package/dist/policy/policy-types.d.ts.map +1 -0
- package/dist/policy/policy-types.js +5 -0
- package/dist/policy/policy-types.js.map +1 -0
- package/dist/policy/risk-level.d.ts +18 -0
- package/dist/policy/risk-level.d.ts.map +1 -0
- package/dist/policy/risk-level.js +46 -0
- package/dist/policy/risk-level.js.map +1 -0
- package/dist/policy/spending-limits.d.ts +17 -0
- package/dist/policy/spending-limits.d.ts.map +1 -0
- package/dist/policy/spending-limits.js +40 -0
- package/dist/policy/spending-limits.js.map +1 -0
- package/dist/prompts/context/sap-agent-context.prompt.d.ts +64 -0
- package/dist/prompts/context/sap-agent-context.prompt.d.ts.map +1 -0
- package/dist/prompts/context/sap-agent-context.prompt.js +336 -0
- package/dist/prompts/context/sap-agent-context.prompt.js.map +1 -0
- package/dist/prompts/developer/debug-sap-error.prompt.d.ts +13 -0
- package/dist/prompts/developer/debug-sap-error.prompt.d.ts.map +1 -0
- package/dist/prompts/developer/debug-sap-error.prompt.js +78 -0
- package/dist/prompts/developer/debug-sap-error.prompt.js.map +1 -0
- package/dist/prompts/developer/generate-sap-integration.prompt.d.ts +13 -0
- package/dist/prompts/developer/generate-sap-integration.prompt.d.ts.map +1 -0
- package/dist/prompts/developer/generate-sap-integration.prompt.js +132 -0
- package/dist/prompts/developer/generate-sap-integration.prompt.js.map +1 -0
- package/dist/prompts/developer/index.d.ts +6 -0
- package/dist/prompts/developer/index.d.ts.map +1 -0
- package/dist/prompts/developer/index.js +6 -0
- package/dist/prompts/developer/index.js.map +1 -0
- package/dist/prompts/execution-proof/explain-proof-of-execution.prompt.d.ts +13 -0
- package/dist/prompts/execution-proof/explain-proof-of-execution.prompt.d.ts.map +1 -0
- package/dist/prompts/execution-proof/explain-proof-of-execution.prompt.js +97 -0
- package/dist/prompts/execution-proof/explain-proof-of-execution.prompt.js.map +1 -0
- package/dist/prompts/execution-proof/index.d.ts +6 -0
- package/dist/prompts/execution-proof/index.d.ts.map +1 -0
- package/dist/prompts/execution-proof/index.js +6 -0
- package/dist/prompts/execution-proof/index.js.map +1 -0
- package/dist/prompts/execution-proof/verify-execution-proof.prompt.d.ts +13 -0
- package/dist/prompts/execution-proof/verify-execution-proof.prompt.d.ts.map +1 -0
- package/dist/prompts/execution-proof/verify-execution-proof.prompt.js +95 -0
- package/dist/prompts/execution-proof/verify-execution-proof.prompt.js.map +1 -0
- package/dist/prompts/index.d.ts +5 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +5 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/payments/create-paid-api.prompt.d.ts +13 -0
- package/dist/prompts/payments/create-paid-api.prompt.d.ts.map +1 -0
- package/dist/prompts/payments/create-paid-api.prompt.js +142 -0
- package/dist/prompts/payments/create-paid-api.prompt.js.map +1 -0
- package/dist/prompts/payments/explain-x402-settlement.prompt.d.ts +13 -0
- package/dist/prompts/payments/explain-x402-settlement.prompt.d.ts.map +1 -0
- package/dist/prompts/payments/explain-x402-settlement.prompt.js +83 -0
- package/dist/prompts/payments/explain-x402-settlement.prompt.js.map +1 -0
- package/dist/prompts/payments/index.d.ts +6 -0
- package/dist/prompts/payments/index.d.ts.map +1 -0
- package/dist/prompts/payments/index.js +6 -0
- package/dist/prompts/payments/index.js.map +1 -0
- package/dist/prompts/register-prompts.d.ts +10 -0
- package/dist/prompts/register-prompts.d.ts.map +1 -0
- package/dist/prompts/register-prompts.js +40 -0
- package/dist/prompts/register-prompts.js.map +1 -0
- package/dist/prompts/registry/analyze-sap-agent.prompt.d.ts +13 -0
- package/dist/prompts/registry/analyze-sap-agent.prompt.d.ts.map +1 -0
- package/dist/prompts/registry/analyze-sap-agent.prompt.js +85 -0
- package/dist/prompts/registry/analyze-sap-agent.prompt.js.map +1 -0
- package/dist/prompts/registry/index.d.ts +6 -0
- package/dist/prompts/registry/index.d.ts.map +1 -0
- package/dist/prompts/registry/index.js +6 -0
- package/dist/prompts/registry/index.js.map +1 -0
- package/dist/prompts/registry/register-sap-agent.prompt.d.ts +13 -0
- package/dist/prompts/registry/register-sap-agent.prompt.d.ts.map +1 -0
- package/dist/prompts/registry/register-sap-agent.prompt.js +152 -0
- package/dist/prompts/registry/register-sap-agent.prompt.js.map +1 -0
- package/dist/remote/auth/index.d.ts +86 -0
- package/dist/remote/auth/index.d.ts.map +1 -0
- package/dist/remote/auth/index.js +152 -0
- package/dist/remote/auth/index.js.map +1 -0
- package/dist/remote/server.d.ts +140 -0
- package/dist/remote/server.d.ts.map +1 -0
- package/dist/remote/server.js +412 -0
- package/dist/remote/server.js.map +1 -0
- package/dist/resources/current/sap-current-config.resource.d.ts +30 -0
- package/dist/resources/current/sap-current-config.resource.d.ts.map +1 -0
- package/dist/resources/current/sap-current-config.resource.js +142 -0
- package/dist/resources/current/sap-current-config.resource.js.map +1 -0
- package/dist/resources/execution-proof/index.d.ts +5 -0
- package/dist/resources/execution-proof/index.d.ts.map +1 -0
- package/dist/resources/execution-proof/index.js +5 -0
- package/dist/resources/execution-proof/index.js.map +1 -0
- package/dist/resources/execution-proof/sap-execution-record.resource.d.ts +13 -0
- package/dist/resources/execution-proof/sap-execution-record.resource.d.ts.map +1 -0
- package/dist/resources/execution-proof/sap-execution-record.resource.js +75 -0
- package/dist/resources/execution-proof/sap-execution-record.resource.js.map +1 -0
- package/dist/resources/index.d.ts +5 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +5 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/memory/index.d.ts +5 -0
- package/dist/resources/memory/index.d.ts.map +1 -0
- package/dist/resources/memory/index.js +5 -0
- package/dist/resources/memory/index.js.map +1 -0
- package/dist/resources/memory/sap-memory.resource.d.ts +13 -0
- package/dist/resources/memory/sap-memory.resource.d.ts.map +1 -0
- package/dist/resources/memory/sap-memory.resource.js +77 -0
- package/dist/resources/memory/sap-memory.resource.js.map +1 -0
- package/dist/resources/profile/sap-active-profile.resource.d.ts +51 -0
- package/dist/resources/profile/sap-active-profile.resource.d.ts.map +1 -0
- package/dist/resources/profile/sap-active-profile.resource.js +119 -0
- package/dist/resources/profile/sap-active-profile.resource.js.map +1 -0
- package/dist/resources/register-resources.d.ts +10 -0
- package/dist/resources/register-resources.d.ts.map +1 -0
- package/dist/resources/register-resources.js +33 -0
- package/dist/resources/register-resources.js.map +1 -0
- package/dist/resources/registry/index.d.ts +6 -0
- package/dist/resources/registry/index.d.ts.map +1 -0
- package/dist/resources/registry/index.js +6 -0
- package/dist/resources/registry/index.js.map +1 -0
- package/dist/resources/registry/sap-agent.resource.d.ts +13 -0
- package/dist/resources/registry/sap-agent.resource.d.ts.map +1 -0
- package/dist/resources/registry/sap-agent.resource.js +75 -0
- package/dist/resources/registry/sap-agent.resource.js.map +1 -0
- package/dist/resources/registry/sap-global-registry.resource.d.ts +13 -0
- package/dist/resources/registry/sap-global-registry.resource.d.ts.map +1 -0
- package/dist/resources/registry/sap-global-registry.resource.js +71 -0
- package/dist/resources/registry/sap-global-registry.resource.js.map +1 -0
- package/dist/resources/reputation/index.d.ts +5 -0
- package/dist/resources/reputation/index.d.ts.map +1 -0
- package/dist/resources/reputation/index.js +5 -0
- package/dist/resources/reputation/index.js.map +1 -0
- package/dist/resources/reputation/sap-reputation.resource.d.ts +13 -0
- package/dist/resources/reputation/sap-reputation.resource.d.ts.map +1 -0
- package/dist/resources/reputation/sap-reputation.resource.js +75 -0
- package/dist/resources/reputation/sap-reputation.resource.js.map +1 -0
- package/dist/resources/stats/sap-network-stats.resource.d.ts +14 -0
- package/dist/resources/stats/sap-network-stats.resource.d.ts.map +1 -0
- package/dist/resources/stats/sap-network-stats.resource.js +86 -0
- package/dist/resources/stats/sap-network-stats.resource.js.map +1 -0
- package/dist/resources/tool-schema/index.d.ts +5 -0
- package/dist/resources/tool-schema/index.d.ts.map +1 -0
- package/dist/resources/tool-schema/index.js +5 -0
- package/dist/resources/tool-schema/index.js.map +1 -0
- package/dist/resources/tool-schema/sap-tool-schema.resource.d.ts +13 -0
- package/dist/resources/tool-schema/sap-tool-schema.resource.d.ts.map +1 -0
- package/dist/resources/tool-schema/sap-tool-schema.resource.js +75 -0
- package/dist/resources/tool-schema/sap-tool-schema.resource.js.map +1 -0
- package/dist/sap/index.d.ts +7 -0
- package/dist/sap/index.d.ts.map +1 -0
- package/dist/sap/index.js +6 -0
- package/dist/sap/index.js.map +1 -0
- package/dist/sap/sap-client-manager.d.ts +54 -0
- package/dist/sap/sap-client-manager.d.ts.map +1 -0
- package/dist/sap/sap-client-manager.js +129 -0
- package/dist/sap/sap-client-manager.js.map +1 -0
- package/dist/sap/sap-errors.d.ts +13 -0
- package/dist/sap/sap-errors.d.ts.map +1 -0
- package/dist/sap/sap-errors.js +23 -0
- package/dist/sap/sap-errors.js.map +1 -0
- package/dist/sap/sap-types.d.ts +69 -0
- package/dist/sap/sap-types.d.ts.map +1 -0
- package/dist/sap/sap-types.js +5 -0
- package/dist/sap/sap-types.js.map +1 -0
- package/dist/schemas/common.schema.d.ts +42 -0
- package/dist/schemas/common.schema.d.ts.map +1 -0
- package/dist/schemas/common.schema.js +36 -0
- package/dist/schemas/common.schema.js.map +1 -0
- package/dist/schemas/developer.schema.d.ts +31 -0
- package/dist/schemas/developer.schema.d.ts.map +1 -0
- package/dist/schemas/developer.schema.js +19 -0
- package/dist/schemas/developer.schema.js.map +1 -0
- package/dist/schemas/execution-proof.schema.d.ts +44 -0
- package/dist/schemas/execution-proof.schema.d.ts.map +1 -0
- package/dist/schemas/execution-proof.schema.js +26 -0
- package/dist/schemas/execution-proof.schema.js.map +1 -0
- package/dist/schemas/identity.schema.d.ts +34 -0
- package/dist/schemas/identity.schema.d.ts.map +1 -0
- package/dist/schemas/identity.schema.js +21 -0
- package/dist/schemas/identity.schema.js.map +1 -0
- package/dist/schemas/index.d.ts +15 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +15 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/memory.schema.d.ts +34 -0
- package/dist/schemas/memory.schema.d.ts.map +1 -0
- package/dist/schemas/memory.schema.js +21 -0
- package/dist/schemas/memory.schema.js.map +1 -0
- package/dist/schemas/payments.schema.d.ts +37 -0
- package/dist/schemas/payments.schema.d.ts.map +1 -0
- package/dist/schemas/payments.schema.js +22 -0
- package/dist/schemas/payments.schema.js.map +1 -0
- package/dist/schemas/registry.schema.d.ts +65 -0
- package/dist/schemas/registry.schema.d.ts.map +1 -0
- package/dist/schemas/registry.schema.js +34 -0
- package/dist/schemas/registry.schema.js.map +1 -0
- package/dist/schemas/reputation.schema.d.ts +31 -0
- package/dist/schemas/reputation.schema.d.ts.map +1 -0
- package/dist/schemas/reputation.schema.js +20 -0
- package/dist/schemas/reputation.schema.js.map +1 -0
- package/dist/schemas/settlement.schema.d.ts +50 -0
- package/dist/schemas/settlement.schema.d.ts.map +1 -0
- package/dist/schemas/settlement.schema.js +29 -0
- package/dist/schemas/settlement.schema.js.map +1 -0
- package/dist/schemas/tool-schema.schema.d.ts +56 -0
- package/dist/schemas/tool-schema.schema.d.ts.map +1 -0
- package/dist/schemas/tool-schema.schema.js +26 -0
- package/dist/schemas/tool-schema.schema.js.map +1 -0
- package/dist/schemas/transaction.schema.d.ts +34 -0
- package/dist/schemas/transaction.schema.d.ts.map +1 -0
- package/dist/schemas/transaction.schema.js +20 -0
- package/dist/schemas/transaction.schema.js.map +1 -0
- package/dist/security/approval-required.d.ts +9 -0
- package/dist/security/approval-required.d.ts.map +1 -0
- package/dist/security/approval-required.js +10 -0
- package/dist/security/approval-required.js.map +1 -0
- package/dist/security/index.d.ts +9 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +9 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/private-key-guard.d.ts +11 -0
- package/dist/security/private-key-guard.d.ts.map +1 -0
- package/dist/security/private-key-guard.js +22 -0
- package/dist/security/private-key-guard.js.map +1 -0
- package/dist/security/prompt-injection-notes.d.ts +13 -0
- package/dist/security/prompt-injection-notes.d.ts.map +1 -0
- package/dist/security/prompt-injection-notes.js +23 -0
- package/dist/security/prompt-injection-notes.js.map +1 -0
- package/dist/security/tool-permissions.d.ts +30 -0
- package/dist/security/tool-permissions.d.ts.map +1 -0
- package/dist/security/tool-permissions.js +270 -0
- package/dist/security/tool-permissions.js.map +1 -0
- package/dist/security/unsafe-action-guard.d.ts +28 -0
- package/dist/security/unsafe-action-guard.d.ts.map +1 -0
- package/dist/security/unsafe-action-guard.js +175 -0
- package/dist/security/unsafe-action-guard.js.map +1 -0
- package/dist/server/create-server.d.ts +12 -0
- package/dist/server/create-server.d.ts.map +1 -0
- package/dist/server/create-server.js +57 -0
- package/dist/server/create-server.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +7 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/register-capabilities.d.ts +10 -0
- package/dist/server/register-capabilities.d.ts.map +1 -0
- package/dist/server/register-capabilities.js +23 -0
- package/dist/server/register-capabilities.js.map +1 -0
- package/dist/server/server-metadata.d.ts +32 -0
- package/dist/server/server-metadata.d.ts.map +1 -0
- package/dist/server/server-metadata.js +32 -0
- package/dist/server/server-metadata.js.map +1 -0
- package/dist/session/agent-session.d.ts +25 -0
- package/dist/session/agent-session.d.ts.map +1 -0
- package/dist/session/agent-session.js +35 -0
- package/dist/session/agent-session.js.map +1 -0
- package/dist/session/delegated-session.d.ts +20 -0
- package/dist/session/delegated-session.d.ts.map +1 -0
- package/dist/session/delegated-session.js +47 -0
- package/dist/session/delegated-session.js.map +1 -0
- package/dist/session/index.d.ts +10 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +9 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/redis-session-store.d.ts +89 -0
- package/dist/session/redis-session-store.d.ts.map +1 -0
- package/dist/session/redis-session-store.js +219 -0
- package/dist/session/redis-session-store.js.map +1 -0
- package/dist/session/session-limits.d.ts +20 -0
- package/dist/session/session-limits.d.ts.map +1 -0
- package/dist/session/session-limits.js +55 -0
- package/dist/session/session-limits.js.map +1 -0
- package/dist/session/session-permissions.d.ts +37 -0
- package/dist/session/session-permissions.d.ts.map +1 -0
- package/dist/session/session-permissions.js +58 -0
- package/dist/session/session-permissions.js.map +1 -0
- package/dist/session/session-store.d.ts +38 -0
- package/dist/session/session-store.d.ts.map +1 -0
- package/dist/session/session-store.js +62 -0
- package/dist/session/session-store.js.map +1 -0
- package/dist/session/session-types.d.ts +33 -0
- package/dist/session/session-types.d.ts.map +1 -0
- package/dist/session/session-types.js +5 -0
- package/dist/session/session-types.js.map +1 -0
- package/dist/signer/external-signer.d.ts +16 -0
- package/dist/signer/external-signer.d.ts.map +1 -0
- package/dist/signer/external-signer.js +128 -0
- package/dist/signer/external-signer.js.map +1 -0
- package/dist/signer/index.d.ts +9 -0
- package/dist/signer/index.d.ts.map +1 -0
- package/dist/signer/index.js +8 -0
- package/dist/signer/index.js.map +1 -0
- package/dist/signer/load-keypair.d.ts +15 -0
- package/dist/signer/load-keypair.d.ts.map +1 -0
- package/dist/signer/load-keypair.js +39 -0
- package/dist/signer/load-keypair.js.map +1 -0
- package/dist/signer/local-keypair-signer.d.ts +11 -0
- package/dist/signer/local-keypair-signer.d.ts.map +1 -0
- package/dist/signer/local-keypair-signer.js +46 -0
- package/dist/signer/local-keypair-signer.js.map +1 -0
- package/dist/signer/signer-resolver.d.ts +10 -0
- package/dist/signer/signer-resolver.d.ts.map +1 -0
- package/dist/signer/signer-resolver.js +63 -0
- package/dist/signer/signer-resolver.js.map +1 -0
- package/dist/signer/signer-types.d.ts +35 -0
- package/dist/signer/signer-types.d.ts.map +1 -0
- package/dist/signer/signer-types.js +5 -0
- package/dist/signer/signer-types.js.map +1 -0
- package/dist/signer/signing-proxy.d.ts +45 -0
- package/dist/signer/signing-proxy.d.ts.map +1 -0
- package/dist/signer/signing-proxy.js +300 -0
- package/dist/signer/signing-proxy.js.map +1 -0
- package/dist/tools/client-sdk-tools.d.ts +22 -0
- package/dist/tools/client-sdk-tools.d.ts.map +1 -0
- package/dist/tools/client-sdk-tools.js +220 -0
- package/dist/tools/client-sdk-tools.js.map +1 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/profile-tools.d.ts +12 -0
- package/dist/tools/profile-tools.d.ts.map +1 -0
- package/dist/tools/profile-tools.js +250 -0
- package/dist/tools/profile-tools.js.map +1 -0
- package/dist/tools/register-tools.d.ts +12 -0
- package/dist/tools/register-tools.d.ts.map +1 -0
- package/dist/tools/register-tools.js +36 -0
- package/dist/tools/register-tools.js.map +1 -0
- package/dist/tools/sap-network-stats.tool.d.ts +14 -0
- package/dist/tools/sap-network-stats.tool.d.ts.map +1 -0
- package/dist/tools/sap-network-stats.tool.js +101 -0
- package/dist/tools/sap-network-stats.tool.js.map +1 -0
- package/dist/tools/sap-sdk-tools.d.ts +15 -0
- package/dist/tools/sap-sdk-tools.d.ts.map +1 -0
- package/dist/tools/sap-sdk-tools.js +1515 -0
- package/dist/tools/sap-sdk-tools.js.map +1 -0
- package/dist/tools/sap-sns-tools.d.ts +35 -0
- package/dist/tools/sap-sns-tools.d.ts.map +1 -0
- package/dist/tools/sap-sns-tools.js +626 -0
- package/dist/tools/sap-sns-tools.js.map +1 -0
- package/dist/tools/skills-tools.d.ts +12 -0
- package/dist/tools/skills-tools.d.ts.map +1 -0
- package/dist/tools/skills-tools.js +273 -0
- package/dist/tools/skills-tools.js.map +1 -0
- package/dist/tools/transaction-tools.d.ts +14 -0
- package/dist/tools/transaction-tools.d.ts.map +1 -0
- package/dist/tools/transaction-tools.js +297 -0
- package/dist/tools/transaction-tools.js.map +1 -0
- package/dist/transports/http.d.ts +40 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +212 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/index.d.ts +6 -0
- package/dist/transports/index.d.ts.map +1 -0
- package/dist/transports/index.js +6 -0
- package/dist/transports/index.js.map +1 -0
- package/dist/transports/stdio.d.ts +14 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +32 -0
- package/dist/transports/stdio.js.map +1 -0
- package/dist/tui/components.d.ts +59 -0
- package/dist/tui/components.d.ts.map +1 -0
- package/dist/tui/components.js +82 -0
- package/dist/tui/components.js.map +1 -0
- package/dist/tui/config-wizard.d.ts +12 -0
- package/dist/tui/config-wizard.d.ts.map +1 -0
- package/dist/tui/config-wizard.js +348 -0
- package/dist/tui/config-wizard.js.map +1 -0
- package/dist/tui/wizard-save.d.ts +51 -0
- package/dist/tui/wizard-save.d.ts.map +1 -0
- package/dist/tui/wizard-save.js +148 -0
- package/dist/tui/wizard-save.js.map +1 -0
- package/docs/00_README.md +45 -0
- package/docs/01_PRODUCT_OVERVIEW.md +69 -0
- package/docs/02_ARCHITECTURE_AND_REQUEST_FLOW.md +120 -0
- package/docs/03_CONFIGURATION_AND_WIZARD.md +143 -0
- package/docs/04_LOCAL_STDIO_USAGE.md +118 -0
- package/docs/05_REMOTE_VPS_DEPLOYMENT.md +136 -0
- package/docs/06_PAYMENTS_X402_AND_PAYSH.md +162 -0
- package/docs/07_ENDPOINTS_AND_CLIENTS.md +114 -0
- package/docs/08_SECURITY_POLICY_AND_SIGNING.md +134 -0
- package/docs/09_TOOLS_SKILLS_AND_AGENT_GUIDE.md +72 -0
- package/docs/10_OPERATIONS_RELEASE_AND_PM2.md +90 -0
- package/docs/11_CODE_QUALITY_AUDIT.md +49 -0
- package/ecosystem.config.example.cjs +55 -0
- package/package.json +132 -0
- package/skills/README.md +146 -0
- package/skills/sap-agent-registry/SKILL.md +39 -0
- package/skills/sap-agentkit/SKILL.md +40 -0
- package/skills/sap-defi/SKILL.md +51 -0
- package/skills/sap-discovery-indexing/SKILL.md +33 -0
- package/skills/sap-escrow-settlement/SKILL.md +37 -0
- package/skills/sap-ledger-session/SKILL.md +24 -0
- package/skills/sap-market-data/SKILL.md +36 -0
- package/skills/sap-mcp/SKILL.md +202 -0
- package/skills/sap-mcp/TOOL_REFERENCE.md +184 -0
- package/skills/sap-memory-vault/SKILL.md +29 -0
- package/skills/sap-nft-metaplex/SKILL.md +38 -0
- package/skills/sap-operations/SKILL.md +97 -0
- package/skills/sap-payments-x402/SKILL.md +47 -0
- package/skills/sap-reputation-attestation/SKILL.md +30 -0
- package/skills/sap-sns/SKILL.md +51 -0
- package/skills/sap-social-gaming/SKILL.md +30 -0
- package/skills/sap-solana-token/SKILL.md +32 -0
- package/skills/sap-staking/SKILL.md +24 -0
- package/skills/sap-tool-registry/SKILL.md +29 -0
|
@@ -0,0 +1,1176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* SAP MCP Server - Configuration Wizard
|
|
4
|
+
*
|
|
5
|
+
* Interactive wizard for initial configuration setup.
|
|
6
|
+
* Guides users through secure configuration with explanations.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx sap-mcp-config wizard
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync, statSync } from 'fs';
|
|
12
|
+
import { homedir } from 'os';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
import readline from 'readline';
|
|
15
|
+
import { Keypair } from '@solana/web3.js';
|
|
16
|
+
import { defaults } from './defaults.js';
|
|
17
|
+
import { defaultGeneratedWalletPath } from './paths.js';
|
|
18
|
+
import { saveWizardSetup } from './setup.js';
|
|
19
|
+
import { applyMcpClientInjection, createCanonicalServerConfig, createManualMcpJsonSnippets, discoverMcpClientTargets, planMcpClientInjection, } from './mcp-client-injection.js';
|
|
20
|
+
class WizardCancelled extends Error {
|
|
21
|
+
constructor() {
|
|
22
|
+
super('Wizard cancelled');
|
|
23
|
+
this.name = 'WizardCancelled';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const EXIT_COMMANDS = new Set(['exit', 'quit', 'cancel', 'q', ':q', '/exit', '/quit', '/cancel']);
|
|
27
|
+
const HELP_COMMANDS = new Set(['?', 'help', '/help']);
|
|
28
|
+
const WIZARD_WIDTH = 72;
|
|
29
|
+
const COLOR_ENABLED = process.env.NO_COLOR !== '1' && process.env.SAP_MCP_NO_COLOR !== 'true';
|
|
30
|
+
const color = {
|
|
31
|
+
aqua: '\x1b[36m',
|
|
32
|
+
blue: '\x1b[34m',
|
|
33
|
+
green: '\x1b[32m',
|
|
34
|
+
red: '\x1b[31m',
|
|
35
|
+
yellow: '\x1b[33m',
|
|
36
|
+
magenta: '\x1b[35m',
|
|
37
|
+
gray: '\x1b[90m',
|
|
38
|
+
bold: '\x1b[1m',
|
|
39
|
+
reset: '\x1b[0m',
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* @name paint
|
|
43
|
+
* @description Applies ANSI color only when terminal color output is enabled.
|
|
44
|
+
*/
|
|
45
|
+
function paint(value, ...colors) {
|
|
46
|
+
if (!COLOR_ENABLED) {
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
return `${colors.map((name) => color[name]).join('')}${value}${color.reset}`;
|
|
50
|
+
}
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Interactive CLI Helper
|
|
53
|
+
// ============================================================================
|
|
54
|
+
const rl = readline.createInterface({
|
|
55
|
+
input: process.stdin,
|
|
56
|
+
output: process.stdout,
|
|
57
|
+
});
|
|
58
|
+
process.once('SIGINT', () => {
|
|
59
|
+
console.log(`\n${paint('Wizard cancelled. No configuration was saved.', 'yellow')}`);
|
|
60
|
+
rl.close();
|
|
61
|
+
process.exit(130);
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Returns true when the user requested wizard cancellation.
|
|
65
|
+
*/
|
|
66
|
+
function isExitCommand(value) {
|
|
67
|
+
return EXIT_COMMANDS.has(value.trim().toLowerCase());
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Returns true when the user requested contextual help.
|
|
71
|
+
*/
|
|
72
|
+
function isHelpCommand(value) {
|
|
73
|
+
return HELP_COMMANDS.has(value.trim().toLowerCase());
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Prints contextual help for a prompt.
|
|
77
|
+
*/
|
|
78
|
+
function printPromptHelp(lines) {
|
|
79
|
+
console.log('');
|
|
80
|
+
console.log(paint('Help', 'aqua', 'bold'));
|
|
81
|
+
for (const line of lines ?? ['Enter a value, or type /exit to cancel the wizard.']) {
|
|
82
|
+
console.log(` ${line}`);
|
|
83
|
+
}
|
|
84
|
+
console.log('');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Prints the common wizard control hints.
|
|
88
|
+
*/
|
|
89
|
+
function printControlHints() {
|
|
90
|
+
console.log(paint('Controls: type ? for help, /exit to cancel, Ctrl+C to abort.', 'gray'));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Builds a user-friendly prompt string with default values.
|
|
94
|
+
*/
|
|
95
|
+
function formatPrompt(question, defaultValue) {
|
|
96
|
+
return defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Formats a selectable option label, preserving labels that already include ANSI styling.
|
|
100
|
+
*/
|
|
101
|
+
function formatChoiceLabel(choice) {
|
|
102
|
+
return choice.includes('\x1b[') ? choice : paint(choice, 'aqua');
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Internal helper for the ask question operation.
|
|
106
|
+
*/
|
|
107
|
+
function askQuestion(question, defaultValueOrOptions) {
|
|
108
|
+
const options = typeof defaultValueOrOptions === 'string'
|
|
109
|
+
? { defaultValue: defaultValueOrOptions }
|
|
110
|
+
: defaultValueOrOptions ?? {};
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
const ask = () => {
|
|
113
|
+
rl.question(formatPrompt(question, options.defaultValue), (answer) => {
|
|
114
|
+
const raw = answer.trim();
|
|
115
|
+
if (isExitCommand(raw)) {
|
|
116
|
+
reject(new WizardCancelled());
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (isHelpCommand(raw)) {
|
|
120
|
+
printPromptHelp(options.help);
|
|
121
|
+
ask();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const candidate = raw || options.defaultValue || '';
|
|
125
|
+
const value = options.transform ? options.transform(candidate) : candidate;
|
|
126
|
+
if (options.required && !value) {
|
|
127
|
+
printError('This field is required.');
|
|
128
|
+
ask();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const validationError = options.validate?.(value);
|
|
132
|
+
if (validationError) {
|
|
133
|
+
printError(validationError);
|
|
134
|
+
ask();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
resolve(value);
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
ask();
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Internal helper for the ask choice operation.
|
|
145
|
+
*/
|
|
146
|
+
function askChoice(question, choices, defaultIndex = 0, help) {
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
const ask = () => {
|
|
149
|
+
console.log(question);
|
|
150
|
+
choices.forEach((choice, i) => {
|
|
151
|
+
const marker = i === defaultIndex ? ' (recommended)' : '';
|
|
152
|
+
console.log(` ${paint(`${i + 1})`, 'gray')} ${formatChoiceLabel(choice)}${paint(marker, 'green')}`);
|
|
153
|
+
});
|
|
154
|
+
const prompt = `Enter choice (1-${choices.length})`;
|
|
155
|
+
const defaultChoice = defaultIndex + 1;
|
|
156
|
+
rl.question(`${paint(`${prompt} [${defaultChoice}]:`, 'gray')} `, (answer) => {
|
|
157
|
+
const raw = answer.trim();
|
|
158
|
+
if (isExitCommand(raw)) {
|
|
159
|
+
reject(new WizardCancelled());
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (isHelpCommand(raw)) {
|
|
163
|
+
printPromptHelp(help);
|
|
164
|
+
ask();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (!raw) {
|
|
168
|
+
resolve(defaultIndex);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const num = parseInt(raw, 10);
|
|
172
|
+
if (isNaN(num) || num < 1 || num > choices.length) {
|
|
173
|
+
printError(`Choose a number between 1 and ${choices.length}.`);
|
|
174
|
+
ask();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
resolve(num - 1);
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
ask();
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Internal helper for selecting multiple numbered options in one prompt.
|
|
185
|
+
*/
|
|
186
|
+
function askMultiChoice(question, choices, defaultIndexes = [], help) {
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
188
|
+
const ask = () => {
|
|
189
|
+
console.log(question);
|
|
190
|
+
choices.forEach((choice, i) => {
|
|
191
|
+
const marker = defaultIndexes.includes(i) ? ' (default)' : '';
|
|
192
|
+
console.log(` ${paint(`${i + 1})`, 'gray')} ${formatChoiceLabel(choice)}${paint(marker, 'green')}`);
|
|
193
|
+
});
|
|
194
|
+
const defaultValue = defaultIndexes.length > 0
|
|
195
|
+
? defaultIndexes.map((index) => String(index + 1)).join(',')
|
|
196
|
+
: 'none';
|
|
197
|
+
rl.question(`${paint(`Enter choices as comma-separated numbers, "all", or "none" [${defaultValue}]:`, 'gray')} `, (answer) => {
|
|
198
|
+
const raw = answer.trim().toLowerCase();
|
|
199
|
+
if (isExitCommand(raw)) {
|
|
200
|
+
reject(new WizardCancelled());
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (isHelpCommand(raw)) {
|
|
204
|
+
printPromptHelp(help);
|
|
205
|
+
ask();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const value = raw || defaultValue;
|
|
209
|
+
if (value === 'none' || value === 'no' || value === 'skip') {
|
|
210
|
+
resolve([]);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (value === 'all') {
|
|
214
|
+
resolve(choices.map((_, index) => index));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const indexes = value
|
|
218
|
+
.split(',')
|
|
219
|
+
.map((item) => Number(item.trim()))
|
|
220
|
+
.filter((item) => Number.isInteger(item));
|
|
221
|
+
if (indexes.length === 0 || indexes.some((item) => item < 1 || item > choices.length)) {
|
|
222
|
+
printError(`Choose numbers between 1 and ${choices.length}, "all", or "none".`);
|
|
223
|
+
ask();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
resolve(Array.from(new Set(indexes.map((item) => item - 1))));
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
ask();
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Internal helper for the ask confirm operation.
|
|
234
|
+
*/
|
|
235
|
+
function askConfirm(question, defaultYes = false, help) {
|
|
236
|
+
return new Promise((resolve, reject) => {
|
|
237
|
+
const ask = () => {
|
|
238
|
+
const suffix = defaultYes ? ' (Y/n)' : ' (y/N)';
|
|
239
|
+
rl.question(`${question}${suffix}: `, (answer) => {
|
|
240
|
+
const lower = answer.toLowerCase().trim();
|
|
241
|
+
if (isExitCommand(lower)) {
|
|
242
|
+
reject(new WizardCancelled());
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (isHelpCommand(lower)) {
|
|
246
|
+
printPromptHelp(help);
|
|
247
|
+
ask();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (lower === '') {
|
|
251
|
+
resolve(defaultYes);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (lower === 'y' || lower === 'yes') {
|
|
255
|
+
resolve(true);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (lower === 'n' || lower === 'no') {
|
|
259
|
+
resolve(false);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
printError('Answer yes or no.');
|
|
263
|
+
ask();
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
ask();
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Internal helper for the clear console operation.
|
|
271
|
+
*/
|
|
272
|
+
function clearConsole() {
|
|
273
|
+
console.clear();
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Internal helper for the print header operation.
|
|
277
|
+
*/
|
|
278
|
+
function printHeader(title, subtitle) {
|
|
279
|
+
const width = WIZARD_WIDTH;
|
|
280
|
+
const line = '═'.repeat(width);
|
|
281
|
+
const space = ' '.repeat(width);
|
|
282
|
+
console.log('');
|
|
283
|
+
console.log(paint('╔' + line + '╗', 'aqua'));
|
|
284
|
+
console.log(paint('║', 'aqua') + space + paint('║', 'aqua'));
|
|
285
|
+
const titlePadding = Math.floor((width - title.length) / 2);
|
|
286
|
+
const titleLine = ' '.repeat(titlePadding) + title + ' '.repeat(width - titlePadding - title.length);
|
|
287
|
+
console.log(paint('║', 'aqua') + paint(titleLine, 'bold') + paint('║', 'aqua'));
|
|
288
|
+
if (subtitle) {
|
|
289
|
+
const subPadding = Math.floor((width - subtitle.length) / 2);
|
|
290
|
+
const subLine = ' '.repeat(subPadding) + subtitle + ' '.repeat(width - subPadding - subtitle.length);
|
|
291
|
+
console.log(paint('║', 'aqua') + paint(subLine, 'gray') + paint('║', 'aqua'));
|
|
292
|
+
}
|
|
293
|
+
console.log(paint('║', 'aqua') + space + paint('║', 'aqua'));
|
|
294
|
+
console.log(paint('╚' + line + '╝', 'aqua'));
|
|
295
|
+
console.log('');
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Print SAP ASCII art logo
|
|
299
|
+
*/
|
|
300
|
+
function printSapLogo() {
|
|
301
|
+
const logo = [
|
|
302
|
+
' ███████╗ █████╗ ██████╗ ███╗ ███╗ ██████╗██████╗ ',
|
|
303
|
+
' ██╔════╝██╔══██╗██╔══██╗════████╗ ████║██╔════╝██╔══██╗',
|
|
304
|
+
' ███████╗███████║██████╔╝════██╔████╔██║██║ ██████╔╝',
|
|
305
|
+
' ╚════██║██╔══██║██╔═══╝ ██║╚██╔╝██║██║ ██╔═══╝ ',
|
|
306
|
+
' ███████║██║ ██║██║ ██║ ╚═╝ ██║╚██████╗██║ ',
|
|
307
|
+
' ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ',
|
|
308
|
+
'',
|
|
309
|
+
' ┌─────────────────────────────────────┐',
|
|
310
|
+
' │ Synapse Agent Protocol │ MCP │',
|
|
311
|
+
' └─────────────────────────────────────┘',
|
|
312
|
+
];
|
|
313
|
+
console.log(logo.map((line) => paint(line, 'aqua')).join('\n'));
|
|
314
|
+
console.log('');
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Internal helper for the print section operation.
|
|
318
|
+
*/
|
|
319
|
+
function printSection(title) {
|
|
320
|
+
console.log(`\n${paint('─'.repeat(WIZARD_WIDTH), 'aqua')}`);
|
|
321
|
+
console.log(` ${paint(title, 'aqua', 'bold')}`);
|
|
322
|
+
console.log(`${paint('─'.repeat(WIZARD_WIDTH), 'aqua')}\n`);
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Internal helper for the print success operation.
|
|
326
|
+
*/
|
|
327
|
+
function printSuccess(message) {
|
|
328
|
+
console.log(paint(`OK: ${message}`, 'green'));
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Internal helper for the print info operation.
|
|
332
|
+
*/
|
|
333
|
+
function printInfo(message) {
|
|
334
|
+
console.log(paint(`Info: ${message}`, 'aqua'));
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Prints a warning message.
|
|
338
|
+
*/
|
|
339
|
+
function printWarning(message) {
|
|
340
|
+
console.log(paint(`Warning: ${message}`, 'yellow'));
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Prints an error message with a text prefix that remains meaningful without color.
|
|
344
|
+
*/
|
|
345
|
+
function printError(message) {
|
|
346
|
+
console.log(paint(`Error: ${message}`, 'red'));
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Prints a descriptive lead paragraph for the current wizard step.
|
|
350
|
+
*/
|
|
351
|
+
function printLead(message) {
|
|
352
|
+
console.log(paint(message, 'aqua'));
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Prints a section label in the wizard's primary color.
|
|
356
|
+
*/
|
|
357
|
+
function printLabel(label) {
|
|
358
|
+
console.log(paint(label, 'aqua', 'bold'));
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Prints one accessible bullet line.
|
|
362
|
+
*/
|
|
363
|
+
function printBullet(message) {
|
|
364
|
+
console.log(` - ${message}`);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Prints a key/value summary row.
|
|
368
|
+
*/
|
|
369
|
+
function printField(label, value) {
|
|
370
|
+
console.log(` ${paint(`${label}:`, 'aqua')} ${value}`);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Expands a shell-style home directory prefix for local file inputs.
|
|
374
|
+
*/
|
|
375
|
+
function expandHomePath(path) {
|
|
376
|
+
if (path === '~') {
|
|
377
|
+
return homedir();
|
|
378
|
+
}
|
|
379
|
+
if (path.startsWith('~/')) {
|
|
380
|
+
return join(homedir(), path.slice(2));
|
|
381
|
+
}
|
|
382
|
+
return path;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Validates profile names used as config and wallet filename components.
|
|
386
|
+
*/
|
|
387
|
+
function validateProfileName(value) {
|
|
388
|
+
if (value === 'default') {
|
|
389
|
+
return 'Use a named profile instead of "default" so wallets and configs stay explicit.';
|
|
390
|
+
}
|
|
391
|
+
if (value.length < 3 || value.length > 48) {
|
|
392
|
+
return 'Profile names must be between 3 and 48 characters.';
|
|
393
|
+
}
|
|
394
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value)) {
|
|
395
|
+
return 'Use lowercase letters, numbers, and single hyphens between words.';
|
|
396
|
+
}
|
|
397
|
+
return undefined;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Validates HTTP(S) URLs.
|
|
401
|
+
*/
|
|
402
|
+
function validateHttpUrl(value) {
|
|
403
|
+
try {
|
|
404
|
+
const url = new URL(value);
|
|
405
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
406
|
+
return 'URL must start with http:// or https://.';
|
|
407
|
+
}
|
|
408
|
+
if (!url.hostname) {
|
|
409
|
+
return 'URL must include a hostname.';
|
|
410
|
+
}
|
|
411
|
+
return undefined;
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
return 'Enter a valid URL, for example https://api.mainnet-beta.solana.com.';
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Validates a Solana keypair JSON file without exposing the secret bytes.
|
|
419
|
+
*/
|
|
420
|
+
function validateWalletFile(value) {
|
|
421
|
+
const walletPath = expandHomePath(value);
|
|
422
|
+
if (!existsSync(walletPath)) {
|
|
423
|
+
return 'Wallet file does not exist.';
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
const stat = statSync(walletPath);
|
|
427
|
+
if (!stat.isFile()) {
|
|
428
|
+
return 'Wallet path must point to a JSON file.';
|
|
429
|
+
}
|
|
430
|
+
const parsed = JSON.parse(readFileSync(walletPath, 'utf-8'));
|
|
431
|
+
if (!Array.isArray(parsed) || parsed.length !== 64) {
|
|
432
|
+
return 'Wallet JSON must be a Solana keypair array with 64 bytes.';
|
|
433
|
+
}
|
|
434
|
+
const bytes = parsed;
|
|
435
|
+
if (!bytes.every((item) => Number.isInteger(item) && Number(item) >= 0 && Number(item) <= 255)) {
|
|
436
|
+
return 'Wallet JSON contains invalid byte values.';
|
|
437
|
+
}
|
|
438
|
+
Keypair.fromSecretKey(Uint8Array.from(bytes));
|
|
439
|
+
return undefined;
|
|
440
|
+
}
|
|
441
|
+
catch {
|
|
442
|
+
return 'Wallet file is not a valid Solana keypair JSON.';
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Creates a validator for positive SOL amount inputs.
|
|
447
|
+
*/
|
|
448
|
+
function validateSolAmount(label, options = {}) {
|
|
449
|
+
return (value) => {
|
|
450
|
+
const amount = Number(value);
|
|
451
|
+
const minimum = options.min ?? 0;
|
|
452
|
+
const maximum = options.max ?? 1_000_000;
|
|
453
|
+
if (!Number.isFinite(amount)) {
|
|
454
|
+
return `${label} must be a number.`;
|
|
455
|
+
}
|
|
456
|
+
if (!options.allowZero && amount <= 0) {
|
|
457
|
+
return `${label} must be greater than 0 SOL.`;
|
|
458
|
+
}
|
|
459
|
+
if (amount < minimum) {
|
|
460
|
+
return `${label} must be at least ${minimum} SOL.`;
|
|
461
|
+
}
|
|
462
|
+
if (amount > maximum) {
|
|
463
|
+
return `${label} is too high; choose a value below ${maximum} SOL.`;
|
|
464
|
+
}
|
|
465
|
+
return undefined;
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Validates that a daily spending limit can contain the per-transaction limit.
|
|
470
|
+
*/
|
|
471
|
+
function validateDailyLimit(maxTxValueSol) {
|
|
472
|
+
return (value) => {
|
|
473
|
+
const amountError = validateSolAmount('Daily spending limit', { allowZero: false })(value);
|
|
474
|
+
if (amountError) {
|
|
475
|
+
return amountError;
|
|
476
|
+
}
|
|
477
|
+
if (Number(value) < maxTxValueSol) {
|
|
478
|
+
return 'Daily spending limit must be greater than or equal to the maximum transaction value.';
|
|
479
|
+
}
|
|
480
|
+
return undefined;
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Validates TCP port numbers.
|
|
485
|
+
*/
|
|
486
|
+
function validatePort(value) {
|
|
487
|
+
const port = Number(value);
|
|
488
|
+
if (!Number.isInteger(port) || port < 1 || port > 65_535) {
|
|
489
|
+
return 'Port must be an integer between 1 and 65535.';
|
|
490
|
+
}
|
|
491
|
+
return undefined;
|
|
492
|
+
}
|
|
493
|
+
// ============================================================================
|
|
494
|
+
// Wizard Steps
|
|
495
|
+
// ============================================================================
|
|
496
|
+
/**
|
|
497
|
+
* Internal helper for the wizard welcome operation.
|
|
498
|
+
*/
|
|
499
|
+
async function wizardWelcome() {
|
|
500
|
+
clearConsole();
|
|
501
|
+
printSapLogo();
|
|
502
|
+
printHeader('SAP MCP Configuration Wizard', 'Secure setup for AI agent access to SAP Protocol');
|
|
503
|
+
printLead('This guided setup creates a named SAP MCP profile, isolates its wallet, and prepares MCP clients to load the active profile safely.');
|
|
504
|
+
printLead('You can review everything before saving. Secret key bytes are never printed or injected into client configs.');
|
|
505
|
+
printControlHints();
|
|
506
|
+
console.log('');
|
|
507
|
+
printLabel('What this wizard configures');
|
|
508
|
+
printBullet('A named profile under ~/.config/mcp-sap/config-<profile>.json.');
|
|
509
|
+
printBullet('A dedicated wallet path under ~/.config/mcp-sap/keypairs/ when signing is enabled.');
|
|
510
|
+
printBullet('Policy limits for transaction value, daily spending, and optional Bento Guard checks.');
|
|
511
|
+
printBullet('Optional MCP client config injection for Claude, Hermes, OpenClaw, and Codex.');
|
|
512
|
+
console.log('');
|
|
513
|
+
printLabel('What this wizard will not do');
|
|
514
|
+
printBullet('It will not modify ~/.config/solana/id.json.');
|
|
515
|
+
printBullet('It will not print, log, or copy keypair bytes.');
|
|
516
|
+
printBullet('It will not write anything until the final confirmation step.');
|
|
517
|
+
console.log('');
|
|
518
|
+
const continueResult = await askConfirm('Continue?', true, [
|
|
519
|
+
'Choose yes to create/update a named SAP MCP profile.',
|
|
520
|
+
'Type /exit at any prompt to leave without saving.',
|
|
521
|
+
]);
|
|
522
|
+
if (!continueResult) {
|
|
523
|
+
throw new WizardCancelled();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Internal helper for the wizard profile operation.
|
|
528
|
+
*/
|
|
529
|
+
async function wizardProfile() {
|
|
530
|
+
while (true) {
|
|
531
|
+
clearConsole();
|
|
532
|
+
printSapLogo();
|
|
533
|
+
printHeader('Step 1: Agent Profile', 'Create or select agent identity');
|
|
534
|
+
printLead('Choose a stable profile name for this agent or operator identity.');
|
|
535
|
+
printControlHints();
|
|
536
|
+
console.log('');
|
|
537
|
+
printLabel('Profile naming convention');
|
|
538
|
+
printBullet('Use a descriptive name such as merchant-lexus-sap.');
|
|
539
|
+
printBullet('Include the agent purpose, environment, or business role.');
|
|
540
|
+
printBullet('Use lowercase letters, numbers, and hyphens only.');
|
|
541
|
+
printBullet('The name controls config and wallet isolation.');
|
|
542
|
+
console.log('');
|
|
543
|
+
printLabel('Examples');
|
|
544
|
+
printBullet('merchant-lexus-sap');
|
|
545
|
+
printBullet('gianni-market-nft-agent');
|
|
546
|
+
printBullet('dev-testing-mainnet');
|
|
547
|
+
printBullet('citizen-support-bot');
|
|
548
|
+
console.log('');
|
|
549
|
+
const profileName = await askQuestion('Profile name', {
|
|
550
|
+
required: true,
|
|
551
|
+
transform: (value) => value.trim().toLowerCase(),
|
|
552
|
+
validate: validateProfileName,
|
|
553
|
+
help: [
|
|
554
|
+
'Use the real agent identity, for example gianni-market-nft-agent.',
|
|
555
|
+
'The wizard reserves "default" to prevent accidental profile ambiguity.',
|
|
556
|
+
'This name becomes config-<profile>.json and <profile>-keypair.json.',
|
|
557
|
+
],
|
|
558
|
+
});
|
|
559
|
+
return profileName;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Internal helper for the wizard mode operation.
|
|
564
|
+
*/
|
|
565
|
+
async function wizardMode() {
|
|
566
|
+
clearConsole();
|
|
567
|
+
printSapLogo();
|
|
568
|
+
printHeader('Step 2: Server Mode', 'How will the MCP server run?');
|
|
569
|
+
printLead('Choose the trust model for this profile. This controls whether SAP MCP can only read data, prepare transactions, or request signatures.');
|
|
570
|
+
console.log('');
|
|
571
|
+
printLabel('Mode guidance');
|
|
572
|
+
printBullet('Choose readonly if the agent only needs discovery, analytics, profile context, or registry reads.');
|
|
573
|
+
printBullet('Choose external-signer for production signing, hardware wallets, custody systems, or the local signing proxy.');
|
|
574
|
+
printBullet('Choose local-dev-keypair only when this machine should hold the dedicated SAP MCP wallet file.');
|
|
575
|
+
printBullet('Choose hosted-api when deploying the MCP server for remote clients behind HTTPS.');
|
|
576
|
+
console.log('');
|
|
577
|
+
printControlHints();
|
|
578
|
+
console.log('');
|
|
579
|
+
const choices = [
|
|
580
|
+
`${paint('readonly', 'aqua', 'bold')} ${paint('[safest]', 'green')} - Read tools only; no transaction signing.`,
|
|
581
|
+
`${paint('local-dev-keypair', 'aqua', 'bold')} ${paint('[local wallet]', 'yellow')} - Signs with this profile's dedicated keypair file.`,
|
|
582
|
+
`${paint('external-signer', 'aqua', 'bold')} ${paint('[production]', 'green')} - Sends signing requests to Ledger, Fireblocks, or signing proxy.`,
|
|
583
|
+
`${paint('delegated-session', 'aqua', 'bold')} ${paint('[limited session]', 'blue')} - Uses session-scoped permissions and spending limits.`,
|
|
584
|
+
`${paint('hosted-api', 'aqua', 'bold')} ${paint('[remote HTTP]', 'magenta')} - Runs Streamable HTTP MCP for VPS/client access.`,
|
|
585
|
+
];
|
|
586
|
+
const index = await askChoice(paint('Select operating mode:', 'aqua', 'bold'), choices, 0, [
|
|
587
|
+
'readonly is recommended when you only need discovery and read tools.',
|
|
588
|
+
'local-dev-keypair signs with the dedicated profile wallet, never Solana CLI id.json.',
|
|
589
|
+
'external-signer is preferred for production signing.',
|
|
590
|
+
'hosted-api enables remote MCP over HTTP and should be deployed behind TLS.',
|
|
591
|
+
]);
|
|
592
|
+
const modes = ['readonly', 'local-dev-keypair', 'external-signer', 'delegated-session', 'hosted-api'];
|
|
593
|
+
return modes[index];
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Internal helper for the wizard rpc url operation.
|
|
597
|
+
*/
|
|
598
|
+
async function wizardRpcUrl(mode) {
|
|
599
|
+
clearConsole();
|
|
600
|
+
printSapLogo();
|
|
601
|
+
printHeader('Step 3: Solana RPC', 'Blockchain connection settings');
|
|
602
|
+
const isDev = mode === 'local-dev-keypair';
|
|
603
|
+
const defaultRpc = isDev
|
|
604
|
+
? 'https://api.devnet.solana.com'
|
|
605
|
+
: 'https://api.mainnet-beta.solana.com';
|
|
606
|
+
printLead('Select the Solana network and RPC endpoint this profile will use. Tools will report and execute against this configured network.');
|
|
607
|
+
printControlHints();
|
|
608
|
+
console.log('');
|
|
609
|
+
printLabel('Common endpoints');
|
|
610
|
+
printField('Mainnet', paint('https://api.mainnet-beta.solana.com', 'green'));
|
|
611
|
+
printField('Devnet', paint('https://api.devnet.solana.com', 'yellow'));
|
|
612
|
+
printField('Testnet', paint('https://api.testnet.solana.com', 'blue'));
|
|
613
|
+
printField('Custom', 'Your own RPC endpoint');
|
|
614
|
+
console.log('');
|
|
615
|
+
const rpcUrl = await askQuestion('RPC URL', {
|
|
616
|
+
defaultValue: defaultRpc,
|
|
617
|
+
required: true,
|
|
618
|
+
validate: validateHttpUrl,
|
|
619
|
+
help: [
|
|
620
|
+
'Use devnet for disposable test wallets and faucet workflows.',
|
|
621
|
+
'Use mainnet-beta only when the profile wallet is intended for production assets.',
|
|
622
|
+
'Custom RPC endpoints are allowed if they use http:// or https://.',
|
|
623
|
+
],
|
|
624
|
+
});
|
|
625
|
+
return rpcUrl;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Internal helper for the wizard signer config operation.
|
|
629
|
+
*/
|
|
630
|
+
async function wizardSignerConfig(mode, profileName) {
|
|
631
|
+
if (mode === 'readonly') {
|
|
632
|
+
return {};
|
|
633
|
+
}
|
|
634
|
+
if (mode === 'local-dev-keypair') {
|
|
635
|
+
clearConsole();
|
|
636
|
+
printSapLogo();
|
|
637
|
+
printHeader('Step 4: Wallet Configuration', 'Local keypair setup');
|
|
638
|
+
printLead('Choose the wallet that will sign transactions for this profile. A new dedicated wallet is safest for first-time setup.');
|
|
639
|
+
printControlHints();
|
|
640
|
+
console.log('');
|
|
641
|
+
printField('Profile', profileName);
|
|
642
|
+
printField('Default wallet', `~/.config/mcp-sap/keypairs/${profileName}-keypair.json`);
|
|
643
|
+
printWarning('The wizard never modifies ~/.config/solana/id.json and never asks you to paste secret key bytes.');
|
|
644
|
+
console.log('');
|
|
645
|
+
const useExisting = await askChoice('Choose option:', [
|
|
646
|
+
'Use existing wallet file',
|
|
647
|
+
`Create new wallet for "${profileName}"`,
|
|
648
|
+
], 1, [
|
|
649
|
+
'Creating a wallet is safest for new agents because it isolates funds and permissions.',
|
|
650
|
+
'Using an existing wallet validates the JSON keypair file and stores only its path.',
|
|
651
|
+
'Do not paste keypair bytes into the terminal.',
|
|
652
|
+
]);
|
|
653
|
+
if (useExisting === 0) {
|
|
654
|
+
// Use existing wallet
|
|
655
|
+
console.log('');
|
|
656
|
+
printLead('Enter the path to a Solana keypair JSON file. The wizard validates the file and stores only the path.');
|
|
657
|
+
printLabel('Examples');
|
|
658
|
+
printBullet(`~/.config/mcp-sap/keypairs/${profileName}-keypair.json`);
|
|
659
|
+
printBullet('/path/to/wallet.json');
|
|
660
|
+
console.log('');
|
|
661
|
+
const defaultPath = defaultGeneratedWalletPath(profileName);
|
|
662
|
+
const walletPath = await askQuestion('Wallet path', {
|
|
663
|
+
defaultValue: defaultPath,
|
|
664
|
+
required: true,
|
|
665
|
+
transform: expandHomePath,
|
|
666
|
+
validate: validateWalletFile,
|
|
667
|
+
help: [
|
|
668
|
+
'Enter the path to a Solana keypair JSON file.',
|
|
669
|
+
'The wizard validates the file and stores the path, not the secret bytes.',
|
|
670
|
+
'Use a dedicated SAP MCP wallet, not your Solana CLI id.json.',
|
|
671
|
+
],
|
|
672
|
+
});
|
|
673
|
+
return { walletPath, createNewWallet: false };
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
// Create new wallet
|
|
677
|
+
const walletFileName = `${profileName}-keypair.json`;
|
|
678
|
+
console.log('');
|
|
679
|
+
printSuccess(`Will create a new dedicated wallet for profile "${profileName}".`);
|
|
680
|
+
printField('Wallet path', `~/.config/mcp-sap/keypairs/${walletFileName}`);
|
|
681
|
+
printInfo('This wallet is isolated from the Solana CLI keypair.');
|
|
682
|
+
printWarning('Back up this keypair after creation; it controls funds for this SAP MCP profile.');
|
|
683
|
+
console.log('');
|
|
684
|
+
return { createNewWallet: true };
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
if (mode === 'external-signer') {
|
|
688
|
+
clearConsole();
|
|
689
|
+
printSapLogo();
|
|
690
|
+
printHeader('Step 4: External Signer', 'Signing service configuration');
|
|
691
|
+
printLead('Enter the URL of the service that will sign transactions without exposing key material to the MCP server.');
|
|
692
|
+
printControlHints();
|
|
693
|
+
console.log('');
|
|
694
|
+
printLabel('Examples');
|
|
695
|
+
printBullet('http://localhost:8080/sign');
|
|
696
|
+
printBullet('https://fireblocks.example.com/api/v1/sign');
|
|
697
|
+
console.log('');
|
|
698
|
+
const externalSignerUrl = await askQuestion('External signer URL', {
|
|
699
|
+
defaultValue: 'http://localhost:8080/sign',
|
|
700
|
+
required: true,
|
|
701
|
+
validate: validateHttpUrl,
|
|
702
|
+
help: [
|
|
703
|
+
'The signer service must expose the SAP MCP signing protocol.',
|
|
704
|
+
'Use HTTPS for remote signer services.',
|
|
705
|
+
'Localhost HTTP is acceptable for local development only.',
|
|
706
|
+
],
|
|
707
|
+
});
|
|
708
|
+
return { externalSignerUrl };
|
|
709
|
+
}
|
|
710
|
+
return {};
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Internal helper for the wizard security limits operation.
|
|
714
|
+
*/
|
|
715
|
+
async function wizardSecurityLimits(mode) {
|
|
716
|
+
if (mode === 'readonly') {
|
|
717
|
+
return { maxTxValueSol: 0, dailyLimitSol: 0 };
|
|
718
|
+
}
|
|
719
|
+
clearConsole();
|
|
720
|
+
printSapLogo();
|
|
721
|
+
printHeader('Step 5: Security Limits', 'Transaction spending controls');
|
|
722
|
+
printLead('Set guardrails before this profile can sign or submit transactions. These limits are enforced before signing.');
|
|
723
|
+
printControlHints();
|
|
724
|
+
console.log('');
|
|
725
|
+
const maxTxValueSol = await askQuestion(paint('Maximum transaction value (SOL)', 'aqua'), {
|
|
726
|
+
defaultValue: defaults.maxTxValueSol.toString(),
|
|
727
|
+
required: true,
|
|
728
|
+
validate: validateSolAmount('Maximum transaction value', { allowZero: false }),
|
|
729
|
+
help: [
|
|
730
|
+
'This is a hard per-transaction ceiling enforced before signing.',
|
|
731
|
+
'For test/dev profiles, 1 SOL or less is usually enough.',
|
|
732
|
+
],
|
|
733
|
+
});
|
|
734
|
+
const dailyLimitSol = await askQuestion(paint('Daily spending limit (SOL)', 'aqua'), {
|
|
735
|
+
defaultValue: defaults.dailyLimitSol.toString(),
|
|
736
|
+
required: true,
|
|
737
|
+
validate: validateDailyLimit(Number(maxTxValueSol)),
|
|
738
|
+
help: [
|
|
739
|
+
'This is the total native SOL value allowed per day.',
|
|
740
|
+
'It must be greater than or equal to the per-transaction maximum.',
|
|
741
|
+
],
|
|
742
|
+
});
|
|
743
|
+
return {
|
|
744
|
+
maxTxValueSol: parseFloat(maxTxValueSol) || defaults.maxTxValueSol,
|
|
745
|
+
dailyLimitSol: parseFloat(dailyLimitSol) || defaults.dailyLimitSol,
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Internal helper for the wizard bento integration operation.
|
|
750
|
+
*/
|
|
751
|
+
async function wizardBentoIntegration() {
|
|
752
|
+
clearConsole();
|
|
753
|
+
printSapLogo();
|
|
754
|
+
printHeader('Step 6: Bento Guard Integration', 'Optional AI-powered security layer');
|
|
755
|
+
printLead('Bento Guard is optional. When enabled, local deterministic policy still runs and Bento adds AI-assisted intent scoring.');
|
|
756
|
+
printControlHints();
|
|
757
|
+
console.log('');
|
|
758
|
+
printWarning('This step is optional. Choose no to use local policy enforcement only.');
|
|
759
|
+
console.log('');
|
|
760
|
+
printLabel('If enabled');
|
|
761
|
+
printBullet('Tool calls are scored for intent and policy risk.');
|
|
762
|
+
printBullet('Suspicious actions can be escalated or blocked.');
|
|
763
|
+
printBullet('Bento outages follow your configured fail-open/fail-closed policy.');
|
|
764
|
+
printBullet('API keys are redacted in summaries.');
|
|
765
|
+
console.log('');
|
|
766
|
+
const enableBento = await askConfirm('Enable Bento Guard integration?', false, [
|
|
767
|
+
'Choose no for local-only policy enforcement.',
|
|
768
|
+
'Choose yes when you have Bento credentials and want hybrid policy checks.',
|
|
769
|
+
]);
|
|
770
|
+
if (!enableBento) {
|
|
771
|
+
console.log('');
|
|
772
|
+
printInfo('Skipping Bento. This profile will use local policy enforcement only.');
|
|
773
|
+
printLabel('Enable later with');
|
|
774
|
+
printBullet('SAP_MCP_BENTO_API_KEY');
|
|
775
|
+
printBullet('SAP_MCP_BENTO_AGENT_ID');
|
|
776
|
+
console.log('');
|
|
777
|
+
return { enableBento: false };
|
|
778
|
+
}
|
|
779
|
+
console.log('');
|
|
780
|
+
printLead('Enter your Bento Guard credentials.');
|
|
781
|
+
printField('Dashboard', 'https://app.bentoguard.xyz');
|
|
782
|
+
console.log('');
|
|
783
|
+
const bentoApiKey = await askQuestion(paint('Bento API Key', 'aqua'), {
|
|
784
|
+
required: true,
|
|
785
|
+
help: [
|
|
786
|
+
'Paste only the Bento API key here.',
|
|
787
|
+
'It is redacted in the summary and can be rotated later.',
|
|
788
|
+
],
|
|
789
|
+
});
|
|
790
|
+
const bentoAgentId = await askQuestion(paint('Bento Agent ID', 'aqua'), {
|
|
791
|
+
defaultValue: 'sap-mcp-server-' + Math.random().toString(36).substring(2, 8),
|
|
792
|
+
required: true,
|
|
793
|
+
validate: (value) => /^[a-zA-Z0-9_.:-]+$/.test(value)
|
|
794
|
+
? undefined
|
|
795
|
+
: 'Bento Agent ID may contain letters, numbers, dot, underscore, colon, or hyphen.',
|
|
796
|
+
help: [
|
|
797
|
+
'This identifies this SAP MCP server inside Bento policy logs.',
|
|
798
|
+
],
|
|
799
|
+
});
|
|
800
|
+
console.log('');
|
|
801
|
+
printSuccess('Bento Guard will be used for policy enforcement.');
|
|
802
|
+
printInfo('Local policies still run as deterministic guardrails.');
|
|
803
|
+
console.log('');
|
|
804
|
+
return {
|
|
805
|
+
enableBento: true,
|
|
806
|
+
bentoApiKey,
|
|
807
|
+
bentoAgentId,
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Internal helper for the wizard http transport operation.
|
|
812
|
+
*/
|
|
813
|
+
async function wizardHttpTransport(mode) {
|
|
814
|
+
if (mode !== 'hosted-api') {
|
|
815
|
+
return { enableHttp: false, httpPort: defaults.httpPort };
|
|
816
|
+
}
|
|
817
|
+
clearConsole();
|
|
818
|
+
printSapLogo();
|
|
819
|
+
printHeader('Step 7: HTTP Transport', 'API server configuration');
|
|
820
|
+
printLead('HTTP mode exposes MCP over Streamable HTTP for remote clients. Use this for VPS deployments and hosted agent workflows.');
|
|
821
|
+
printControlHints();
|
|
822
|
+
console.log('');
|
|
823
|
+
printWarning('Production HTTP deployments must sit behind HTTPS/TLS and operational monitoring.');
|
|
824
|
+
console.log('');
|
|
825
|
+
const enableHttp = await askConfirm('Enable HTTP API server?', true, [
|
|
826
|
+
'HTTP mode is for remote MCP clients and VPS deployment.',
|
|
827
|
+
'Use a reverse proxy such as Caddy or nginx for HTTPS/TLS.',
|
|
828
|
+
]);
|
|
829
|
+
if (!enableHttp) {
|
|
830
|
+
return { enableHttp: false, httpPort: defaults.httpPort };
|
|
831
|
+
}
|
|
832
|
+
const httpPort = await askQuestion(paint('HTTP port', 'aqua'), {
|
|
833
|
+
defaultValue: defaults.httpPort.toString(),
|
|
834
|
+
required: true,
|
|
835
|
+
validate: validatePort,
|
|
836
|
+
help: [
|
|
837
|
+
'Use 8787 locally unless another service already uses it.',
|
|
838
|
+
'In production, expose HTTPS via a reverse proxy and forward to this port.',
|
|
839
|
+
],
|
|
840
|
+
});
|
|
841
|
+
return {
|
|
842
|
+
enableHttp: true,
|
|
843
|
+
httpPort: parseInt(httpPort, 10) || defaults.httpPort,
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Internal helper for the wizard logging operation.
|
|
848
|
+
*/
|
|
849
|
+
async function wizardLogging() {
|
|
850
|
+
clearConsole();
|
|
851
|
+
printSapLogo();
|
|
852
|
+
printHeader('Step 8: Logging & Observability', 'Debugging and monitoring');
|
|
853
|
+
printLead('Choose how much operational detail SAP MCP should write to logs.');
|
|
854
|
+
printControlHints();
|
|
855
|
+
console.log('');
|
|
856
|
+
const logChoices = ['debug', 'info', 'warn', 'error'];
|
|
857
|
+
const logIndex = await askChoice('Log level:', logChoices.map((level, i) => {
|
|
858
|
+
const colors = ['blue', 'aqua', 'yellow', 'red'];
|
|
859
|
+
return paint(level, colors[i]);
|
|
860
|
+
}), 1, [
|
|
861
|
+
'info is recommended for normal use.',
|
|
862
|
+
'debug is useful while integrating Hermes, Claude, Codex, or OpenClaw.',
|
|
863
|
+
'error is quietest and best for stable production logs.',
|
|
864
|
+
]);
|
|
865
|
+
const enableMetrics = await askConfirm('Enable Prometheus metrics?', false, [
|
|
866
|
+
'Metrics expose operational counters for monitoring.',
|
|
867
|
+
'Enable when deploying behind a trusted network or protected reverse proxy.',
|
|
868
|
+
]);
|
|
869
|
+
return {
|
|
870
|
+
logLevel: logChoices[logIndex],
|
|
871
|
+
enableMetrics,
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Formats a discovered MCP client target for selector output.
|
|
876
|
+
*/
|
|
877
|
+
function formatMcpClientTarget(target) {
|
|
878
|
+
const state = target.exists ? 'found' : 'will create';
|
|
879
|
+
const profile = target.profileName ? ` (${target.profileName})` : '';
|
|
880
|
+
return `${target.label}${profile} - ${state} - ${target.path}`;
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Prints copy/paste JSON snippets for manual MCP client setup.
|
|
884
|
+
*/
|
|
885
|
+
function printManualMcpJsonSnippets(canonical = createCanonicalServerConfig(process.cwd())) {
|
|
886
|
+
const snippets = createManualMcpJsonSnippets(canonical);
|
|
887
|
+
console.log('');
|
|
888
|
+
printSection('Manual MCP Client Configuration');
|
|
889
|
+
printLead('Paste one of these JSON snippets into the MCP config for Claude, Hermes, OpenClaw, Codex, or another MCP-capable agent.');
|
|
890
|
+
printWarning('Do not add wallet paths, RPC overrides, profile names, or keypair bytes to client config.');
|
|
891
|
+
console.log('');
|
|
892
|
+
for (const snippet of snippets) {
|
|
893
|
+
printLabel(snippet.title);
|
|
894
|
+
printBullet(snippet.description);
|
|
895
|
+
console.log('');
|
|
896
|
+
console.log(snippet.content.trimEnd());
|
|
897
|
+
console.log('');
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Prints the recommended hosted MCP client configuration.
|
|
902
|
+
*/
|
|
903
|
+
function printHostedMcpJsonSnippet(canonical = createCanonicalServerConfig(process.cwd())) {
|
|
904
|
+
const hostedSnippet = createManualMcpJsonSnippets(canonical)
|
|
905
|
+
.find((snippet) => snippet.title === 'Hosted SAP MCP JSON');
|
|
906
|
+
if (!hostedSnippet) {
|
|
907
|
+
printError('Hosted SAP MCP snippet is not available.');
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
console.log('');
|
|
911
|
+
printSection('Hosted SAP MCP Configuration');
|
|
912
|
+
printLead('Use this for agents that should connect to the OOBE hosted MCP server.');
|
|
913
|
+
printInfo('Hosted mode uses the remote MCP transport, but the user SAP profile and signer are still created locally by this wizard.');
|
|
914
|
+
printInfo('The local wallet or external signer is what authorizes x402, pay.sh, and any value-moving tool transaction.');
|
|
915
|
+
console.log('');
|
|
916
|
+
printField('Hosted MCP URL', 'https://mcp.sap.oobeprotocol.ai/mcp');
|
|
917
|
+
printWarning('Do not paste keypair bytes into hosted client config. Keep wallet material in ~/.config/mcp-sap or an external signer.');
|
|
918
|
+
printWarning('Do not add stale SAP_MCP_RPC_URL or SAP_WALLET_PATH overrides to the hosted MCP block.');
|
|
919
|
+
console.log('');
|
|
920
|
+
printLabel(`${hostedSnippet.title} ${paint('[RECOMMENDED]', 'green', 'bold')}`);
|
|
921
|
+
printBullet(hostedSnippet.description);
|
|
922
|
+
printBullet('Run the wizard first to create the user SAP profile, wallet path, policy limits, and signing preferences.');
|
|
923
|
+
printBullet('For signing flows, the agent must use the configured local wallet/external signer rather than expecting the hosted server to hold private keys.');
|
|
924
|
+
console.log('');
|
|
925
|
+
console.log(hostedSnippet.content.trimEnd());
|
|
926
|
+
console.log('');
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Runs the optional MCP client injection step after profile config has been saved.
|
|
930
|
+
*/
|
|
931
|
+
async function wizardMcpClientInjection(result) {
|
|
932
|
+
clearConsole();
|
|
933
|
+
printSapLogo();
|
|
934
|
+
printHeader('Optional MCP Client Setup', 'Connect agents to hosted or local SAP MCP');
|
|
935
|
+
printLead('Choose how Claude, Hermes, OpenClaw, Codex, or another MCP client should reach SAP MCP.');
|
|
936
|
+
printInfo('For most users, run this wizard to create the SAP profile/signer, then connect the agent to https://mcp.sap.oobeprotocol.ai/mcp.');
|
|
937
|
+
printInfo('Injected client config does not pin wallet paths, RPC overrides, profile names, or keypair bytes.');
|
|
938
|
+
console.log('');
|
|
939
|
+
printField('Agent public key', result.config.agentPubkey ?? 'not configured');
|
|
940
|
+
printField('Config path', result.configPath);
|
|
941
|
+
printField('Hosted MCP URL', 'https://mcp.sap.oobeprotocol.ai/mcp');
|
|
942
|
+
printControlHints();
|
|
943
|
+
console.log('');
|
|
944
|
+
const setupMode = await askChoice('How do you want to configure MCP clients?', [
|
|
945
|
+
`${paint('Connect to hosted SAP MCP at https://mcp.sap.oobeprotocol.ai/mcp', 'aqua', 'bold')} ${paint('[RECOMMENDED]', 'green', 'bold')}`,
|
|
946
|
+
'Print manual JSON snippets for hosted and local setup',
|
|
947
|
+
'Automatically inject local active-profile config into detected client files',
|
|
948
|
+
'Skip MCP client configuration',
|
|
949
|
+
], 0, [
|
|
950
|
+
'Hosted agents should use https://mcp.sap.oobeprotocol.ai/mcp, but signing still requires the wizard-created user SAP profile.',
|
|
951
|
+
'Manual snippets are useful when configuring an unknown client or comparing hosted and local setup.',
|
|
952
|
+
'Automatic injection updates known local config files after preview and confirmation.',
|
|
953
|
+
]);
|
|
954
|
+
const canonical = createCanonicalServerConfig(process.cwd());
|
|
955
|
+
if (setupMode === 0) {
|
|
956
|
+
printHostedMcpJsonSnippet(canonical);
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
if (setupMode === 1) {
|
|
960
|
+
printManualMcpJsonSnippets(canonical);
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
if (setupMode === 3) {
|
|
964
|
+
printInfo('Skipped MCP client injection.');
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
const targets = discoverMcpClientTargets();
|
|
968
|
+
if (targets.length === 0) {
|
|
969
|
+
printWarning('No known MCP client config paths were found.');
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
const selectedIndexes = await askMultiChoice('Select client configs to update:', targets.map(formatMcpClientTarget), [], [
|
|
973
|
+
'Use "all" to select every discovered config.',
|
|
974
|
+
'The wizard previews every change and asks again before writing.',
|
|
975
|
+
'Existing SAP MCP entries trigger merge/override/skip choices.',
|
|
976
|
+
]);
|
|
977
|
+
if (selectedIndexes.length === 0) {
|
|
978
|
+
printInfo('No MCP client configs selected.');
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
const applied = [];
|
|
982
|
+
for (const index of selectedIndexes) {
|
|
983
|
+
const target = targets[index];
|
|
984
|
+
const previewPlan = planMcpClientInjection(target, canonical, 'merge');
|
|
985
|
+
console.log('');
|
|
986
|
+
printSection(target.label);
|
|
987
|
+
printField('Path', target.path);
|
|
988
|
+
printField('Current', previewPlan.beforeSummary);
|
|
989
|
+
printField('Result', previewPlan.afterSummary);
|
|
990
|
+
if (previewPlan.legacyFindings.length > 0) {
|
|
991
|
+
printWarning('Existing config contains SAP MCP related entries:');
|
|
992
|
+
for (const finding of previewPlan.legacyFindings) {
|
|
993
|
+
printBullet(finding);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
let mode = 'merge';
|
|
997
|
+
if (previewPlan.hadSapConfig || previewPlan.legacyFindings.length > 0) {
|
|
998
|
+
const choice = await askChoice('How should this SAP MCP config be updated?', [
|
|
999
|
+
'Merge and clean stale SAP env overrides',
|
|
1000
|
+
'Override the SAP MCP block completely',
|
|
1001
|
+
'Skip this client config',
|
|
1002
|
+
], 0, [
|
|
1003
|
+
'Merge preserves unrelated environment values and removes wallet/RPC/profile overrides.',
|
|
1004
|
+
'Override replaces only the SAP MCP server entry/block.',
|
|
1005
|
+
'Skip leaves this file unchanged.',
|
|
1006
|
+
]);
|
|
1007
|
+
if (choice === 2) {
|
|
1008
|
+
printInfo(`Skipped ${target.label}.`);
|
|
1009
|
+
continue;
|
|
1010
|
+
}
|
|
1011
|
+
mode = choice === 1 ? 'override' : 'merge';
|
|
1012
|
+
}
|
|
1013
|
+
const plan = planMcpClientInjection(target, canonical, mode);
|
|
1014
|
+
const shouldApply = await askConfirm(`Apply ${mode} to ${target.label}?`, true, [
|
|
1015
|
+
`Backup will be created when the file already exists: ${plan.backupPath ?? 'not needed for new file'}`,
|
|
1016
|
+
'The injected SAP MCP entry follows the active profile manager and does not include wallet paths or keypair bytes.',
|
|
1017
|
+
]);
|
|
1018
|
+
if (!shouldApply) {
|
|
1019
|
+
printInfo(`Skipped ${target.label}.`);
|
|
1020
|
+
continue;
|
|
1021
|
+
}
|
|
1022
|
+
const writeResult = applyMcpClientInjection(plan);
|
|
1023
|
+
applied.push(`${writeResult.message}${writeResult.backupPath ? ` (backup: ${writeResult.backupPath})` : ''}`);
|
|
1024
|
+
printSuccess(writeResult.message);
|
|
1025
|
+
}
|
|
1026
|
+
console.log('');
|
|
1027
|
+
if (applied.length === 0) {
|
|
1028
|
+
printInfo('No MCP client config files were changed.');
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
printSuccess('MCP client injection complete.');
|
|
1032
|
+
for (const item of applied) {
|
|
1033
|
+
console.log(` - ${item}`);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Internal helper for the wizard summary operation.
|
|
1038
|
+
*/
|
|
1039
|
+
async function wizardSummary(config) {
|
|
1040
|
+
clearConsole();
|
|
1041
|
+
printSapLogo();
|
|
1042
|
+
printHeader('Configuration Summary', 'Review before saving');
|
|
1043
|
+
printLead('Review the profile before it becomes active for MCP clients. Values marked redacted are intentionally not displayed.');
|
|
1044
|
+
console.log('');
|
|
1045
|
+
// Pretty print with colors
|
|
1046
|
+
const summary = {};
|
|
1047
|
+
for (const [key, value] of Object.entries(config)) {
|
|
1048
|
+
if (key.includes('Key') || key.includes('Secret')) {
|
|
1049
|
+
summary[key] = '[REDACTED]';
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
summary[key] = value;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
1056
|
+
console.log('');
|
|
1057
|
+
printLabel('Operational impact');
|
|
1058
|
+
printBullet(`Active profile will be set to: ${config.profileName}`);
|
|
1059
|
+
printBullet('MCP clients should omit SAP_MCP_PROFILE to follow the active profile manager.');
|
|
1060
|
+
printBullet('Wallet secret bytes are never printed in this wizard output.');
|
|
1061
|
+
if (config.mode === 'local-dev-keypair') {
|
|
1062
|
+
printBullet('This profile can sign transactions; preview and policy checks still apply.');
|
|
1063
|
+
}
|
|
1064
|
+
if (config.mode === 'hosted-api') {
|
|
1065
|
+
printBullet('Remote deployments require TLS termination, rate limits, and deliberate auth/payment settings.');
|
|
1066
|
+
}
|
|
1067
|
+
console.log('');
|
|
1068
|
+
const confirmed = await askConfirm('Save this configuration?', true, [
|
|
1069
|
+
'Choose yes to write the profile config and update .active-profile.',
|
|
1070
|
+
'Choose no or type /exit to leave without saving.',
|
|
1071
|
+
]);
|
|
1072
|
+
if (!confirmed) {
|
|
1073
|
+
console.log('');
|
|
1074
|
+
printError('Configuration cancelled. Run wizard again to retry.');
|
|
1075
|
+
return false;
|
|
1076
|
+
}
|
|
1077
|
+
return true;
|
|
1078
|
+
}
|
|
1079
|
+
// ============================================================================
|
|
1080
|
+
// Main Wizard Function
|
|
1081
|
+
// ============================================================================
|
|
1082
|
+
/**
|
|
1083
|
+
* Executes the run wizard operation.
|
|
1084
|
+
*/
|
|
1085
|
+
export async function runWizard() {
|
|
1086
|
+
try {
|
|
1087
|
+
// Welcome
|
|
1088
|
+
await wizardWelcome();
|
|
1089
|
+
// Step 1: Profile
|
|
1090
|
+
const profileName = await wizardProfile();
|
|
1091
|
+
// Step 2: Mode
|
|
1092
|
+
const mode = await wizardMode();
|
|
1093
|
+
// Step 3: RPC
|
|
1094
|
+
const rpcUrl = await wizardRpcUrl(mode);
|
|
1095
|
+
// Step 4: Signer (pass profileName for wallet path)
|
|
1096
|
+
const signerConfig = await wizardSignerConfig(mode, profileName);
|
|
1097
|
+
// Step 5: Security
|
|
1098
|
+
const securityLimits = await wizardSecurityLimits(mode);
|
|
1099
|
+
// Step 6: Bento Integration (optional)
|
|
1100
|
+
const bentoConfig = await wizardBentoIntegration();
|
|
1101
|
+
// Step 7: HTTP (if hosted-api)
|
|
1102
|
+
const httpConfig = await wizardHttpTransport(mode);
|
|
1103
|
+
// Step 8: Logging
|
|
1104
|
+
const loggingConfig = await wizardLogging();
|
|
1105
|
+
// Build final config
|
|
1106
|
+
const config = {
|
|
1107
|
+
mode,
|
|
1108
|
+
rpcUrl,
|
|
1109
|
+
profileName, // Include profile name for wallet path generation
|
|
1110
|
+
...signerConfig,
|
|
1111
|
+
...securityLimits,
|
|
1112
|
+
...httpConfig,
|
|
1113
|
+
...loggingConfig,
|
|
1114
|
+
enableBento: bentoConfig.enableBento,
|
|
1115
|
+
bentoApiKey: bentoConfig.bentoApiKey,
|
|
1116
|
+
bentoAgentId: bentoConfig.bentoAgentId,
|
|
1117
|
+
};
|
|
1118
|
+
// Summary and confirmation
|
|
1119
|
+
const confirmed = await wizardSummary(config);
|
|
1120
|
+
if (!confirmed) {
|
|
1121
|
+
rl.close();
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
// Save configuration
|
|
1125
|
+
clearConsole();
|
|
1126
|
+
printSapLogo();
|
|
1127
|
+
printHeader('Saving Configuration', 'Please wait...');
|
|
1128
|
+
const result = await saveWizardSetup(config);
|
|
1129
|
+
printSuccess(`Configuration saved to ${result.configPath}`);
|
|
1130
|
+
if (result.walletPath) {
|
|
1131
|
+
printSuccess(`${result.walletCreated ? 'Wallet created' : 'Wallet configured'} at ${result.walletPath}`);
|
|
1132
|
+
if (result.config.agentPubkey) {
|
|
1133
|
+
console.log('');
|
|
1134
|
+
printField('Agent public key', result.config.agentPubkey);
|
|
1135
|
+
printInfo('Use this public key for SAP agent registration, SNS linking, and operator identity.');
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
await wizardMcpClientInjection(result);
|
|
1139
|
+
console.log('\n');
|
|
1140
|
+
printSuccess('Configuration complete!');
|
|
1141
|
+
console.log('');
|
|
1142
|
+
printLabel('Start local stdio MCP');
|
|
1143
|
+
printBullet(paint('npx sap-mcp-server', 'aqua'));
|
|
1144
|
+
console.log('');
|
|
1145
|
+
printLabel('Recommended MCP client environment');
|
|
1146
|
+
printBullet(`${paint('SAP_MCP_ALLOW_ENV_CONFIG_OVERRIDE=false', 'aqua')} keeps clients pointed at the active profile manager.`);
|
|
1147
|
+
printBullet(`${paint('SAP_LOG_LEVEL=info', 'aqua')} keeps logs useful without debug noise.`);
|
|
1148
|
+
console.log('');
|
|
1149
|
+
printLabel('Manage this setup later');
|
|
1150
|
+
printBullet(paint('npx sap-mcp-config show', 'aqua'));
|
|
1151
|
+
printBullet(paint('npx sap-mcp-config profiles', 'aqua'));
|
|
1152
|
+
printBullet(paint('npx sap-mcp-config profile <name>', 'aqua'));
|
|
1153
|
+
printBullet(paint('npx sap-mcp-config set <field> <value>', 'aqua'));
|
|
1154
|
+
console.log('');
|
|
1155
|
+
rl.close();
|
|
1156
|
+
}
|
|
1157
|
+
catch (error) {
|
|
1158
|
+
if (error instanceof WizardCancelled) {
|
|
1159
|
+
console.log('');
|
|
1160
|
+
printWarning('Wizard cancelled. No configuration was saved.');
|
|
1161
|
+
rl.close();
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
console.error('');
|
|
1165
|
+
printError(`Error during wizard: ${error instanceof Error ? error.message : String(error)}`);
|
|
1166
|
+
rl.close();
|
|
1167
|
+
process.exit(1);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
// ============================================================================
|
|
1171
|
+
// CLI Entry Point
|
|
1172
|
+
// ============================================================================
|
|
1173
|
+
if (process.argv[1]?.endsWith('wizard.ts') || process.argv[1]?.endsWith('wizard.js')) {
|
|
1174
|
+
runWizard();
|
|
1175
|
+
}
|
|
1176
|
+
//# sourceMappingURL=wizard.js.map
|