@aifabrix/builder 2.49.1 → 2.50.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/.cursor/process/README.md +9 -0
- package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +49 -0
- package/.cursor/rules/plan-rules/application-lifecycle.mdc +30 -0
- package/.cursor/rules/plan-rules/plan-frontmatter.mdc +35 -0
- package/.cursor/rules/plan-rules/plan-lifecycle.mdc +31 -0
- package/.cursor/rules/plan-rules/plan-validation-gate.mdc +34 -0
- package/.cursor/skills/README.md +1 -0
- package/.dockerignore +52 -0
- package/.eslintignore +22 -0
- package/README.md +2 -0
- package/bin/builder-api-cleanup.js +26 -0
- package/bin/builder-api-nest.js +10 -0
- package/bin/builder-api-spike.js +19 -0
- package/enterprise-knowledge/README.md +50 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +22 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +15 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +69 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +52 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +29 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +2 -0
- package/integration/README.md +81 -0
- package/integration/github/README.md +53 -0
- package/integration/github/application.json +21 -0
- package/integration/github/deploy.js +72 -0
- package/integration/github/env.template +11 -0
- package/integration/github/github-datasource-issue-comments.json +239 -0
- package/integration/github/github-datasource-issues.json +399 -0
- package/integration/github/github-datasource-repository.json +354 -0
- package/integration/github/github-deploy.json +1202 -0
- package/integration/github/github-system.json +82 -0
- package/integration/hubspot-test/README.md +1 -1
- package/jest.isolated-projects.js +31 -1
- package/jest.projects.js +87 -1
- package/lib/api/dev-server-https.js +1 -1
- package/lib/api/dev.api.js +1 -0
- package/lib/api/enterprise-knowledge.api.js +63 -0
- package/lib/api/evidence.api.js +172 -0
- package/lib/api/external-systems.api.js +8 -2
- package/lib/api/host-ops.api.js +69 -0
- package/lib/api/resource-types.api.js +1 -0
- package/lib/api/types/enterprise-knowledge.types.js +46 -0
- package/lib/api/types/evidence.types.js +67 -0
- package/lib/api/types/resource-types.types.js +2 -0
- package/lib/app/controller-application-filter.js +36 -0
- package/lib/app/deploy.js +1 -1
- package/lib/app/list-external-systems.js +130 -0
- package/lib/app/list.js +20 -8
- package/lib/app/run.js +3 -1
- package/lib/app/show-display.js +8 -3
- package/lib/app/show-online.js +178 -0
- package/lib/app/show.js +37 -88
- package/lib/build/builder-api-docker-staging.js +47 -0
- package/lib/build/miso-controller-npm-sdk-guard.js +2 -2
- package/lib/build/standard-docker-build.js +2 -0
- package/lib/certification/post-unified-cert-sync.js +4 -31
- package/lib/certification/sync-after-external-command.js +0 -1
- package/lib/certification/sync-system-certification.js +0 -3
- package/lib/channels/add-channel.js +40 -34
- package/lib/channels/approval-guides/chatgpt.js +33 -0
- package/lib/channels/approval-guides/credential-portal.js +38 -0
- package/lib/channels/approval-guides/index.js +110 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +34 -0
- package/lib/channels/approval-guides/slack.js +34 -0
- package/lib/channels/approval-guides/teams-bot.js +35 -0
- package/lib/channels/approval-guides/web-embed.js +32 -0
- package/lib/channels/channel-approval-guide.js +11 -0
- package/lib/channels/channel-artifact-generator.js +16 -4
- package/lib/channels/channel-audit.js +3 -0
- package/lib/channels/channel-auth-context.js +1 -1
- package/lib/channels/channel-description.js +59 -0
- package/lib/channels/channel-integration-generator.js +13 -230
- package/lib/channels/channel-integration-template.js +94 -0
- package/lib/channels/channel-runtime-resolver.js +43 -3
- package/lib/channels/channel-status-display.js +66 -26
- package/lib/channels/channel-targets.js +3 -3
- package/lib/cli/index.js +27 -3
- package/lib/cli/infra-guided.js +5 -1
- package/lib/cli/setup-app-external-create.js +111 -0
- package/lib/cli/setup-app.help.js +1 -1
- package/lib/cli/setup-app.js +38 -125
- package/lib/cli/setup-app.test-commands.js +26 -52
- package/lib/cli/setup-certification-commands.js +4 -4
- package/lib/cli/setup-certification.help.js +9 -9
- package/lib/cli/setup-dev-path-commands.js +24 -0
- package/lib/cli/setup-dev.js +115 -16
- package/lib/cli/setup-external-system-help.js +4 -6
- package/lib/cli/setup-external-system.js +58 -52
- package/lib/cli/setup-infra-up-builder-api-action.js +64 -0
- package/lib/cli/setup-infra-up-platform-action.js +3 -1
- package/lib/cli/setup-infra.js +15 -0
- package/lib/cli/setup-list.js +43 -0
- package/lib/cli/setup-utility-repair.js +26 -7
- package/lib/cli/setup-utility.js +5 -3
- package/lib/commands/app.js +15 -43
- package/lib/commands/channel-add-setup.js +110 -0
- package/lib/commands/channel.js +42 -8
- package/lib/commands/datasource-sync-display.js +96 -0
- package/lib/commands/datasource-sync-policy.js +210 -0
- package/lib/commands/datasource-test-trust-cli.js +6 -6
- package/lib/commands/datasource-unified-test-cli.js +2 -1
- package/lib/commands/datasource-unified-test-cli.options.js +33 -23
- package/lib/commands/deploy-gate-failure-details.js +163 -0
- package/lib/commands/deploy-gate-orchestrator.js +322 -0
- package/lib/commands/dev-cli-handlers.js +64 -61
- package/lib/commands/dev-host-ops-params.js +91 -0
- package/lib/commands/dev-host-ops-poll.js +111 -0
- package/lib/commands/dev-host-ops.js +252 -0
- package/lib/commands/dev-init.js +3 -1
- package/lib/commands/enterprise-knowledge.js +284 -0
- package/lib/commands/evidence-cli-leaves.js +250 -0
- package/lib/commands/evidence.js +51 -0
- package/lib/commands/governance-cli-shared.js +2 -2
- package/lib/commands/governance-command-action.js +2 -2
- package/lib/commands/governance-fixture-subjects.js +85 -0
- package/lib/commands/governance.js +1 -1
- package/lib/commands/lifecycle-command-action.js +2 -2
- package/lib/commands/lifecycle-external.js +3 -3
- package/lib/commands/manifest-cli-auth.js +29 -0
- package/lib/commands/manifest-cli-commands.js +170 -0
- package/lib/commands/manifest-cli-integration-path.js +63 -0
- package/lib/commands/manifest.js +21 -0
- package/lib/commands/protection-cli-leaves.js +3 -3
- package/lib/commands/repair-auth-apply.js +15 -1
- package/lib/commands/repair-authentications-454.js +169 -0
- package/lib/commands/repair-capability-openapi-warnings.js +126 -0
- package/lib/commands/repair-datasource-apply.js +135 -0
- package/lib/commands/repair-datasource-auto-rbac.js +62 -1
- package/lib/commands/repair-datasource-http-service-contract.js +239 -0
- package/lib/commands/repair-datasource-operation-security.js +180 -0
- package/lib/commands/repair-datasource-run.js +7 -2
- package/lib/commands/repair-datasource-sync-operations.js +177 -0
- package/lib/commands/repair-datasource-webhooks-sync-bridge.js +133 -0
- package/lib/commands/repair-datasource.js +12 -68
- package/lib/commands/repair-env-template.js +11 -1
- package/lib/commands/repair-external-run.js +121 -31
- package/lib/commands/repair-internal.js +1 -1
- package/lib/commands/repair-openapi-export.js +156 -0
- package/lib/commands/repair-openapi-sync.js +19 -2
- package/lib/commands/repair-orchestration-datasource-split.js +259 -0
- package/lib/commands/repair-persist.js +22 -1
- package/lib/commands/repair-rbac-platform-preset.js +204 -0
- package/lib/commands/repair-rbac-reader-roles.js +191 -0
- package/lib/commands/repair-rbac.js +163 -86
- package/lib/commands/repair-steps.js +83 -18
- package/lib/commands/repair-system-permissions.js +1 -0
- package/lib/commands/repair.js +1 -1
- package/lib/commands/resource-type.js +65 -26
- package/lib/commands/run-post-publish-data-sync.js +68 -0
- package/lib/commands/setup-modes.js +1 -1
- package/lib/commands/test-e2e-external.js +21 -8
- package/lib/commands/test-governance-cli-options.js +2 -2
- package/lib/commands/test-trust-cli-options.js +2 -2
- package/lib/commands/up-builder-api-bootstrap.js +71 -0
- package/lib/commands/up-builder-api-provision.js +241 -0
- package/lib/commands/up-builder-api.js +88 -0
- package/lib/commands/up-common.js +25 -1
- package/lib/commands/upload-credential-push-log.js +117 -0
- package/lib/commands/upload-data-sync-finalize.js +60 -0
- package/lib/commands/upload-probe.js +66 -0
- package/lib/commands/upload-publish-context.js +4 -1
- package/lib/commands/upload-sidecar-followups.js +55 -27
- package/lib/commands/upload.js +116 -157
- package/lib/commands/verify-governance-combined-external.js +1 -1
- package/lib/commands/verify-governance-db.js +2 -2
- package/lib/commands/verify-operations-command-action.js +2 -2
- package/lib/commands/verify-operations-step-plan.js +2 -2
- package/lib/commands/verify-operations-steps.js +2 -2
- package/lib/commands/verify-trust-command-action.js +1 -1
- package/lib/commands/wizard-core.js +1 -1
- package/lib/commands/wizard-headless.js +2 -1
- package/lib/core/admin-secrets.js +2 -6
- package/lib/core/secrets-env-content.js +10 -4
- package/lib/core/secrets-env-write.js +2 -13
- package/lib/datasource/agent-trust-run.js +3 -3
- package/lib/datasource/deploy.js +3 -1
- package/lib/datasource/test-e2e.js +6 -1
- package/lib/datasource/unified-validation-run-body.js +4 -1
- package/lib/datasource/unified-validation-run.js +1 -1
- package/lib/deployment/deploy-poll-ui.js +73 -12
- package/lib/deployment/deployer-poll-run.js +113 -0
- package/lib/deployment/deployer.js +17 -87
- package/lib/evidence/dataplane-context.js +21 -0
- package/lib/evidence/evidence-display.js +78 -0
- package/lib/evidence/evidence-service.js +392 -0
- package/lib/external-system/deploy.js +290 -112
- package/lib/external-system/download.js +7 -3
- package/lib/external-system/test-execution.js +1 -1
- package/lib/external-system/test-system-level.js +8 -10
- package/lib/external-system/test.js +12 -6
- package/lib/generator/deploy-script.js +73 -0
- package/lib/generator/external.js +2 -1
- package/lib/generator/index.js +17 -2
- package/lib/generator/wizard.js +3 -36
- package/lib/internal/fs-real-sync.js +22 -1
- package/lib/internal/node-fs.js +2 -0
- package/lib/lifecycle/lifecycle-governance-options.js +1 -1
- package/lib/lifecycle/verify-step-progress.js +1 -1
- package/lib/programmatic/access-log.js +26 -0
- package/lib/programmatic/auth-config.js +44 -0
- package/lib/programmatic/bearer-auth.js +176 -0
- package/lib/programmatic/builder-api-request.js +175 -0
- package/lib/programmatic/builder-api-route-dispatch.js +82 -0
- package/lib/programmatic/builder-api-runtime-config.js +42 -0
- package/lib/programmatic/builder-api-server.js +230 -0
- package/lib/programmatic/builder-help-authentication-catalog.js +282 -0
- package/lib/programmatic/builder-help-connected-system-ui.js +266 -0
- package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +60 -0
- package/lib/programmatic/builder-help-envelope.js +36 -0
- package/lib/programmatic/builder-help-fixtures.js +200 -0
- package/lib/programmatic/builder-help-governance.js +172 -0
- package/lib/programmatic/builder-help-schema-catalog.js +92 -0
- package/lib/programmatic/builder-help.js +361 -0
- package/lib/programmatic/capability-registry.js +77 -0
- package/lib/programmatic/command-options.js +32 -0
- package/lib/programmatic/enterprise-mcp-client.js +98 -0
- package/lib/programmatic/http-problem-details.js +99 -0
- package/lib/programmatic/http-route-match.js +40 -0
- package/lib/programmatic/idempotency-cache.js +69 -0
- package/lib/programmatic/index.js +53 -0
- package/lib/programmatic/integration-path-scope.js +39 -0
- package/lib/programmatic/log-redaction.js +66 -0
- package/lib/programmatic/manifest-get-section.js +146 -0
- package/lib/programmatic/manifest-patch-section.js +252 -0
- package/lib/programmatic/manifest-repair.js +122 -0
- package/lib/programmatic/manifest-section-dependency-graph.js +160 -0
- package/lib/programmatic/manifest-section-io.js +225 -0
- package/lib/programmatic/manifest-section-quality.js +171 -0
- package/lib/programmatic/manifest-section-registry-data.js +269 -0
- package/lib/programmatic/manifest-section-registry.js +205 -0
- package/lib/programmatic/nest-http-bridge.js +34 -0
- package/lib/programmatic/openapi-component-schemas.js +68 -0
- package/lib/programmatic/openapi-description-enricher.js +117 -0
- package/lib/programmatic/openapi-descriptions.js +190 -0
- package/lib/programmatic/openapi-docs-serving.js +123 -0
- package/lib/programmatic/openapi-help-schemas.js +63 -0
- package/lib/programmatic/openapi-manifest-schemas.js +141 -0
- package/lib/programmatic/openapi-operation-bindings.js +274 -0
- package/lib/programmatic/openapi-request-schemas.js +155 -0
- package/lib/programmatic/openapi-result-schemas.js +476 -0
- package/lib/programmatic/openapi-schema-descriptions-certify.js +139 -0
- package/lib/programmatic/openapi-schema-descriptions-core.js +159 -0
- package/lib/programmatic/openapi-schema-descriptions-help.js +40 -0
- package/lib/programmatic/openapi-schema-descriptions-manifest.js +143 -0
- package/lib/programmatic/openapi-schema-descriptions-mcp.js +118 -0
- package/lib/programmatic/openapi-schema-descriptions-operations.js +281 -0
- package/lib/programmatic/openapi-schema-helpers.js +93 -0
- package/lib/programmatic/openapi-spec.js +203 -0
- package/lib/programmatic/orchestration-openapi-meta.js +159 -0
- package/lib/programmatic/platform-rbac-catalog.js +90 -0
- package/lib/programmatic/request-timeout.js +53 -0
- package/lib/programmatic/route-handler-map.js +143 -0
- package/lib/programmatic/route-handlers-context.js +29 -0
- package/lib/programmatic/route-handlers.js +33 -0
- package/lib/programmatic/run-certify.js +57 -0
- package/lib/programmatic/run-enterprise-mcp.js +32 -0
- package/lib/programmatic/run-lifecycle.js +29 -0
- package/lib/programmatic/run-repair.js +41 -0
- package/lib/programmatic/run-repository-emcp.js +54 -0
- package/lib/programmatic/run-template-workspace.js +61 -0
- package/lib/programmatic/run-test.js +49 -0
- package/lib/programmatic/run-upload.js +63 -0
- package/lib/programmatic/run-validate.js +53 -0
- package/lib/programmatic/run-wizard.js +40 -0
- package/lib/programmatic/system-key.js +48 -0
- package/lib/programmatic/wizard-config-normalize.js +118 -0
- package/lib/programmatic/workspace-cleanup.js +128 -0
- package/lib/programmatic/workspace-context.js +145 -0
- package/lib/programmatic/workspace-lock.js +75 -0
- package/lib/programmatic/workspace-meta.js +64 -0
- package/lib/programmatic/workspace-ops.js +149 -0
- package/lib/protection/run-commands-upload-sync.js +35 -0
- package/lib/protection/run-commands.js +2 -20
- package/lib/protection/upload-batch.js +11 -7
- package/lib/resolvers/resource-type-file.js +22 -0
- package/lib/schema/external-datasource.schema.json +161 -1
- package/lib/schema/external-system.schema.json +242 -4
- package/lib/schema/flag-map-validation-run.json +3 -0
- package/lib/schema/type/credential-field-registry.json +2 -2
- package/lib/schema/type/document-storage.json +9 -0
- package/lib/utils/agent-trust-run-display.js +1 -1
- package/lib/utils/app-path-resolve.js +168 -0
- package/lib/utils/authentication-env-template.js +222 -0
- package/lib/utils/cli-sync-options.js +7 -11
- package/lib/utils/cli-utils.js +4 -0
- package/lib/utils/cli-workspace-options.js +29 -0
- package/lib/utils/compose-generate-docker-compose.js +102 -0
- package/lib/utils/configuration-env-resolver.js +203 -27
- package/lib/utils/datasource-test-run-certificate-tty.js +28 -2
- package/lib/utils/datasource-test-run-certification-debug.js +130 -0
- package/lib/utils/datasource-test-run-debug-display.js +2 -0
- package/lib/utils/datasource-test-run-debug-slice.js +7 -0
- package/lib/utils/datasource-test-run-display.js +2 -1
- package/lib/utils/dev-init-ssh-merge.js +165 -23
- package/lib/utils/dev-pin-share-instructions.js +110 -0
- package/lib/utils/dev-ssh-config-helper.js +177 -33
- package/lib/utils/enterprise-knowledge-paths.js +142 -0
- package/lib/utils/env-copy.js +2 -1
- package/lib/utils/env-dotenv-format.js +103 -0
- package/lib/utils/external-env-template.js +4 -1
- package/lib/utils/external-system-display.js +5 -1
- package/lib/utils/external-system-readiness-compact-blocks.js +221 -0
- package/lib/utils/external-system-readiness-compact-display.js +324 -0
- package/lib/utils/external-system-readiness-core.js +16 -0
- package/lib/utils/external-system-readiness-deploy-display.js +29 -11
- package/lib/utils/external-system-readiness-display-internals.js +3 -1
- package/lib/utils/external-system-readiness-display.js +20 -30
- package/lib/utils/external-system-system-test-tty-certification.js +135 -0
- package/lib/utils/external-system-system-test-tty.js +5 -41
- package/lib/utils/help-builder.js +6 -1
- package/lib/utils/host-ops-job-labels.js +236 -0
- package/lib/utils/host-ops-job-result.js +61 -0
- package/lib/utils/host-ops-poll-ui.js +163 -0
- package/lib/utils/integration-path-resolve.js +112 -0
- package/lib/utils/paths-reload-source.js +148 -0
- package/lib/utils/paths-system-builder-keys.js +25 -0
- package/lib/utils/paths.js +151 -26
- package/lib/utils/runtime-configuration-values.js +64 -2
- package/lib/utils/secrets-helpers.js +5 -1
- package/lib/utils/ssh-known-hosts.js +130 -0
- package/lib/utils/test-target-cli-options.js +75 -0
- package/lib/utils/upload-sync-options.js +4 -0
- package/lib/utils/validation-run-request.js +11 -2
- package/lib/validation/external-manifest-validator.js +11 -1
- package/lib/validation/openapi-contract-surface-validator.js +426 -0
- package/lib/validation/openapi-contract-vendor-validation.js +238 -0
- package/lib/validation/validate-external-file.js +160 -0
- package/lib/validation/validate.js +6 -117
- package/package.json +46 -29
- package/packages/builder-api/README.md +120 -0
- package/packages/builder-api/package.json +30 -0
- package/packages/builder-api/src/app.module.ts +7 -0
- package/packages/builder-api/src/auth/auth.module.ts +5 -0
- package/packages/builder-api/src/external-system/external-system.module.ts +5 -0
- package/packages/builder-api/src/main.ts +16 -0
- package/packages/builder-api/tsconfig.json +15 -0
- package/scripts/check-builder-api-architecture-grep.js +79 -0
- package/scripts/docker_image_content_gate.js +47 -0
- package/scripts/docker_image_content_gate.sh +5 -0
- package/scripts/export-builder-api-evidence.js +262 -0
- package/scripts/lib/builder-api-docker-staging-copy.js +60 -0
- package/scripts/lib/builder-api-docker-staging-core.js +183 -0
- package/scripts/lib/docker-image-content-gate-core.js +166 -0
- package/scripts/lib/plan-actor.js +109 -0
- package/scripts/lib/plan-config.js +20 -0
- package/scripts/lib/plan-gates.js +154 -0
- package/scripts/lib/plan-meta.js +104 -0
- package/scripts/lib/plan-parse.js +162 -0
- package/scripts/lib/plan-prevalidate-gates.js +326 -0
- package/scripts/lib/plan-run-core.js +125 -0
- package/scripts/lib/plan-run-report.js +108 -0
- package/scripts/plan-approve.js +24 -0
- package/scripts/plan-archive.js +49 -0
- package/scripts/plan-run.js +13 -0
- package/scripts/plan-set-actor.js +21 -0
- package/scripts/plan-validate.js +80 -0
- package/scripts/pnpm/af.mjs +110 -0
- package/scripts/pnpm/check-quiet.mjs +32 -0
- package/scripts/pnpm/dev-install.mjs +29 -0
- package/scripts/pnpm/dev-reload.mjs +18 -0
- package/scripts/pnpm/help.mjs +55 -0
- package/scripts/pnpm/lib/dev-reload-core.mjs +189 -0
- package/scripts/pnpm/lib/dev-reload-log-capture.mjs +67 -0
- package/scripts/pnpm/lib/dev-reload-log-utils.mjs +32 -0
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +124 -0
- package/scripts/pnpm/lib/resolve-app-url.mjs +183 -0
- package/scripts/pnpm/lib/spinner.mjs +42 -0
- package/scripts/stage_builder_api_for_docker.js +65 -0
- package/scripts/sync-builder-api-template.js +44 -0
- package/templates/README.md +3 -0
- package/templates/applications/builder-api/Dockerfile +38 -0
- package/templates/applications/builder-api/application.yaml +75 -0
- package/templates/applications/builder-api/env.template +48 -0
- package/templates/applications/dataplane/application.yaml +1 -1
- package/templates/applications/dataplane/env.template +10 -6
- package/templates/applications/dataplane/rbac.yaml +21 -1
- package/templates/applications/miso-controller/application.yaml +1 -1
- package/templates/applications/miso-controller/env.template +1 -3
- package/templates/channels/README.md +18 -0
- package/templates/channels/ai-fabrix-icon.jpg +0 -0
- package/templates/channels/chatgpt/install.template.md.hbs +21 -24
- package/templates/channels/chatgpt/integration/README.md +11 -0
- package/templates/channels/chatgpt/integration/application.json +15 -0
- package/templates/channels/chatgpt/integration/chatgpt-system.json +29 -0
- package/templates/channels/chatgpt/integration/env.template +4 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +20 -25
- package/templates/channels/microsoft-copilot/integration/README.md +11 -0
- package/templates/channels/microsoft-copilot/integration/application.json +15 -0
- package/templates/channels/microsoft-copilot/integration/env.template +6 -0
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +34 -0
- package/templates/channels/slack/install.template.md.hbs +48 -18
- package/templates/channels/slack/integration/README.md +38 -0
- package/templates/channels/slack/integration/application.json +18 -0
- package/templates/channels/slack/integration/env.template +29 -0
- package/templates/channels/slack/integration/slack-datasource-conversations.json +226 -0
- package/templates/channels/slack/integration/slack-datasource-messages.json +269 -0
- package/templates/channels/slack/integration/slack-system.json +86 -0
- package/templates/channels/slack/manifest.template.json.hbs +20 -10
- package/templates/channels/teams-bot/install.template.md.hbs +31 -17
- package/templates/channels/teams-bot/integration/README.md +18 -0
- package/templates/channels/teams-bot/integration/application.json +17 -0
- package/templates/channels/teams-bot/integration/env.template +5 -0
- package/templates/channels/teams-bot/integration/teams-bot-system.json +55 -0
- package/templates/channels/teams-bot/manifest.template.json.hbs +27 -0
- package/templates/channels/web-embed/install.template.md.hbs +16 -26
- package/templates/channels/web-embed/integration/README.md +11 -0
- package/templates/channels/web-embed/integration/application.json +15 -0
- package/templates/channels/web-embed/integration/env.template +4 -0
- package/templates/channels/web-embed/integration/web-embed-system.json +29 -0
- package/templates/openapi/redoc_page.html +86 -0
- package/templates/python/docker-compose.hbs +11 -0
- package/templates/python/requirements.txt +1 -1
- package/templates/typescript/docker-compose.hbs +11 -0
- package/lib/certification/cli-cert-sync-skip.js +0 -21
|
@@ -16,6 +16,8 @@ const {
|
|
|
16
16
|
validateDevGroups,
|
|
17
17
|
augmentDevUserGroupsServerError
|
|
18
18
|
} = require('../utils/dev-user-groups');
|
|
19
|
+
const { handleProvisionDevUser, handleRemoveDevUser } = require('./dev-host-ops');
|
|
20
|
+
const { logDevPinShareInstructions } = require('../utils/dev-pin-share-instructions');
|
|
19
21
|
|
|
20
22
|
const REMOTE_NOT_CONFIGURED_MSG = 'Remote server is not configured. Set remote-server and run "aifabrix dev init" first.';
|
|
21
23
|
|
|
@@ -26,6 +28,19 @@ const CERT_WIDTH = 10;
|
|
|
26
28
|
const UNTIL_WIDTH = 22; // 2026-03-20T17:31:14
|
|
27
29
|
const TABLE_SEPARATOR_LENGTH = 130;
|
|
28
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Normalize numeric developer id for comparison (e.g. 3 → 03).
|
|
33
|
+
* @param {string} id - Developer ID
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
36
|
+
function normalizeDeveloperIdForCompare(id) {
|
|
37
|
+
const trimmed = String(id ?? '').trim();
|
|
38
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
39
|
+
return trimmed;
|
|
40
|
+
}
|
|
41
|
+
return String(parseInt(trimmed, 10)).padStart(2, '0');
|
|
42
|
+
}
|
|
43
|
+
|
|
29
44
|
/**
|
|
30
45
|
* Format certificate validity end for display (e.g. 2026-03-20T17:31:14.000Z -> 2026-03-20T17:31:14).
|
|
31
46
|
* @param {string} iso - ISO 8601 date string
|
|
@@ -91,6 +106,10 @@ async function handleDevAdd(options) {
|
|
|
91
106
|
groups
|
|
92
107
|
}, auth.serverCaPem || undefined);
|
|
93
108
|
logger.log(formatSuccessLine(`Developer ${user.id} created. Use "aifabrix dev pin ${user.id}" to create a PIN for onboarding.`));
|
|
109
|
+
const noProvision = options.noProvision || options['no-provision'];
|
|
110
|
+
if (!noProvision) {
|
|
111
|
+
await handleProvisionDevUser(user.id, options);
|
|
112
|
+
}
|
|
94
113
|
} catch (err) {
|
|
95
114
|
augmentDevUserGroupsServerError(err, groups);
|
|
96
115
|
throw err;
|
|
@@ -131,64 +150,6 @@ async function handleDevUpdate(developerId, options) {
|
|
|
131
150
|
}
|
|
132
151
|
}
|
|
133
152
|
|
|
134
|
-
function logPinHostsVariantLines(baseInit, id, hostsIp) {
|
|
135
|
-
logger.log(
|
|
136
|
-
chalk.cyan('2) Hosts file / administrator')
|
|
137
|
-
+ chalk.gray(
|
|
138
|
-
' — use when the hostname does not resolve and your organisation does not publish DNS for it. '
|
|
139
|
-
+ 'Run in an elevated terminal so the hosts file can be updated, or add the entry manually:'
|
|
140
|
-
)
|
|
141
|
-
);
|
|
142
|
-
if (hostsIp) {
|
|
143
|
-
logger.log(` ${baseInit} --add-hosts --hosts-ip ${hostsIp}`);
|
|
144
|
-
} else {
|
|
145
|
-
logger.log(` ${baseInit} --add-hosts --hosts-ip <server-LAN-IPv4>`);
|
|
146
|
-
logger.log(
|
|
147
|
-
chalk.gray(
|
|
148
|
-
` Replace <server-LAN-IPv4> with the Builder Server IPv4, or re-run: aifabrix dev pin ${id} --hosts-ip <ip>`
|
|
149
|
-
)
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Log copy-paste dev init commands for the developer (standard vs hosts-file).
|
|
156
|
-
* @param {Object} p
|
|
157
|
-
* @param {string} p.id - Developer ID
|
|
158
|
-
* @param {string} p.serverUrl - Builder Server base URL
|
|
159
|
-
* @param {string} p.pin - One-time PIN
|
|
160
|
-
* @param {string} p.expiresAt - PIN expiry (API string)
|
|
161
|
-
* @param {string} [p.hostsIp] - Optional IPv4 for the hosts variant
|
|
162
|
-
* @returns {void}
|
|
163
|
-
*/
|
|
164
|
-
function logDevPinShareInstructions(p) {
|
|
165
|
-
const { id, serverUrl, pin, expiresAt, hostsIp } = p;
|
|
166
|
-
const baseInit = `aifabrix dev init --developer-id ${id} --server ${serverUrl} --pin ${pin}`;
|
|
167
|
-
const pinOnly = `aifabrix dev init --pin ${pin}`;
|
|
168
|
-
logger.log(formatSuccessLine(`PIN created for ${id}, expires ${expiresAt}.`));
|
|
169
|
-
logger.log('');
|
|
170
|
-
logger.log(
|
|
171
|
-
chalk.bold('Share with the developer — they run one command (the PIN is one-time):')
|
|
172
|
-
);
|
|
173
|
-
logger.log('');
|
|
174
|
-
logger.log(
|
|
175
|
-
chalk.cyan('1) Standard')
|
|
176
|
-
+ chalk.gray(' — use when this machine can resolve the server hostname (DNS or hosts already set):')
|
|
177
|
-
);
|
|
178
|
-
logger.log(` ${baseInit}`);
|
|
179
|
-
logger.log('');
|
|
180
|
-
logPinHostsVariantLines(baseInit, id, hostsIp);
|
|
181
|
-
logger.log('');
|
|
182
|
-
logger.log(
|
|
183
|
-
chalk.cyan('3) Config already has remote-server + developer-id')
|
|
184
|
-
+ chalk.gray(
|
|
185
|
-
' — e.g. second machine / SSH session after settings were merged; same onboarding, PIN only:'
|
|
186
|
-
)
|
|
187
|
-
);
|
|
188
|
-
logger.log(` ${pinOnly}`);
|
|
189
|
-
logger.log('');
|
|
190
|
-
}
|
|
191
|
-
|
|
192
153
|
/**
|
|
193
154
|
* Handle dev pin – create/regenerate PIN (remote only).
|
|
194
155
|
* @param {string} [developerId] - Developer ID (optional; uses config if omitted)
|
|
@@ -222,18 +183,60 @@ async function handleDevPin(developerId, options = {}) {
|
|
|
222
183
|
});
|
|
223
184
|
}
|
|
224
185
|
|
|
186
|
+
/**
|
|
187
|
+
* @param {string} question
|
|
188
|
+
* @returns {Promise<boolean>}
|
|
189
|
+
*/
|
|
190
|
+
async function promptYesNo(question) {
|
|
191
|
+
if (!process.stdin.isTTY) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
const readline = require('readline');
|
|
195
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
196
|
+
return new Promise((resolve) => {
|
|
197
|
+
rl.question(`${question} [y/N] `, (answer) => {
|
|
198
|
+
rl.close();
|
|
199
|
+
resolve(/^y(es)?$/i.test(String(answer || '').trim()));
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
225
204
|
/**
|
|
226
205
|
* Handle dev delete – remove developer (remote only).
|
|
206
|
+
* Default: full host removal via host-ops. Use --db-only for API-only delete.
|
|
227
207
|
* @param {string} developerId - Developer ID
|
|
208
|
+
* @param {Object} [options] - Commander options
|
|
228
209
|
* @returns {Promise<void>}
|
|
229
210
|
*/
|
|
230
|
-
async function handleDevDelete(developerId) {
|
|
211
|
+
async function handleDevDelete(developerId, options = {}) {
|
|
231
212
|
const auth = await getRemoteDevAuth();
|
|
232
213
|
if (!auth) throw new Error(REMOTE_NOT_CONFIGURED_MSG);
|
|
233
214
|
const id = developerId;
|
|
234
215
|
if (!id) throw new Error('Developer ID is required (positional argument or --developer-id).');
|
|
235
|
-
|
|
236
|
-
|
|
216
|
+
const actorId = await config.getDeveloperId();
|
|
217
|
+
if (
|
|
218
|
+
actorId &&
|
|
219
|
+
normalizeDeveloperIdForCompare(actorId) === normalizeDeveloperIdForCompare(id)
|
|
220
|
+
) {
|
|
221
|
+
throw new Error('You cannot delete your own developer account.');
|
|
222
|
+
}
|
|
223
|
+
const dbOnly = options.dbOnly || options['db-only'];
|
|
224
|
+
if (dbOnly) {
|
|
225
|
+
await devApi.deleteUser(auth.serverUrl, auth.clientCertPem, id, auth.serverCaPem || undefined);
|
|
226
|
+
logger.log(formatSuccessLine(`Developer ${id} removed from server database.`));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const assumeYes = options.yes || options.y;
|
|
230
|
+
if (!assumeYes) {
|
|
231
|
+
const ok = await promptYesNo(
|
|
232
|
+
`Remove developer ${id} from host and server (containers, OS user, database)?`
|
|
233
|
+
);
|
|
234
|
+
if (!ok) {
|
|
235
|
+
logger.log(chalk.gray('Cancelled.'));
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
await handleRemoveDevUser(id, { ...options, developerId: id });
|
|
237
240
|
}
|
|
238
241
|
|
|
239
242
|
module.exports = {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Map Commander options to host-ops job params
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {Object} options
|
|
9
|
+
* @param {string[]} keys
|
|
10
|
+
* @returns {string|undefined}
|
|
11
|
+
*/
|
|
12
|
+
function firstOption(options, ...keys) {
|
|
13
|
+
for (const key of keys) {
|
|
14
|
+
const value = options[key];
|
|
15
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {Object} params
|
|
24
|
+
* @param {Object} options
|
|
25
|
+
* @param {Array<[string, ...string[]]>} mappings
|
|
26
|
+
*/
|
|
27
|
+
function assignStringParams(params, options, mappings) {
|
|
28
|
+
for (const [paramKey, ...optionKeys] of mappings) {
|
|
29
|
+
const value = firstOption(options, ...optionKeys);
|
|
30
|
+
if (value !== undefined) {
|
|
31
|
+
params[paramKey] = value;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {Object} params
|
|
38
|
+
* @param {Object} options
|
|
39
|
+
* @param {Array<[string, ...string[]]>} mappings
|
|
40
|
+
*/
|
|
41
|
+
function assignFlagParams(params, options, mappings) {
|
|
42
|
+
for (const [paramKey, ...optionKeys] of mappings) {
|
|
43
|
+
if (optionKeys.some((k) => Boolean(options[k]))) {
|
|
44
|
+
params[paramKey] = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const STRING_PARAM_MAPPINGS = [
|
|
50
|
+
['include', 'include'],
|
|
51
|
+
['exclude', 'exclude'],
|
|
52
|
+
['builderVersion', 'builderVersion', 'builder-version'],
|
|
53
|
+
['adminEmail', 'adminEmail', 'admin-email'],
|
|
54
|
+
['adminPassword', 'adminPassword', 'admin-password'],
|
|
55
|
+
['platform', 'platform'],
|
|
56
|
+
['installation', 'installation']
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
const FLAG_PARAM_MAPPINGS = [
|
|
60
|
+
['skipCert', 'skipCert', 'skip-cert'],
|
|
61
|
+
['skipPlatform', 'skipPlatform', 'skip-platform'],
|
|
62
|
+
['skipCli', 'skipCli', 'skip-cli'],
|
|
63
|
+
['check', 'check'],
|
|
64
|
+
['failOnBlocked', 'failOnBlocked']
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Build job params from Commander options.
|
|
69
|
+
* @param {Object} options
|
|
70
|
+
* @param {string} [developerId]
|
|
71
|
+
* @returns {Object}
|
|
72
|
+
*/
|
|
73
|
+
function buildJobParams(options, developerId) {
|
|
74
|
+
const params = {};
|
|
75
|
+
const id = developerId || firstOption(options, 'developerId', 'developer-id');
|
|
76
|
+
if (id) {
|
|
77
|
+
params.developerId = String(id).trim();
|
|
78
|
+
}
|
|
79
|
+
assignStringParams(params, options, STRING_PARAM_MAPPINGS);
|
|
80
|
+
assignFlagParams(params, options, FLAG_PARAM_MAPPINGS);
|
|
81
|
+
const timeoutMinutes = firstOption(options, 'timeoutMinutes', 'timeout-minutes');
|
|
82
|
+
if (timeoutMinutes) {
|
|
83
|
+
params.timeoutMinutes = parseInt(timeoutMinutes, 10);
|
|
84
|
+
}
|
|
85
|
+
return params;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
buildJobParams,
|
|
90
|
+
firstOption
|
|
91
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Host-ops job polling loop
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const hostOpsApi = require('../api/host-ops.api');
|
|
8
|
+
const { assertHostOpsJobSucceeded } = require('../utils/host-ops-job-result');
|
|
9
|
+
|
|
10
|
+
const POLL_INTERVAL_MS = 3000;
|
|
11
|
+
const POLL_TIMEOUT_MS = 3 * 60 * 60 * 1000;
|
|
12
|
+
const TRANSIENT_HTTP_STATUSES = new Set([502, 503, 504]);
|
|
13
|
+
/** Allow ~3 min of consecutive gateway errors (container restart during remove-dev-user). */
|
|
14
|
+
const MAX_TRANSIENT_POLL_ERRORS = 60;
|
|
15
|
+
|
|
16
|
+
function sleep(ms) {
|
|
17
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {Error} err
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
24
|
+
function isTransientHostOpsPollError(err) {
|
|
25
|
+
return Boolean(err && TRANSIENT_HTTP_STATUSES.has(err.status));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {Error} err
|
|
30
|
+
* @param {string} jobId
|
|
31
|
+
* @returns {Error}
|
|
32
|
+
*/
|
|
33
|
+
function enhanceTransientHostOpsPollError(err, jobId) {
|
|
34
|
+
const status = err && err.status;
|
|
35
|
+
const base =
|
|
36
|
+
status === 502
|
|
37
|
+
? 'Builder server returned Bad Gateway while waiting for the host job.'
|
|
38
|
+
: `Builder server returned HTTP ${status} while waiting for the host job.`;
|
|
39
|
+
const hint =
|
|
40
|
+
'The job may still be running on the host (common during platform teardown or container restart). ' +
|
|
41
|
+
'Wait 1–2 minutes, then run "aifabrix dev list" to verify. ' +
|
|
42
|
+
`Job id: ${jobId}`;
|
|
43
|
+
return new Error(`${base} ${hint}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {Object} auth
|
|
48
|
+
* @param {string} jobId
|
|
49
|
+
* @param {Object} pollUi
|
|
50
|
+
* @returns {Promise<Object>}
|
|
51
|
+
*/
|
|
52
|
+
async function fetchHostOpsJobWithRetry(auth, jobId, pollUi) {
|
|
53
|
+
const started = Date.now();
|
|
54
|
+
for (let attempt = 0; attempt <= MAX_TRANSIENT_POLL_ERRORS; attempt += 1) {
|
|
55
|
+
try {
|
|
56
|
+
return await hostOpsApi.getHostOpsJob(
|
|
57
|
+
auth.serverUrl,
|
|
58
|
+
auth.clientCertPem,
|
|
59
|
+
jobId,
|
|
60
|
+
auth.serverCaPem || undefined
|
|
61
|
+
);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
if (!isTransientHostOpsPollError(err)) {
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
if (attempt >= MAX_TRANSIENT_POLL_ERRORS) {
|
|
67
|
+
throw enhanceTransientHostOpsPollError(err, jobId);
|
|
68
|
+
}
|
|
69
|
+
if (pollUi && typeof pollUi.onTransientError === 'function') {
|
|
70
|
+
pollUi.onTransientError(err, Date.now() - started);
|
|
71
|
+
}
|
|
72
|
+
await sleep(POLL_INTERVAL_MS);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`Failed to fetch host-ops job ${jobId} after transient retries`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @param {Object} auth
|
|
80
|
+
* @param {string} jobId
|
|
81
|
+
* @param {Object} pollUi
|
|
82
|
+
* @param {boolean} json
|
|
83
|
+
* @returns {Promise<Object>}
|
|
84
|
+
*/
|
|
85
|
+
async function pollHostOpsJobUntilTerminal(auth, jobId, pollUi, json) {
|
|
86
|
+
const started = Date.now();
|
|
87
|
+
while (Date.now() - started < POLL_TIMEOUT_MS) {
|
|
88
|
+
const job = await fetchHostOpsJobWithRetry(auth, jobId, pollUi);
|
|
89
|
+
if (!json) {
|
|
90
|
+
pollUi.onPollProgress(job.status);
|
|
91
|
+
}
|
|
92
|
+
if (job.status === 'failed') {
|
|
93
|
+
throw new Error(job.error || `Host-ops job ${jobId} failed`);
|
|
94
|
+
}
|
|
95
|
+
if (job.status === 'completed') {
|
|
96
|
+
assertHostOpsJobSucceeded(job);
|
|
97
|
+
return job;
|
|
98
|
+
}
|
|
99
|
+
await sleep(POLL_INTERVAL_MS);
|
|
100
|
+
}
|
|
101
|
+
throw new Error(`Timed out waiting for host-ops job ${jobId}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
POLL_INTERVAL_MS,
|
|
106
|
+
POLL_TIMEOUT_MS,
|
|
107
|
+
isTransientHostOpsPollError,
|
|
108
|
+
enhanceTransientHostOpsPollError,
|
|
109
|
+
fetchHostOpsJobWithRetry,
|
|
110
|
+
pollHostOpsJobUntilTerminal
|
|
111
|
+
};
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Dev host-ops CLI handlers (platform-install, platform-update, etc.)
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const readline = require('readline');
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const logger = require('../utils/logger');
|
|
10
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
11
|
+
const { getRemoteDevAuth } = require('../utils/remote-dev-auth');
|
|
12
|
+
const { createHostOpsPollHandlers } = require('../utils/host-ops-poll-ui');
|
|
13
|
+
const { buildHostOpsActionLabel, resolveHostOpsTargetLabel } = require('../utils/host-ops-job-labels');
|
|
14
|
+
const { pollHostOpsJobUntilTerminal } = require('./dev-host-ops-poll');
|
|
15
|
+
const { buildJobParams } = require('./dev-host-ops-params');
|
|
16
|
+
const hostOpsApi = require('../api/host-ops.api');
|
|
17
|
+
const { assertHostOpsJobSucceeded } = require('../utils/host-ops-job-result');
|
|
18
|
+
|
|
19
|
+
const REMOTE_NOT_CONFIGURED_MSG =
|
|
20
|
+
'Remote server is not configured. Set remote-server and run "aifabrix dev init" first.';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} type
|
|
24
|
+
* @param {Object} params
|
|
25
|
+
* @param {Object} options
|
|
26
|
+
* @returns {Object}
|
|
27
|
+
*/
|
|
28
|
+
function buildHostOpsWaitOpts(type, params, options) {
|
|
29
|
+
return {
|
|
30
|
+
wait: options.wait !== false,
|
|
31
|
+
json: Boolean(options.json),
|
|
32
|
+
jobType: type,
|
|
33
|
+
targetLabel: resolveHostOpsTargetLabel(params),
|
|
34
|
+
params
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Poll host-ops job until terminal state.
|
|
40
|
+
* @param {Object} auth
|
|
41
|
+
* @param {string} jobId
|
|
42
|
+
* @param {Object} [opts]
|
|
43
|
+
* @param {boolean} [opts.wait=true]
|
|
44
|
+
* @param {boolean} [opts.json=false]
|
|
45
|
+
* @returns {Promise<Object>}
|
|
46
|
+
*/
|
|
47
|
+
async function waitForHostOpsJob(auth, jobId, opts = {}) {
|
|
48
|
+
const wait = opts.wait !== false;
|
|
49
|
+
const json = Boolean(opts.json);
|
|
50
|
+
if (!wait) {
|
|
51
|
+
return { jobId, status: 'pending' };
|
|
52
|
+
}
|
|
53
|
+
const pollContext = {
|
|
54
|
+
jobType: opts.jobType,
|
|
55
|
+
targetLabel: opts.targetLabel,
|
|
56
|
+
params: opts.params,
|
|
57
|
+
startedAt: Date.now()
|
|
58
|
+
};
|
|
59
|
+
const pollUi = json
|
|
60
|
+
? { onPollProgress: () => {}, onTransientError: () => {}, finish: () => {} }
|
|
61
|
+
: createHostOpsPollHandlers(jobId, pollContext);
|
|
62
|
+
try {
|
|
63
|
+
return await pollHostOpsJobUntilTerminal(auth, jobId, pollUi, json);
|
|
64
|
+
} finally {
|
|
65
|
+
pollUi.finish();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {string} question
|
|
71
|
+
* @returns {Promise<boolean>}
|
|
72
|
+
*/
|
|
73
|
+
function promptYesNo(question) {
|
|
74
|
+
if (!process.stdin.isTTY) {
|
|
75
|
+
return Promise.resolve(false);
|
|
76
|
+
}
|
|
77
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
rl.question(`${question} [y/N] `, (answer) => {
|
|
80
|
+
rl.close();
|
|
81
|
+
resolve(/^y(es)?$/i.test(String(answer || '').trim()));
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function platformAlreadyInstalled(outcomes) {
|
|
87
|
+
if (!Array.isArray(outcomes)) return false;
|
|
88
|
+
return outcomes.some(
|
|
89
|
+
(row) =>
|
|
90
|
+
row &&
|
|
91
|
+
(row.overall === 'SKIP' || row.status === 'SKIP') &&
|
|
92
|
+
String(row.detail || '').toLowerCase().includes('installed')
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Run a host-ops job and optionally wait.
|
|
98
|
+
* @param {string} type
|
|
99
|
+
* @param {Object} params
|
|
100
|
+
* @param {Object} options - Commander options (yes, wait, json)
|
|
101
|
+
* @returns {Promise<Object>}
|
|
102
|
+
*/
|
|
103
|
+
async function runHostOpsJob(type, params, options = {}) {
|
|
104
|
+
const auth = await getRemoteDevAuth();
|
|
105
|
+
if (!auth) throw new Error(REMOTE_NOT_CONFIGURED_MSG);
|
|
106
|
+
const { jobId } = await hostOpsApi.createHostOpsJob(
|
|
107
|
+
auth.serverUrl,
|
|
108
|
+
auth.clientCertPem,
|
|
109
|
+
{ type, params },
|
|
110
|
+
auth.serverCaPem || undefined
|
|
111
|
+
);
|
|
112
|
+
const waitOpts = buildHostOpsWaitOpts(type, params, options);
|
|
113
|
+
if (options.wait === false) {
|
|
114
|
+
if (options.json) {
|
|
115
|
+
logger.log(JSON.stringify({ jobId, status: 'pending', type }, null, 2));
|
|
116
|
+
} else {
|
|
117
|
+
const action = buildHostOpsActionLabel(type, waitOpts.targetLabel);
|
|
118
|
+
logger.log(formatSuccessLine(`${action} queued (job ${jobId}).`));
|
|
119
|
+
}
|
|
120
|
+
return { jobId, status: 'pending' };
|
|
121
|
+
}
|
|
122
|
+
if (options.json) {
|
|
123
|
+
const job = await waitForHostOpsJob(auth, jobId, waitOpts);
|
|
124
|
+
assertHostOpsJobSucceeded(job);
|
|
125
|
+
logger.log(JSON.stringify(job, null, 2));
|
|
126
|
+
return job;
|
|
127
|
+
}
|
|
128
|
+
const job = await waitForHostOpsJob(auth, jobId, waitOpts);
|
|
129
|
+
assertHostOpsJobSucceeded(job);
|
|
130
|
+
const action = buildHostOpsActionLabel(type, waitOpts.targetLabel);
|
|
131
|
+
logger.log(formatSuccessLine(`${action} completed.`));
|
|
132
|
+
return job;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function handlePlatformInstallCli(developerId, options) {
|
|
136
|
+
const params = buildJobParams(options, developerId);
|
|
137
|
+
if (options.check) {
|
|
138
|
+
params.check = true;
|
|
139
|
+
} else if (!params.builderVersion) {
|
|
140
|
+
throw new Error('--builder-version is required unless --check is set');
|
|
141
|
+
}
|
|
142
|
+
await runHostOpsJob('install-builder-cli', params, options);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function handlePlatformUpdate(developerId, options) {
|
|
146
|
+
const params = buildJobParams(options, developerId);
|
|
147
|
+
if (options.check) params.check = true;
|
|
148
|
+
await runHostOpsJob('update-dev-platform', params, options);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function logPlatformInstallOutcomes(developerId, job, json) {
|
|
152
|
+
if (json) {
|
|
153
|
+
logger.log(JSON.stringify(job, null, 2));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (!Array.isArray(job.outcomes)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
job.outcomes.forEach((row) => {
|
|
160
|
+
logger.log(` ${row.linuxUser || developerId}: ${row.overall || row.status}${row.detail ? ` — ${row.detail}` : ''}`);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function runPlatformInstallPreflight(auth, params) {
|
|
165
|
+
const { jobId } = await hostOpsApi.preflightHostOps(
|
|
166
|
+
auth.serverUrl,
|
|
167
|
+
auth.clientCertPem,
|
|
168
|
+
{ type: 'install-dev-platform', params },
|
|
169
|
+
auth.serverCaPem || undefined
|
|
170
|
+
);
|
|
171
|
+
return waitForHostOpsJob(auth, jobId, buildHostOpsWaitOpts('install-dev-platform', params, {}));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function handlePlatformInstallCheck(developerId, params, options) {
|
|
175
|
+
const auth = await getRemoteDevAuth();
|
|
176
|
+
if (!auth) throw new Error(REMOTE_NOT_CONFIGURED_MSG);
|
|
177
|
+
params.check = true;
|
|
178
|
+
const { jobId } = await hostOpsApi.preflightHostOps(
|
|
179
|
+
auth.serverUrl,
|
|
180
|
+
auth.clientCertPem,
|
|
181
|
+
{ type: 'install-dev-platform', params },
|
|
182
|
+
auth.serverCaPem || undefined
|
|
183
|
+
);
|
|
184
|
+
const job = await waitForHostOpsJob(auth, jobId, buildHostOpsWaitOpts('install-dev-platform', params, options));
|
|
185
|
+
logPlatformInstallOutcomes(developerId, job, options.json);
|
|
186
|
+
assertHostOpsJobSucceeded(job);
|
|
187
|
+
return job;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function confirmPlatformReinstall(developerId, params, options) {
|
|
191
|
+
const auth = await getRemoteDevAuth();
|
|
192
|
+
if (!auth) throw new Error(REMOTE_NOT_CONFIGURED_MSG);
|
|
193
|
+
const preflight = await runPlatformInstallPreflight(auth, { ...params, developerId });
|
|
194
|
+
if (!platformAlreadyInstalled(preflight.outcomes)) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const ok = await promptYesNo(
|
|
198
|
+
`Platform already installed for dev${String(developerId).padStart(2, '0')}. Re-install?`
|
|
199
|
+
);
|
|
200
|
+
if (!ok) {
|
|
201
|
+
logger.log(chalk.gray('Cancelled.'));
|
|
202
|
+
return preflight;
|
|
203
|
+
}
|
|
204
|
+
await runHostOpsJob('reinstall-dev-platform', params, options);
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function handlePlatformInstall(developerId, options) {
|
|
209
|
+
if (!developerId) {
|
|
210
|
+
throw new Error('Developer ID is required (positional argument).');
|
|
211
|
+
}
|
|
212
|
+
const params = buildJobParams(options, developerId);
|
|
213
|
+
|
|
214
|
+
if (options.check) {
|
|
215
|
+
return handlePlatformInstallCheck(developerId, params, options);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!options.force && !options.yes) {
|
|
219
|
+
const cancelled = await confirmPlatformReinstall(developerId, params, options);
|
|
220
|
+
if (cancelled) {
|
|
221
|
+
return cancelled;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const jobType = options.force ? 'reinstall-dev-platform' : 'install-dev-platform';
|
|
226
|
+
await runHostOpsJob(jobType, params, options);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function handleProvisionDevUser(developerId, options) {
|
|
230
|
+
const params = buildJobParams(options, developerId);
|
|
231
|
+
await runHostOpsJob('provision-dev-user', params, options);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function handleRemoveDevUser(developerId, options) {
|
|
235
|
+
const params = buildJobParams(options, developerId);
|
|
236
|
+
if (!params.developerId) {
|
|
237
|
+
throw new Error('Developer ID is required.');
|
|
238
|
+
}
|
|
239
|
+
await runHostOpsJob('remove-dev-user', params, options);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
module.exports = {
|
|
243
|
+
buildJobParams,
|
|
244
|
+
buildHostOpsWaitOpts,
|
|
245
|
+
waitForHostOpsJob,
|
|
246
|
+
runHostOpsJob,
|
|
247
|
+
handlePlatformInstallCli,
|
|
248
|
+
handlePlatformUpdate,
|
|
249
|
+
handlePlatformInstall,
|
|
250
|
+
handleProvisionDevUser,
|
|
251
|
+
handleRemoveDevUser
|
|
252
|
+
};
|
package/lib/commands/dev-init.js
CHANGED
|
@@ -33,7 +33,7 @@ const {
|
|
|
33
33
|
isLinuxCaSudoRequiredError
|
|
34
34
|
} = require('../utils/dev-ca-install');
|
|
35
35
|
const { runOptionalHostsSetup } = require('../utils/dev-hosts-helper');
|
|
36
|
-
const { mergeDevSshConfigAfterInit } = require('../utils/dev-init-ssh-merge');
|
|
36
|
+
const { mergeDevSshConfigAfterInit, logDevSshConnectHint } = require('../utils/dev-init-ssh-merge');
|
|
37
37
|
const { resolveInitOptions } = require('../utils/dev-init-resolve');
|
|
38
38
|
const { displayDevConfig } = require('./dev-show-display');
|
|
39
39
|
const {
|
|
@@ -426,6 +426,7 @@ async function runCertificateRefresh(auth) {
|
|
|
426
426
|
warn: (msg) => logger.log(chalk.yellow(` ⚠ ${msg}`))
|
|
427
427
|
});
|
|
428
428
|
logger.log(formatSuccessLine('Certificate refreshed and config updated from server.\n'));
|
|
429
|
+
logDevSshConnectHint(await mergeDevSshConfigAfterInit(auth.serverUrl, devId));
|
|
429
430
|
}
|
|
430
431
|
|
|
431
432
|
/**
|
|
@@ -481,6 +482,7 @@ async function runDevRefresh(options = {}) {
|
|
|
481
482
|
return;
|
|
482
483
|
}
|
|
483
484
|
await fetchAndMergeRemoteSettings(auth, clientCertPem, clientKeyPem, devId);
|
|
485
|
+
logDevSshConnectHint(await mergeDevSshConfigAfterInit(auth.serverUrl, devId));
|
|
484
486
|
}
|
|
485
487
|
|
|
486
488
|
module.exports = { runDevInit, runDevRefresh };
|