@aifabrix/builder 2.42.1 → 2.44.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/rules/anchor-docs.mdc +15 -0
- package/README.md +2 -2
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +157 -0
- package/integration/{hubspot → hubspot-test}/application.json +6 -6
- package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
- package/integration/hubspot-test/env.template +4 -0
- package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
- package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
- package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
- package/integration/hubspot-test/rbac.json +166 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
- package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
- package/integration/{hubspot → hubspot-test}/test.js +137 -102
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +288 -0
- package/lib/api/datasources-core.api.js +3 -3
- package/lib/api/dev-mtls-request.js +110 -0
- package/lib/api/dev-server-https.js +145 -0
- package/lib/api/dev.api.js +133 -144
- package/lib/api/index.js +0 -1
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/service-users.api.js +111 -2
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/service-users.types.js +41 -0
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +99 -0
- package/lib/api/validation-runner.js +99 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +19 -8
- package/lib/app/rotate-secret.js +17 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +1 -1
- package/lib/app/show.js +1 -1
- package/lib/build/index.js +13 -10
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +59 -123
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +36 -14
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +190 -103
- package/lib/cli/setup-environment.js +11 -20
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +139 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +147 -10
- package/lib/cli/setup-service-user.js +146 -20
- package/lib/cli/setup-utility.js +47 -19
- package/lib/commands/app-down.js +5 -7
- package/lib/commands/app-install.js +14 -7
- package/lib/commands/app-logs.js +13 -10
- package/lib/commands/app-shell.js +4 -1
- package/lib/commands/app-test.js +25 -19
- package/lib/commands/app.js +22 -10
- package/lib/commands/auth-config.js +10 -14
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +495 -0
- package/lib/commands/datasource-unified-test-cli.options.js +149 -0
- package/lib/commands/datasource-validation-cli.js +129 -0
- package/lib/commands/datasource.js +123 -71
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +16 -10
- package/lib/commands/repair-rbac.js +25 -19
- package/lib/commands/repair.js +116 -32
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +22 -13
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +20 -7
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +243 -13
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +28 -2
- package/lib/commands/up-dataplane.js +31 -18
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +138 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +16 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +59 -58
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +2 -4
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +228 -42
- package/lib/core/templates-env.js +4 -3
- package/lib/core/templates.js +1 -1
- package/lib/datasource/abac-validator.js +148 -0
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +77 -36
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +252 -0
- package/lib/datasource/resolve-app.js +109 -0
- package/lib/datasource/test-e2e.js +95 -155
- package/lib/datasource/test-integration.js +121 -109
- package/lib/datasource/unified-validation-run-body.js +65 -0
- package/lib/datasource/unified-validation-run-post.js +23 -0
- package/lib/datasource/unified-validation-run-resolve.js +43 -0
- package/lib/datasource/unified-validation-run.js +92 -0
- package/lib/datasource/validate.js +162 -15
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +131 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +104 -14
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external-controller-manifest.js +3 -3
- package/lib/generator/external.js +23 -11
- package/lib/generator/helpers.js +71 -12
- package/lib/generator/index.js +8 -4
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +46 -11
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +16 -13
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +238 -51
- package/lib/infrastructure/index.js +64 -37
- package/lib/infrastructure/services.js +21 -15
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1201 -433
- package/lib/schema/external-system.schema.json +181 -5
- package/lib/schema/flag-map-validation-run.json +31 -0
- package/lib/schema/infra-parameter.schema.json +106 -0
- package/lib/schema/infra.parameter.yaml +421 -0
- package/lib/schema/type/credential-auth-templates.json +40 -0
- package/lib/schema/type/document-storage.json +213 -0
- package/lib/schema/type/message-service.json +123 -0
- package/lib/schema/type/vector-store.json +88 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
- package/lib/utils/api-error-handler.js +2 -2
- package/lib/utils/api.js +49 -14
- package/lib/utils/app-config-resolver.js +23 -1
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +209 -6
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +16 -1
- package/lib/utils/dataplane-pipeline-warning.js +4 -3
- package/lib/utils/datasource-test-run-capability-scope.js +43 -0
- package/lib/utils/datasource-test-run-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +442 -0
- package/lib/utils/datasource-test-run-exit.js +58 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +42 -11
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +125 -9
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-env-template.js +180 -0
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +277 -136
- package/lib/utils/external-system-local-test-tty.js +389 -0
- package/lib/utils/external-system-readiness-core.js +377 -0
- package/lib/utils/external-system-readiness-deploy-display.js +270 -0
- package/lib/utils/external-system-readiness-display-internals.js +150 -0
- package/lib/utils/external-system-readiness-display.js +186 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +32 -14
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +14 -13
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +29 -7
- package/lib/utils/paths.js +136 -48
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +171 -51
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +35 -37
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/secure-file-permissions.js +91 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +37 -5
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +89 -0
- package/lib/utils/validation-run-post-retry.js +73 -0
- package/lib/utils/validation-run-request.js +98 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +78 -1
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +50 -2
- package/lib/validation/external-manifest-validator.js +35 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +9 -10
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +32 -78
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +11 -3
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +304 -55
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +80 -18
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +55 -14
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/env.template.hbs +22 -0
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +20 -4
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/integration/hubspot/README.md +0 -102
- package/integration/hubspot/env.template +0 -4
- package/integration/hubspot/hubspot-datasource-company.json +0 -541
- package/integration/hubspot/hubspot-datasource-contact.json +0 -639
- package/integration/hubspot/hubspot-datasource-deal.json +0 -588
- package/integration/hubspot/hubspot-datasource-users.json +0 -116
- package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -43
- /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Optional hosts-file helper for dev init: map Builder Server hostname to an IP on this machine.
|
|
3
|
+
* Wildcard DNS (*.host) is documented for router/DNS; hosts file only supports exact hostnames (OS limitation).
|
|
4
|
+
* Writing hosts usually requires administrator rights on Windows and macOS.
|
|
5
|
+
*
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 2.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const dns = require('dns').promises;
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const readline = require('readline');
|
|
13
|
+
const chalk = require('chalk');
|
|
14
|
+
const { nodeFs } = require('../internal/node-fs');
|
|
15
|
+
|
|
16
|
+
const IPV4_RE = /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$/;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} url - https://builder02.local or similar
|
|
20
|
+
* @returns {string} Hostname only
|
|
21
|
+
*/
|
|
22
|
+
function hostnameFromServerUrl(url) {
|
|
23
|
+
try {
|
|
24
|
+
return new URL(url.trim()).hostname;
|
|
25
|
+
} catch {
|
|
26
|
+
throw new Error('Invalid --server URL for hosts setup');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} s
|
|
32
|
+
* @returns {boolean}
|
|
33
|
+
*/
|
|
34
|
+
function isValidIpv4(s) {
|
|
35
|
+
return typeof s === 'string' && IPV4_RE.test(s.trim());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Path to system hosts file.
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
function getHostsFilePath() {
|
|
43
|
+
if (process.platform === 'win32') {
|
|
44
|
+
const windir = process.env.WINDIR || process.env.SystemRoot || 'C:\\Windows';
|
|
45
|
+
return path.join(windir, 'System32', 'drivers', 'etc', 'hosts');
|
|
46
|
+
}
|
|
47
|
+
return '/etc/hosts';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Hostnames to map to the Builder Server IP: the URL host plus devNN.url-host for
|
|
52
|
+
* per-developer subdomains. Wildcards (*.zone) are not supported by OS hosts files.
|
|
53
|
+
* @param {string|undefined} developerId - e.g. "02"
|
|
54
|
+
* @param {string} primaryHostname - Hostname from --server (e.g. builder02.local)
|
|
55
|
+
* @returns {string[]} Deduped list (primary first, then per-dev if applicable)
|
|
56
|
+
*/
|
|
57
|
+
function hostsNamesForDevInit(developerId, primaryHostname) {
|
|
58
|
+
const primary = String(primaryHostname || '').trim();
|
|
59
|
+
if (!primary) return [];
|
|
60
|
+
const names = [primary];
|
|
61
|
+
const id = developerId !== undefined && developerId !== null ? String(developerId).trim() : '';
|
|
62
|
+
if (!id || isValidIpv4(primary)) return names;
|
|
63
|
+
if (/^dev\d+\./i.test(primary)) return names;
|
|
64
|
+
const perDev = `dev${id}.${primary}`;
|
|
65
|
+
if (perDev !== primary && !names.includes(perDev)) names.push(perDev);
|
|
66
|
+
return names;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Display URL for the per-developer host (devNN.zone), same scheme and port as --server.
|
|
71
|
+
* @param {string|undefined} developerId
|
|
72
|
+
* @param {string} baseUrl - Builder Server URL
|
|
73
|
+
* @returns {string|null} e.g. https://dev02.builder02.local
|
|
74
|
+
*/
|
|
75
|
+
function perDeveloperServerDisplayUrl(developerId, baseUrl) {
|
|
76
|
+
let u;
|
|
77
|
+
try {
|
|
78
|
+
u = new URL(String(baseUrl || '').trim());
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const list = hostsNamesForDevInit(developerId, u.hostname);
|
|
83
|
+
if (list.length < 2) return null;
|
|
84
|
+
const perDevHost = list[1];
|
|
85
|
+
u.hostname = perDevHost;
|
|
86
|
+
const portPart = u.port ? `:${u.port}` : '';
|
|
87
|
+
return `${u.protocol}//${u.hostname}${portPart}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {{ log: function }} logger
|
|
92
|
+
* @param {string|undefined} developerId
|
|
93
|
+
* @param {string} baseUrl
|
|
94
|
+
* @returns {void}
|
|
95
|
+
*/
|
|
96
|
+
function logPerDeveloperUrlHint(logger, developerId, baseUrl) {
|
|
97
|
+
const displayUrl = perDeveloperServerDisplayUrl(developerId, baseUrl);
|
|
98
|
+
if (!displayUrl) return;
|
|
99
|
+
logger.log(chalk.green(' Your per-developer URL: ') + chalk.cyan(displayUrl));
|
|
100
|
+
logger.log('');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* True if hosts file already maps hostname (any IP).
|
|
105
|
+
* @param {string} hostsPath
|
|
106
|
+
* @param {string} hostname
|
|
107
|
+
* @returns {boolean}
|
|
108
|
+
*/
|
|
109
|
+
function hostsFileHasHostname(hostsPath, hostname) {
|
|
110
|
+
const want = String(hostname || '').trim();
|
|
111
|
+
if (!want) return false;
|
|
112
|
+
let text;
|
|
113
|
+
try {
|
|
114
|
+
text = nodeFs().readFileSync(hostsPath, 'utf8');
|
|
115
|
+
} catch (e) {
|
|
116
|
+
if (e.code === 'ENOENT') return false;
|
|
117
|
+
throw e;
|
|
118
|
+
}
|
|
119
|
+
if (typeof text !== 'string') return false;
|
|
120
|
+
for (const line of text.split(/\r?\n/)) {
|
|
121
|
+
const t = line.replace(/#.*/, '').trim();
|
|
122
|
+
if (!t) continue;
|
|
123
|
+
const parts = t.split(/\s+/).filter(Boolean);
|
|
124
|
+
if (parts.length < 2) continue;
|
|
125
|
+
const names = parts.slice(1).map((n) => String(n).trim());
|
|
126
|
+
if (names.includes(want)) return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {string} question
|
|
133
|
+
* @returns {Promise<string>}
|
|
134
|
+
*/
|
|
135
|
+
function promptLine(question) {
|
|
136
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
137
|
+
return new Promise(resolve => {
|
|
138
|
+
rl.question(question, answer => {
|
|
139
|
+
rl.close();
|
|
140
|
+
resolve((answer || '').trim());
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @param {string} question
|
|
147
|
+
* @returns {Promise<boolean>}
|
|
148
|
+
*/
|
|
149
|
+
async function promptYesNo(question) {
|
|
150
|
+
const a = (await promptLine(question)).toLowerCase();
|
|
151
|
+
return a === 'y' || a === 'yes';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Try IPv4 lookup for hostname.
|
|
156
|
+
* @param {string} hostname
|
|
157
|
+
* @returns {Promise<string|null>}
|
|
158
|
+
*/
|
|
159
|
+
async function lookupIpv4(hostname) {
|
|
160
|
+
try {
|
|
161
|
+
const r = await dns.lookup(hostname, { family: 4 });
|
|
162
|
+
return r.address || null;
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Print how to add the line with admin/sudo when direct write failed.
|
|
170
|
+
* @param {{ log: function }} logger
|
|
171
|
+
* @param {string} hostsPath
|
|
172
|
+
* @param {string} line
|
|
173
|
+
*/
|
|
174
|
+
function printManualHostsInstructions(logger, hostsPath, line) {
|
|
175
|
+
if (process.platform === 'win32') {
|
|
176
|
+
logger.log(chalk.yellow('\n Could not write hosts file (need Administrator). Run PowerShell as Administrator, then:\n'));
|
|
177
|
+
logger.log(chalk.cyan(` Add-Content -Path "${hostsPath}" -Value "\`r\`n${line}\`r\`n"`));
|
|
178
|
+
} else {
|
|
179
|
+
logger.log(chalk.yellow('\n Could not write hosts file (need elevated permissions). Run:\n'));
|
|
180
|
+
logger.log(chalk.cyan(` echo '${line}' | sudo tee -a ${hostsPath}`));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @param {{ log: function }} logger
|
|
186
|
+
* @param {string[]} hostnames - Names we may add (URL host + optional devNN.zone)
|
|
187
|
+
*/
|
|
188
|
+
function logHostsIntro(logger, hostnames) {
|
|
189
|
+
const list = (hostnames && hostnames.length ? hostnames : []).join(', ');
|
|
190
|
+
logger.log(chalk.blue('\n📍 Local name resolution (optional)\n'));
|
|
191
|
+
logger.log(
|
|
192
|
+
chalk.gray(
|
|
193
|
+
' Wildcards such as *.local are not supported in the hosts file (OS limitation). '
|
|
194
|
+
+ 'Use DNS or router DNS for wildcard zones; here we add exact names only.'
|
|
195
|
+
)
|
|
196
|
+
);
|
|
197
|
+
logger.log(chalk.gray(` Names to map to that IP (same line where possible): ${list}`));
|
|
198
|
+
logger.log('');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* @param {string} hostname
|
|
203
|
+
* @param {string|undefined} hostsIp - From --hosts-ip
|
|
204
|
+
* @param {{ log: function }} logger
|
|
205
|
+
* @returns {Promise<string|null>} IPv4 or null if user skipped
|
|
206
|
+
*/
|
|
207
|
+
async function resolveHostsIpForInit(hostname, hostsIp, logger) {
|
|
208
|
+
let ip = typeof hostsIp === 'string' && hostsIp.trim() ? hostsIp.trim() : null;
|
|
209
|
+
if (ip && !isValidIpv4(ip)) {
|
|
210
|
+
throw new Error(`Invalid --hosts-ip: "${ip}" (use an IPv4 address, e.g. 192.168.1.25)`);
|
|
211
|
+
}
|
|
212
|
+
if (!ip) {
|
|
213
|
+
const lookedUp = await lookupIpv4(hostname);
|
|
214
|
+
if (lookedUp && isValidIpv4(lookedUp)) {
|
|
215
|
+
logger.log(chalk.gray(` ${hostname} currently resolves to ${lookedUp} (DNS or existing hosts).`));
|
|
216
|
+
ip = lookedUp;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (ip) return ip;
|
|
220
|
+
const entered = await promptLine(chalk.yellow(` Enter IPv4 address for ${hostname} (e.g. 192.168.1.25): `));
|
|
221
|
+
if (!entered) {
|
|
222
|
+
logger.log(chalk.gray(' Skipping hosts file (no IP entered).\n'));
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
if (!isValidIpv4(entered)) {
|
|
226
|
+
throw new Error(`Invalid IP address: "${entered}"`);
|
|
227
|
+
}
|
|
228
|
+
return entered;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @param {string} hostsPath
|
|
233
|
+
* @param {string} block - Full text to append
|
|
234
|
+
* @param {string} line - Single-line form for manual instructions
|
|
235
|
+
* @param {{ log: function }} logger
|
|
236
|
+
* @returns {Promise<void>}
|
|
237
|
+
*/
|
|
238
|
+
async function appendHostsBlockOrPrintManual(hostsPath, block, line, logger) {
|
|
239
|
+
try {
|
|
240
|
+
await nodeFs().promises.appendFile(hostsPath, block, { encoding: 'utf8' });
|
|
241
|
+
logger.log(chalk.green(` ✔ Updated ${hostsPath}\n`));
|
|
242
|
+
} catch (e) {
|
|
243
|
+
if (e.code === 'EACCES' || e.code === 'EPERM') {
|
|
244
|
+
logger.log(chalk.yellow(` ✖ Could not write ${hostsPath} (permission denied).`));
|
|
245
|
+
printManualHostsInstructions(logger, hostsPath, line);
|
|
246
|
+
logger.log('');
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
throw e;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @param {string} hostsPath
|
|
255
|
+
* @param {string[]} hostnames
|
|
256
|
+
* @param {string} ip
|
|
257
|
+
* @param {boolean} skipConfirm
|
|
258
|
+
* @param {{ log: function }} logger
|
|
259
|
+
* @returns {Promise<void>}
|
|
260
|
+
*/
|
|
261
|
+
async function tryWriteHostsEntry(hostsPath, hostnames, ip, skipConfirm, logger) {
|
|
262
|
+
const missing = hostnames.filter((h) => !hostsFileHasHostname(hostsPath, h));
|
|
263
|
+
if (missing.length === 0) {
|
|
264
|
+
logger.log(chalk.green(` ✔ Required hostnames are already listed in ${hostsPath}. Nothing to do.\n`));
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const line = `${ip} ${missing.join(' ')}`;
|
|
268
|
+
logger.log(chalk.gray(` Suggested hosts line: ${line}`));
|
|
269
|
+
const yn = chalk.yellow(` Add this line to ${hostsPath}? This may require administrator approval. (y/n) `);
|
|
270
|
+
const confirm = skipConfirm || (await promptYesNo(yn));
|
|
271
|
+
if (!confirm) {
|
|
272
|
+
logger.log(chalk.gray(' Skipping hosts file update.\n'));
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const block = `\n# aifabrix dev init — ${missing.join(', ')}\n${line}\n`;
|
|
276
|
+
await appendHostsBlockOrPrintManual(hostsPath, block, line, logger);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Optional hosts setup for dev init (--add-hosts).
|
|
281
|
+
* @param {Object} params
|
|
282
|
+
* @param {string} params.baseUrl - Builder Server URL
|
|
283
|
+
* @param {string} [params.developerId] - From --developer-id (adds devNN.hostname)
|
|
284
|
+
* @param {string} [params.hostsIp] - From --hosts-ip
|
|
285
|
+
* @param {boolean} params.skipConfirm - When true (-y), append without y/n
|
|
286
|
+
* @param {{ log: function }} params.logger - logger like lib/utils/logger
|
|
287
|
+
* @returns {Promise<void>}
|
|
288
|
+
*/
|
|
289
|
+
async function runOptionalHostsSetup({ baseUrl, developerId, hostsIp, skipConfirm, logger }) {
|
|
290
|
+
const primary = hostnameFromServerUrl(baseUrl);
|
|
291
|
+
const hostnames = hostsNamesForDevInit(developerId, primary);
|
|
292
|
+
logHostsIntro(logger, hostnames);
|
|
293
|
+
const ip = await resolveHostsIpForInit(primary, hostsIp, logger);
|
|
294
|
+
if (ip === null) return;
|
|
295
|
+
await tryWriteHostsEntry(getHostsFilePath(), hostnames, ip, skipConfirm, logger);
|
|
296
|
+
logPerDeveloperUrlHint(logger, developerId, baseUrl);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
module.exports = {
|
|
300
|
+
hostnameFromServerUrl,
|
|
301
|
+
hostsNamesForDevInit,
|
|
302
|
+
perDeveloperServerDisplayUrl,
|
|
303
|
+
isValidIpv4,
|
|
304
|
+
getHostsFilePath,
|
|
305
|
+
hostsFileHasHostname,
|
|
306
|
+
runOptionalHostsSetup
|
|
307
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Cert troubleshooting hints for dev init (keeps dev-init.js under max-lines).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const { getCertDir } = require('./dev-cert-helper');
|
|
10
|
+
const logger = require('./logger');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Message for 400 Bad Request: nginx often forwards X-Client-Cert with literal newlines.
|
|
14
|
+
* @returns {string} Hint for server-side nginx fix
|
|
15
|
+
*/
|
|
16
|
+
function getBadRequestHint() {
|
|
17
|
+
return 'Bad Request (400) often means the server\'s nginx is forwarding the client certificate with literal newlines in X-Client-Cert. On the server, use nginx njs to escape newlines (see .cursor/plans/builder-cli.md §5).';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Log a one-line hint for cert troubleshooting (curl test and docs).
|
|
22
|
+
* @param {string} configDir - Config directory
|
|
23
|
+
* @param {string} devId - Developer ID
|
|
24
|
+
* @param {string} baseUrl - Builder Server base URL
|
|
25
|
+
*/
|
|
26
|
+
function logCertTroubleshootingHint(configDir, devId, baseUrl) {
|
|
27
|
+
const certDir = getCertDir(configDir, devId);
|
|
28
|
+
const certPath = path.join(certDir, 'cert.pem');
|
|
29
|
+
const keyPath = path.join(certDir, 'key.pem');
|
|
30
|
+
logger.log(chalk.gray(` Test with: curl -v --cert ${certPath} --key ${keyPath} ${baseUrl}/api/dev/settings`));
|
|
31
|
+
logger.log(chalk.gray(' See .cursor/plans/builder-cli.md §5 for 200 vs 401 vs 400 and nginx/server fix.'));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
getBadRequestHint,
|
|
36
|
+
logCertTroubleshootingHint
|
|
37
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Health / TLS failure messages for dev init (keeps dev-init.js under max-lines).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { isLinuxCaSudoRequiredError } = require('./dev-ca-install');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* True when /health returned a 5xx (server or gateway error). TLS succeeded; app may still be degraded.
|
|
11
|
+
* @param {Error} err - Thrown from getHealth
|
|
12
|
+
* @returns {boolean}
|
|
13
|
+
*/
|
|
14
|
+
function isHealthHttpServerError(err) {
|
|
15
|
+
const s = err && typeof err.status === 'number' ? err.status : null;
|
|
16
|
+
return s !== null && s >= 500 && s < 600;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Message when trust/health step fails (avoid calling HTTP 5xx "cannot reach").
|
|
21
|
+
* @param {string} baseUrl - Builder Server URL
|
|
22
|
+
* @param {Error} err - Failure from getHealth or TLS
|
|
23
|
+
* @returns {string}
|
|
24
|
+
*/
|
|
25
|
+
function formatEnsureServerTrustedFailure(baseUrl, err) {
|
|
26
|
+
const s = err && typeof err.status === 'number' ? err.status : null;
|
|
27
|
+
if (s !== null) {
|
|
28
|
+
const detail = err.message || `HTTP ${s}`;
|
|
29
|
+
if (s >= 500 && s < 600) {
|
|
30
|
+
return (
|
|
31
|
+
`Builder Server at ${baseUrl} returned HTTP ${s} (${detail}) on GET /health. ` +
|
|
32
|
+
'TLS succeeded; the service reported an error or is not fully healthy. Check server logs or open /health in a browser.'
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return (
|
|
36
|
+
`Builder Server at ${baseUrl} returned HTTP ${s} (${detail}) on GET /health. ` +
|
|
37
|
+
'The host was reached but health did not succeed. Check the URL and server configuration.'
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
if (isLinuxCaSudoRequiredError(err)) {
|
|
41
|
+
return (
|
|
42
|
+
`Could not add the development CA to the system trust store for ${baseUrl} (Linux needs sudo for that step). ` +
|
|
43
|
+
`${err.message}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return `Cannot reach Builder Server at ${baseUrl}. Check URL and network. ${err.message}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
isHealthHttpServerError,
|
|
51
|
+
formatEnsureServerTrustedFailure
|
|
52
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve Builder URL, developer id, and PIN for dev init.
|
|
3
|
+
* CLI flags override config. Developer id from config is not used when it is "0" (local default).
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview Shared onboarding option resolution for dev-init command
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 2.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const config = require('../core/config');
|
|
11
|
+
|
|
12
|
+
function requirePin(options) {
|
|
13
|
+
const pin = options.pin;
|
|
14
|
+
if (!pin || typeof pin !== 'string' || !pin.trim()) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
'--pin is required (one-time PIN). On an enrolled admin PC run: aifabrix dev pin <developer-id>, ' +
|
|
17
|
+
'then use the PIN on this machine.'
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {Object} options - Commander options
|
|
24
|
+
* @returns {Promise<{ devId: string, devIdFromConfig: boolean }>}
|
|
25
|
+
*/
|
|
26
|
+
async function resolveDeveloperIdPart(options) {
|
|
27
|
+
const rawOptDev = options.developerId ?? options['developer-id'];
|
|
28
|
+
let devId;
|
|
29
|
+
let devIdFromConfig = false;
|
|
30
|
+
if (rawOptDev !== undefined && rawOptDev !== null && String(rawOptDev).trim() !== '') {
|
|
31
|
+
devId = String(rawOptDev).trim();
|
|
32
|
+
} else {
|
|
33
|
+
const fromCfg = await config.getDeveloperId();
|
|
34
|
+
devId = fromCfg !== undefined && fromCfg !== null ? String(fromCfg).trim() : '';
|
|
35
|
+
devIdFromConfig = true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!devId || !/^[0-9]+$/.test(devId)) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
'Pass --developer-id <id> (digits only) or set developer-id in config (aifabrix dev set-id <id>).'
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (devIdFromConfig && devId === '0') {
|
|
45
|
+
throw new Error(
|
|
46
|
+
'Cannot use default developer-id 0 from config for Builder onboarding. Pass --developer-id <id> (e.g. 02) or run aifabrix dev set-id first.'
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { devId, devIdFromConfig };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {Object} options - Commander options
|
|
55
|
+
* @returns {Promise<string>} Normalized base URL (no trailing slash)
|
|
56
|
+
*/
|
|
57
|
+
async function resolveServerBaseUrl(options) {
|
|
58
|
+
let server = options.server;
|
|
59
|
+
if (!server || typeof server !== 'string' || !String(server).trim()) {
|
|
60
|
+
const fromCfg = await config.getRemoteServer();
|
|
61
|
+
server = fromCfg && typeof fromCfg === 'string' ? fromCfg.trim() : '';
|
|
62
|
+
} else {
|
|
63
|
+
server = String(server).trim();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!server) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
'Pass --server <Builder URL> or set remote-server in ~/.aifabrix/config.yaml (from settings merge or aifabrix dev show).'
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return server.replace(/\/+$/, '');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {Object} options - Commander options
|
|
77
|
+
* @returns {Promise<{ baseUrl: string, devId: string }>}
|
|
78
|
+
*/
|
|
79
|
+
async function resolveInitOptions(options) {
|
|
80
|
+
requirePin(options);
|
|
81
|
+
const { devId } = await resolveDeveloperIdPart(options);
|
|
82
|
+
const baseUrl = await resolveServerBaseUrl(options);
|
|
83
|
+
return { baseUrl, devId };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = { resolveInitOptions };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview After dev init: merge SSH config Host alias from sync settings / server URL.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const config = require('../core/config');
|
|
7
|
+
const logger = require('./logger');
|
|
8
|
+
const { ensureDevSshConfigBlock } = require('./dev-ssh-config-helper');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Hostname from Builder Server URL (for sync-ssh-host fallback).
|
|
12
|
+
* @param {string} baseUrl - e.g. https://builder02.local
|
|
13
|
+
* @returns {string|null}
|
|
14
|
+
*/
|
|
15
|
+
function hostnameFromBaseUrl(baseUrl) {
|
|
16
|
+
if (!baseUrl || typeof baseUrl !== 'string') return null;
|
|
17
|
+
const s = baseUrl.trim().replace(/\/+$/, '');
|
|
18
|
+
const withProtocol = /^https?:\/\//i.test(s) ? s : `https://${s}`;
|
|
19
|
+
try {
|
|
20
|
+
return new URL(withProtocol).hostname || null;
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Update ~/.ssh/config with Host <user>.<host> for interactive SSH; log result.
|
|
28
|
+
* @param {string} baseUrl - Builder Server base URL
|
|
29
|
+
* @param {string} devId - Developer ID (digits)
|
|
30
|
+
* @returns {Promise<{ hostAlias: string|null, syncUser: string, syncHost: string|null }>}
|
|
31
|
+
*/
|
|
32
|
+
async function mergeDevSshConfigAfterInit(baseUrl, devId) {
|
|
33
|
+
const syncHost = (await config.getSyncSshHost()) || hostnameFromBaseUrl(baseUrl);
|
|
34
|
+
const syncUser = (await config.getSyncSshUser()) || `dev${devId}`;
|
|
35
|
+
if (!syncHost) {
|
|
36
|
+
return { hostAlias: null, syncUser, syncHost: null };
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const res = await ensureDevSshConfigBlock(syncUser, syncHost);
|
|
40
|
+
if (res.ok && res.configPath && res.hostAlias) {
|
|
41
|
+
if (res.skippedDuplicate) {
|
|
42
|
+
logger.log(
|
|
43
|
+
chalk.gray(' SSH config already has ') +
|
|
44
|
+
chalk.cyan(`${syncUser}@${syncHost}`) +
|
|
45
|
+
chalk.gray(` (Host ${res.hostAlias}); left unchanged.`)
|
|
46
|
+
);
|
|
47
|
+
} else {
|
|
48
|
+
logger.log(
|
|
49
|
+
chalk.green(' ✔ SSH config updated: ') +
|
|
50
|
+
chalk.cyan(`Host ${res.hostAlias}`) +
|
|
51
|
+
chalk.gray(` → ${res.configPath}`)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return { hostAlias: res.hostAlias, syncUser, syncHost };
|
|
55
|
+
}
|
|
56
|
+
if (!res.ok && res.error) {
|
|
57
|
+
logger.log(chalk.yellow(` ⚠ Could not update SSH config: ${res.error}`));
|
|
58
|
+
}
|
|
59
|
+
} catch (e) {
|
|
60
|
+
logger.log(chalk.yellow(` ⚠ Could not update SSH config: ${e.message || e}`));
|
|
61
|
+
}
|
|
62
|
+
return { hostAlias: null, syncUser, syncHost };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = { mergeDevSshConfigAfterInit, hostnameFromBaseUrl };
|