@stkxp/cli 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +273 -0
- package/bin/stkxp.mjs +198 -0
- package/package.json +97 -0
- package/src/bootstrap.mjs +37 -0
- package/src/bootstrap.test.mjs +73 -0
- package/src/deploy.mjs +145 -0
- package/src/deploy.test.mjs +131 -0
- package/src/export.mjs +30 -0
- package/src/export.test.mjs +56 -0
- package/src/secret-input.mjs +64 -0
- package/src/secret-input.test.mjs +58 -0
- package/src/serve.mjs +83 -0
- package/src/serve.test.mjs +93 -0
- package/vendor/dist-server/asyncapi/generator.js +1 -0
- package/vendor/dist-server/asyncapi/messages.js +1 -0
- package/vendor/dist-server/asyncapi/viewer.html +43 -0
- package/vendor/dist-server/core/app-config/branding.js +1 -0
- package/vendor/dist-server/core/app-config/mantine-theme.js +1 -0
- package/vendor/dist-server/core/app-config/mermaid-theme.js +2 -0
- package/vendor/dist-server/core/app-config/prompt-optimization.js +1 -0
- package/vendor/dist-server/core/app-config/settings.js +1 -0
- package/vendor/dist-server/core/config.js +1 -0
- package/vendor/dist-server/core/graph/a2a-agent-executor.js +2 -0
- package/vendor/dist-server/core/graph/app.js +120 -0
- package/vendor/dist-server/core/graph/delegated-agent-adapter.js +1 -0
- package/vendor/dist-server/core/graph/graph-builder.js +3 -0
- package/vendor/dist-server/core/graph/kibana-agent-executor.js +1 -0
- package/vendor/dist-server/core/graph/nodes/context/assistants-context.js +5 -0
- package/vendor/dist-server/core/graph/nodes/context/compare-context.js +10 -0
- package/vendor/dist-server/core/graph/nodes/context/enrich-context.js +8 -0
- package/vendor/dist-server/core/graph/nodes/context/inventory-context.js +4 -0
- package/vendor/dist-server/core/graph/nodes/context/namespace-context.js +2 -0
- package/vendor/dist-server/core/graph/nodes/context/node-types-context.js +4 -0
- package/vendor/dist-server/core/graph/nodes/context/relevant-assistants-context.js +5 -0
- package/vendor/dist-server/core/graph/nodes/context/relevant-skills-context.js +5 -0
- package/vendor/dist-server/core/graph/nodes/context/skills-context.js +8 -0
- package/vendor/dist-server/core/graph/nodes/context/state-setter.js +1 -0
- package/vendor/dist-server/core/graph/nodes/control/check-reset.js +1 -0
- package/vendor/dist-server/core/graph/nodes/control/topic-detection.js +1 -0
- package/vendor/dist-server/core/graph/nodes/governance/human-approval.js +16 -0
- package/vendor/dist-server/core/graph/nodes/index.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/suggestion-generator.js +17 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-decider.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/decider-error.js +4 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/decider-standalone-runner.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/decider-synthesis.js +29 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/pipeline-memory.js +2 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/pipeline-runner.js +7 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/team-assistant-utils.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-finder.js +13 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-invoker.js +3 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-parallel.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-pipeline.js +6 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-router.js +26 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/index.js +6 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/resource-bridge.js +2 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/sandbox.js +6 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/tool-bridge.js +1 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/local-extractor.js +5 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/response-generator.js +47 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/static-code-executor/index.js +1 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/system.js +54 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/tool-executor.js +9 -0
- package/vendor/dist-server/core/graph/nodes/tools/raw-output.js +4 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-cleaner.js +7 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-execution/execute-tool-calls.js +3 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-execution/invoke.js +1 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-execution/namespace-guard.js +1 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-execution/result-limits.js +3 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-invoker.js +1 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool.js +4 -0
- package/vendor/dist-server/core/graph/schemas.js +1 -0
- package/vendor/dist-server/core/graph/topic-variants.js +1 -0
- package/vendor/dist-server/core/graph/types.js +1 -0
- package/vendor/dist-server/core/graph/utils/content-utils.js +17 -0
- package/vendor/dist-server/core/graph/utils/edge-jsonata-condition.js +1 -0
- package/vendor/dist-server/core/graph/utils/engine-vars.js +1 -0
- package/vendor/dist-server/core/graph/utils/logging-utils.js +4 -0
- package/vendor/dist-server/core/graph/utils/message-utils.js +5 -0
- package/vendor/dist-server/core/graph/utils/node-type-defaults-cache.js +1 -0
- package/vendor/dist-server/core/graph/utils/sandbox-catalog.js +1 -0
- package/vendor/dist-server/core/graph/utils/schema-utils.js +1 -0
- package/vendor/dist-server/core/graph/utils/team-context-policy.js +5 -0
- package/vendor/dist-server/core/graph/utils/team-node-resolvers.js +1 -0
- package/vendor/dist-server/core/graph/utils/tool-result.js +4 -0
- package/vendor/dist-server/core/graph/utils/tool-wrapper.js +14 -0
- package/vendor/dist-server/core/llm/init-indices.js +1 -0
- package/vendor/dist-server/core/llm/models/index.js +1 -0
- package/vendor/dist-server/core/llm/models/model.model.js +1 -0
- package/vendor/dist-server/core/llm/models/provider.model.js +1 -0
- package/vendor/dist-server/core/llm/models/routing-rule.model.js +1 -0
- package/vendor/dist-server/core/llm/providers.js +1 -0
- package/vendor/dist-server/core/mcp/client.js +1 -0
- package/vendor/dist-server/core/runtime/active-runs-registry.js +1 -0
- package/vendor/dist-server/core/runtime/system-prompt-cache.js +1 -0
- package/vendor/dist-server/core/runtime/trace-bus.js +1 -0
- package/vendor/dist-server/core/schema/cluster_health_report.js +1 -0
- package/vendor/dist-server/core/schema/cluster_info.js +1 -0
- package/vendor/dist-server/core/schema/cluster_license.js +5 -0
- package/vendor/dist-server/core/schema/cluster_stats.js +12 -0
- package/vendor/dist-server/core/schema/dashboard.js +1 -0
- package/vendor/dist-server/core/schema/indices_settings.js +1 -0
- package/vendor/dist-server/core/schema/indices_shards.js +1 -0
- package/vendor/dist-server/core/schema/indices_stats.js +1 -0
- package/vendor/dist-server/core/schema/nodes_info.js +2 -0
- package/vendor/dist-server/core/schema/nodes_stats.js +11 -0
- package/vendor/dist-server/core/schema/pricing.js +1 -0
- package/vendor/dist-server/core/schema/ui.js +1 -0
- package/vendor/dist-server/core/schema/zod_client.js +83 -0
- package/vendor/dist-server/core/services/a2a-client.js +2 -0
- package/vendor/dist-server/core/services/alerts-service.js +1 -0
- package/vendor/dist-server/core/services/api-keys-service.js +1 -0
- package/vendor/dist-server/core/services/assistant-resolver.js +1 -0
- package/vendor/dist-server/core/services/assistants-index-service.js +1 -0
- package/vendor/dist-server/core/services/async-conversations-service.js +22 -0
- package/vendor/dist-server/core/services/asyncapi-dispatch.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/driver-manager.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/driver-types.js +0 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/http-driver.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/nats-driver.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/websocket-driver.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-events-service.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-reply-service.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-sink.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-tools-service.js +1 -0
- package/vendor/dist-server/core/services/block-repair-service.js +13 -0
- package/vendor/dist-server/core/services/chart-renderer.js +1 -0
- package/vendor/dist-server/core/services/chat-llms-service.js +1 -0
- package/vendor/dist-server/core/services/chat-runs-service.js +1 -0
- package/vendor/dist-server/core/services/chat-tools-service.js +1 -0
- package/vendor/dist-server/core/services/chat-traces-service.js +1 -0
- package/vendor/dist-server/core/services/chats-service.js +5 -0
- package/vendor/dist-server/core/services/comparison-service.js +107 -0
- package/vendor/dist-server/core/services/default-model.service.js +1 -0
- package/vendor/dist-server/core/services/elastic-stack-sync-service.js +2 -0
- package/vendor/dist-server/core/services/elasticsearch-wrapper.js +1 -0
- package/vendor/dist-server/core/services/embed-rate-limiter.js +1 -0
- package/vendor/dist-server/core/services/error-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/es-field-resolver.js +1 -0
- package/vendor/dist-server/core/services/gateway-platform-types.js +1 -0
- package/vendor/dist-server/core/services/gliner-tagging-service.js +1 -0
- package/vendor/dist-server/core/services/golden-questions-scoring.js +1 -0
- package/vendor/dist-server/core/services/golden-questions-service.js +1 -0
- package/vendor/dist-server/core/services/graph-drilldown-service.js +1 -0
- package/vendor/dist-server/core/services/graph-registry-service.js +1 -0
- package/vendor/dist-server/core/services/hitl-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/ingestion-jobs-service.js +1 -0
- package/vendor/dist-server/core/services/ingestion-service.js +5 -0
- package/vendor/dist-server/core/services/kibana-client-factory.js +1 -0
- package/vendor/dist-server/core/services/kibana-client.js +2 -0
- package/vendor/dist-server/core/services/kibana-dashboard-extractor.js +1 -0
- package/vendor/dist-server/core/services/kibana-service.js +1 -0
- package/vendor/dist-server/core/services/llm-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/llm-client-resolver.js +1 -0
- package/vendor/dist-server/core/services/llm-models-service.js +1 -0
- package/vendor/dist-server/core/services/llm-pricing-pure.js +1 -0
- package/vendor/dist-server/core/services/llm-pricing-service.js +1 -0
- package/vendor/dist-server/core/services/llm-providers-service.js +1 -0
- package/vendor/dist-server/core/services/llm-routing-service.js +1 -0
- package/vendor/dist-server/core/services/llm-services.js +1 -0
- package/vendor/dist-server/core/services/llm-sync-service.js +1 -0
- package/vendor/dist-server/core/services/manifest-loader.js +1 -0
- package/vendor/dist-server/core/services/mcp-servers-service.js +1 -0
- package/vendor/dist-server/core/services/mcp-sync-service.js +1 -0
- package/vendor/dist-server/core/services/mcp-tools-service.js +1 -0
- package/vendor/dist-server/core/services/memories-service.js +2 -0
- package/vendor/dist-server/core/services/memory-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/monitoring-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/monitoring-service.js +1 -0
- package/vendor/dist-server/core/services/multi-kibana-service.js +1 -0
- package/vendor/dist-server/core/services/node-latency-service.js +1 -0
- package/vendor/dist-server/core/services/package-policy-service.js +2 -0
- package/vendor/dist-server/core/services/pdf-service.js +572 -0
- package/vendor/dist-server/core/services/plan-service.js +1 -0
- package/vendor/dist-server/core/services/platform-direction.js +1 -0
- package/vendor/dist-server/core/services/platform-secrets.js +1 -0
- package/vendor/dist-server/core/services/platforms-service.js +1 -0
- package/vendor/dist-server/core/services/policy-factory.js +1 -0
- package/vendor/dist-server/core/services/prompt-cache-service.js +1 -0
- package/vendor/dist-server/core/services/provider-rate-limits.js +1 -0
- package/vendor/dist-server/core/services/quota-service.js +1 -0
- package/vendor/dist-server/core/services/report-assets-service.js +1 -0
- package/vendor/dist-server/core/services/run-analytics-collector.js +1 -0
- package/vendor/dist-server/core/services/run-stream-sink.js +1 -0
- package/vendor/dist-server/core/services/send_mail.js +460 -0
- package/vendor/dist-server/core/services/share-service.js +1 -0
- package/vendor/dist-server/core/services/slack-signature.js +1 -0
- package/vendor/dist-server/core/services/sources-service.js +6 -0
- package/vendor/dist-server/core/services/team-mcp-result.js +4 -0
- package/vendor/dist-server/core/services/team-mcp-run-tokens.js +1 -0
- package/vendor/dist-server/core/services/team-mcp-runner.js +1 -0
- package/vendor/dist-server/core/services/team-mcp-server.js +1 -0
- package/vendor/dist-server/core/services/team-mcp-tools.js +1 -0
- package/vendor/dist-server/core/services/team-mcp-ui.js +551 -0
- package/vendor/dist-server/core/services/team-run-progress.js +1 -0
- package/vendor/dist-server/core/services/team-runner-headless.js +7 -0
- package/vendor/dist-server/core/services/team-search-service.js +1 -0
- package/vendor/dist-server/core/services/teams-service.js +1 -0
- package/vendor/dist-server/core/services/token-projection-service.js +1 -0
- package/vendor/dist-server/core/services/tool-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/tool-history-service.js +1 -0
- package/vendor/dist-server/core/services/tool-metrics-service.js +1 -0
- package/vendor/dist-server/core/services/tool-scoring.js +1 -0
- package/vendor/dist-server/core/services/toolbox-import-mappers.js +1 -0
- package/vendor/dist-server/core/services/toolbox-import-service.js +1 -0
- package/vendor/dist-server/core/services/trigger-service.js +1 -0
- package/vendor/dist-server/core/services/version-snapshot-service.js +1 -0
- package/vendor/dist-server/core/services/webhook-calls-service.js +1 -0
- package/vendor/dist-server/core/tools/compare-chat.js +46 -0
- package/vendor/dist-server/core/tools/enrich-chat.js +50 -0
- package/vendor/dist-server/core/tools/variable-encoding.js +1 -0
- package/vendor/dist-server/core/types/settings.js +1 -0
- package/vendor/dist-server/core/utils/ab-evaluator.js +5 -0
- package/vendor/dist-server/core/utils/condition-evaluator.js +1 -0
- package/vendor/dist-server/core/utils/http-client.js +1 -0
- package/vendor/dist-server/core/utils/json-schema-to-form.js +1 -0
- package/vendor/dist-server/core/utils/logger.js +3 -0
- package/vendor/dist-server/core/utils/owner-scope.js +1 -0
- package/vendor/dist-server/core/utils/ownership.js +1 -0
- package/vendor/dist-server/core/utils/parallel-tool-executor.js +1 -0
- package/vendor/dist-server/core/utils/performance-tracker.js +3 -0
- package/vendor/dist-server/core/utils/prompt-optimizer.js +40 -0
- package/vendor/dist-server/core/utils/response-cache.js +1 -0
- package/vendor/dist-server/core/utils/schema-validator.js +1 -0
- package/vendor/dist-server/core/utils/streaming-optimizer.js +2 -0
- package/vendor/dist-server/core/utils/string-helpers.js +1 -0
- package/vendor/dist-server/core/utils/test-responses.js +9 -0
- package/vendor/dist-server/core/utils/text-utils.js +1 -0
- package/vendor/dist-server/core/utils/tool-form-trigger.js +1 -0
- package/vendor/dist-server/entrypoints/cli-bootstrap-run.js +1 -0
- package/vendor/dist-server/entrypoints/cli-deploy-run.js +1 -0
- package/vendor/dist-server/entrypoints/cli-deploy.js +1 -0
- package/vendor/dist-server/entrypoints/team-runner.js +1 -0
- package/vendor/dist-server/generated/toolbox-catalog.js +1 -0
- package/vendor/dist-server/index.js +2 -0
- package/vendor/dist-server/middleware/integration-logos.js +1 -0
- package/vendor/dist-server/middleware/plan-guard.js +1 -0
- package/vendor/dist-server/openapi/generator.js +1 -0
- package/vendor/dist-server/openapi/html-tool-spec.js +1 -0
- package/vendor/dist-server/routes/a2a-routes.js +1 -0
- package/vendor/dist-server/routes/a2a-server-routes.js +5 -0
- package/vendor/dist-server/routes/admin.js +1 -0
- package/vendor/dist-server/routes/assistants-routes.js +1 -0
- package/vendor/dist-server/routes/asyncapi-routes.js +1 -0
- package/vendor/dist-server/routes/auth.js +1 -0
- package/vendor/dist-server/routes/billing-routes.js +1 -0
- package/vendor/dist-server/routes/chat-llms.js +1 -0
- package/vendor/dist-server/routes/chat-tools.js +1 -0
- package/vendor/dist-server/routes/chat-traces.js +1 -0
- package/vendor/dist-server/routes/chats.js +1 -0
- package/vendor/dist-server/routes/clusters.js +1 -0
- package/vendor/dist-server/routes/compare.js +43 -0
- package/vendor/dist-server/routes/connectors-routes.js +1 -0
- package/vendor/dist-server/routes/consumptions-routes.js +1 -0
- package/vendor/dist-server/routes/data-admin-routes.js +1 -0
- package/vendor/dist-server/routes/data-transfer-routes.js +1 -0
- package/vendor/dist-server/routes/elastic-tool-execution-routes.js +1 -0
- package/vendor/dist-server/routes/geo-proxy-routes.js +1 -0
- package/vendor/dist-server/routes/golden-questions-routes.js +1 -0
- package/vendor/dist-server/routes/graph-registry.js +1 -0
- package/vendor/dist-server/routes/graph-templates-routes.js +1 -0
- package/vendor/dist-server/routes/helpdesk-routes.js +35 -0
- package/vendor/dist-server/routes/html-routes.js +1 -0
- package/vendor/dist-server/routes/index.js +1 -0
- package/vendor/dist-server/routes/indices.js +1 -0
- package/vendor/dist-server/routes/integrations-routes.js +1 -0
- package/vendor/dist-server/routes/langgraph.js +7 -0
- package/vendor/dist-server/routes/live-resources-routes.js +1 -0
- package/vendor/dist-server/routes/llm-analytics.js +1 -0
- package/vendor/dist-server/routes/llm-control-plane.js +1 -0
- package/vendor/dist-server/routes/llm.js +1 -0
- package/vendor/dist-server/routes/mcp-gateway-routes.js +1 -0
- package/vendor/dist-server/routes/mcp-query-routes.js +1 -0
- package/vendor/dist-server/routes/mcp-servers-routes.js +1 -0
- package/vendor/dist-server/routes/mcp-team-routes.js +1 -0
- package/vendor/dist-server/routes/mcp-tools-routes.js +1 -0
- package/vendor/dist-server/routes/me-routes.js +63 -0
- package/vendor/dist-server/routes/memories-routes.js +1 -0
- package/vendor/dist-server/routes/monitoring-analytics.js +12 -0
- package/vendor/dist-server/routes/monitoring.js +1 -0
- package/vendor/dist-server/routes/node-types-routes.js +171 -0
- package/vendor/dist-server/routes/nodes.js +1 -0
- package/vendor/dist-server/routes/packages.js +1 -0
- package/vendor/dist-server/routes/pdf.js +3 -0
- package/vendor/dist-server/routes/plan-routes.js +1 -0
- package/vendor/dist-server/routes/platform-requests-routes.js +1 -0
- package/vendor/dist-server/routes/platforms-routes.js +1 -0
- package/vendor/dist-server/routes/prompts-routes.js +1 -0
- package/vendor/dist-server/routes/proxy-logos.js +1 -0
- package/vendor/dist-server/routes/quality-routes.js +1 -0
- package/vendor/dist-server/routes/resources-ingest-routes.js +1 -0
- package/vendor/dist-server/routes/resources-routes.js +1 -0
- package/vendor/dist-server/routes/schema-routes.js +1 -0
- package/vendor/dist-server/routes/settings-original.js +1 -0
- package/vendor/dist-server/routes/settings.js +1 -0
- package/vendor/dist-server/routes/share-routes.js +1 -0
- package/vendor/dist-server/routes/sources-catalog-routes.js +1 -0
- package/vendor/dist-server/routes/sources-routes.js +1 -0
- package/vendor/dist-server/routes/team-optimizer-routes.js +1 -0
- package/vendor/dist-server/routes/team-schedule-routes.js +1 -0
- package/vendor/dist-server/routes/teams-routes.js +1 -0
- package/vendor/dist-server/routes/tool-analytics.js +1 -0
- package/vendor/dist-server/routes/tool-history-routes.js +1 -0
- package/vendor/dist-server/routes/tool-metrics-routes.js +1 -0
- package/vendor/dist-server/routes/toolbox-import-routes.js +1 -0
- package/vendor/dist-server/routes/tools-routes.js +5 -0
- package/vendor/dist-server/routes/transcribe-routes.js +1 -0
- package/vendor/dist-server/routes/triggers.js +1 -0
- package/vendor/dist-server/routes/versions-routes.js +1 -0
- package/vendor/dist-server/routes/webhooks-routes.js +1 -0
- package/vendor/dist-server/scripts/add-label-to-tools.js +4 -0
- package/vendor/dist-server/scripts/migrate-assistants-to-mcp.js +10 -0
- package/vendor/dist-server/scripts/migrate-chat-runs.js +8 -0
- package/vendor/dist-server/scripts/migrate-mcp-protocol.js +8 -0
- package/vendor/dist-server/scripts/migrate-mcp-to-platforms.js +15 -0
- package/vendor/dist-server/services/alert-evaluator.js +3 -0
- package/vendor/dist-server/services/auth.js +1 -0
- package/vendor/dist-server/services/billing-service.js +1 -0
- package/vendor/dist-server/services/chat-title-generator.js +12 -0
- package/vendor/dist-server/services/clone/clone-executor.js +1 -0
- package/vendor/dist-server/services/clone/closure-resolver.js +3 -0
- package/vendor/dist-server/services/clone/entity-graph.js +3 -0
- package/vendor/dist-server/services/clone/team-bundle-bootstrap.js +1 -0
- package/vendor/dist-server/services/clone/team-bundle-crypto.js +1 -0
- package/vendor/dist-server/services/clone/team-bundle-encrypted.js +1 -0
- package/vendor/dist-server/services/clone/team-bundle.js +1 -0
- package/vendor/dist-server/services/cluster-service.js +1 -0
- package/vendor/dist-server/services/connection-adapters.js +1 -0
- package/vendor/dist-server/services/connectors-service.js +10 -0
- package/vendor/dist-server/services/cost-forecast-service.js +1 -0
- package/vendor/dist-server/services/eui-ssr-renderer.js +4 -0
- package/vendor/dist-server/services/graph-canvas/full-structure-builder.js +1 -0
- package/vendor/dist-server/services/graph-templates-service.js +13 -0
- package/vendor/dist-server/services/guest-service.js +1 -0
- package/vendor/dist-server/services/html-service.js +1 -0
- package/vendor/dist-server/services/langgraph-service.js +2 -0
- package/vendor/dist-server/services/leaflet-render-service.js +80 -0
- package/vendor/dist-server/services/live-resources-service.js +16 -0
- package/vendor/dist-server/services/mcp-app-tester-package.js +1 -0
- package/vendor/dist-server/services/mcp-gateway/executors/openapi-executor.js +1 -0
- package/vendor/dist-server/services/mcp-gateway/gateway-grant-service.js +2 -0
- package/vendor/dist-server/services/team-optimizer-service.js +1 -0
- package/vendor/dist-server/services/trace-bus-sink.js +1 -0
- package/vendor/dist-server/services/user-provisioning-service.js +3 -0
- package/vendor/dist-server/templates/mcp-app-tester/src/mcp-http.js +3 -0
- package/vendor/dist-server/templates/mcp-app-tester/src/server.js +1 -0
- package/vendor/dist-server/utils.js +1 -0
- package/vendor/dist-server/ws/assistant-executor.js +7 -0
- package/vendor/dist-server/ws/classify-streamed-json-block.js +1 -0
- package/vendor/dist-server/ws/collect-response-generator-node-ids.js +1 -0
- package/vendor/dist-server/ws/extractors/blockkit-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/echarts-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/eui-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/form-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/index.js +1 -0
- package/vendor/dist-server/ws/extractors/leaflet-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/mantine-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/markdown-extractor.js +7 -0
- package/vendor/dist-server/ws/extractors/mermaid-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/recharts-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/remotion-extractor.js +1 -0
- package/vendor/dist-server/ws/handler.js +66 -0
- package/vendor/dist-server/ws/parsers/anthropic-parser.js +7 -0
- package/vendor/dist-server/ws/parsers/base-parser.js +3 -0
- package/vendor/dist-server/ws/parsers/gemini-parser.js +8 -0
- package/vendor/dist-server/ws/parsers/index.js +1 -0
- package/vendor/dist-server/ws/parsers/parse-json-blocks.js +1 -0
- package/vendor/dist-server/ws/types.js +0 -0
- package/vendor/dist-server/ws/utils.js +1 -0
- package/vendor/shared/engine-vars.ts +51 -0
- package/vendor/shared/llm-providers-config.ts +69 -0
package/src/deploy.mjs
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// packages/cli/src/deploy.mjs
|
|
2
|
+
//
|
|
3
|
+
// `stkxp deploy` spawns the vendored server/entrypoints/cli-deploy.js under
|
|
4
|
+
// tsx (its emitted imports are extensionless — see scripts/bundle-server.mjs
|
|
5
|
+
// in the main repo — tsx's loader is what resolves them; a plain `node` run
|
|
6
|
+
// would fail). A child process, not an in-process dynamic import, so this
|
|
7
|
+
// package never needs its OWN module loader hacks: tsx owns its process
|
|
8
|
+
// fully, and cli-deploy.js's own dynamic-import env-var-then-import ordering
|
|
9
|
+
// (see server/entrypoints/cli-deploy.ts's file header) is self-contained
|
|
10
|
+
// inside that child.
|
|
11
|
+
//
|
|
12
|
+
// tsx is located with require.resolve("tsx/cli") — its package.json exports
|
|
13
|
+
// map declares "./cli" → "./dist/cli.mjs" — and run as
|
|
14
|
+
// `process.execPath <tsx/dist/cli.mjs> <runner>`. Resolving the module (not a
|
|
15
|
+
// node_modules/.bin/tsx shim path) is what makes this work both inside this
|
|
16
|
+
// pnpm monorepo, where tsx is hoisted well above packages/cli/, and after a
|
|
17
|
+
// bare `npm install @stkxp/cli`, where there is no packages/cli/node_modules
|
|
18
|
+
// at all and the shim lands in the consumer's own node_modules/.bin.
|
|
19
|
+
import { spawn } from "node:child_process";
|
|
20
|
+
import { readFile } from "node:fs/promises";
|
|
21
|
+
import { createRequire } from "node:module";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
24
|
+
|
|
25
|
+
const CLI_ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
26
|
+
const require = createRequire(import.meta.url);
|
|
27
|
+
|
|
28
|
+
/** Must stay byte-identical to RESULT_SENTINEL in server/entrypoints/cli-deploy-run.ts. */
|
|
29
|
+
export const RESULT_SENTINEL = "__STKXP_DEPLOY_RESULT__";
|
|
30
|
+
|
|
31
|
+
export function resolveTsxCli() {
|
|
32
|
+
return require.resolve("tsx/cli");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function runDeployCommand({
|
|
36
|
+
bundlePath,
|
|
37
|
+
secret,
|
|
38
|
+
esUrl,
|
|
39
|
+
esUser,
|
|
40
|
+
esPassword,
|
|
41
|
+
webhookPort,
|
|
42
|
+
webhookHost,
|
|
43
|
+
esCaPath,
|
|
44
|
+
esInsecure,
|
|
45
|
+
}) {
|
|
46
|
+
const bundle = JSON.parse(await readFile(bundlePath, "utf8"));
|
|
47
|
+
|
|
48
|
+
const runnerScript = path.join(CLI_ROOT, "vendor", "dist-server", "entrypoints", "cli-deploy-run.js");
|
|
49
|
+
|
|
50
|
+
return spawnAndAwaitJsonResult(process.execPath, [resolveTsxCli(), runnerScript], {
|
|
51
|
+
input: JSON.stringify({
|
|
52
|
+
bundle,
|
|
53
|
+
secret,
|
|
54
|
+
esUrl,
|
|
55
|
+
esUser,
|
|
56
|
+
esPassword,
|
|
57
|
+
webhookPort,
|
|
58
|
+
webhookHost,
|
|
59
|
+
esCaPath,
|
|
60
|
+
esInsecure,
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Spawns `command args` and resolves as soon as the child's stdout produces a
|
|
66
|
+
// line prefixed with `sentinel` (defaults to this module's own
|
|
67
|
+
// RESULT_SENTINEL; packages/cli/src/bootstrap.mjs passes its own) — NOT on
|
|
68
|
+
// child exit. Extracted from runDeployCommand so it can be exercised in
|
|
69
|
+
// tests against a tiny hermetic mock child process instead of the real
|
|
70
|
+
// (tsx + cli-deploy-run.js) child.
|
|
71
|
+
export function spawnAndAwaitJsonResult(command, args, { input, env, onSpawn } = {}, sentinel = RESULT_SENTINEL) {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
const child = spawn(command, args, {
|
|
74
|
+
env: { ...process.env, ...env },
|
|
75
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
76
|
+
});
|
|
77
|
+
// Test-only hook: lets tests grab the child handle (e.g. to kill a mock
|
|
78
|
+
// child left running after the "resolves without waiting for exit"
|
|
79
|
+
// case) without changing runDeployCommand's production call signature.
|
|
80
|
+
onSpawn?.(child);
|
|
81
|
+
|
|
82
|
+
let settled = false;
|
|
83
|
+
let stdout = "";
|
|
84
|
+
|
|
85
|
+
// The child boots a webhook server and, on success, keeps running in the
|
|
86
|
+
// foreground forever (same precedent as server/entrypoints/team-runner.ts)
|
|
87
|
+
// — it never exits on the success path. So we can't wait for `exit` to
|
|
88
|
+
// resolve: we resolve as soon as the child prints its sentinel-prefixed
|
|
89
|
+
// result line, and let the child keep running afterwards (no kill/unref
|
|
90
|
+
// here — the webhook must stay up).
|
|
91
|
+
const onData = (chunk) => {
|
|
92
|
+
if (settled) return; // Post-settle output is piped straight through (see below).
|
|
93
|
+
stdout += chunk.toString();
|
|
94
|
+
|
|
95
|
+
// The last element of split("\n") is either an incomplete,
|
|
96
|
+
// not-yet-newline-terminated line, or (if stdout ends with "\n") an
|
|
97
|
+
// empty string — either way it's not a candidate line yet.
|
|
98
|
+
const completeLines = stdout.split("\n").slice(0, -1);
|
|
99
|
+
for (const line of completeLines) {
|
|
100
|
+
const trimmed = line.trim();
|
|
101
|
+
if (!trimmed.startsWith(sentinel)) continue;
|
|
102
|
+
let parsed;
|
|
103
|
+
try {
|
|
104
|
+
parsed = JSON.parse(trimmed.slice(sentinel.length));
|
|
105
|
+
} catch (e) {
|
|
106
|
+
settled = true;
|
|
107
|
+
child.stdout.off("data", onData);
|
|
108
|
+
reject(new Error(`stkxp deploy child printed an unparseable result line: ${e.message}`));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
settled = true;
|
|
112
|
+
// Stop accumulating (the child runs forever — an unbounded buffer
|
|
113
|
+
// here would leak for the whole life of the deploy) and forward its
|
|
114
|
+
// ongoing logs to the operator's terminal instead.
|
|
115
|
+
stdout = "";
|
|
116
|
+
child.stdout.off("data", onData);
|
|
117
|
+
child.stdout.pipe(process.stdout);
|
|
118
|
+
resolve(parsed);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
child.stdout.on("data", onData);
|
|
123
|
+
|
|
124
|
+
child.on("error", (err) => {
|
|
125
|
+
if (settled) return;
|
|
126
|
+
settled = true;
|
|
127
|
+
reject(err);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
child.on("exit", (code) => {
|
|
131
|
+
if (settled) return; // Already resolved from the sentinel line — no-op.
|
|
132
|
+
settled = true;
|
|
133
|
+
if (code !== 0) {
|
|
134
|
+
reject(new Error(`stkxp deploy child process exited with code ${code}`));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
reject(new Error(`stkxp deploy child process exited cleanly (code 0) without printing a deploy result: ${stdout}`));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (input !== undefined) {
|
|
141
|
+
child.stdin.write(input);
|
|
142
|
+
}
|
|
143
|
+
child.stdin.end();
|
|
144
|
+
});
|
|
145
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// packages/cli/src/deploy.test.mjs
|
|
2
|
+
//
|
|
3
|
+
// Covers spawnAndAwaitJsonResult's promise-resolution contract (used by
|
|
4
|
+
// runDeployCommand): it must resolve as soon as the child prints its
|
|
5
|
+
// RESULT_SENTINEL-prefixed JSON line to stdout — even if the child then keeps
|
|
6
|
+
// running forever (the real cli-deploy-run.js child boots a webhook server
|
|
7
|
+
// and never exits on success) — must ignore non-sentinel log lines even when
|
|
8
|
+
// they happen to be valid JSON, and must reject if the child exits without
|
|
9
|
+
// ever printing a sentinel line.
|
|
10
|
+
//
|
|
11
|
+
// We spawn tiny inline `node -e "..."` scripts rather than the real
|
|
12
|
+
// tsx + cli-deploy-run.js child, to keep this hermetic and fast.
|
|
13
|
+
import { describe, it, expect, afterEach } from "vitest";
|
|
14
|
+
import { spawnAndAwaitJsonResult, resolveTsxCli, RESULT_SENTINEL } from "./deploy.mjs";
|
|
15
|
+
|
|
16
|
+
describe("resolveTsxCli", () => {
|
|
17
|
+
it("resolves tsx's CLI entry point as a real file path (no node_modules/.bin shim)", () => {
|
|
18
|
+
const resolved = resolveTsxCli();
|
|
19
|
+
expect(resolved).toMatch(/tsx[\\/]dist[\\/]cli\.mjs$/);
|
|
20
|
+
expect(resolved).not.toMatch(/node_modules[\\/]\.bin/);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("spawnAndAwaitJsonResult", () => {
|
|
25
|
+
let spawnedChildren = [];
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
// Clean up any mock children left running (the "keeps running" case is
|
|
29
|
+
// expected to leave its child alive — don't leak processes across tests).
|
|
30
|
+
for (const child of spawnedChildren) {
|
|
31
|
+
if (!child.killed) child.kill();
|
|
32
|
+
}
|
|
33
|
+
spawnedChildren = [];
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("resolves with parsed JSON as soon as the child prints the sentinel line, without waiting for exit", async () => {
|
|
37
|
+
// Prints the sentinel result line, then blocks forever (setInterval keeps
|
|
38
|
+
// the event loop alive) — simulates the real deploy child staying up to
|
|
39
|
+
// serve the webhook.
|
|
40
|
+
const script = `
|
|
41
|
+
console.log(${JSON.stringify(RESULT_SENTINEL)} + JSON.stringify({ webhookUrl: "http://localhost:8081/hook", webhookToken: "tok" }));
|
|
42
|
+
setInterval(() => {}, 1000);
|
|
43
|
+
`;
|
|
44
|
+
let childHandle;
|
|
45
|
+
const resultPromise = spawnAndAwaitJsonResult("node", ["-e", script], {
|
|
46
|
+
onSpawn: (child) => { childHandle = child; spawnedChildren.push(child); },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const result = await Promise.race([
|
|
50
|
+
resultPromise,
|
|
51
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timed out waiting for resolve")), 5000)),
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
expect(result).toEqual({ webhookUrl: "http://localhost:8081/hook", webhookToken: "tok" });
|
|
55
|
+
// The mock child is still running at this point (it never exited) —
|
|
56
|
+
// proving resolution happened without waiting for exit. It's cleaned up
|
|
57
|
+
// in afterEach via spawnedChildren.
|
|
58
|
+
expect(childHandle.exitCode).toBeNull();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("ignores JSON-parseable log lines that lack the sentinel prefix", async () => {
|
|
62
|
+
const script = `
|
|
63
|
+
console.log(JSON.stringify({ level: "info", msg: "not the result" }));
|
|
64
|
+
console.log("plain log line");
|
|
65
|
+
console.log(${JSON.stringify(RESULT_SENTINEL)} + JSON.stringify({ webhookToken: "real" }));
|
|
66
|
+
setInterval(() => {}, 1000);
|
|
67
|
+
`;
|
|
68
|
+
const result = await Promise.race([
|
|
69
|
+
spawnAndAwaitJsonResult("node", ["-e", script], { onSpawn: (c) => spawnedChildren.push(c) }),
|
|
70
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timed out waiting for resolve")), 5000)),
|
|
71
|
+
]);
|
|
72
|
+
expect(result).toEqual({ webhookToken: "real" });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("forwards the child's post-settle stdout to the parent's terminal instead of buffering it", async () => {
|
|
76
|
+
const script = `
|
|
77
|
+
console.log(${JSON.stringify(RESULT_SENTINEL)} + JSON.stringify({ ok: true }));
|
|
78
|
+
let n = 0;
|
|
79
|
+
const t = setInterval(() => { console.log("ongoing webhook log " + (++n)); if (n > 2) clearInterval(t); }, 20);
|
|
80
|
+
setInterval(() => {}, 1000);
|
|
81
|
+
`;
|
|
82
|
+
let childHandle;
|
|
83
|
+
const forwarded = [];
|
|
84
|
+
const realWrite = process.stdout.write.bind(process.stdout);
|
|
85
|
+
process.stdout.write = (chunk, ...rest) => {
|
|
86
|
+
forwarded.push(chunk.toString());
|
|
87
|
+
return realWrite(chunk, ...rest);
|
|
88
|
+
};
|
|
89
|
+
try {
|
|
90
|
+
const result = await spawnAndAwaitJsonResult("node", ["-e", script], {
|
|
91
|
+
onSpawn: (child) => { childHandle = child; spawnedChildren.push(child); },
|
|
92
|
+
});
|
|
93
|
+
expect(result).toEqual({ ok: true });
|
|
94
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
95
|
+
} finally {
|
|
96
|
+
process.stdout.write = realWrite;
|
|
97
|
+
}
|
|
98
|
+
expect(forwarded.join("")).toContain("ongoing webhook log 1");
|
|
99
|
+
expect(childHandle.exitCode).toBeNull();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("rejects if the child exits with a non-zero code before printing a result", async () => {
|
|
103
|
+
const script = `
|
|
104
|
+
console.error("boom before printing anything");
|
|
105
|
+
process.exit(3);
|
|
106
|
+
`;
|
|
107
|
+
await expect(spawnAndAwaitJsonResult("node", ["-e", script])).rejects.toThrow(
|
|
108
|
+
/exited with code 3/
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("rejects if the child exits with code 0 but never printed a sentinel line", async () => {
|
|
113
|
+
const script = `
|
|
114
|
+
console.log("just some log output, not JSON");
|
|
115
|
+
console.log(JSON.stringify({ json: "but no sentinel" }));
|
|
116
|
+
`;
|
|
117
|
+
await expect(spawnAndAwaitJsonResult("node", ["-e", script])).rejects.toThrow(
|
|
118
|
+
/exited cleanly \(code 0\) without printing a deploy result/
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("rejects if the sentinel line's payload is not parseable JSON", async () => {
|
|
123
|
+
const script = `
|
|
124
|
+
console.log(${JSON.stringify(RESULT_SENTINEL)} + "{not json");
|
|
125
|
+
setInterval(() => {}, 1000);
|
|
126
|
+
`;
|
|
127
|
+
await expect(
|
|
128
|
+
spawnAndAwaitJsonResult("node", ["-e", script], { onSpawn: (c) => spawnedChildren.push(c) }),
|
|
129
|
+
).rejects.toThrow(/unparseable result line/);
|
|
130
|
+
});
|
|
131
|
+
});
|
package/src/export.mjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// packages/cli/src/export.mjs
|
|
2
|
+
//
|
|
3
|
+
// `stkxp export` is pure networking: it calls the SOURCE stkxp-app instance's
|
|
4
|
+
// POST /api/teams/:id/export-encrypted (already running, reachable over
|
|
5
|
+
// HTTPS) with a JWT bearer token and the chosen passphrase, then writes the
|
|
6
|
+
// returned encrypted bundle to a local file. It never touches the vendored
|
|
7
|
+
// dist-server payload used by `stkxp deploy` — that only runs on the TARGET.
|
|
8
|
+
import { writeFile } from "node:fs/promises";
|
|
9
|
+
|
|
10
|
+
export async function runExport({ sourceUrl, token, teamId, secret, outFile }) {
|
|
11
|
+
const url = new URL(`/api/teams/${teamId}/export-encrypted`, sourceUrl);
|
|
12
|
+
const response = await fetch(url, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
Authorization: `Bearer ${token}`,
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify({ secret }),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const body = await response.json();
|
|
22
|
+
if (!response.ok || !body.success) {
|
|
23
|
+
throw new Error(`Export failed (${response.status}): ${body.error ?? response.statusText}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 0600: the bundle carries every one of the team's credentials, encrypted
|
|
27
|
+
// but offline-crackable against the passphrase — don't leave it world-readable.
|
|
28
|
+
await writeFile(outFile, JSON.stringify(body.bundle, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
29
|
+
return { outFile, rootName: body.bundle.rootName, totalDocs: body.bundle.summary.totalDocs };
|
|
30
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// packages/cli/src/export.test.mjs
|
|
2
|
+
import { describe, it, expect, afterEach, vi } from "vitest";
|
|
3
|
+
import { mkdtemp, rm, stat, readFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { runExport } from "./export.mjs";
|
|
7
|
+
|
|
8
|
+
const tmpDirs = [];
|
|
9
|
+
async function tmpOut(name) {
|
|
10
|
+
const dir = await mkdtemp(path.join(tmpdir(), "stkxp-export-test-"));
|
|
11
|
+
tmpDirs.push(dir);
|
|
12
|
+
return path.join(dir, name);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
afterEach(async () => {
|
|
16
|
+
vi.unstubAllGlobals();
|
|
17
|
+
await Promise.all(tmpDirs.splice(0).map((d) => rm(d, { recursive: true, force: true })));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
function stubFetchOk(bundle) {
|
|
21
|
+
vi.stubGlobal(
|
|
22
|
+
"fetch",
|
|
23
|
+
vi.fn(async () => ({ ok: true, status: 200, statusText: "OK", json: async () => ({ success: true, bundle }) })),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe("runExport", () => {
|
|
28
|
+
it("writes the bundle file owner-readable only (mode 0600)", async () => {
|
|
29
|
+
stubFetchOk({ rootName: "Ops Team", summary: { totalDocs: 3 } });
|
|
30
|
+
const outFile = await tmpOut("bundle.json");
|
|
31
|
+
|
|
32
|
+
await runExport({ sourceUrl: "https://app.example.com", token: "jwt", teamId: "team-1", secret: "pw", outFile });
|
|
33
|
+
|
|
34
|
+
const mode = (await stat(outFile)).mode & 0o777;
|
|
35
|
+
expect(mode.toString(8)).toBe("600");
|
|
36
|
+
expect(JSON.parse(await readFile(outFile, "utf8")).rootName).toBe("Ops Team");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("returns the bundle summary", async () => {
|
|
40
|
+
stubFetchOk({ rootName: "Ops Team", summary: { totalDocs: 3 } });
|
|
41
|
+
const outFile = await tmpOut("bundle.json");
|
|
42
|
+
const result = await runExport({ sourceUrl: "https://app.example.com", token: "jwt", teamId: "team-1", secret: "pw", outFile });
|
|
43
|
+
expect(result).toEqual({ outFile, rootName: "Ops Team", totalDocs: 3 });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("throws (without echoing the passphrase) when the source rejects the export", async () => {
|
|
47
|
+
vi.stubGlobal(
|
|
48
|
+
"fetch",
|
|
49
|
+
vi.fn(async () => ({ ok: false, status: 403, statusText: "Forbidden", json: async () => ({ success: false, error: "not the owner" }) })),
|
|
50
|
+
);
|
|
51
|
+
const outFile = await tmpOut("bundle.json");
|
|
52
|
+
const promise = runExport({ sourceUrl: "https://app.example.com", token: "jwt", teamId: "team-1", secret: "super-secret-pw", outFile });
|
|
53
|
+
await expect(promise).rejects.toThrow(/Export failed \(403\): not the owner/);
|
|
54
|
+
await expect(promise).rejects.not.toThrow(/super-secret-pw/);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// packages/cli/src/secret-input.mjs
|
|
2
|
+
//
|
|
3
|
+
// Resolves a secret (the bundle passphrase, the target ES password) WITHOUT
|
|
4
|
+
// requiring it on the command line. Passing a secret as an argv flag leaks it
|
|
5
|
+
// to every process on the box via `ps` / /proc/<pid>/cmdline and writes it
|
|
6
|
+
// into the operator's shell history, so the flags are now optional and fall
|
|
7
|
+
// back, in order, to:
|
|
8
|
+
// 1. the explicit CLI flag (unchanged behaviour when given),
|
|
9
|
+
// 2. an environment variable,
|
|
10
|
+
// 3. an interactive prompt, when stdin is a TTY.
|
|
11
|
+
// Nothing here logs, echoes, or persists the resolved value.
|
|
12
|
+
import readline from "node:readline";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Prompt on the TTY without echoing what is typed. Uses readline's
|
|
16
|
+
* _writeToOutput hook — the standard zero-dependency way to mask input; if a
|
|
17
|
+
* future Node drops it, the prompt degrades to visible input rather than
|
|
18
|
+
* failing (and we never add a dependency just for masking).
|
|
19
|
+
*/
|
|
20
|
+
export function promptHidden(question, { input = process.stdin, output = process.stdout } = {}) {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const rl = readline.createInterface({ input, output, terminal: true });
|
|
23
|
+
let masking = false;
|
|
24
|
+
rl._writeToOutput = function (chunk) {
|
|
25
|
+
if (masking) return; // Swallow the echo of typed characters entirely.
|
|
26
|
+
rl.output.write(chunk);
|
|
27
|
+
};
|
|
28
|
+
rl.question(question, (answer) => {
|
|
29
|
+
masking = false;
|
|
30
|
+
output.write("\n");
|
|
31
|
+
rl.close();
|
|
32
|
+
resolve(answer);
|
|
33
|
+
});
|
|
34
|
+
masking = true;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {object} args
|
|
40
|
+
* @param {string|undefined} args.flagValue Value from the CLI flag, if given.
|
|
41
|
+
* @param {string} args.envVar Env var name to fall back to.
|
|
42
|
+
* @param {string} args.promptLabel Prompt text (never includes a value).
|
|
43
|
+
* @param {string} args.flagName Flag name, for the error message only.
|
|
44
|
+
*/
|
|
45
|
+
export async function resolveSecret({
|
|
46
|
+
flagValue,
|
|
47
|
+
envVar,
|
|
48
|
+
promptLabel,
|
|
49
|
+
flagName,
|
|
50
|
+
env = process.env,
|
|
51
|
+
isTTY = process.stdin.isTTY,
|
|
52
|
+
prompt = promptHidden,
|
|
53
|
+
}) {
|
|
54
|
+
if (flagValue) return flagValue;
|
|
55
|
+
if (env[envVar]) return env[envVar];
|
|
56
|
+
if (isTTY) {
|
|
57
|
+
const answer = (await prompt(promptLabel)).trim();
|
|
58
|
+
if (answer) return answer;
|
|
59
|
+
}
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Missing ${flagName}. Provide it with ${flagName}, set ${envVar} in the environment, ` +
|
|
62
|
+
`or run this command from an interactive terminal to be prompted for it.`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// packages/cli/src/secret-input.test.mjs
|
|
2
|
+
import { describe, it, expect, vi } from "vitest";
|
|
3
|
+
import { resolveSecret } from "./secret-input.mjs";
|
|
4
|
+
|
|
5
|
+
const base = { envVar: "STKXP_SECRET", promptLabel: "Passphrase: ", flagName: "--secret" };
|
|
6
|
+
|
|
7
|
+
describe("resolveSecret", () => {
|
|
8
|
+
it("returns the CLI flag value when given, without reading the env or prompting", async () => {
|
|
9
|
+
const prompt = vi.fn();
|
|
10
|
+
const value = await resolveSecret({
|
|
11
|
+
...base,
|
|
12
|
+
flagValue: "from-flag",
|
|
13
|
+
env: { STKXP_SECRET: "from-env" },
|
|
14
|
+
isTTY: true,
|
|
15
|
+
prompt,
|
|
16
|
+
});
|
|
17
|
+
expect(value).toBe("from-flag");
|
|
18
|
+
expect(prompt).not.toHaveBeenCalled();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("falls back to the environment variable when no flag is given", async () => {
|
|
22
|
+
const prompt = vi.fn();
|
|
23
|
+
const value = await resolveSecret({ ...base, flagValue: undefined, env: { STKXP_SECRET: "from-env" }, isTTY: true, prompt });
|
|
24
|
+
expect(value).toBe("from-env");
|
|
25
|
+
expect(prompt).not.toHaveBeenCalled();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("prompts interactively when neither flag nor env var is present and stdin is a TTY", async () => {
|
|
29
|
+
const prompt = vi.fn().mockResolvedValue(" typed-secret ");
|
|
30
|
+
const value = await resolveSecret({ ...base, flagValue: undefined, env: {}, isTTY: true, prompt });
|
|
31
|
+
expect(value).toBe("typed-secret");
|
|
32
|
+
expect(prompt).toHaveBeenCalledWith("Passphrase: ");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("errors clearly (naming the flag and env var, never a value) when nothing is available and stdin is not a TTY", async () => {
|
|
36
|
+
await expect(
|
|
37
|
+
resolveSecret({ ...base, flagValue: undefined, env: {}, isTTY: false, prompt: vi.fn() }),
|
|
38
|
+
).rejects.toThrow(/Missing --secret.*STKXP_SECRET/s);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("errors when the interactive prompt yields an empty answer", async () => {
|
|
42
|
+
await expect(
|
|
43
|
+
resolveSecret({ ...base, flagValue: undefined, env: {}, isTTY: true, prompt: vi.fn().mockResolvedValue(" ") }),
|
|
44
|
+
).rejects.toThrow(/Missing --secret/);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("supports a distinct env var per secret (e.g. the ES password)", async () => {
|
|
48
|
+
const value = await resolveSecret({
|
|
49
|
+
flagValue: undefined,
|
|
50
|
+
envVar: "STKXP_ES_PASSWORD",
|
|
51
|
+
promptLabel: "ES password: ",
|
|
52
|
+
flagName: "--es-password",
|
|
53
|
+
env: { STKXP_ES_PASSWORD: "es-pw" },
|
|
54
|
+
isTTY: false,
|
|
55
|
+
});
|
|
56
|
+
expect(value).toBe("es-pw");
|
|
57
|
+
});
|
|
58
|
+
});
|
package/src/serve.mjs
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// packages/cli/src/serve.mjs
|
|
2
|
+
//
|
|
3
|
+
// `stkxp serve` — starts the standalone webhook façade (the same
|
|
4
|
+
// server/entrypoints/team-runner.ts façade already deployed in-fleet as PM2
|
|
5
|
+
// process stkxp-team-runner) against an already-bootstrapped target
|
|
6
|
+
// Elasticsearch cluster. Does NOT bootstrap — run `stkxp bootstrap` first.
|
|
7
|
+
// Long-running and restart-safe: unlike `stkxp deploy`, this never mints a
|
|
8
|
+
// token or writes to ES itself, so a crash/restart under
|
|
9
|
+
// `docker restart: unless-stopped` is harmless — it just reconnects and
|
|
10
|
+
// keeps serving whatever team(s) the target ES already has webhookEnabled.
|
|
11
|
+
import { spawn } from "node:child_process";
|
|
12
|
+
import { createRequire } from "node:module";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
|
|
16
|
+
const CLI_ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
|
|
19
|
+
export function resolveTsxCli() {
|
|
20
|
+
return require.resolve("tsx/cli");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Pure: target-ES + bind env vars for the spawned team-runner.js child. Same TLS convention as cli-deploy.ts's bootstrapTeam(). */
|
|
24
|
+
export function buildServeEnv({ esUrl, esUser, esPassword, esCaPath, esInsecure, port, host }) {
|
|
25
|
+
return {
|
|
26
|
+
ELASTICSEARCH_HOST: esUrl,
|
|
27
|
+
ELASTICSEARCH_USER: esUser,
|
|
28
|
+
ELASTICSEARCH_PASSWORD: esPassword,
|
|
29
|
+
...(esCaPath ? { ELASTICSEARCH_CA_PATH: esCaPath } : {}),
|
|
30
|
+
ELASTICSEARCH_TLS_REJECT_UNAUTHORIZED: esInsecure === true ? "false" : "true",
|
|
31
|
+
TEAM_RUNNER_PORT: String(port),
|
|
32
|
+
TEAM_RUNNER_HOST: host,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Spawns `command args` with stdio inherited straight through (team-runner
|
|
38
|
+
* logs its own "listening on ..." line — there's no single JSON result to
|
|
39
|
+
* capture the way deploy/bootstrap have) and forwards SIGINT/SIGTERM to the
|
|
40
|
+
* child so its graceful-shutdown handler runs instead of the child being
|
|
41
|
+
* killed abruptly by `docker stop`. Resolves on a clean (code 0) exit,
|
|
42
|
+
* rejects otherwise — extracted from runServeCommand so it can be exercised
|
|
43
|
+
* in tests against a tiny hermetic mock child instead of the real
|
|
44
|
+
* (tsx + team-runner.js) child.
|
|
45
|
+
*/
|
|
46
|
+
export function spawnForeground(command, args, { env, onSpawn } = {}) {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const child = spawn(command, args, {
|
|
49
|
+
env: { ...process.env, ...env },
|
|
50
|
+
stdio: "inherit",
|
|
51
|
+
});
|
|
52
|
+
onSpawn?.(child);
|
|
53
|
+
|
|
54
|
+
const forwardSignal = (signal) => () => child.kill(signal);
|
|
55
|
+
const onSigint = forwardSignal("SIGINT");
|
|
56
|
+
const onSigterm = forwardSignal("SIGTERM");
|
|
57
|
+
process.on("SIGINT", onSigint);
|
|
58
|
+
process.on("SIGTERM", onSigterm);
|
|
59
|
+
const cleanupSignalForwarding = () => {
|
|
60
|
+
process.off("SIGINT", onSigint);
|
|
61
|
+
process.off("SIGTERM", onSigterm);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
child.on("error", (err) => {
|
|
65
|
+
cleanupSignalForwarding();
|
|
66
|
+
reject(err);
|
|
67
|
+
});
|
|
68
|
+
child.on("exit", (code) => {
|
|
69
|
+
cleanupSignalForwarding();
|
|
70
|
+
if (code === 0) {
|
|
71
|
+
resolve();
|
|
72
|
+
} else {
|
|
73
|
+
reject(new Error(`stkxp serve child process exited with code ${code}`));
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function runServeCommand({ esUrl, esUser, esPassword, esCaPath, esInsecure, port, host }) {
|
|
80
|
+
const runnerScript = path.join(CLI_ROOT, "vendor", "dist-server", "entrypoints", "team-runner.js");
|
|
81
|
+
const env = buildServeEnv({ esUrl, esUser, esPassword, esCaPath, esInsecure, port, host });
|
|
82
|
+
return spawnForeground(process.execPath, [resolveTsxCli(), runnerScript], { env });
|
|
83
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// packages/cli/src/serve.test.mjs
|
|
2
|
+
import { describe, it, expect, afterEach } from "vitest";
|
|
3
|
+
import { spawnForeground, buildServeEnv, resolveTsxCli } from "./serve.mjs";
|
|
4
|
+
|
|
5
|
+
describe("resolveTsxCli", () => {
|
|
6
|
+
it("resolves tsx's CLI entry point as a real file path (no node_modules/.bin shim)", () => {
|
|
7
|
+
const resolved = resolveTsxCli();
|
|
8
|
+
expect(resolved).toMatch(/tsx[\\/]dist[\\/]cli\.mjs$/);
|
|
9
|
+
expect(resolved).not.toMatch(/node_modules[\\/]\.bin/);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe("buildServeEnv", () => {
|
|
14
|
+
it("maps target-ES options to the ELASTICSEARCH_*/TEAM_RUNNER_* env vars team-runner.ts reads", () => {
|
|
15
|
+
expect(
|
|
16
|
+
buildServeEnv({ esUrl: "https://es:9200", esUser: "elastic", esPassword: "pw", port: 8081, host: "0.0.0.0" }),
|
|
17
|
+
).toEqual({
|
|
18
|
+
ELASTICSEARCH_HOST: "https://es:9200",
|
|
19
|
+
ELASTICSEARCH_USER: "elastic",
|
|
20
|
+
ELASTICSEARCH_PASSWORD: "pw",
|
|
21
|
+
ELASTICSEARCH_TLS_REJECT_UNAUTHORIZED: "true",
|
|
22
|
+
TEAM_RUNNER_PORT: "8081",
|
|
23
|
+
TEAM_RUNNER_HOST: "0.0.0.0",
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("only disables TLS verification when esInsecure is explicitly true", () => {
|
|
28
|
+
const env = buildServeEnv({ esUrl: "x", esUser: "e", esPassword: "p", esInsecure: true, port: 1, host: "h" });
|
|
29
|
+
expect(env.ELASTICSEARCH_TLS_REJECT_UNAUTHORIZED).toBe("false");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("includes ELASTICSEARCH_CA_PATH only when esCaPath is given", () => {
|
|
33
|
+
expect(buildServeEnv({ esUrl: "x", esUser: "e", esPassword: "p", port: 1, host: "h" })).not.toHaveProperty(
|
|
34
|
+
"ELASTICSEARCH_CA_PATH",
|
|
35
|
+
);
|
|
36
|
+
expect(
|
|
37
|
+
buildServeEnv({ esUrl: "x", esUser: "e", esPassword: "p", esCaPath: "/ca.pem", port: 1, host: "h" }),
|
|
38
|
+
).toHaveProperty("ELASTICSEARCH_CA_PATH", "/ca.pem");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("spawnForeground", () => {
|
|
43
|
+
let spawnedChildren = [];
|
|
44
|
+
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
for (const child of spawnedChildren) {
|
|
47
|
+
if (!child.killed) child.kill();
|
|
48
|
+
}
|
|
49
|
+
spawnedChildren = [];
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("resolves once the child exits cleanly (code 0)", async () => {
|
|
53
|
+
const result = await spawnForeground("node", ["-e", "process.exit(0)"], {
|
|
54
|
+
onSpawn: (c) => spawnedChildren.push(c),
|
|
55
|
+
});
|
|
56
|
+
expect(result).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("rejects when the child exits with a non-zero code", async () => {
|
|
60
|
+
await expect(
|
|
61
|
+
spawnForeground("node", ["-e", "process.exit(3)"], { onSpawn: (c) => spawnedChildren.push(c) }),
|
|
62
|
+
).rejects.toThrow(/exited with code 3/);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("passes the given env through to the child", async () => {
|
|
66
|
+
const script = `process.exit(process.env.STKXP_TEST_VAR === "marker" ? 0 : 7)`;
|
|
67
|
+
await expect(
|
|
68
|
+
spawnForeground("node", ["-e", script], {
|
|
69
|
+
env: { STKXP_TEST_VAR: "marker" },
|
|
70
|
+
onSpawn: (c) => spawnedChildren.push(c),
|
|
71
|
+
}),
|
|
72
|
+
).resolves.toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("forwards SIGTERM sent to this process to the child", async () => {
|
|
76
|
+
const script = `
|
|
77
|
+
process.on("SIGTERM", () => process.exit(0));
|
|
78
|
+
setInterval(() => {}, 1000);
|
|
79
|
+
`;
|
|
80
|
+
let childHandle;
|
|
81
|
+
const resultPromise = spawnForeground("node", ["-e", script], {
|
|
82
|
+
onSpawn: (c) => { childHandle = c; spawnedChildren.push(c); },
|
|
83
|
+
});
|
|
84
|
+
// Give the child a moment to install its SIGTERM handler before we send one.
|
|
85
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
86
|
+
process.emit("SIGTERM");
|
|
87
|
+
await Promise.race([
|
|
88
|
+
resultPromise,
|
|
89
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timed out waiting for forwarded SIGTERM")), 3000)),
|
|
90
|
+
]);
|
|
91
|
+
expect(childHandle.exitCode).toBe(0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{OpenAPIRegistry as p,OpenApiGeneratorV3 as d,extendZodWithOpenApi as g}from"@asteasolutions/zod-to-openapi";import{z as l}from"zod";import{messages as i}from"./messages";import{BRAND_NAME as h}from"../core/app-config/branding";g(l);const c=(process.env.STKXP_APP_PUBLIC_URL||"https://localhost:3003").replace(/^https?:\/\//,"").replace(/\/$/,"");function y(){const s=new p;for(const n of i)s.register(n.name,n.schema);return new d(s.definitions).generateComponents()?.components?.schemas??{}}function f(s){return`${s.direction==="serverToClient"?"publish":"receive"}${s.name}`}function P(){const s=y(),t={},n={},o={};let r=0;for(const e of i){t[e.name]={name:e.name,title:e.summary,summary:e.summary,description:e.description,contentType:"application/json",payload:{schemaFormat:"application/vnd.oai.openapi+json;version=3.0.0",schema:s[e.name]??{type:"object"}},tags:e.tags?.map(a=>({name:a}))},n[e.name]={$ref:`#/components/messages/${e.name}`};const m=e.direction==="serverToClient"?"send":"receive";o[f(e)]={action:m,channel:{$ref:"#/channels/stream"},summary:e.summary,description:e.description,messages:[{$ref:`#/channels/stream/messages/${e.name}`}],tags:e.tags?.map(a=>({name:a}))},r++}return{doc:{asyncapi:"3.0.0",info:{title:`${h} App \u2014 WebSocket API`,version:"1.0.0",description:"Real-time streaming protocol used by the chat interface. Connect a WebSocket to `wss://"+c+"/?token=<JWT>` after logging in via `POST /api/auth/login`. Messages are JSON envelopes discriminated by a `type` field \u2014 only the message types declared in `server/asyncapi/messages.ts` appear in this spec."},servers:{main:{host:c,protocol:"wss",pathname:"/",description:"WebSocket chat handler. Authenticate with a `?token=<JWT>` query param."}},channels:{stream:{address:"/",title:"Chat stream",description:"Single WebSocket carrying both client\u2192server commands and server\u2192client streaming events. Messages are discriminated by the `type` field.",messages:n}},operations:o,components:{messages:t}},stats:{registered:r}}}export{P as buildAsyncApiDocument};
|