@aifabrix/builder 2.43.0 → 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 +1 -1
- 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 +31 -0
- package/integration/hubspot-test/create-hubspot.js +5 -5
- package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
- package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
- package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
- package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
- package/integration/hubspot-test/test-dataplane-down.js +3 -3
- package/integration/hubspot-test/test.js +35 -43
- 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/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- 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 +16 -7
- package/lib/app/rotate-secret.js +14 -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 +57 -121
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +19 -5
- 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 +170 -113
- package/lib/cli/setup-environment.js +7 -1
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +126 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +106 -8
- package/lib/cli/setup-service-user.js +1 -1
- package/lib/cli/setup-utility.js +36 -20
- 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 +6 -6
- 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 +105 -98
- 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 +2 -2
- package/lib/commands/repair.js +21 -3
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +21 -12
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +4 -4
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +26 -25
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +3 -2
- package/lib/commands/up-dataplane.js +29 -16
- 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 +14 -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 +55 -56
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +1 -1
- 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 +200 -37
- package/lib/core/templates-env.js +4 -3
- package/lib/datasource/abac-validator.js +1 -10
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +9 -6
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +84 -53
- package/lib/datasource/resolve-app.js +4 -4
- package/lib/datasource/test-e2e.js +95 -146
- package/lib/datasource/test-integration.js +114 -122
- 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 +157 -13
- 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 +92 -6
- 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.js +16 -4
- package/lib/generator/helpers.js +58 -3
- package/lib/generator/index.js +4 -0
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +1 -1
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +8 -8
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +201 -29
- package/lib/infrastructure/index.js +28 -17
- 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 +1200 -442
- 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-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 +166 -7
- 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/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 +35 -8
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +92 -13
- 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-readme.js +8 -1
- package/lib/utils/external-system-display.js +234 -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 +30 -12
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +11 -8
- 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 +3 -4
- package/lib/utils/paths.js +134 -47
- 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 +169 -49
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +32 -38
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -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 +1 -2
- 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 +33 -14
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +1 -1
- package/lib/validation/external-manifest-validator.js +27 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +4 -13
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +22 -65
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +7 -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 +75 -17
- 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 +42 -12
- 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/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/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -60
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CI helper: fail when Builder lib/schema/datasource-test-run.schema.json drifts from Dataplane copy.
|
|
4
|
+
* @fileoverview Schema sync gate (plan §8.1)
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable no-console -- CLI script */
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { assertDatasourceTestRunSchemasInSync } = require('../lib/utils/datasource-test-run-schema-sync');
|
|
10
|
+
|
|
11
|
+
const root = path.join(__dirname, '..');
|
|
12
|
+
const builderSchema = path.join(root, 'lib/schema/datasource-test-run.schema.json');
|
|
13
|
+
const dpRoot = process.env.AIFABRIX_DATAPLANE_ROOT || path.join(root, '..', 'aifabrix-dataplane');
|
|
14
|
+
const dataplaneSchema = path.join(dpRoot, 'app/schemas/json/datasource-test-run.schema.json');
|
|
15
|
+
|
|
16
|
+
const strict = process.env.AIFABRIX_SCHEMA_SYNC_STRICT === '1';
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const result = assertDatasourceTestRunSchemasInSync(builderSchema, dataplaneSchema);
|
|
20
|
+
if (result.skipped) {
|
|
21
|
+
const msg = result.reason || 'Dataplane schema path missing';
|
|
22
|
+
if (strict) {
|
|
23
|
+
console.error(`Schema sync failed (strict): ${msg}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
console.warn(`Schema sync skipped: ${msg}`);
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
console.log(`DatasourceTestRun schema OK (sha256 ${result.builderSha})`);
|
|
30
|
+
process.exit(0);
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.error(e.message || String(e));
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* List every PATH hit for aifabrix / af and each --version (find duplicate installs).
|
|
6
|
+
*
|
|
7
|
+
* @fileoverview CLI path diagnostic for @aifabrix/builder
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { execFileSync, execSync } = require('child_process');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Reads package.json `bin` field.
|
|
16
|
+
* @returns {Record<string, string>|string} Bin map or single path string
|
|
17
|
+
*/
|
|
18
|
+
function readBins() {
|
|
19
|
+
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
20
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
21
|
+
return pkg.bin || { aifabrix: 'bin/aifabrix.js' };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Resolves every PATH directory that exposes an executable named `binName`.
|
|
26
|
+
* @param {string} binName - CLI name (e.g. aifabrix)
|
|
27
|
+
* @returns {Array<{ path: string, real: string }>} Deduped hits with real paths
|
|
28
|
+
*/
|
|
29
|
+
function locationsOnPath(binName) {
|
|
30
|
+
if (process.platform === 'win32') {
|
|
31
|
+
try {
|
|
32
|
+
const out = execSync(`where ${binName}`, {
|
|
33
|
+
encoding: 'utf8',
|
|
34
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
35
|
+
}).trim();
|
|
36
|
+
return out.split(/\r?\n/).filter(Boolean).map((p) => ({ path: p, real: p }));
|
|
37
|
+
} catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const dirs = (process.env.PATH || '').split(path.delimiter).filter(Boolean);
|
|
43
|
+
const out = [];
|
|
44
|
+
const seenReal = new Set();
|
|
45
|
+
for (const dir of dirs) {
|
|
46
|
+
const candidate = path.join(dir, binName);
|
|
47
|
+
try {
|
|
48
|
+
const st = fs.lstatSync(candidate);
|
|
49
|
+
if (!st.isFile() && !st.isSymbolicLink()) continue;
|
|
50
|
+
fs.accessSync(candidate, fs.constants.X_OK);
|
|
51
|
+
const real = fs.realpathSync(candidate);
|
|
52
|
+
if (seenReal.has(real)) continue;
|
|
53
|
+
seenReal.add(real);
|
|
54
|
+
out.push({ path: candidate, real });
|
|
55
|
+
} catch {
|
|
56
|
+
// not found or not executable
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Runs `executablePath --version` and returns stdout or null on failure.
|
|
64
|
+
* @param {string} executablePath - Absolute path to the binary
|
|
65
|
+
* @returns {string|null} Trimmed version output
|
|
66
|
+
*/
|
|
67
|
+
function versionAt(executablePath) {
|
|
68
|
+
try {
|
|
69
|
+
return execFileSync(executablePath, ['--version'], {
|
|
70
|
+
encoding: 'utf8',
|
|
71
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
72
|
+
}).trim();
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Prints PNPM_HOME and npm prefix for debugging PATH issues.
|
|
80
|
+
* @returns {void}
|
|
81
|
+
*/
|
|
82
|
+
function printEnvironment() {
|
|
83
|
+
console.log('Environment (relevant to global CLIs)\n');
|
|
84
|
+
console.log(` PNPM_HOME ${process.env.PNPM_HOME || '(not set)'}`);
|
|
85
|
+
try {
|
|
86
|
+
const prefix = execSync('npm config get prefix', {
|
|
87
|
+
encoding: 'utf8',
|
|
88
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
89
|
+
}).trim();
|
|
90
|
+
console.log(` npm prefix ${prefix}`);
|
|
91
|
+
} catch {
|
|
92
|
+
console.log(' npm prefix (could not read)');
|
|
93
|
+
}
|
|
94
|
+
console.log('');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @param {string[]} names - Bin names from package.json
|
|
99
|
+
* @returns {void}
|
|
100
|
+
*/
|
|
101
|
+
function printBinReports(names) {
|
|
102
|
+
for (const name of names) {
|
|
103
|
+
console.log(`── ${name} ──`);
|
|
104
|
+
const hits = locationsOnPath(name);
|
|
105
|
+
if (!hits.length) {
|
|
106
|
+
console.log(' (not found on PATH)\n');
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
hits.forEach((h, i) => {
|
|
110
|
+
const ver = versionAt(h.path);
|
|
111
|
+
const marker = i === 0 ? ' ← first on PATH (what your shell runs)' : '';
|
|
112
|
+
console.log(` [${i + 1}] ${h.path}`);
|
|
113
|
+
if (h.real !== h.path) console.log(` → ${h.real}`);
|
|
114
|
+
console.log(` --version: ${ver ?? '(failed to run)'}${marker}`);
|
|
115
|
+
});
|
|
116
|
+
console.log('');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @param {string[]} names - Bin names from package.json
|
|
122
|
+
* @returns {void}
|
|
123
|
+
*/
|
|
124
|
+
function warnIfMultipleVersions(names) {
|
|
125
|
+
const uniqVersions = new Set();
|
|
126
|
+
for (const name of names) {
|
|
127
|
+
for (const h of locationsOnPath(name)) {
|
|
128
|
+
const v = versionAt(h.path);
|
|
129
|
+
if (v) uniqVersions.add(v);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (uniqVersions.size > 1) {
|
|
133
|
+
console.log('⚠ Multiple distinct --version values above: remove or reorder PATH so only one install remains.');
|
|
134
|
+
console.log(' Often: npm uninstall -g @aifabrix/builder, then ensure PNPM_HOME is before /usr/local/bin in PATH.\n');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Entry: list PATH hits and versions for each package bin.
|
|
140
|
+
* @returns {void}
|
|
141
|
+
*/
|
|
142
|
+
function main() {
|
|
143
|
+
const binField = readBins();
|
|
144
|
+
const names = typeof binField === 'string' ? ['aifabrix'] : Object.keys(binField);
|
|
145
|
+
printEnvironment();
|
|
146
|
+
printBinReports(names);
|
|
147
|
+
warnIfMultipleVersions(names);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
main();
|
package/scripts/install-local.js
CHANGED
|
@@ -10,38 +10,157 @@
|
|
|
10
10
|
* @version 2.0.0
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
const { execSync } = require('child_process');
|
|
13
|
+
const { execSync, execFileSync } = require('child_process');
|
|
14
14
|
const fs = require('fs');
|
|
15
|
+
const os = require('os');
|
|
15
16
|
const path = require('path');
|
|
16
17
|
|
|
18
|
+
const PACKAGE_NAME = '@aifabrix/builder';
|
|
19
|
+
/** Primary CLI name used for “current version” before link */
|
|
20
|
+
const PRIMARY_BIN = 'aifabrix';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default PNPM_HOME when not set in the environment (matches `pnpm setup` on Linux/macOS; Windows uses LOCALAPPDATA).
|
|
24
|
+
* @returns {string} Resolved PNPM global bin home directory
|
|
25
|
+
*/
|
|
26
|
+
function defaultPnpmHome() {
|
|
27
|
+
if (process.env.PNPM_HOME) {
|
|
28
|
+
return process.env.PNPM_HOME;
|
|
29
|
+
}
|
|
30
|
+
if (process.platform === 'win32' && process.env.LOCALAPPDATA) {
|
|
31
|
+
return path.join(process.env.LOCALAPPDATA, 'pnpm');
|
|
32
|
+
}
|
|
33
|
+
return path.join(os.homedir(), '.local', 'share', 'pnpm');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Environment with PNPM_HOME and PATH set so `pnpm link --global` can find the global bin dir
|
|
38
|
+
* (same idea as aifabrix-setup/scripts/install-local.js).
|
|
39
|
+
* @returns {NodeJS.ProcessEnv} Copy of process.env with pnpm paths prepended
|
|
40
|
+
*/
|
|
41
|
+
function pnpmEnv() {
|
|
42
|
+
const env = { ...process.env };
|
|
43
|
+
const pnpmHome = defaultPnpmHome();
|
|
44
|
+
env.PNPM_HOME = pnpmHome;
|
|
45
|
+
env.PATH = [pnpmHome, env.PATH].filter(Boolean).join(path.delimiter);
|
|
46
|
+
return env;
|
|
47
|
+
}
|
|
48
|
+
|
|
17
49
|
/**
|
|
18
50
|
* Detect which package manager is being used (pnpm or npm)
|
|
19
51
|
* @returns {string} 'pnpm' or 'npm'
|
|
20
52
|
*/
|
|
21
53
|
function detectPackageManager() {
|
|
22
54
|
try {
|
|
23
|
-
// Check if pnpm is available
|
|
24
55
|
execSync('which pnpm', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
25
56
|
return 'pnpm';
|
|
26
57
|
} catch {
|
|
27
|
-
// Fall back to npm
|
|
28
58
|
return 'npm';
|
|
29
59
|
}
|
|
30
60
|
}
|
|
31
61
|
|
|
32
62
|
/**
|
|
33
|
-
*
|
|
34
|
-
* @returns {string
|
|
63
|
+
* Reads package.json `bin` keys (or default primary bin).
|
|
64
|
+
* @returns {string[]} CLI executable names published by this package
|
|
65
|
+
*/
|
|
66
|
+
function listCliBinNames() {
|
|
67
|
+
try {
|
|
68
|
+
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
69
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
70
|
+
const bin = packageJson.bin;
|
|
71
|
+
if (!bin) return [PRIMARY_BIN];
|
|
72
|
+
if (typeof bin === 'string') return [PRIMARY_BIN];
|
|
73
|
+
return Object.keys(bin);
|
|
74
|
+
} catch {
|
|
75
|
+
return [PRIMARY_BIN];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {string} binName - CLI name on PATH
|
|
81
|
+
* @param {NodeJS.ProcessEnv} [env] - Optional env (e.g. pnpm-adjusted PATH)
|
|
82
|
+
* @returns {string|null} Trimmed `--version` output or null if command fails
|
|
83
|
+
*/
|
|
84
|
+
function getBinVersion(binName, env) {
|
|
85
|
+
try {
|
|
86
|
+
return execSync(`${binName} --version`, {
|
|
87
|
+
encoding: 'utf8',
|
|
88
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
89
|
+
env: env || process.env
|
|
90
|
+
}).trim();
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {string} binName - CLI name on PATH
|
|
98
|
+
* @param {NodeJS.ProcessEnv} [env] - Optional env for `which`
|
|
99
|
+
* @returns {string|null} First resolved path or null
|
|
100
|
+
*/
|
|
101
|
+
function getBinPath(binName, env) {
|
|
102
|
+
try {
|
|
103
|
+
const which = execSync(`which ${binName}`, {
|
|
104
|
+
encoding: 'utf8',
|
|
105
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
106
|
+
env: env || process.env
|
|
107
|
+
}).trim();
|
|
108
|
+
return which || null;
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* First executable `binName` on PATH (same resolution order as a POSIX shell).
|
|
116
|
+
* @param {string} binName - CLI name
|
|
117
|
+
* @param {string} pathString - PATH value (e.g. process.env.PATH)
|
|
118
|
+
* @returns {{ candidate: string, real: string }|null} First hit or null
|
|
119
|
+
*/
|
|
120
|
+
function firstExecutableOnPath(binName, pathString) {
|
|
121
|
+
if (process.platform === 'win32') {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const dirs = (pathString || '').split(path.delimiter).filter(Boolean);
|
|
125
|
+
for (const dir of dirs) {
|
|
126
|
+
const candidate = path.join(dir, binName);
|
|
127
|
+
try {
|
|
128
|
+
const st = fs.lstatSync(candidate);
|
|
129
|
+
if (!st.isFile() && !st.isSymbolicLink()) continue;
|
|
130
|
+
fs.accessSync(candidate, fs.constants.X_OK);
|
|
131
|
+
const real = fs.realpathSync(candidate);
|
|
132
|
+
return { candidate, real };
|
|
133
|
+
} catch {
|
|
134
|
+
// continue
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @param {string} executablePath - Absolute path to CLI
|
|
142
|
+
* @returns {string|null} Trimmed --version or null
|
|
35
143
|
*/
|
|
36
|
-
function
|
|
144
|
+
function versionAtExecutablePath(executablePath) {
|
|
37
145
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
146
|
+
return execFileSync(executablePath, ['--version'], {
|
|
147
|
+
encoding: 'utf8',
|
|
148
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
149
|
+
}).trim();
|
|
40
150
|
} catch {
|
|
41
151
|
return null;
|
|
42
152
|
}
|
|
43
153
|
}
|
|
44
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Get currently installed version of primary CLI (aifabrix)
|
|
157
|
+
* @param {NodeJS.ProcessEnv} [env] - Optional env for the version probe
|
|
158
|
+
* @returns {string|null} Trimmed version or null if not on PATH
|
|
159
|
+
*/
|
|
160
|
+
function getCurrentVersion(env) {
|
|
161
|
+
return getBinVersion(PRIMARY_BIN, env);
|
|
162
|
+
}
|
|
163
|
+
|
|
45
164
|
/**
|
|
46
165
|
* Get version from local package.json
|
|
47
166
|
* @returns {string|null} Version string or null if not found
|
|
@@ -81,53 +200,192 @@ function displayVersionInfo(currentVersion, packageVersion) {
|
|
|
81
200
|
}
|
|
82
201
|
}
|
|
83
202
|
|
|
203
|
+
/**
|
|
204
|
+
* @typedef {{ name: string, path: string|null, real: string|null, version: string|null }} PathBinRow
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @param {string[]} binNames - CLI names from package.json
|
|
209
|
+
* @returns {PathBinRow[]} Resolution rows for current PATH
|
|
210
|
+
*/
|
|
211
|
+
function collectPathResolutionRows(binNames) {
|
|
212
|
+
const rows = [];
|
|
213
|
+
if (process.platform === 'win32') {
|
|
214
|
+
for (const name of binNames) {
|
|
215
|
+
const p = getBinPath(name, process.env);
|
|
216
|
+
const version = p
|
|
217
|
+
? versionAtExecutablePath(p) || getBinVersion(name, process.env)
|
|
218
|
+
: getBinVersion(name, process.env);
|
|
219
|
+
rows.push({ name, path: p, real: p, version });
|
|
220
|
+
}
|
|
221
|
+
return rows;
|
|
222
|
+
}
|
|
223
|
+
for (const name of binNames) {
|
|
224
|
+
const hit = firstExecutableOnPath(name, process.env.PATH);
|
|
225
|
+
if (!hit) {
|
|
226
|
+
rows.push({ name, path: null, real: null, version: null });
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const version =
|
|
230
|
+
versionAtExecutablePath(hit.candidate) || getBinVersion(name, process.env);
|
|
231
|
+
rows.push({ name, path: hit.candidate, real: hit.real, version });
|
|
232
|
+
}
|
|
233
|
+
return rows;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @param {PathBinRow[]} rows - Rows from collectPathResolutionRows
|
|
238
|
+
* @param {boolean} multipleBins - Whether package exposes more than one CLI name
|
|
239
|
+
* @returns {void}
|
|
240
|
+
*/
|
|
241
|
+
function printPathResolutionTable(rows, multipleBins) {
|
|
242
|
+
const label = multipleBins
|
|
243
|
+
? 'First match on your PATH for each command (what new programs see):'
|
|
244
|
+
: 'First match on your PATH (what new programs see):';
|
|
245
|
+
console.log(`\n${label}`);
|
|
246
|
+
for (const r of rows) {
|
|
247
|
+
if (!r.path) {
|
|
248
|
+
console.log(` ${r.name}: (not found on PATH)`);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const ver = r.version !== null && r.version !== undefined ? r.version : '(could not run --version)';
|
|
252
|
+
const arrow = r.real !== r.path ? ` → ${r.real}` : '';
|
|
253
|
+
console.log(` ${r.name}: ${r.path}${arrow} → ${ver}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* @param {PathBinRow[]} rows - Rows from collectPathResolutionRows
|
|
259
|
+
* @param {string|null} expectedVersion - Linked package version
|
|
260
|
+
* @param {string[]} binNames - Bin names (length for multi-alias tip)
|
|
261
|
+
* @returns {void}
|
|
262
|
+
*/
|
|
263
|
+
function printPathResolutionWarnings(rows, expectedVersion, binNames) {
|
|
264
|
+
const versions = rows
|
|
265
|
+
.map((r) => r.version)
|
|
266
|
+
.filter((v) => v !== null && v !== undefined && v !== '(could not run --version)');
|
|
267
|
+
const uniq = [...new Set(versions)];
|
|
268
|
+
const mismatchAliases = uniq.length > 1;
|
|
269
|
+
const hasStaleVers =
|
|
270
|
+
Boolean(expectedVersion) &&
|
|
271
|
+
rows.some(
|
|
272
|
+
(r) => r.version !== null && r.version !== undefined && r.version !== expectedVersion
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
if (hasStaleVers) {
|
|
276
|
+
console.log(`\n⚠️ At least one command above is not ${expectedVersion} (linked package version).`);
|
|
277
|
+
console.log(' Another install is winning on PATH for that name — often an old npm global copy.');
|
|
278
|
+
console.log(' Try: pnpm run diagnose:cli');
|
|
279
|
+
console.log(` Then: npm uninstall -g ${PACKAGE_NAME}`);
|
|
280
|
+
console.log(' Put PNPM_HOME (or ~/.local/share/pnpm) before other global bin dirs in PATH if needed.');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (mismatchAliases) {
|
|
284
|
+
console.log('\n⚠️ `af` and `aifabrix` resolve to different installs on PATH.');
|
|
285
|
+
console.log(' Fix PATH as above, or if PATH looks correct, your shell may be using a stale location for one of them.');
|
|
286
|
+
console.log(' Bash: hash -r Zsh: rehash Then run both with --version again.');
|
|
287
|
+
} else if (binNames.length > 1 && expectedVersion && uniq.length === 1 && uniq[0] === expectedVersion) {
|
|
288
|
+
console.log('\nTip: Bash caches `af` and `aifabrix` separately. If your terminal shows a wrong version for only one, run: hash -r');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Report first PATH hit per bin (matches new subprocesses). Warn on mismatch vs link or between aliases.
|
|
294
|
+
* Bash/zsh cache each command name separately — `af` can stay stale while `aifabrix` updates; suggest hash -r.
|
|
295
|
+
* @param {string|null} expectedVersion - Version from the linked package (pnpm env probe)
|
|
296
|
+
* @param {string[]} binNames - All bin entries from package.json
|
|
297
|
+
* @returns {void}
|
|
298
|
+
*/
|
|
299
|
+
function reportCliAliasesOnPath(expectedVersion, binNames) {
|
|
300
|
+
if (!binNames.length) return;
|
|
301
|
+
const rows = collectPathResolutionRows(binNames);
|
|
302
|
+
printPathResolutionTable(rows, binNames.length > 1);
|
|
303
|
+
printPathResolutionWarnings(rows, expectedVersion, binNames);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Prints pnpm-specific hints when shell PATH still resolves an old binary.
|
|
308
|
+
* @param {boolean} usedPnpm - Whether link used pnpm
|
|
309
|
+
* @param {string|null} newVersion - Version after link
|
|
310
|
+
* @param {Object} [pathInfo] - Shell vs linked path probe
|
|
311
|
+
* @param {string|null} [pathInfo.versionInShell] - Version from default shell env
|
|
312
|
+
* @param {string|null} [pathInfo.linkedPath] - Path under pnpm env
|
|
313
|
+
* @returns {void}
|
|
314
|
+
*/
|
|
315
|
+
function printPnpmPathHints(usedPnpm, newVersion, pathInfo) {
|
|
316
|
+
if (!usedPnpm) return;
|
|
317
|
+
const shellVersion = pathInfo && pathInfo.versionInShell;
|
|
318
|
+
const linkedPath = pathInfo && pathInfo.linkedPath;
|
|
319
|
+
if (newVersion && shellVersion !== newVersion) {
|
|
320
|
+
console.log(`\n⚠️ Your shell is still running an older ${PRIMARY_BIN} (${shellVersion || 'unknown'}).`);
|
|
321
|
+
console.log(` The linked binary is at: ${linkedPath || 'unknown'}`);
|
|
322
|
+
console.log(' Fix: run source ~/.bashrc (or open a new terminal).');
|
|
323
|
+
console.log(' If it still shows the old version, put pnpm\'s global bin first in PATH, or run:');
|
|
324
|
+
console.log(` npm uninstall -g ${PACKAGE_NAME}`);
|
|
325
|
+
} else {
|
|
326
|
+
console.log('If you still see an old version, run: source ~/.bashrc (or open a new terminal)');
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
84
330
|
/**
|
|
85
331
|
* Display success message with version information
|
|
86
332
|
* @param {string|null} currentVersion - Version before linking
|
|
87
333
|
* @param {string|null} newVersion - Version after linking
|
|
334
|
+
* @param {boolean} [usedPnpm] - Link used pnpm
|
|
335
|
+
* @param {Object} [pathInfo] - Optional shell vs linked path info
|
|
336
|
+
* @param {string|null} [pathInfo.versionInShell] - Version from default shell env
|
|
337
|
+
* @param {string|null} [pathInfo.linkedPath] - Path under pnpm env
|
|
338
|
+
* @param {string[]} [binNames] - Bin names from package.json
|
|
88
339
|
* @returns {void}
|
|
89
340
|
*/
|
|
90
|
-
function displaySuccessMessage(currentVersion, newVersion) {
|
|
91
|
-
|
|
341
|
+
function displaySuccessMessage(currentVersion, newVersion, usedPnpm, pathInfo, binNames) {
|
|
342
|
+
const bins = binNames && binNames.length ? binNames : [PRIMARY_BIN];
|
|
343
|
+
console.log('\n✔ Successfully linked!');
|
|
92
344
|
if (currentVersion && newVersion && currentVersion !== newVersion) {
|
|
93
345
|
console.log(`📊 Version updated: ${currentVersion} → ${newVersion}`);
|
|
94
346
|
} else if (newVersion) {
|
|
95
347
|
console.log(`📊 Installed version: ${newVersion}`);
|
|
96
348
|
}
|
|
97
|
-
|
|
349
|
+
const verifyHint =
|
|
350
|
+
bins.length > 1
|
|
351
|
+
? bins.map((b) => `${b} --version`).join('" or "')
|
|
352
|
+
: `${bins[0]} --version`;
|
|
353
|
+
console.log(`Run "${verifyHint}" to verify.`);
|
|
354
|
+
if (bins.length > 1) {
|
|
355
|
+
console.log(
|
|
356
|
+
'If only one alias shows the wrong version in your terminal, clear the shell command cache (bash: hash -r, zsh: rehash).'
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
printPnpmPathHints(usedPnpm, newVersion, pathInfo);
|
|
361
|
+
reportCliAliasesOnPath(newVersion, bins);
|
|
98
362
|
}
|
|
99
363
|
|
|
100
364
|
/**
|
|
101
|
-
*
|
|
102
|
-
* @param {string}
|
|
365
|
+
* Runs global link and reports success (throws on failure).
|
|
366
|
+
* @param {string} pm - 'pnpm' or 'npm'
|
|
367
|
+
* @param {string|null} currentVersion - Version before link
|
|
368
|
+
* @param {string[]} binNames - CLI bin names
|
|
103
369
|
* @returns {void}
|
|
104
|
-
* @throws {Error} If linking fails when pnpm global bin is not configured
|
|
105
370
|
*/
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
const msg = (pnpmErr.message || String(pnpmErr));
|
|
113
|
-
if (msg.includes('global bin directory') || msg.includes('ERR_PNPM_NO_GLOBAL_BIN_DIR')) {
|
|
114
|
-
console.log(
|
|
115
|
-
'⚠️ pnpm global bin is not set up. Run "pnpm setup" and add PNPM_HOME to PATH, or we will use npm link.\n'
|
|
116
|
-
);
|
|
117
|
-
} else {
|
|
118
|
-
throw pnpmErr;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
try {
|
|
371
|
+
function runGlobalLink(pm, currentVersion, binNames) {
|
|
372
|
+
const projectRoot = path.join(__dirname, '..');
|
|
373
|
+
const env = pm === 'pnpm' ? pnpmEnv() : undefined;
|
|
374
|
+
if (pm === 'pnpm') {
|
|
375
|
+
execSync('pnpm link --global', { stdio: 'inherit', cwd: projectRoot, env });
|
|
376
|
+
} else {
|
|
122
377
|
execSync('npm link', { stdio: 'inherit', cwd: projectRoot });
|
|
123
|
-
} catch {
|
|
124
|
-
if (!pnpmLinked) {
|
|
125
|
-
console.error(
|
|
126
|
-
'\n💡 To fix: run "pnpm setup" and add the suggested line to your shell config, then run install:local again.'
|
|
127
|
-
);
|
|
128
|
-
throw new Error('Linking failed. pnpm global bin not configured and npm link failed.');
|
|
129
|
-
}
|
|
130
378
|
}
|
|
379
|
+
|
|
380
|
+
const newVersion = getCurrentVersion(env);
|
|
381
|
+
let pathInfo;
|
|
382
|
+
if (pm === 'pnpm') {
|
|
383
|
+
pathInfo = {
|
|
384
|
+
versionInShell: getCurrentVersion(),
|
|
385
|
+
linkedPath: getBinPath(PRIMARY_BIN, env)
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
displaySuccessMessage(currentVersion, newVersion, pm === 'pnpm', pathInfo, binNames);
|
|
131
389
|
}
|
|
132
390
|
|
|
133
391
|
/**
|
|
@@ -137,23 +395,17 @@ function runPnpmLink(projectRoot) {
|
|
|
137
395
|
function installLocal() {
|
|
138
396
|
const pm = detectPackageManager();
|
|
139
397
|
const packageVersion = getPackageVersion();
|
|
398
|
+
const binNames = listCliBinNames();
|
|
140
399
|
const currentVersion = getCurrentVersion();
|
|
141
400
|
|
|
142
401
|
console.log(`Detected package manager: ${pm}\n`);
|
|
143
402
|
displayVersionInfo(currentVersion, packageVersion);
|
|
144
|
-
console.log(
|
|
403
|
+
console.log(`Linking ${PACKAGE_NAME} globally...\n`);
|
|
145
404
|
|
|
146
405
|
try {
|
|
147
|
-
|
|
148
|
-
if (pm === 'pnpm') {
|
|
149
|
-
runPnpmLink(projectRoot);
|
|
150
|
-
} else {
|
|
151
|
-
execSync('npm link', { stdio: 'inherit', cwd: projectRoot });
|
|
152
|
-
}
|
|
153
|
-
const newVersion = getCurrentVersion();
|
|
154
|
-
displaySuccessMessage(currentVersion, newVersion);
|
|
406
|
+
runGlobalLink(pm, currentVersion, binNames);
|
|
155
407
|
} catch (error) {
|
|
156
|
-
console.error('\n
|
|
408
|
+
console.error('\n✖ Failed to link package:', error.message);
|
|
157
409
|
process.exit(1);
|
|
158
410
|
}
|
|
159
411
|
}
|
|
@@ -192,7 +444,7 @@ function displayUninstallVersionInfo(currentVersion, packageVersion) {
|
|
|
192
444
|
* @returns {void}
|
|
193
445
|
*/
|
|
194
446
|
function displayUninstallSuccess(pm, currentVersion) {
|
|
195
|
-
console.log(`\n
|
|
447
|
+
console.log(`\n✔ Successfully unlinked with ${pm}!`);
|
|
196
448
|
if (currentVersion) {
|
|
197
449
|
console.log(`📊 Uninstalled version: ${currentVersion}`);
|
|
198
450
|
}
|
|
@@ -208,22 +460,19 @@ function uninstallLocal() {
|
|
|
208
460
|
const packageVersion = getPackageVersion();
|
|
209
461
|
|
|
210
462
|
console.log(`Detected package manager: ${pm}\n`);
|
|
211
|
-
|
|
212
|
-
// Show version information before unlinking
|
|
213
463
|
displayUninstallVersionInfo(currentVersion, packageVersion);
|
|
214
|
-
|
|
215
|
-
console.log('Unlinking @aifabrix/builder globally...\n');
|
|
464
|
+
console.log(`Unlinking ${PACKAGE_NAME} globally...\n`);
|
|
216
465
|
|
|
217
466
|
try {
|
|
218
467
|
if (pm === 'pnpm') {
|
|
219
|
-
execSync(
|
|
468
|
+
execSync(`pnpm unlink --global ${PACKAGE_NAME}`, { stdio: 'inherit', env: pnpmEnv() });
|
|
220
469
|
displayUninstallSuccess(pm, currentVersion);
|
|
221
470
|
} else {
|
|
222
|
-
execSync(
|
|
471
|
+
execSync(`npm unlink -g ${PACKAGE_NAME}`, { stdio: 'inherit' });
|
|
223
472
|
displayUninstallSuccess(pm, currentVersion);
|
|
224
473
|
}
|
|
225
474
|
} catch (error) {
|
|
226
|
-
console.error('\n
|
|
475
|
+
console.error('\n✖ Failed to unlink package:', error.message);
|
|
227
476
|
process.exit(1);
|
|
228
477
|
}
|
|
229
478
|
}
|
package/templates/README.md
CHANGED
|
@@ -8,7 +8,7 @@ The templates directory is organized as follows:
|
|
|
8
8
|
|
|
9
9
|
### Application Templates (for `--template` flag)
|
|
10
10
|
|
|
11
|
-
Application templates are folder-based and located under `templates/applications/`. When you use `--template <name>`, the tool looks for `templates/applications/<name>/` and copies all files from that folder to `builder/<
|
|
11
|
+
Application templates are folder-based and located under `templates/applications/`. When you use `--template <name>`, the tool looks for `templates/applications/<name>/` and copies all files from that folder to `builder/<appKey>/`.
|
|
12
12
|
|
|
13
13
|
**Example:**
|
|
14
14
|
- `templates/applications/miso-controller/` - Miso Controller application template
|
|
@@ -18,7 +18,7 @@ Application templates are folder-based and located under `templates/applications
|
|
|
18
18
|
- Template folder must exist in `templates/applications/<name>/`
|
|
19
19
|
- Template folder must contain at least one file
|
|
20
20
|
- Hidden files (starting with `.`) are skipped
|
|
21
|
-
- If a template includes a `Dockerfile`, it will be copied to `builder/<
|
|
21
|
+
- If a template includes a `Dockerfile`, it will be copied to `builder/<appKey>/Dockerfile` along with other files
|
|
22
22
|
|
|
23
23
|
### Language Templates
|
|
24
24
|
|
|
@@ -63,6 +63,19 @@ Extra workflow steps are located in `templates/github/steps/`. When you use `--g
|
|
|
63
63
|
### Health Check Configuration
|
|
64
64
|
- `{{healthCheck.path}}` - Health check endpoint path (e.g., "/health")
|
|
65
65
|
- `{{healthCheck.interval}}` - Health check interval in seconds
|
|
66
|
+
- `{{healthCheck.bashProbe}}` - When true, generated Docker Compose uses a bash TCP probe (no `curl` dependency) instead of `curl -f`.
|
|
67
|
+
|
|
68
|
+
**Why `bashProbe` exists**
|
|
69
|
+
|
|
70
|
+
Some application images intentionally do not ship with `curl` (for smaller images or stricter runtime environments). If Compose uses a `curl`-based healthcheck in those images, Docker will mark the container as **unhealthy** even when the app is actually serving traffic.
|
|
71
|
+
|
|
72
|
+
Set `healthCheck.bashProbe: true` to make Compose healthchecks work without `curl` by performing a minimal HTTP request over `/dev/tcp`.
|
|
73
|
+
|
|
74
|
+
### Traefik (Docker Compose labels)
|
|
75
|
+
|
|
76
|
+
Generated compose includes `traefik.http.routers.<app>.service=<app>` so Traefik’s Docker provider always binds the router to the in-compose service (required for HTTP-only routers when TLS terminates at nginx).
|
|
77
|
+
|
|
78
|
+
Infra Traefik is started with `--providers.docker.allowEmptyServices=true` so routes are published while a container is still in Docker’s `starting` / `unhealthy` health state (common during slow boots or when a health probe differs from real readiness).
|
|
66
79
|
|
|
67
80
|
### Service Requirements
|
|
68
81
|
- `{{requiresDatabase}}` - Database requirement flag (conditional db-init service)
|