@aifabrix/builder 2.45.0 → 2.46.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.
Files changed (352) hide show
  1. package/.cursor/rules/cli-layout.mdc +2 -0
  2. package/.cursor/rules/cli-product-neutral.mdc +43 -0
  3. package/.cursor/rules/docs-rules.mdc +3 -1
  4. package/.cursor/rules/project-rules.mdc +1 -0
  5. package/README.md +43 -17
  6. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
  7. package/jest.config.default.js +2 -1
  8. package/jest.config.isolated.js +2 -1
  9. package/jest.global-live-fabrix-hooks.js +36 -0
  10. package/jest.isolated-projects.js +130 -0
  11. package/jest.projects.js +69 -121
  12. package/lib/api/agent-metadata-validation.api.js +93 -0
  13. package/lib/api/api-response-errors.js +124 -0
  14. package/lib/api/audit-api-helpers.js +68 -0
  15. package/lib/api/audit.api.js +119 -0
  16. package/lib/api/auth-cache.api.js +44 -0
  17. package/lib/api/certificates.api.js +4 -4
  18. package/lib/api/credential.api.js +2 -2
  19. package/lib/api/dataplane-health.api.js +137 -0
  20. package/lib/api/dataplane-sync.api.js +27 -0
  21. package/lib/api/datasources-core.api.js +21 -18
  22. package/lib/api/datasources-extended.api.js +22 -22
  23. package/lib/api/dimensions.api.js +3 -0
  24. package/lib/api/external-systems.api.js +13 -13
  25. package/lib/api/governance-scenario-pack.api.js +159 -0
  26. package/lib/api/governance-scenarios.api.js +39 -0
  27. package/lib/api/groups.api.js +79 -0
  28. package/lib/api/index.js +88 -5
  29. package/lib/api/lifecycle.api.js +77 -0
  30. package/lib/api/pipeline.api.js +7 -5
  31. package/lib/api/protection.api.js +157 -0
  32. package/lib/api/records-bulk.api.js +43 -0
  33. package/lib/api/records-search-parse.js +49 -0
  34. package/lib/api/records-search.api.js +29 -0
  35. package/lib/api/types/agent-metadata-validation.types.js +67 -0
  36. package/lib/api/types/audit.types.js +72 -0
  37. package/lib/api/types/dataplane-health.types.js +27 -0
  38. package/lib/api/types/dimensions.types.js +2 -0
  39. package/lib/api/types/governance-scenarios.types.js +39 -0
  40. package/lib/api/types/protection.types.js +69 -0
  41. package/lib/api/types/records-bulk.types.js +35 -0
  42. package/lib/api/types/records-search.types.js +28 -0
  43. package/lib/api/user-groups.api.js +50 -0
  44. package/lib/api/users.api.js +95 -0
  45. package/lib/api/validation-run.api.js +3 -3
  46. package/lib/api/validation-runner.js +5 -3
  47. package/lib/api/wizard-platform.api.js +3 -3
  48. package/lib/api/wizard.api.js +21 -21
  49. package/lib/app/deploy-config.js +4 -1
  50. package/lib/app/deploy.js +34 -19
  51. package/lib/app/down.js +20 -1
  52. package/lib/app/push.js +4 -5
  53. package/lib/app/register.js +7 -4
  54. package/lib/app/run-env-compose.js +84 -30
  55. package/lib/build/index.js +5 -0
  56. package/lib/certification/sync-system-certification.js +13 -6
  57. package/lib/cli/index.js +8 -2
  58. package/lib/cli/infra-guided-auth.js +109 -0
  59. package/lib/cli/infra-guided.js +91 -69
  60. package/lib/cli/setup-app.help.js +19 -2
  61. package/lib/cli/setup-app.js +58 -23
  62. package/lib/cli/setup-app.test-commands.js +28 -21
  63. package/lib/cli/setup-auth.js +55 -3
  64. package/lib/cli/setup-certification-commands.js +147 -0
  65. package/lib/cli/setup-certification.help.js +141 -0
  66. package/lib/cli/setup-environment.js +19 -2
  67. package/lib/cli/setup-external-system-help.js +62 -0
  68. package/lib/cli/setup-external-system.js +62 -6
  69. package/lib/cli/setup-infra.js +9 -1
  70. package/lib/cli/setup-platform.js +6 -1
  71. package/lib/cli/setup-secrets.js +33 -1
  72. package/lib/cli/setup-utility-help-after.js +65 -0
  73. package/lib/cli/setup-utility-repair.js +198 -0
  74. package/lib/cli/setup-utility-resolve.js +42 -6
  75. package/lib/cli/setup-utility-validate.js +197 -0
  76. package/lib/cli/setup-utility.js +41 -258
  77. package/lib/commands/auth-status-client-tokens.js +214 -0
  78. package/lib/commands/auth-status-dataplane-version.js +269 -0
  79. package/lib/commands/auth-status-display.js +94 -0
  80. package/lib/commands/auth-status.js +111 -53
  81. package/lib/commands/credential-push.js +10 -5
  82. package/lib/commands/datasource-load-export-cli.js +178 -0
  83. package/lib/commands/datasource-test-trust-cli.js +118 -0
  84. package/lib/commands/datasource-unified-test-cli.js +31 -20
  85. package/lib/commands/datasource-unified-test-cli.options.js +22 -3
  86. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
  87. package/lib/commands/datasource-verify-audit-cli.js +96 -0
  88. package/lib/commands/datasource.js +68 -1
  89. package/lib/commands/dev-show-display.js +8 -1
  90. package/lib/commands/dimension-value.js +43 -13
  91. package/lib/commands/dimension.js +38 -7
  92. package/lib/commands/governance-cli-shared.js +94 -0
  93. package/lib/commands/governance-command-action.js +132 -0
  94. package/lib/commands/governance-download-external.js +34 -0
  95. package/lib/commands/governance-generate-external.js +71 -0
  96. package/lib/commands/governance-upload-external.js +36 -0
  97. package/lib/commands/governance-verify-external.js +64 -0
  98. package/lib/commands/governance.js +144 -0
  99. package/lib/commands/identity-apply-sync.js +131 -0
  100. package/lib/commands/identity-group-cli.js +146 -0
  101. package/lib/commands/identity-membership-role-cache.js +175 -0
  102. package/lib/commands/identity-shared.js +94 -0
  103. package/lib/commands/identity-user-cli.js +158 -0
  104. package/lib/commands/identity.js +43 -0
  105. package/lib/commands/lifecycle-command-action.js +123 -0
  106. package/lib/commands/lifecycle-external.js +268 -0
  107. package/lib/commands/login.js +56 -17
  108. package/lib/commands/protection-cli-leaves.js +286 -0
  109. package/lib/commands/protection.js +50 -0
  110. package/lib/commands/repair-auth-apply.js +127 -0
  111. package/lib/commands/repair-changed-files.js +41 -0
  112. package/lib/commands/repair-datasource-keys.js +4 -1
  113. package/lib/commands/repair-datasource-run.js +59 -0
  114. package/lib/commands/repair-datasource-test-payload.js +259 -0
  115. package/lib/commands/repair-datasource.js +1 -51
  116. package/lib/commands/repair-env-template.js +64 -13
  117. package/lib/commands/repair-external-run.js +216 -0
  118. package/lib/commands/repair-openapi-sync.js +23 -0
  119. package/lib/commands/repair-persist.js +4 -0
  120. package/lib/commands/repair-rbac.js +52 -1
  121. package/lib/commands/repair-steps.js +145 -0
  122. package/lib/commands/repair.js +29 -286
  123. package/lib/commands/secrets-get.js +184 -0
  124. package/lib/commands/secrets-remove-all.js +3 -1
  125. package/lib/commands/setup-image-refresh.js +146 -0
  126. package/lib/commands/setup-modes.js +158 -162
  127. package/lib/commands/setup-platform-auth.js +76 -0
  128. package/lib/commands/setup-prompts-admin.js +244 -0
  129. package/lib/commands/setup-prompts-platform-mode.js +67 -0
  130. package/lib/commands/setup-prompts-validators.js +36 -0
  131. package/lib/commands/setup-prompts.js +24 -76
  132. package/lib/commands/setup-run-context.js +45 -0
  133. package/lib/commands/setup-spinners.js +39 -0
  134. package/lib/commands/setup.js +27 -5
  135. package/lib/commands/teardown.js +39 -0
  136. package/lib/commands/test-e2e-external.js +61 -14
  137. package/lib/commands/test-governance-cli-options.js +47 -0
  138. package/lib/commands/test-governance-external.js +67 -0
  139. package/lib/commands/test-trust-cli-options.js +32 -0
  140. package/lib/commands/test-trust-external.js +126 -0
  141. package/lib/commands/up-common.js +25 -13
  142. package/lib/commands/up-dataplane.js +50 -13
  143. package/lib/commands/upload-publish-context.js +75 -0
  144. package/lib/commands/upload-sidecar-followups.js +89 -0
  145. package/lib/commands/upload.js +108 -105
  146. package/lib/commands/verify-governance-combined-external.js +61 -0
  147. package/lib/commands/verify-governance-command-action.js +64 -0
  148. package/lib/commands/verify-governance-db.js +102 -0
  149. package/lib/commands/verify-governance-external.js +77 -0
  150. package/lib/commands/verify-governance-result-builders.js +71 -0
  151. package/lib/commands/verify-operations-command-action.js +68 -0
  152. package/lib/commands/verify-operations-external.js +268 -0
  153. package/lib/commands/verify-operations-persist.js +75 -0
  154. package/lib/commands/verify-operations-step-plan.js +68 -0
  155. package/lib/commands/verify-operations-steps.js +111 -0
  156. package/lib/commands/verify-trust-command-action.js +70 -0
  157. package/lib/commands/verify-trust-external.js +67 -0
  158. package/lib/commands/wizard-config-normalizer.js +43 -23
  159. package/lib/commands/wizard-core.js +5 -0
  160. package/lib/core/admin-password-generator.js +38 -0
  161. package/lib/core/admin-secrets-bundle.js +111 -0
  162. package/lib/core/admin-secrets-env-overlay.js +62 -0
  163. package/lib/core/admin-secrets.js +32 -4
  164. package/lib/core/config-attach-extensions.js +3 -0
  165. package/lib/core/config-device-dataplane.js +185 -0
  166. package/lib/core/config-platform-controller.js +44 -0
  167. package/lib/core/config-setup-installation-profile.js +42 -0
  168. package/lib/core/config-setup-platform-mode.js +46 -0
  169. package/lib/core/config.js +46 -36
  170. package/lib/core/secrets-admin-env.js +6 -2
  171. package/lib/core/secrets-ensure.js +4 -0
  172. package/lib/core/secrets-env-content.js +54 -48
  173. package/lib/core/secrets-env-write.js +10 -1
  174. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  175. package/lib/core/setup-installation-profile.js +43 -0
  176. package/lib/core/setup-platform-mode.js +55 -0
  177. package/lib/datasource/agent-trust-debug-log.js +45 -0
  178. package/lib/datasource/agent-trust-fetch.js +115 -0
  179. package/lib/datasource/agent-trust-map.js +101 -0
  180. package/lib/datasource/agent-trust-mock.js +44 -0
  181. package/lib/datasource/agent-trust-run.js +95 -0
  182. package/lib/datasource/agent-trust-timeout.js +25 -0
  183. package/lib/datasource/audit-evidence-display.js +80 -0
  184. package/lib/datasource/audit-evidence-extract-debug.js +115 -0
  185. package/lib/datasource/audit-evidence-extract.js +180 -0
  186. package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
  187. package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
  188. package/lib/datasource/audit-evidence-poll.js +109 -0
  189. package/lib/datasource/audit-evidence-run.js +177 -0
  190. package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
  191. package/lib/datasource/audit-evidence-verify-matrix.js +205 -0
  192. package/lib/datasource/audit-evidence-verify.js +108 -0
  193. package/lib/datasource/bulk-loader-run-batches.js +100 -0
  194. package/lib/datasource/bulk-loader-service-retry.js +52 -0
  195. package/lib/datasource/bulk-loader-service.js +127 -0
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -1
  197. package/lib/datasource/datasource-exporter-resolve.js +82 -0
  198. package/lib/datasource/datasource-exporter-service.js +144 -0
  199. package/lib/datasource/datasource-identifier.js +148 -0
  200. package/lib/datasource/datasource-load-export-context.js +95 -0
  201. package/lib/datasource/integration-context.js +6 -4
  202. package/lib/datasource/local-data-paths.js +145 -0
  203. package/lib/datasource/log-cleaner.js +241 -0
  204. package/lib/datasource/log-viewer.js +111 -6
  205. package/lib/datasource/record-file-parser.js +85 -0
  206. package/lib/datasource/record-mapper.js +129 -0
  207. package/lib/datasource/resolve-app.js +74 -55
  208. package/lib/datasource/test-e2e.js +29 -2
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run-resolve.js +45 -12
  211. package/lib/datasource/unified-validation-run.js +47 -18
  212. package/lib/datasource/validate.js +37 -20
  213. package/lib/deployment/environment-poll-status.js +138 -0
  214. package/lib/deployment/environment.js +42 -34
  215. package/lib/external-system/download.js +21 -20
  216. package/lib/external-system/generator.js +5 -1
  217. package/lib/external-system/integration-auth-context.js +45 -0
  218. package/lib/external-system/test-auth.js +12 -5
  219. package/lib/external-system/test-system-level.js +25 -4
  220. package/lib/external-system/test.js +9 -7
  221. package/lib/generator/external-controller-manifest.js +15 -0
  222. package/lib/governance/governance-cli-errors.js +96 -0
  223. package/lib/governance/governance-download-display.js +38 -0
  224. package/lib/governance/governance-pack-loader.js +70 -0
  225. package/lib/governance/governance-run-display.js +309 -0
  226. package/lib/identity/identity-apply-core.js +108 -0
  227. package/lib/identity/identity-apply-phases.js +244 -0
  228. package/lib/identity/identity-apply-service.js +77 -0
  229. package/lib/identity/identity-csv-parser.js +114 -0
  230. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  231. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  232. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  233. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  234. package/lib/infrastructure/helpers.js +23 -129
  235. package/lib/infrastructure/index.js +5 -6
  236. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  237. package/lib/internal/fs-real-sync.js +29 -1
  238. package/lib/lifecycle/certification-progress.js +231 -0
  239. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  240. package/lib/lifecycle/exit-codes.js +24 -0
  241. package/lib/lifecycle/json-envelope.js +25 -0
  242. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  243. package/lib/lifecycle/logger-quiet.js +29 -0
  244. package/lib/lifecycle/open-api-published.js +59 -0
  245. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  246. package/lib/lifecycle/product-model.js +196 -0
  247. package/lib/lifecycle/report-display.js +471 -0
  248. package/lib/lifecycle/scenario-upload.js +191 -0
  249. package/lib/lifecycle/verify-step-progress.js +87 -0
  250. package/lib/parameters/infra-kv-discovery.js +27 -2
  251. package/lib/protection/auth-context.js +51 -0
  252. package/lib/protection/convert-batch.js +90 -0
  253. package/lib/protection/load.js +41 -0
  254. package/lib/protection/paths.js +158 -0
  255. package/lib/protection/preflight-datasource-ready.js +46 -0
  256. package/lib/protection/protection-create-probe-lines.js +142 -0
  257. package/lib/protection/protection-create-probes.js +95 -0
  258. package/lib/protection/protection-create-scaffold.js +281 -0
  259. package/lib/protection/protection-display-helpers.js +445 -0
  260. package/lib/protection/protection-display.js +215 -0
  261. package/lib/protection/protection-preset-registry.js +97 -0
  262. package/lib/protection/report-exit.js +62 -0
  263. package/lib/protection/resolve.js +202 -0
  264. package/lib/protection/run-commands-validate.js +130 -0
  265. package/lib/protection/run-commands.js +216 -0
  266. package/lib/protection/run-protection-create-helpers.js +134 -0
  267. package/lib/protection/run-protection-create-probes-flow.js +43 -0
  268. package/lib/protection/run-protection-create.js +191 -0
  269. package/lib/protection/scope.js +22 -0
  270. package/lib/protection/sync-after-upload.js +64 -0
  271. package/lib/protection/upload-batch.js +127 -0
  272. package/lib/protection/validate-batch.js +113 -0
  273. package/lib/protection/validate-local.js +65 -0
  274. package/lib/resolvers/dimension-file.js +29 -4
  275. package/lib/schema/application-schema.json +1 -1
  276. package/lib/schema/datasource-test-run.schema.json +89 -6
  277. package/lib/schema/external-datasource.schema.json +2636 -2588
  278. package/lib/schema/external-system.schema.json +1089 -761
  279. package/lib/schema/flag-map-validation-run.json +2 -2
  280. package/lib/schema/infra.parameter.yaml +45 -0
  281. package/lib/schema/protection.schema.json +374 -0
  282. package/lib/schema/type/credential-field-registry.json +642 -0
  283. package/lib/schema/wizard-config.schema.json +1 -1
  284. package/lib/utils/agent-trust-run-display.js +231 -0
  285. package/lib/utils/agent-trust-run-exit.js +59 -0
  286. package/lib/utils/agent-trust-wait-ui.js +94 -0
  287. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  288. package/lib/utils/api.js +55 -31
  289. package/lib/utils/app-relative-path-env.js +112 -0
  290. package/lib/utils/cli-exit-codes.js +30 -0
  291. package/lib/utils/cli-secrets-error-format.js +83 -21
  292. package/lib/utils/cli-sync-options.js +33 -0
  293. package/lib/utils/cli-utils.js +16 -4
  294. package/lib/utils/compose-generate-docker-compose.js +4 -0
  295. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  296. package/lib/utils/config-secrets-path.js +46 -0
  297. package/lib/utils/controller-url.js +88 -1
  298. package/lib/utils/credential-push-ui.js +90 -0
  299. package/lib/utils/credential-secrets-env.js +137 -9
  300. package/lib/utils/dataplane-cli-version-gate.js +202 -0
  301. package/lib/utils/dataplane-cli-version-help.js +74 -0
  302. package/lib/utils/dataplane-resolver.js +129 -2
  303. package/lib/utils/datasource-export-display.js +137 -0
  304. package/lib/utils/datasource-load-display.js +174 -0
  305. package/lib/utils/datasource-load-export-ui.js +120 -0
  306. package/lib/utils/datasource-test-run-capability-scope.js +3 -3
  307. package/lib/utils/datasource-test-run-display.js +3 -3
  308. package/lib/utils/datasource-test-run-tty-log.js +5 -1
  309. package/lib/utils/declarative-url-ports.js +3 -3
  310. package/lib/utils/deployment-auth-mode.js +41 -0
  311. package/lib/utils/developer-volume-id.js +33 -0
  312. package/lib/utils/env-copy.js +14 -9
  313. package/lib/utils/env-kv-orphan-lines.js +43 -0
  314. package/lib/utils/error-formatters/network-errors.js +13 -4
  315. package/lib/utils/external-env-template.js +1 -0
  316. package/lib/utils/external-system-readiness-core.js +10 -0
  317. package/lib/utils/external-system-readiness-display.js +80 -23
  318. package/lib/utils/health-check.js +4 -1
  319. package/lib/utils/help-builder.js +35 -26
  320. package/lib/utils/keycloak-realm-ready.js +101 -0
  321. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  322. package/lib/utils/manifest-source-emit.js +24 -0
  323. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  324. package/lib/utils/platform-controller-url.js +156 -0
  325. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  326. package/lib/utils/postgres-wipe.js +9 -2
  327. package/lib/utils/resolve-env-mode.js +47 -0
  328. package/lib/utils/secrets-generator.js +31 -25
  329. package/lib/utils/secrets-missing-error.js +164 -0
  330. package/lib/utils/semver-compare.js +127 -0
  331. package/lib/utils/service-url-label.js +81 -0
  332. package/lib/utils/setup-quiet-output.js +25 -0
  333. package/lib/utils/template-helpers.js +15 -0
  334. package/lib/utils/token-manager-client-credentials.js +201 -0
  335. package/lib/utils/token-manager-messages.js +8 -0
  336. package/lib/utils/token-manager-refresh.js +12 -2
  337. package/lib/utils/token-manager.js +86 -105
  338. package/lib/utils/upload-pipeline-ui.js +98 -0
  339. package/lib/utils/upload-sync-options.js +42 -0
  340. package/lib/utils/url-declarative-public-base.js +21 -3
  341. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  342. package/lib/utils/validation-poll-ui.js +22 -7
  343. package/lib/utils/validation-run-stage.js +45 -0
  344. package/lib/validation/wizard-config-validator.js +58 -19
  345. package/package.json +1 -1
  346. package/templates/applications/dataplane/application.yaml +2 -1
  347. package/templates/applications/dataplane/env.template +36 -1
  348. package/templates/applications/dataplane/rbac.yaml +4 -0
  349. package/templates/applications/miso-controller/env.template +16 -0
  350. package/templates/external-system/README.md.hbs +116 -11
  351. package/templates/python/docker-compose.hbs +19 -18
  352. package/templates/typescript/docker-compose.hbs +18 -17
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Admin credential prompts for `aifabrix setup` (dev / pro installation profiles).
3
+ *
4
+ * @fileoverview Setup installation profile + password bundle prompts
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const chalk = require('chalk');
12
+ const inquirer = require('inquirer');
13
+ const logger = require('../utils/logger');
14
+ const config = require('../core/config');
15
+ const { generateProAdminPasswords } = require('../core/admin-password-generator');
16
+ const {
17
+ singlePasswordBundle,
18
+ splitPasswordBundle
19
+ } = require('../core/admin-secrets-bundle');
20
+ const {
21
+ INSTALLATION_PROFILE,
22
+ normalizeInstallationProfile,
23
+ isProInstallationProfile
24
+ } = require('../core/setup-installation-profile');
25
+ const { validateEmail, validatePassword } = require('./setup-prompts-validators');
26
+
27
+ /**
28
+ * Resolve installation profile from CLI options or config (interactive fallback in orchestrator).
29
+ * @param {Object} [options]
30
+ * @returns {Promise<'dev'|'pro'>}
31
+ */
32
+ async function resolveInstallationProfileFromOptions(options = {}) {
33
+ const cli = options.installation ?? options.installationProfile;
34
+ if (cli !== undefined && cli !== null && String(cli).trim() !== '') {
35
+ return normalizeInstallationProfile(cli);
36
+ }
37
+ try {
38
+ return await config.getSetupInstallationProfile();
39
+ } catch {
40
+ return INSTALLATION_PROFILE.DEV;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * @async
46
+ * @returns {Promise<'dev'|'pro'>}
47
+ */
48
+ async function promptInstallationProfile() {
49
+ const { profile } = await inquirer.prompt([
50
+ {
51
+ type: 'list',
52
+ name: 'profile',
53
+ message: 'Installation profile:',
54
+ choices: [
55
+ {
56
+ name: 'Development (dev) — one admin password for all services',
57
+ value: INSTALLATION_PROFILE.DEV
58
+ },
59
+ {
60
+ name: 'Production (pro) — autogenerate strong passwords or enter manually',
61
+ value: INSTALLATION_PROFILE.PRO
62
+ }
63
+ ],
64
+ default: INSTALLATION_PROFILE.DEV
65
+ }
66
+ ]);
67
+ return profile;
68
+ }
69
+
70
+ /**
71
+ * @param {Object} [options]
72
+ * @returns {Promise<string>}
73
+ */
74
+ async function promptAdminEmail(options = {}) {
75
+ const cli = String(options.adminEmail || '').trim();
76
+ if (cli) return cli;
77
+
78
+ let defaultEmail;
79
+ try {
80
+ const saved = await config.getAdminEmail();
81
+ defaultEmail = saved && saved.trim() ? saved.trim() : undefined;
82
+ } catch {
83
+ defaultEmail = undefined;
84
+ }
85
+ const emailQuestion = {
86
+ type: 'input',
87
+ name: 'adminEmail',
88
+ message: 'Admin email (Keycloak / pgAdmin login):',
89
+ validate: validateEmail
90
+ };
91
+ if (defaultEmail !== undefined) {
92
+ emailQuestion.default = defaultEmail;
93
+ }
94
+ const { adminEmail } = await inquirer.prompt([emailQuestion]);
95
+ return String(adminEmail).trim();
96
+ }
97
+
98
+ /**
99
+ * @async
100
+ * @returns {Promise<import('../core/admin-secrets-bundle').AdminPasswordBundleSingle>}
101
+ */
102
+ async function promptDevPasswordBundle() {
103
+ const answers = await inquirer.prompt([
104
+ {
105
+ type: 'password',
106
+ name: 'adminPassword',
107
+ message: 'Admin password (Postgres / Keycloak / pgAdmin / platform login):',
108
+ mask: '*',
109
+ validate: validatePassword
110
+ },
111
+ {
112
+ type: 'password',
113
+ name: 'adminPasswordConfirm',
114
+ message: 'Confirm admin password:',
115
+ mask: '*',
116
+ validate(input, all) {
117
+ if (input !== all.adminPassword) return 'Passwords do not match';
118
+ return true;
119
+ }
120
+ }
121
+ ]);
122
+ return singlePasswordBundle(answers.adminPassword);
123
+ }
124
+
125
+ /**
126
+ * Print pro autogenerated passwords once (never log plaintext elsewhere).
127
+ * @param {{ infra: string, keycloak: string, platform: string }} passwords
128
+ */
129
+ function displayProPasswordsOnce(passwords) {
130
+ logger.log('');
131
+ logger.log(chalk.bold.yellow('Save these passwords now — they will not be shown again.'));
132
+ logger.log(chalk.gray('────────────────────────────────────────'));
133
+ logger.log(` Infra (Postgres / pgAdmin / Redis Commander): ${passwords.infra}`);
134
+ logger.log(` Keycloak install admin: ${passwords.keycloak}`);
135
+ logger.log(` Platform UI login (user admin): ${passwords.platform}`);
136
+ logger.log(chalk.gray('────────────────────────────────────────'));
137
+ logger.log('');
138
+ }
139
+
140
+ /**
141
+ * @param {Object} [options]
142
+ * @returns {Promise<import('../core/admin-secrets-bundle').AdminPasswordBundleSingle|import('../core/admin-secrets-bundle').AdminPasswordBundleSplit>}
143
+ */
144
+ async function promptProPasswordBundle(options = {}) {
145
+ const modeCli = String(options.proPasswordMode || '').trim().toLowerCase();
146
+ if (modeCli === 'autogen') {
147
+ const generated = generateProAdminPasswords();
148
+ if (options.quiet !== true) {
149
+ displayProPasswordsOnce(generated);
150
+ }
151
+ return splitPasswordBundle(generated);
152
+ }
153
+ if (modeCli === 'manual' && String(options.adminPassword || '').trim()) {
154
+ return singlePasswordBundle(String(options.adminPassword).trim());
155
+ }
156
+
157
+ const { method } = await inquirer.prompt([
158
+ {
159
+ type: 'list',
160
+ name: 'method',
161
+ message: 'How do you want to set admin passwords (pro installation)?',
162
+ choices: [
163
+ { name: 'Autogenerate strong passwords (recommended, shown once)', value: 'autogen' },
164
+ { name: 'Enter one password manually (same for all roles)', value: 'manual-single' },
165
+ { name: 'Enter separate passwords (infra / Keycloak / platform)', value: 'manual-split' }
166
+ ],
167
+ default: 'autogen'
168
+ }
169
+ ]);
170
+
171
+ if (method === 'autogen') {
172
+ const generated = generateProAdminPasswords();
173
+ displayProPasswordsOnce(generated);
174
+ return splitPasswordBundle(generated);
175
+ }
176
+ if (method === 'manual-split') {
177
+ return promptProManualSplitBundle();
178
+ }
179
+ return promptDevPasswordBundle();
180
+ }
181
+
182
+ /**
183
+ * @async
184
+ * @returns {Promise<import('../core/admin-secrets-bundle').AdminPasswordBundleSplit>}
185
+ */
186
+ async function promptProManualSplitBundle() {
187
+ const answers = await inquirer.prompt([
188
+ {
189
+ type: 'password',
190
+ name: 'infra',
191
+ message: 'Infra password (Postgres / pgAdmin / Redis Commander):',
192
+ mask: '*',
193
+ validate: validatePassword
194
+ },
195
+ {
196
+ type: 'password',
197
+ name: 'keycloak',
198
+ message: 'Keycloak install admin password:',
199
+ mask: '*',
200
+ validate: validatePassword
201
+ },
202
+ {
203
+ type: 'password',
204
+ name: 'platform',
205
+ message: 'Platform UI login password (user admin):',
206
+ mask: '*',
207
+ validate: validatePassword
208
+ }
209
+ ]);
210
+ return splitPasswordBundle(answers);
211
+ }
212
+
213
+ /**
214
+ * @param {Object} [options]
215
+ * @returns {Promise<{ adminEmail: string, passwordBundle: object, profile: 'dev'|'pro' }>}
216
+ */
217
+ async function promptAdminCredentialsWithProfile(options = {}) {
218
+ let profile = await resolveInstallationProfileFromOptions(options);
219
+ const hasCliProfile =
220
+ options.installation !== undefined ||
221
+ options.installationProfile !== undefined;
222
+ if (!hasCliProfile) {
223
+ profile = await promptInstallationProfile();
224
+ }
225
+ await config.setSetupInstallationProfile(profile);
226
+
227
+ const adminEmail = await promptAdminEmail(options);
228
+ const passwordBundle = isProInstallationProfile(profile)
229
+ ? await promptProPasswordBundle(options)
230
+ : await promptDevPasswordBundle();
231
+
232
+ return { adminEmail, passwordBundle, profile };
233
+ }
234
+
235
+ module.exports = {
236
+ INSTALLATION_PROFILE,
237
+ resolveInstallationProfileFromOptions,
238
+ promptInstallationProfile,
239
+ promptAdminEmail,
240
+ promptDevPasswordBundle,
241
+ promptProPasswordBundle,
242
+ displayProPasswordsOnce,
243
+ promptAdminCredentialsWithProfile
244
+ };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Setup prompts for platform topology mode (single vs full).
3
+ *
4
+ * @fileoverview Setup platform mode prompt + CLI option normalization
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const inquirer = require('inquirer');
12
+ const { normalizeSetupPlatformMode, SETUP_PLATFORM_MODE } = require('../core/setup-platform-mode');
13
+
14
+ /**
15
+ * Resolve platform mode from CLI options, if provided.
16
+ * @param {Object} [options]
17
+ * @returns {'single'|'full'|null}
18
+ */
19
+ function resolvePlatformModeFromOptions(options = {}) {
20
+ const raw = options.platform;
21
+ if (raw === undefined || raw === null || String(raw).trim() === '') {
22
+ return null;
23
+ }
24
+ const normalized = normalizeSetupPlatformMode(raw);
25
+ // Guard: only accept exact canonical values from CLI; reject unexpected to avoid silent typos.
26
+ const rawNorm = String(raw).trim().toLowerCase();
27
+ if (rawNorm !== 'single' && rawNorm !== 'full') {
28
+ throw new Error('--platform must be single or full (example: aifabrix setup --platform full)');
29
+ }
30
+ return normalized;
31
+ }
32
+
33
+ /**
34
+ * @async
35
+ * @param {Object} [options]
36
+ * @returns {Promise<'single'|'full'>}
37
+ */
38
+ async function promptSetupPlatformMode(options = {}) {
39
+ const fromCli = resolvePlatformModeFromOptions(options);
40
+ if (fromCli) return fromCli;
41
+
42
+ const { mode } = await inquirer.prompt([
43
+ {
44
+ type: 'list',
45
+ name: 'mode',
46
+ message: 'Platform mode:',
47
+ choices: [
48
+ {
49
+ name: 'Single environment — direct ports (no Traefik front door)',
50
+ value: SETUP_PLATFORM_MODE.SINGLE
51
+ },
52
+ {
53
+ name: 'Full platform — Traefik front door + miso/dev/tst/pro (shared infra)',
54
+ value: SETUP_PLATFORM_MODE.FULL
55
+ }
56
+ ],
57
+ default: SETUP_PLATFORM_MODE.SINGLE
58
+ }
59
+ ]);
60
+ return normalizeSetupPlatformMode(mode);
61
+ }
62
+
63
+ module.exports = {
64
+ resolvePlatformModeFromOptions,
65
+ promptSetupPlatformMode
66
+ };
67
+
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shared validators for setup prompts.
3
+ *
4
+ * @fileoverview Email/password validation for setup wizard
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /**
12
+ * @param {string} input
13
+ * @returns {true|string}
14
+ */
15
+ function validateEmail(input) {
16
+ const value = (input || '').trim();
17
+ if (!value) return 'Admin email is required';
18
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return 'Enter a valid email address';
19
+ return true;
20
+ }
21
+
22
+ /**
23
+ * @param {string} input
24
+ * @returns {true|string}
25
+ */
26
+ function validatePassword(input) {
27
+ const value = String(input ?? '');
28
+ if (value.length === 0) return 'Admin password is required';
29
+ if (value.length < 8) return 'Admin password must be at least 8 characters';
30
+ return true;
31
+ }
32
+
33
+ module.exports = {
34
+ validateEmail,
35
+ validatePassword
36
+ };
@@ -28,16 +28,20 @@ const path = require('path');
28
28
  const inquirer = require('inquirer');
29
29
  const chalk = require('chalk');
30
30
  const logger = require('../utils/logger');
31
- const config = require('../core/config');
32
31
  const secretsCore = require('../core/secrets');
33
32
  const secretsEnsure = require('../core/secrets-ensure');
34
33
  const { formatSuccessLine, infoLine } = require('../utils/cli-test-layout-chalk');
34
+ const { validateEmail, validatePassword } = require('./setup-prompts-validators');
35
+ const {
36
+ promptAdminCredentialsWithProfile,
37
+ promptInstallationProfile,
38
+ INSTALLATION_PROFILE
39
+ } = require('./setup-prompts-admin');
35
40
 
36
41
  /** Mode identifiers. Public so callers can switch on them without string typos. */
37
42
  const MODE = Object.freeze({
38
43
  REINSTALL: 'reinstall',
39
44
  WIPE_DATA: 'wipe-data',
40
- CLEAN_FILES: 'clean-files',
41
45
  UPDATE_IMAGES: 'update-images'
42
46
  });
43
47
 
@@ -76,10 +80,6 @@ async function promptModeSelection() {
76
80
  name: 'Reset databases (keeps volumes, removes DBs/users)',
77
81
  value: MODE.WIPE_DATA
78
82
  },
79
- {
80
- name: 'Refresh platform config (keeps data, re-copy platform files)',
81
- value: MODE.CLEAN_FILES
82
- },
83
83
  {
84
84
  name: 'Update images + restart services (keeps data)',
85
85
  value: MODE.UPDATE_IMAGES
@@ -111,79 +111,23 @@ async function confirmDestructiveMode(mode, assumeYes) {
111
111
  }
112
112
 
113
113
  /**
114
- * Validate an email address (RFC 5322-lite for CLI use).
115
- * @param {string} input
116
- * @returns {true|string}
117
- */
118
- function validateEmail(input) {
119
- const value = (input || '').trim();
120
- if (!value) return 'Admin email is required';
121
- if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return 'Enter a valid email address';
122
- return true;
123
- }
124
-
125
- /**
126
- * Validate a password (non-empty, at least 8 chars).
127
- * @param {string} input
128
- * @returns {true|string}
129
- */
130
- function validatePassword(input) {
131
- const value = String(input ?? '');
132
- if (value.length === 0) return 'Admin password is required';
133
- if (value.length < 8) return 'Admin password must be at least 8 characters';
134
- return true;
135
- }
136
-
137
- /**
138
- * Prompt for admin email + password (fresh install only).
139
- * Reads {@link module:lib/core/config.getAdminEmail} so a previous `aifabrix setup` can prefill the
140
- * email field (user may change it before continuing).
141
- * Asks once for the password and once for confirmation; returns trimmed email
142
- * and the verbatim password (never logged).
114
+ * Prompt for admin credentials (dev or pro installation profile).
143
115
  *
144
116
  * @async
145
- * @returns {Promise<{ adminEmail: string, adminPassword: string }>}
117
+ * @param {Object} [options] - CLI options (`installation`, `proPasswordMode`, `adminEmail`, `adminPassword`, `quiet`)
118
+ * @returns {Promise<{ adminEmail: string, adminPassword: string, passwordBundle: object, profile: string }>}
146
119
  */
147
- async function promptAdminCredentials() {
148
- let defaultEmail;
149
- try {
150
- const saved = await config.getAdminEmail();
151
- defaultEmail = saved && saved.trim() ? saved.trim() : undefined;
152
- } catch {
153
- defaultEmail = undefined;
154
- }
155
- const emailQuestion = {
156
- type: 'input',
157
- name: 'adminEmail',
158
- message: 'Admin email (Keycloak / pgAdmin login):',
159
- validate: validateEmail
160
- };
161
- if (defaultEmail !== undefined) {
162
- emailQuestion.default = defaultEmail;
163
- }
164
- const answers = await inquirer.prompt([
165
- emailQuestion,
166
- {
167
- type: 'password',
168
- name: 'adminPassword',
169
- message: 'Admin password (Postgres / Keycloak / pgAdmin):',
170
- mask: '*',
171
- validate: validatePassword
172
- },
173
- {
174
- type: 'password',
175
- name: 'adminPasswordConfirm',
176
- message: 'Confirm admin password:',
177
- mask: '*',
178
- validate(input, all) {
179
- if (input !== all.adminPassword) return 'Passwords do not match';
180
- return true;
181
- }
182
- }
183
- ]);
120
+ async function promptAdminCredentials(options = {}) {
121
+ const result = await promptAdminCredentialsWithProfile(options);
122
+ const legacyPassword =
123
+ result.passwordBundle.mode === 'single'
124
+ ? result.passwordBundle.password
125
+ : result.passwordBundle.platform;
184
126
  return {
185
- adminEmail: String(answers.adminEmail).trim(),
186
- adminPassword: answers.adminPassword
127
+ adminEmail: result.adminEmail,
128
+ adminPassword: legacyPassword,
129
+ passwordBundle: result.passwordBundle,
130
+ profile: result.profile
187
131
  };
188
132
  }
189
133
 
@@ -411,11 +355,15 @@ module.exports = {
411
355
  MODE,
412
356
  AI_KEYS,
413
357
  BUILDER_DIR_ACTION,
358
+ INSTALLATION_PROFILE,
414
359
  formatBuilderPlatformReplaceLines,
415
360
  promptModeSelection,
416
361
  confirmDestructiveMode,
362
+ promptInstallationProfile,
417
363
  promptAdminCredentials,
418
364
  promptAiTool,
419
365
  detectAiToolStatus,
420
- promptBuilderDirConflict
366
+ promptBuilderDirConflict,
367
+ validateEmail,
368
+ validatePassword
421
369
  };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Marks when `aifabrix setup` is running platform bring-up (suppress noisy token refresh warnings).
3
+ *
4
+ * @fileoverview Setup flow context flag
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ let setupPlatformFlowActive = false;
12
+ let setupCommandFlowActive = false;
13
+
14
+ function beginSetupCommandFlow() {
15
+ setupCommandFlowActive = true;
16
+ }
17
+
18
+ function endSetupCommandFlow() {
19
+ setupCommandFlowActive = false;
20
+ }
21
+
22
+ function isSetupCommandFlow() {
23
+ return setupCommandFlowActive === true;
24
+ }
25
+
26
+ function beginSetupPlatformFlow() {
27
+ setupPlatformFlowActive = true;
28
+ }
29
+
30
+ function endSetupPlatformFlow() {
31
+ setupPlatformFlowActive = false;
32
+ }
33
+
34
+ function isSetupPlatformFlow() {
35
+ return setupPlatformFlowActive === true;
36
+ }
37
+
38
+ module.exports = {
39
+ beginSetupCommandFlow,
40
+ endSetupCommandFlow,
41
+ isSetupCommandFlow,
42
+ beginSetupPlatformFlow,
43
+ endSetupPlatformFlow,
44
+ isSetupPlatformFlow
45
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Spinner helpers for `aifabrix setup` mode handlers.
3
+ *
4
+ * @fileoverview TTY progress spinners for setup commands
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const ora = require('ora');
12
+ const logger = require('../utils/logger');
13
+ const { formatProgress, formatSuccessLine } = require('../utils/cli-test-layout-chalk');
14
+
15
+ function shouldUseSpinner() {
16
+ return Boolean(process && process.stdout && process.stdout.isTTY);
17
+ }
18
+
19
+ function startSpinner(text) {
20
+ if (!shouldUseSpinner()) {
21
+ logger.log(formatProgress(text));
22
+ return null;
23
+ }
24
+ return ora({ text, spinner: 'dots' }).start();
25
+ }
26
+
27
+ function stopSpinnerSuccess(spinner, text) {
28
+ if (!spinner) {
29
+ logger.log(formatSuccessLine(text));
30
+ return;
31
+ }
32
+ spinner.succeed(text);
33
+ }
34
+
35
+ module.exports = {
36
+ shouldUseSpinner,
37
+ startSpinner,
38
+ stopSpinnerSuccess
39
+ };
@@ -2,8 +2,8 @@
2
2
  * Top-level handler for `aifabrix setup`.
3
3
  *
4
4
  * Decides between:
5
- * - fresh install (no infra running) — wizard for admin creds + AI tool, then up-infra + up-platform.
6
- * - mode menu (infra already running) — dispatch one of four destructive/refresh paths.
5
+ * - fresh install (no infra running) — wipe volumes, wizard for admin creds + AI tool, then up-infra + up-platform.
6
+ * - mode menu (infra already running) — dispatch one of three destructive/refresh paths.
7
7
  *
8
8
  * The mode handlers live in `setup-modes.js`; the prompts live in
9
9
  * `setup-prompts.js`. This module is a thin orchestrator so it stays well
@@ -28,8 +28,12 @@ const {
28
28
  } = require('../utils/cli-test-layout-chalk');
29
29
 
30
30
  const setupPrompts = require('./setup-prompts');
31
+ const setupPlatformModePrompts = require('./setup-prompts-platform-mode');
32
+ const { flagsForSetupPlatformMode } = require('../core/setup-platform-mode');
31
33
  const setupModes = require('./setup-modes');
34
+ const { syncPlatformControllerUrlsInConfig } = require('./setup-platform-auth');
32
35
  const installationLog = require('../utils/installation-log');
36
+ const { beginSetupCommandFlow, endSetupCommandFlow } = require('./setup-run-context');
33
37
 
34
38
  const MODE = setupPrompts.MODE;
35
39
 
@@ -54,10 +58,24 @@ async function maybePinDeveloperIdForFreshInstall(rawDeveloper) {
54
58
  logger.log(infoLine(`Developer ID pinned to ${dev}.`));
55
59
  }
56
60
 
61
+ async function applySetupPlatformMode(options) {
62
+ const mode = await setupPlatformModePrompts.promptSetupPlatformMode(options);
63
+ await config.setSetupPlatformMode(mode);
64
+ const derived = flagsForSetupPlatformMode(mode);
65
+ // These are the user gates that control full-mode behavior.
66
+ const cfg = await config.getConfig();
67
+ cfg.traefik = derived.traefik;
68
+ cfg.useEnvironmentScopedResources = derived.useEnvironmentScopedResources;
69
+ await config.saveConfig(cfg);
70
+ await syncPlatformControllerUrlsInConfig();
71
+ return mode;
72
+ }
73
+
57
74
  async function runFreshInstallFlow(options) {
58
75
  await maybePinDeveloperIdForFreshInstall(options.developer);
59
76
  logger.log(infoLine('No infrastructure detected; starting fresh install.'));
60
- const adminCreds = await setupPrompts.promptAdminCredentials();
77
+ await applySetupPlatformMode(options);
78
+ const adminCreds = await setupPrompts.promptAdminCredentials(options);
61
79
  await config.setAdminEmail(adminCreds.adminEmail);
62
80
  await setupModes.runFreshInstall(adminCreds);
63
81
  logger.log(formatSuccessParagraph('aifabrix setup complete (fresh install).'));
@@ -74,6 +92,10 @@ async function runExistingInfraFlow(assumeYes) {
74
92
  logger.log(chalk.yellow('Aborted by user.'));
75
93
  return { aborted: true, mode };
76
94
  }
95
+ // Re-install / wipe-data can change platform topology; re-prompt so the next up-platform matches intent.
96
+ if (mode === MODE.REINSTALL || mode === MODE.WIPE_DATA) {
97
+ await applySetupPlatformMode({});
98
+ }
77
99
  await dispatchMode(mode);
78
100
  logger.log(formatSuccessParagraph(`aifabrix setup complete (mode: ${mode}).`));
79
101
  return { aborted: false, mode };
@@ -114,8 +136,6 @@ async function dispatchMode(mode) {
114
136
  return setupModes.runReinstall();
115
137
  case MODE.WIPE_DATA:
116
138
  return setupModes.runWipeData();
117
- case MODE.CLEAN_FILES:
118
- return setupModes.runCleanInstallFiles();
119
139
  case MODE.UPDATE_IMAGES:
120
140
  return setupModes.runUpdateImages();
121
141
  default:
@@ -224,6 +244,7 @@ async function handleSetup(options = {}) {
224
244
  let setupMode = null;
225
245
  let err = null;
226
246
 
247
+ beginSetupCommandFlow();
227
248
  try {
228
249
  const main = await runSetupMainPath(options, assumeYes);
229
250
  outcome = main.outcome;
@@ -232,6 +253,7 @@ async function handleSetup(options = {}) {
232
253
  outcome = 'failure';
233
254
  err = e;
234
255
  } finally {
256
+ endSetupCommandFlow();
235
257
  await appendSetupInstallationRecord({
236
258
  outcome,
237
259
  startedAt,