@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,109 @@
1
+ /**
2
+ * Guided platform install authentication (device login URL + Dataplane recovery).
3
+ *
4
+ * @fileoverview Auth helpers for infra-guided up-platform / setup
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const chalk = require('chalk');
12
+ const logger = require('../utils/logger');
13
+ const config = require('../core/config');
14
+ const { resolvePlatformControllerUrl } = require('../utils/platform-controller-url');
15
+ const { withMutedLogger } = require('../utils/with-muted-logger');
16
+ const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
17
+ const { isAuthenticationError } = require('../utils/cli-utils');
18
+ const { resolveControllerUrl, isPlatformAuthValidForController } = require('../utils/controller-url');
19
+
20
+ /**
21
+ * @param {Object} authOpts
22
+ * @returns {Promise<string>}
23
+ */
24
+ async function resolveGuidedAuthControllerUrl(authOpts = {}) {
25
+ return (
26
+ authOpts.platformControllerUrl ||
27
+ (await config.getPlatformControllerUrl()) ||
28
+ (await resolvePlatformControllerUrl())
29
+ );
30
+ }
31
+
32
+ /**
33
+ * @async
34
+ * @param {Function} handleLoginFn
35
+ * @param {string} controllerUrl
36
+ * @param {{ skipDataplaneVersionRefresh?: boolean }} [opts]
37
+ * @returns {Promise<void>}
38
+ */
39
+ async function runGuidedDeviceLogin(handleLoginFn, controllerUrl, opts = {}) {
40
+ await handleLoginFn({
41
+ method: 'device',
42
+ controller: controllerUrl,
43
+ environment: 'dev',
44
+ compact: true,
45
+ skipDataplaneVersionRefresh: opts.skipDataplaneVersionRefresh === true,
46
+ exitOnFailure: false
47
+ });
48
+ }
49
+
50
+ /**
51
+ * @async
52
+ * @param {Function} handleLoginFn
53
+ * @param {Object} authOpts
54
+ * @param {{ startSpinner: Function, stopSpinnerSuccess: Function }} spinners
55
+ * @returns {Promise<void>}
56
+ */
57
+ async function runGuidedAuthStep(handleLoginFn, authOpts, spinners) {
58
+ const spin = spinners.startSpinner('Authenticating...');
59
+ const controllerUrl = await resolveGuidedAuthControllerUrl(authOpts);
60
+ const skipLogin =
61
+ authOpts.skipLoginIfAuthenticated === true ||
62
+ (await isPlatformAuthValidForController(controllerUrl));
63
+ try {
64
+ if (skipLogin) {
65
+ spinners.stopSpinnerSuccess(spin, 'Already authenticated');
66
+ return;
67
+ }
68
+ await runGuidedDeviceLogin(handleLoginFn, controllerUrl, { skipDataplaneVersionRefresh: true });
69
+ } catch (authErr) {
70
+ if (spin) spin.fail('Authentication required');
71
+ logger.error(formatBlockingError('Authentication required. Complete sign-in in your browser.'));
72
+ await runGuidedDeviceLogin(handleLoginFn, controllerUrl, { skipDataplaneVersionRefresh: true });
73
+ }
74
+ spinners.stopSpinnerSuccess(spin, 'Authenticated');
75
+ }
76
+
77
+ /**
78
+ * @async
79
+ * @param {Object} options
80
+ * @param {Function} handleUpDataplane
81
+ * @param {Function} handleLoginFn
82
+ * @param {string} controllerUrl
83
+ * @returns {Promise<void>}
84
+ */
85
+ async function runGuidedDataplaneWithAuthRecovery(options, handleUpDataplane, handleLoginFn, controllerUrl) {
86
+ try {
87
+ await withMutedLogger(() =>
88
+ handleUpDataplane({ ...options, platformInstall: true, skipInfraCheck: true })
89
+ );
90
+ } catch (error) {
91
+ if (!isAuthenticationError(error)) {
92
+ throw error;
93
+ }
94
+ const loginUrl = error.controllerUrl || controllerUrl || (await resolveControllerUrl());
95
+ logger.log('');
96
+ logger.log(chalk.yellow('Device login required to register and deploy Dataplane.'));
97
+ await runGuidedDeviceLogin(handleLoginFn, loginUrl, { skipDataplaneVersionRefresh: false });
98
+ await withMutedLogger(() =>
99
+ handleUpDataplane({ ...options, platformInstall: true, skipInfraCheck: true })
100
+ );
101
+ }
102
+ }
103
+
104
+ module.exports = {
105
+ resolveGuidedAuthControllerUrl,
106
+ runGuidedDeviceLogin,
107
+ runGuidedAuthStep,
108
+ runGuidedDataplaneWithAuthRecovery
109
+ };
@@ -10,16 +10,19 @@ const config = require('../core/config');
10
10
  const devConfig = require('../utils/dev-config');
11
11
  const pathsUtil = require('../utils/paths');
12
12
  const { loadConfigFile } = require('../utils/config-format');
13
- const { resolveControllerUrl } = require('../utils/controller-url');
13
+ const { computeAppBaseUrl, resolvePlatformControllerUrl } = require('../utils/platform-controller-url');
14
14
  const { withMutedLogger } = require('../utils/with-muted-logger');
15
- const { formatBlockingError, formatProgress, formatSuccessLine, successGlyph } = require('../utils/cli-test-layout-chalk');
16
- const { computePublicUrlBaseString } = require('../utils/url-declarative-public-base');
17
- const { joinUrlPath, normalizeFrontDoorPatternForHealth } = require('../utils/health-check-url');
15
+ const { formatProgress, formatSuccessLine, successGlyph } = require('../utils/cli-test-layout-chalk');
18
16
  const ora = require('ora');
19
17
  const infra = require('../infrastructure');
20
18
  const { execWithDockerEnv } = require('../utils/docker-exec');
21
19
  const { getLogLevel, passesLevelFilter } = require('../commands/app-logs');
22
20
  const { handleLogin } = require('../commands/login');
21
+ const {
22
+ resolveGuidedAuthControllerUrl,
23
+ runGuidedAuthStep,
24
+ runGuidedDataplaneWithAuthRecovery
25
+ } = require('./infra-guided-auth');
23
26
  const healthCheck = require('../utils/health-check');
24
27
  const { prepareUrlsLocalRegistryForUpPlatform } = require('../commands/up-common');
25
28
  const { assertDevInfraUp } = require('../commands/dev-infra-gate');
@@ -126,44 +129,17 @@ function resolveInfraHost(remoteServer) {
126
129
  }
127
130
  }
128
131
 
129
- async function computeAppBaseUrl(appName) {
130
- const builderPath = pathsUtil.getBuilderPath(appName);
131
- const configPath = pathsUtil.resolveApplicationConfigPath(builderPath);
132
- const variables = loadConfigFile(configPath) || {};
133
- const basePort = Number(variables.port || 3000);
134
- const developerIdRaw = await config.getDeveloperId();
135
- const developerIdNum = typeof developerIdRaw === 'string' ? parseInt(developerIdRaw, 10) : developerIdRaw;
136
- const userCfg = await config.getConfig();
137
- const remoteServer = await config.getRemoteServer();
138
- const infraTlsEnabled = Boolean(userCfg && userCfg.tlsEnabled);
139
-
140
- const fd = variables.frontDoorRouting || null;
141
- const frontDoorEnabled = Boolean(fd && fd.enabled === true);
142
- const traefikOn = Boolean(userCfg && userCfg.traefik);
143
- const pathActive = Boolean(traefikOn && frontDoorEnabled);
144
-
145
- const publicBase = computePublicUrlBaseString({
146
- traefik: traefikOn,
147
- pathActive,
148
- hostTemplate: fd ? fd.host : null,
149
- tls: fd ? fd.tls : true,
150
- developerIdRaw,
151
- remoteServer,
152
- // These guided bootstrap commands start services via Docker Compose, so we want the
153
- // docker-published host port (no workstation +10 offset).
154
- profile: 'docker',
155
- listenPort: basePort,
156
- developerIdNum,
157
- infraTlsEnabled
158
- });
159
-
160
- if (pathActive) {
161
- const mount = normalizeFrontDoorPatternForHealth(fd.pattern);
162
- return joinUrlPath(publicBase, mount);
132
+ /**
133
+ * Prefer stored platform controller URL, then compute from routing rules.
134
+ * @async
135
+ * @returns {Promise<string>}
136
+ */
137
+ async function resolvePlatformControllerUrlForDisplay() {
138
+ const stored = await config.getPlatformControllerUrl();
139
+ if (stored) {
140
+ return stored;
163
141
  }
164
-
165
- // No Traefik front-door routing: publicBase is localhost + published port unless Traefik/proxy opts into remote.
166
- return String(publicBase).replace(/\/+$/, '');
142
+ return resolvePlatformControllerUrl();
167
143
  }
168
144
 
169
145
  function logSection(label, value) {
@@ -186,7 +162,7 @@ function logFooterEnd() {
186
162
 
187
163
  async function logPlatformReadyFooter() {
188
164
  const [controllerUrl, dataplaneUrl, keycloakUrl] = await Promise.all([
189
- resolveControllerUrl(),
165
+ resolvePlatformControllerUrlForDisplay(),
190
166
  computeAppBaseUrl('dataplane'),
191
167
  computeAppBaseUrl('keycloak')
192
168
  ]);
@@ -206,7 +182,7 @@ async function logPlatformReadyFooter() {
206
182
 
207
183
  async function logMisoReadyFooter() {
208
184
  const [controllerUrl, keycloakUrl] = await Promise.all([
209
- resolveControllerUrl(),
185
+ resolvePlatformControllerUrlForDisplay(),
210
186
  computeAppBaseUrl('keycloak')
211
187
  ]);
212
188
  logFooterStart('Miso Ready');
@@ -280,6 +256,8 @@ async function runGuidedUpMiso(options, handleUpMiso) {
280
256
  logger.log(title('AI Fabrix Platform Setup'));
281
257
  logger.log(SEPARATOR);
282
258
  logger.log('');
259
+ logPlatformSetupDurationHint('platform');
260
+ logger.log('');
283
261
  const kcSpin = startSpinner('Starting Keycloak...');
284
262
  await withMutedLogger(() => handleUpMiso({ ...options, platformInstall: true }));
285
263
  stopSpinnerSuccess(kcSpin, 'Keycloak ready');
@@ -291,13 +269,11 @@ async function runGuidedUpMiso(options, handleUpMiso) {
291
269
  await validateAppErrorLogs(['miso-controller']);
292
270
  }
293
271
 
294
- async function runGuidedUpDataplane(options, handleUpDataplane) {
295
- logger.log('');
296
- logger.log(title('AI Fabrix Dataplane Setup'));
297
- logger.log(SEPARATOR);
298
- logger.log('');
299
- // Infra must be checked before auth: device login talks to the controller, which needs
300
- // Postgres/Redis when the controller runs locally — a down infra looks like "network error".
272
+ /**
273
+ * Infra must be checked before auth: device login talks to the controller, which needs
274
+ * Postgres/Redis when the controller runs locally — a down infra looks like "network error".
275
+ */
276
+ async function assertDevInfraForGuidedDataplane() {
301
277
  const infraSpin = startSpinner('Checking infrastructure...');
302
278
  try {
303
279
  await assertDevInfraUp({ quietSuccess: true });
@@ -307,11 +283,21 @@ async function runGuidedUpDataplane(options, handleUpDataplane) {
307
283
  if (infraSpin) infraSpin.stop();
308
284
  throw infraErr;
309
285
  }
286
+ }
287
+
288
+ async function runGuidedUpDataplane(options, handleUpDataplane) {
289
+ logger.log('');
290
+ logger.log(title('AI Fabrix Dataplane Setup'));
291
+ logger.log(SEPARATOR);
292
+ logger.log('');
293
+ logPlatformSetupDurationHint('dataplane');
294
+ logger.log('');
295
+ await assertDevInfraForGuidedDataplane();
310
296
  // Avoid an outer long-running spinner here: up-dataplane has multiple internal
311
297
  // phases and may print some output. An outer spinner causes "spinner over spinner"
312
298
  // rendering artifacts. Instead, do the same single auth step as up-platform, then
313
299
  // show one spinner for the dataplane install/run phase.
314
- await runGuidedAuthStep(handleLogin);
300
+ await runGuidedAuthStep(handleLogin, {}, { startSpinner, stopSpinnerSuccess });
315
301
 
316
302
  logger.log('');
317
303
  emitSystemBuilderAppManifestLineIfTTY(logger, 'dataplane');
@@ -320,6 +306,7 @@ async function runGuidedUpDataplane(options, handleUpDataplane) {
320
306
  handleUpDataplane({ ...options, platformInstall: true, skipInfraCheck: true })
321
307
  );
322
308
  stopSpinnerSuccess(dpSpin, 'Dataplane ready');
309
+ await refreshDataplaneVersionAfterPlatformInstall();
323
310
  await validateAppErrorLogs(['dataplane']);
324
311
  await logDataplaneReadyFooter();
325
312
  }
@@ -330,6 +317,8 @@ async function runGuidedUpDataplane(options, handleUpDataplane) {
330
317
  * @param {string[]} cleanedApps
331
318
  */
332
319
  function logUpPlatformForceCleanSummary(forceSummary, cleanedApps) {
320
+ const { isSetupQuietOutput } = require('../utils/setup-quiet-output');
321
+ if (isSetupQuietOutput()) return;
333
322
  const check = successGlyph();
334
323
  logger.log(chalk.bold('Clean installation files'));
335
324
  logger.log(
@@ -349,27 +338,35 @@ function logUpPlatformForceCleanSummary(forceSummary, cleanedApps) {
349
338
  logger.log('');
350
339
  }
351
340
 
341
+ /**
342
+ * Yellow notice before long-running platform/dataplane install steps (setup and guided up-*).
343
+ * @param {'platform'|'dataplane'} [scope]
344
+ */
345
+ function logPlatformSetupDurationHint(scope = 'platform') {
346
+ const line =
347
+ scope === 'dataplane'
348
+ ? 'Installation may take a few minutes. Authenticating and starting Dataplane — please wait.'
349
+ : 'Installation may take a few minutes. Keycloak, Miso Controller, and Dataplane are starting — please wait.';
350
+ logger.log(chalk.yellow(`⚠ ${line}`));
351
+ }
352
+
352
353
  function logGuidedPlatformSetupHeader() {
353
354
  logger.log('');
354
355
  logger.log(title('AI Fabrix Platform Setup'));
355
356
  logger.log(SEPARATOR);
356
- logger.log(chalk.gray('This may take a few minutes...'));
357
+ logger.log('');
358
+ logPlatformSetupDurationHint('platform');
357
359
  logger.log('');
358
360
  }
359
361
 
360
- async function runGuidedAuthStep(handleLogin) {
361
- const spin = startSpinner('Authenticating...');
362
+ async function refreshDataplaneVersionAfterPlatformInstall() {
362
363
  try {
363
- const controllerUrl = await resolveControllerUrl();
364
- await handleLogin({ method: 'device', controller: controllerUrl, environment: 'dev', compact: true });
365
- } catch (authErr) {
366
- if (spin) spin.fail('Authentication failed');
367
- logger.error(formatBlockingError('Authentication failed'));
368
- logger.log(chalk.gray('\nRun:\n af login\n\nThen retry:\n af up-platform\n'));
369
- throw authErr;
364
+ const { tryRefreshDataplaneVersionAfterLogin } = require('../commands/auth-status-dataplane-version');
365
+ const controllerUrl = await resolvePlatformControllerUrlForDisplay();
366
+ await tryRefreshDataplaneVersionAfterLogin(controllerUrl, {});
367
+ } catch {
368
+ // best-effort only
370
369
  }
371
- // Compact device-login already prints a success line; don't duplicate it.
372
- if (spin) spin.stop();
373
370
  }
374
371
 
375
372
  async function runGuidedKeycloakAndMisoControllerPhase(options, handleUpMiso) {
@@ -385,14 +382,27 @@ async function runGuidedKeycloakAndMisoControllerPhase(options, handleUpMiso) {
385
382
  logger.log('');
386
383
  }
387
384
 
388
- async function runGuidedDataplaneInstallPhase(options, handleUpDataplane) {
385
+ async function runGuidedDataplaneInstallPhase(options, handleUpDataplane, handleLoginFn, controllerUrl) {
389
386
  logger.log('');
390
387
  emitSystemBuilderAppManifestLineIfTTY(logger, 'dataplane');
391
388
  const dpSpin = startSpinner('Starting Dataplane...');
392
- await withMutedLogger(() =>
393
- handleUpDataplane({ ...options, platformInstall: true, skipInfraCheck: true })
394
- );
389
+ const platformMode = await config.getSetupPlatformMode();
390
+ if (platformMode === 'full') {
391
+ // Full platform: three dataplane containers + per-env registrations.
392
+ const envKeys = ['pro', 'dev', 'tst'];
393
+ for (const envKey of envKeys) {
394
+ await runGuidedDataplaneWithAuthRecovery(
395
+ { ...options, envKey, runEnvKey: envKey, allowNonDev: true },
396
+ handleUpDataplane,
397
+ handleLoginFn,
398
+ controllerUrl
399
+ );
400
+ }
401
+ } else {
402
+ await runGuidedDataplaneWithAuthRecovery(options, handleUpDataplane, handleLoginFn, controllerUrl);
403
+ }
395
404
  stopSpinnerSuccess(dpSpin, 'Dataplane ready');
405
+ await refreshDataplaneVersionAfterPlatformInstall();
396
406
  }
397
407
 
398
408
  async function runGuidedUpPlatform(options, handleUpMiso, handleUpDataplane, handleLogin, forceCleanSummary = null) {
@@ -401,10 +411,22 @@ async function runGuidedUpPlatform(options, handleUpMiso, handleUpDataplane, han
401
411
  logUpPlatformForceCleanSummary(forceCleanSummary.forceSummary, forceCleanSummary.cleanedApps);
402
412
  }
403
413
 
414
+ const authOpts = {
415
+ platformControllerUrl: options && options.platformControllerUrl,
416
+ skipLoginIfAuthenticated: options && options.skipLoginIfAuthenticated === true
417
+ };
418
+
404
419
  await withMutedLogger(() => prepareUrlsLocalRegistryForUpPlatform());
405
420
  await runGuidedKeycloakAndMisoControllerPhase(options, handleUpMiso);
406
- await runGuidedAuthStep(handleLogin);
407
- await runGuidedDataplaneInstallPhase(options, handleUpDataplane);
421
+ if (options && options.requireKeycloakRealm === true) {
422
+ const { waitForKeycloakRealmReady } = require('../utils/keycloak-realm-ready');
423
+ const realmSpin = startSpinner('Waiting for Keycloak realm (aifabrix)...');
424
+ await waitForKeycloakRealmReady({ timeoutSeconds: 180 });
425
+ stopSpinnerSuccess(realmSpin, 'Keycloak realm ready');
426
+ }
427
+ await runGuidedAuthStep(handleLogin, authOpts, { startSpinner, stopSpinnerSuccess });
428
+ const controllerUrl = await resolveGuidedAuthControllerUrl(authOpts);
429
+ await runGuidedDataplaneInstallPhase(options, handleUpDataplane, handleLogin, controllerUrl);
408
430
  await validateAppErrorLogs(['miso-controller', 'dataplane']);
409
431
  await logPlatformReadyFooter();
410
432
  }
@@ -56,12 +56,29 @@ Examples:
56
56
  Notes:
57
57
  - To run E2E for one datasource, use:
58
58
  aifabrix datasource test-e2e <datasourceKey>
59
- - External integration: local system and datasource files are published to the dataplane before E2E (same as upload). Use --no-sync to exercise only config already deployed. The old --sync flag is a no-op (kept for scripts).
59
+ - External integration: local system and datasource files are published to the dataplane before E2E (same as upload). Use --no-sync to exercise only config already deployed.
60
+ `;
61
+
62
+ const IDENTITY_HELP_AFTER = `
63
+ Examples:
64
+ # Bulk seed from demo users.csv (test-protection prefix) + sync + cache purge
65
+ $ aifabrix identity apply --file ./users.csv --filter-prefix test-protection -e dev --sync --purge-cache
66
+ $ aifabrix identity sync -e dev --purge-cache
67
+ $ aifabrix identity cache clear
68
+
69
+ # Single user / group
70
+ $ aifabrix identity user create --email alice@example.com --first-name Alice --last-name HR
71
+ $ aifabrix identity group create --name test-protection-sales-fi --description "Sales Finland"
72
+
73
+ Notes:
74
+ - Requires aifabrix login (controller token). See docs/commands/identity-management.md.
75
+ - Prefer identity apply over SQL in tests/fixtures/protection/optional-dev-identity-dataplane.sql.
60
76
  `;
61
77
 
62
78
  module.exports = {
63
79
  TEST_HELP_AFTER,
64
80
  TEST_INTEGRATION_HELP_AFTER,
65
- TEST_E2E_HELP_AFTER
81
+ TEST_E2E_HELP_AFTER,
82
+ IDENTITY_HELP_AFTER
66
83
  };
67
84
 
@@ -16,14 +16,49 @@ const { setupInstallTestE2eLintCommands } = require('./setup-app.test-commands')
16
16
 
17
17
  const CREATE_HELP_AFTER = `
18
18
  Examples:
19
+ # Builder app → builder/<appKey>/
19
20
  $ aifabrix create myapi --type webapp -l typescript
20
- $ aifabrix create mycrm --wizard
21
+ $ aifabrix create mysvc --type api -l python
22
+
23
+ # External system → integration/<systemKey>/ (default --type external)
24
+ $ aifabrix create hubspot --wizard
25
+ $ aifabrix create mycrm --type external --display-name "My CRM" --description "..." \\
26
+ --system-type openapi --auth-type oauth2 --entity-type recordStorage --datasources 1
27
+
28
+ Positional: appKey for builder types; systemKey for --type external (folder under integration/).
29
+ Prefer aifabrix wizard [systemKey] for guided external setup.
21
30
  `;
22
31
 
23
32
  const DEPLOY_HELP_AFTER = `
24
33
  Examples:
34
+ # Local — builder app (builder/<appKey>/)
25
35
  $ aifabrix deploy myapp
26
- $ aifabrix deploy myext --local
36
+ $ aifabrix deploy myapp --local
37
+
38
+ # Local — external system (integration/<systemKey>/); manifest regenerated on deploy
39
+ $ aifabrix deploy hubspot-demo
40
+ $ aifabrix deploy hubspot-demo --local
41
+ $ aifabrix deploy hubspot-demo --probe
42
+
43
+ # CI/CD — builder app (GitHub Actions / Azure DevOps; pipeline client credentials in secrets)
44
+ $ aifabrix validate myapp
45
+ $ aifabrix build myapp
46
+ $ aifabrix push myapp --registry $ACR_REGISTRY --tag $IMAGE_TAG
47
+ $ aifabrix deploy myapp \\
48
+ --client-id "$DEV_MISO_CLIENTID" \\
49
+ --client-secret "$DEV_MISO_CLIENTSECRET" \\
50
+ --no-poll
51
+
52
+ # CI/CD — external integration (after upload/tests; promote to controller)
53
+ $ aifabrix validate hubspot-demo
54
+ $ aifabrix upload hubspot-demo --probe
55
+ $ aifabrix deploy hubspot-demo --probe --no-poll
56
+
57
+ Notes:
58
+ - Login or set MISO_CONTROLLER_URL + environment (aifabrix login / aifabrix auth).
59
+ - CI: register once (aifabrix app register <appKey>), store DEV_MISO_CLIENTID and DEV_MISO_CLIENTSECRET in pipeline secrets.
60
+ - upload = dataplane publish for dev iteration; deploy = controller validate + deploy (Azure or local Docker).
61
+ - --repository-url overrides repo URL for pipeline validate (default: application.yaml repository.repositoryUrl).
27
62
  `;
28
63
 
29
64
  const PUSH_HELP_AFTER = `
@@ -133,8 +168,8 @@ async function handleCreateCommand(appName, options) {
133
168
  }
134
169
 
135
170
  function setupCreateCommand(program) {
136
- program.command('create <app>')
137
- .description('Scaffold builder or external app (flags or --wizard)')
171
+ program.command('create <appKey|systemKey>')
172
+ .description('Create builder app (builder/<appKey>/) or external system (integration/<systemKey>/; --type, flags, or --wizard)')
138
173
  .addHelpText('after', CREATE_HELP_AFTER)
139
174
  .option('-p, --port <port>', 'Application port', '3000')
140
175
  .option('-d, --database', 'Requires database')
@@ -148,7 +183,7 @@ function setupCreateCommand(program) {
148
183
  .option('-g, --github', 'Generate GitHub Actions workflows')
149
184
  .option('--github-steps <steps>', 'Extra GitHub workflow steps (comma-separated, e.g., npm,test)')
150
185
  .option('--main-branch <branch>', 'Main branch name for workflows', 'main')
151
- .option('--wizard', 'Use interactive wizard for external system creation')
186
+ .option('--wizard', 'Run wizard for external system (systemKey → integration/<systemKey>/; same as aifabrix wizard)')
152
187
  .option('--display-name <name>', 'External system display name')
153
188
  .option('--description <desc>', 'External system description')
154
189
  .option('--system-type <type>', 'External system type (openapi, mcp, custom)')
@@ -209,8 +244,8 @@ Examples:
209
244
  $ aifabrix run myapp --base
210
245
  $ aifabrix run myapp --reload
211
246
  $ aifabrix run myapp --no-proxy # same as --proxy false: localhost for Docker declarative public URLs; saves applications.<app>.proxy: false`;
212
- program.command('run <app>')
213
- .description('Run app locally or on remote Docker host')
247
+ program.command('run <appKey>')
248
+ .description('Run builder app by appKey locally or on remote Docker host')
214
249
  .option('-p, --port <port>', 'Override local port')
215
250
  .option('-d, --debug', 'Enable debug output with detailed container information')
216
251
  .option('-t, --tag <tag>', 'Image tag to run (e.g. v1.0.0); overrides application.yaml image.tag')
@@ -238,8 +273,8 @@ Examples:
238
273
  }
239
274
 
240
275
  function setupBuildRunLogsDownCommands(program) {
241
- program.command('build <app>')
242
- .description('Build Docker image (auto-detect runtime)')
276
+ program.command('build <appKey>')
277
+ .description('Build Docker image for builder appKey (auto-detect runtime)')
243
278
  .option('-l, --language <lang>', 'Override language detection')
244
279
  .option('-f, --force-template', 'Force rebuild from template')
245
280
  .option('--no-cache', 'Full Docker rebuild (disable layer cache); use after Dockerfile or context fixes')
@@ -257,8 +292,8 @@ function setupBuildRunLogsDownCommands(program) {
257
292
 
258
293
  registerRunCommand(program);
259
294
 
260
- program.command('logs <app>')
261
- .description('Tail app container logs (optional env summary; secrets masked)')
295
+ program.command('logs <appKey>')
296
+ .description('Tail container logs for appKey (optional env summary; secrets masked)')
262
297
  .option('-f', 'Follow log stream')
263
298
  .option('-t, --tail <lines>', 'Number of lines (default: 100); 0 = full list', '100')
264
299
  .option('-l, --level <level>', 'Show only logs at this level or above (debug|info|warn|error)')
@@ -275,8 +310,8 @@ function setupBuildRunLogsDownCommands(program) {
275
310
  }
276
311
  });
277
312
 
278
- program.command('down-app <app>')
279
- .description('Stop and remove app container (--volumes removes data volume)')
313
+ program.command('down-app <appKey>')
314
+ .description('Stop and remove container for appKey (--volumes removes data volume)')
280
315
  .option('--volumes', 'Remove application Docker volume')
281
316
  .action(async(appName, options) => {
282
317
  try {
@@ -290,8 +325,8 @@ function setupBuildRunLogsDownCommands(program) {
290
325
  }
291
326
 
292
327
  function setupShellTestStopCommands(program) {
293
- program.command('stop <app>')
294
- .description('Alias for down-app: stop and remove container')
328
+ program.command('stop <appKey>')
329
+ .description('Alias for down-app: stop and remove container for appKey')
295
330
  .option('--volumes', 'Remove application Docker volume')
296
331
  .action(async(appName, options) => {
297
332
  try {
@@ -303,8 +338,8 @@ function setupShellTestStopCommands(program) {
303
338
  }
304
339
  });
305
340
 
306
- program.command('shell <app>')
307
- .description('Interactive shell in running or ephemeral container')
341
+ program.command('shell <appKey>')
342
+ .description('Interactive shell in container for builder appKey')
308
343
  .option('--env <env>', 'Environment (dev|tst); dev uses running container', 'dev')
309
344
  .action(async(appName, options) => {
310
345
  try {
@@ -318,8 +353,8 @@ function setupShellTestStopCommands(program) {
318
353
  }
319
354
 
320
355
  function setupDockerfileGenerateCommand(program) {
321
- program.command('dockerfile <app>')
322
- .description('Generate Dockerfile from detected runtime')
356
+ program.command('dockerfile <appKey>')
357
+ .description('Generate Dockerfile for builder appKey from detected runtime')
323
358
  .option('-l, --language <lang>', 'Override language detection')
324
359
  .option('-f, --force', 'Overwrite existing Dockerfile')
325
360
  .action(async(appName, options) => {
@@ -335,8 +370,8 @@ function setupDockerfileGenerateCommand(program) {
335
370
  }
336
371
 
337
372
  function setupPushDeployDockerfileCommands(program) {
338
- program.command('push <app>')
339
- .description('Push image to Azure Container Registry')
373
+ program.command('push <appKey>')
374
+ .description('Push builder appKey image to Azure Container Registry')
340
375
  .addHelpText('after', PUSH_HELP_AFTER)
341
376
  .option('-r, --registry <registry>', 'ACR registry URL (overrides application.yaml)')
342
377
  .option('-t, --tag <tag>', 'Image tag(s) - comma-separated for multiple (default: latest)')
@@ -349,8 +384,8 @@ function setupPushDeployDockerfileCommands(program) {
349
384
  }
350
385
  });
351
386
 
352
- program.command('deploy <app>')
353
- .description('Deploy via Miso Controller (Azure or --local)')
387
+ program.command('deploy <appKey|systemKey>')
388
+ .description('Deploy builder app or external system via Miso Controller (Azure or --local)')
354
389
  .addHelpText('after', DEPLOY_HELP_AFTER)
355
390
  .option('--local', 'Send manifest to controller then run app locally (app: same as aifabrix run <app>; external: restart dataplane)')
356
391
  .option('--client-id <id>', 'Client ID (overrides config)')