@aifabrix/builder 2.43.0 → 2.44.1

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 (371) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/.cursor/rules/cli-layout.mdc +75 -0
  3. package/.cursor/rules/project-rules.mdc +8 -0
  4. package/.npmrc.token +1 -0
  5. package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  6. package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  7. package/.nyc_output/processinfo/index.json +1 -0
  8. package/README.md +1 -1
  9. package/anchor-docs/README.md +10 -0
  10. package/anchor-docs/_TEMPLATE +24 -0
  11. package/bin/aifabrix.js +13 -4
  12. package/integration/hubspot-test/README.md +31 -0
  13. package/integration/hubspot-test/create-hubspot.js +5 -5
  14. package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
  15. package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
  16. package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
  17. package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
  18. package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
  19. package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
  20. package/integration/hubspot-test/test-dataplane-down.js +3 -3
  21. package/integration/hubspot-test/test.js +35 -43
  22. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  23. package/integration/roundtrip-test-local/README.md +144 -0
  24. package/integration/roundtrip-test-local/application.yaml +13 -0
  25. package/integration/roundtrip-test-local/env.template +15 -0
  26. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  27. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  28. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  29. package/integration/roundtrip-test-local2/README.md +144 -0
  30. package/integration/roundtrip-test-local2/application.yaml +13 -0
  31. package/integration/roundtrip-test-local2/env.template +15 -0
  32. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  33. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  34. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  35. package/integration/test/wizard.yaml +8 -0
  36. package/jest.config.default.js +10 -0
  37. package/jest.config.integration.fixtures.js +22 -0
  38. package/jest.config.integration.js +21 -18
  39. package/jest.config.isolated.js +10 -0
  40. package/jest.projects.js +301 -0
  41. package/lib/api/certificates.api.js +62 -0
  42. package/lib/api/datasources-core.api.js +3 -3
  43. package/lib/api/dev-mtls-request.js +110 -0
  44. package/lib/api/dev-server-https.js +145 -0
  45. package/lib/api/dev.api.js +133 -144
  46. package/lib/api/index.js +11 -3
  47. package/lib/api/pipeline.api.js +67 -20
  48. package/lib/api/types/certificates.types.js +48 -0
  49. package/lib/api/types/dev.types.js +4 -3
  50. package/lib/api/types/pipeline.types.js +8 -5
  51. package/lib/api/types/validation-run.types.js +56 -0
  52. package/lib/api/validation-run.api.js +111 -0
  53. package/lib/api/validation-runner.js +109 -0
  54. package/lib/app/certification-show-enrich.js +129 -0
  55. package/lib/app/certification-verify-rows.js +60 -0
  56. package/lib/app/config.js +1 -1
  57. package/lib/app/deploy-status-display.js +2 -2
  58. package/lib/app/deploy.js +7 -6
  59. package/lib/app/display.js +2 -1
  60. package/lib/app/dockerfile.js +3 -2
  61. package/lib/app/down.js +2 -1
  62. package/lib/app/helpers.js +6 -5
  63. package/lib/app/index.js +27 -8
  64. package/lib/app/list.js +7 -6
  65. package/lib/app/push.js +4 -3
  66. package/lib/app/register.js +16 -7
  67. package/lib/app/rotate-secret.js +14 -13
  68. package/lib/app/run-container-start.js +184 -0
  69. package/lib/app/run-docker-fallback.js +108 -0
  70. package/lib/app/run-env-compose.js +30 -42
  71. package/lib/app/run-helpers.js +49 -126
  72. package/lib/app/run-infra-requirements.js +30 -0
  73. package/lib/app/run-resolve-image.js +21 -0
  74. package/lib/app/run.js +74 -21
  75. package/lib/app/show-display.js +44 -1
  76. package/lib/app/show.js +93 -9
  77. package/lib/build/index.js +13 -10
  78. package/lib/certification/cli-cert-sync-skip.js +21 -0
  79. package/lib/certification/merge-certification-from-artifact.js +185 -0
  80. package/lib/certification/post-unified-cert-sync.js +33 -0
  81. package/lib/certification/sync-after-external-command.js +52 -0
  82. package/lib/certification/sync-system-certification.js +197 -0
  83. package/lib/cli/index.js +2 -0
  84. package/lib/cli/setup-app.help.js +67 -0
  85. package/lib/cli/setup-app.js +61 -121
  86. package/lib/cli/setup-app.test-commands.js +195 -0
  87. package/lib/cli/setup-auth.js +19 -5
  88. package/lib/cli/setup-credential-deployment.js +22 -8
  89. package/lib/cli/setup-dev-path-commands.js +124 -0
  90. package/lib/cli/setup-dev.js +170 -113
  91. package/lib/cli/setup-environment.js +7 -1
  92. package/lib/cli/setup-external-system.js +84 -23
  93. package/lib/cli/setup-infra.js +126 -47
  94. package/lib/cli/setup-parameters.js +32 -0
  95. package/lib/cli/setup-secrets.js +137 -18
  96. package/lib/cli/setup-service-user.js +1 -1
  97. package/lib/cli/setup-utility.js +54 -22
  98. package/lib/commands/app-down.js +5 -7
  99. package/lib/commands/app-install.js +14 -7
  100. package/lib/commands/app-logs.js +13 -10
  101. package/lib/commands/app-shell.js +4 -1
  102. package/lib/commands/app-test.js +25 -19
  103. package/lib/commands/app.js +32 -11
  104. package/lib/commands/auth-config.js +6 -6
  105. package/lib/commands/auth-status.js +4 -3
  106. package/lib/commands/credential-env.js +4 -3
  107. package/lib/commands/credential-list.js +5 -4
  108. package/lib/commands/credential-push.js +4 -3
  109. package/lib/commands/datasource-unified-test-cli.js +428 -0
  110. package/lib/commands/datasource-unified-test-cli.options.js +191 -0
  111. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +106 -0
  112. package/lib/commands/datasource-validation-cli.js +143 -0
  113. package/lib/commands/datasource.js +125 -95
  114. package/lib/commands/deployment-list.js +6 -5
  115. package/lib/commands/dev-cli-handlers.js +122 -18
  116. package/lib/commands/dev-down.js +4 -3
  117. package/lib/commands/dev-init.js +231 -116
  118. package/lib/commands/dev-show-display.js +473 -0
  119. package/lib/commands/login-credentials.js +3 -2
  120. package/lib/commands/login-device.js +4 -3
  121. package/lib/commands/login.js +5 -4
  122. package/lib/commands/logout.js +8 -7
  123. package/lib/commands/parameters-validate.js +54 -0
  124. package/lib/commands/repair-datasource.js +314 -68
  125. package/lib/commands/repair-env-template.js +2 -2
  126. package/lib/commands/repair.js +21 -3
  127. package/lib/commands/secrets-list.js +23 -12
  128. package/lib/commands/secrets-remove-all.js +220 -0
  129. package/lib/commands/secrets-remove.js +21 -12
  130. package/lib/commands/secrets-set.js +21 -12
  131. package/lib/commands/secrets-validate.js +4 -4
  132. package/lib/commands/secure.js +10 -9
  133. package/lib/commands/service-user.js +26 -25
  134. package/lib/commands/test-e2e-external.js +27 -1
  135. package/lib/commands/up-common.js +3 -2
  136. package/lib/commands/up-dataplane.js +29 -16
  137. package/lib/commands/up-miso.js +19 -29
  138. package/lib/commands/upload.js +149 -39
  139. package/lib/commands/wizard-core-helpers.js +1 -1
  140. package/lib/commands/wizard-dataplane.js +4 -3
  141. package/lib/commands/wizard-helpers.js +3 -3
  142. package/lib/commands/wizard.js +2 -2
  143. package/lib/core/admin-secrets.js +14 -5
  144. package/lib/core/audit-logger.js +12 -4
  145. package/lib/core/config-attach-extensions.js +46 -0
  146. package/lib/core/config-runtime-paths.js +29 -0
  147. package/lib/core/config.js +55 -56
  148. package/lib/core/diff.js +3 -2
  149. package/lib/core/ensure-encryption-key.js +1 -1
  150. package/lib/core/secrets-ensure-infra.js +77 -0
  151. package/lib/core/secrets-ensure.js +120 -64
  152. package/lib/core/secrets-env-write.js +35 -7
  153. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  154. package/lib/core/secrets.js +200 -37
  155. package/lib/core/templates-env.js +4 -3
  156. package/lib/datasource/abac-validator.js +1 -10
  157. package/lib/datasource/deploy.js +75 -53
  158. package/lib/datasource/field-reference-validator.js +9 -6
  159. package/lib/datasource/integration-context.js +63 -0
  160. package/lib/datasource/list.js +8 -7
  161. package/lib/datasource/log-viewer.js +189 -67
  162. package/lib/datasource/resolve-app.js +4 -4
  163. package/lib/datasource/test-e2e.js +113 -146
  164. package/lib/datasource/test-integration.js +114 -122
  165. package/lib/datasource/unified-validation-run-body.js +68 -0
  166. package/lib/datasource/unified-validation-run-post.js +23 -0
  167. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  168. package/lib/datasource/unified-validation-run.js +93 -0
  169. package/lib/datasource/validate.js +157 -13
  170. package/lib/deployment/deployer.js +4 -3
  171. package/lib/deployment/environment.js +7 -6
  172. package/lib/deployment/push.js +17 -8
  173. package/lib/external-system/delete.js +4 -3
  174. package/lib/external-system/deploy.js +166 -53
  175. package/lib/external-system/download-helpers.js +1 -1
  176. package/lib/external-system/download.js +7 -6
  177. package/lib/external-system/generator.js +92 -6
  178. package/lib/external-system/integration-test-dispatch.js +26 -0
  179. package/lib/external-system/test-execution.js +5 -1
  180. package/lib/external-system/test-helpers.js +0 -4
  181. package/lib/external-system/test-system-level-helpers.js +110 -0
  182. package/lib/external-system/test-system-level.js +83 -44
  183. package/lib/external-system/test.js +59 -8
  184. package/lib/generator/builders.js +23 -11
  185. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  186. package/lib/generator/external.js +16 -4
  187. package/lib/generator/helpers.js +58 -3
  188. package/lib/generator/index.js +4 -0
  189. package/lib/generator/split-readme.js +12 -7
  190. package/lib/generator/split-variables.js +2 -1
  191. package/lib/generator/split.js +1 -1
  192. package/lib/generator/wizard-readme.js +3 -3
  193. package/lib/generator/wizard.js +8 -8
  194. package/lib/infrastructure/compose.js +70 -7
  195. package/lib/infrastructure/helpers-docker-check.js +67 -0
  196. package/lib/infrastructure/helpers.js +203 -42
  197. package/lib/infrastructure/index.js +31 -18
  198. package/lib/infrastructure/services.js +21 -67
  199. package/lib/internal/fs-real-sync.js +104 -0
  200. package/lib/internal/node-fs.js +98 -0
  201. package/lib/parameters/database-secret-values.js +173 -0
  202. package/lib/parameters/infra-kv-discovery.js +121 -0
  203. package/lib/parameters/infra-parameter-catalog.js +458 -0
  204. package/lib/parameters/infra-parameter-validate.js +64 -0
  205. package/lib/schema/application-schema.json +37 -17
  206. package/lib/schema/datasource-test-run.schema.json +493 -0
  207. package/lib/schema/deployment-rules.yaml +102 -63
  208. package/lib/schema/external-datasource.schema.json +1200 -442
  209. package/lib/schema/external-system.schema.json +203 -5
  210. package/lib/schema/flag-map-validation-run.json +31 -0
  211. package/lib/schema/infra-parameter.schema.json +106 -0
  212. package/lib/schema/infra.parameter.yaml +421 -0
  213. package/lib/schema/type/credential-auth-templates.json +40 -0
  214. package/lib/schema/type/document-storage.json +226 -0
  215. package/lib/schema/type/message-service.json +123 -0
  216. package/lib/schema/type/vector-store.json +88 -0
  217. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  218. package/lib/utils/api-error-handler.js +2 -2
  219. package/lib/utils/api.js +77 -17
  220. package/lib/utils/app-register-api.js +3 -2
  221. package/lib/utils/app-register-auth.js +1 -1
  222. package/lib/utils/app-register-config.js +4 -4
  223. package/lib/utils/app-register-display.js +3 -2
  224. package/lib/utils/app-register-validator.js +3 -2
  225. package/lib/utils/app-run-containers.js +26 -22
  226. package/lib/utils/app-scoped-config.js +31 -0
  227. package/lib/utils/app-service-env-from-builder.js +164 -0
  228. package/lib/utils/build-copy.js +1 -1
  229. package/lib/utils/build-helpers.js +20 -20
  230. package/lib/utils/build-resolve-image.js +165 -0
  231. package/lib/utils/cli-layout-chalk.js +8 -0
  232. package/lib/utils/cli-test-layout-chalk.js +267 -0
  233. package/lib/utils/cli-utils.js +88 -11
  234. package/lib/utils/compose-db-passwords.js +138 -0
  235. package/lib/utils/compose-generate-docker-compose.js +216 -0
  236. package/lib/utils/compose-generator.js +197 -291
  237. package/lib/utils/compose-miso-env.js +18 -0
  238. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  239. package/lib/utils/config-paths.js +166 -7
  240. package/lib/utils/config-scoped-resources-preference.js +41 -0
  241. package/lib/utils/configuration-env-resolver.js +11 -8
  242. package/lib/utils/controller-deployment-outcome.js +68 -0
  243. package/lib/utils/credential-display.js +2 -2
  244. package/lib/utils/credential-secrets-env.js +5 -5
  245. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  246. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  247. package/lib/utils/datasource-test-run-certificate-tty.js +82 -0
  248. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  249. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  250. package/lib/utils/datasource-test-run-display.js +459 -0
  251. package/lib/utils/datasource-test-run-exit.js +83 -0
  252. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  253. package/lib/utils/datasource-test-run-report-version.js +51 -0
  254. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  255. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  256. package/lib/utils/datasource-validation-watch.js +266 -0
  257. package/lib/utils/declarative-url-ports.js +47 -0
  258. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  259. package/lib/utils/dev-ca-install.js +185 -23
  260. package/lib/utils/dev-cert-helper.js +266 -17
  261. package/lib/utils/dev-hosts-helper.js +307 -0
  262. package/lib/utils/dev-init-cert-hints.js +37 -0
  263. package/lib/utils/dev-init-health-messages.js +52 -0
  264. package/lib/utils/dev-init-resolve.js +86 -0
  265. package/lib/utils/dev-init-ssh-merge.js +65 -0
  266. package/lib/utils/dev-ssh-config-helper.js +196 -0
  267. package/lib/utils/dev-user-groups.js +93 -0
  268. package/lib/utils/docker-build.js +42 -17
  269. package/lib/utils/docker-exec.js +28 -0
  270. package/lib/utils/docker-manifest-public-port.js +116 -0
  271. package/lib/utils/docker-not-running-hint.js +52 -0
  272. package/lib/utils/docker.js +98 -11
  273. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  274. package/lib/utils/env-config-loader.js +10 -91
  275. package/lib/utils/env-copy.js +19 -10
  276. package/lib/utils/env-map.js +35 -8
  277. package/lib/utils/env-template.js +2 -2
  278. package/lib/utils/environment-scoped-resources.js +144 -0
  279. package/lib/utils/error-formatter.js +92 -13
  280. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  281. package/lib/utils/error-formatters/network-errors.js +2 -1
  282. package/lib/utils/error-formatters/permission-errors.js +2 -1
  283. package/lib/utils/error-formatters/validation-errors.js +2 -1
  284. package/lib/utils/external-readme.js +8 -1
  285. package/lib/utils/external-system-display.js +242 -136
  286. package/lib/utils/external-system-local-test-tty.js +389 -0
  287. package/lib/utils/external-system-readiness-core.js +377 -0
  288. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  289. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  290. package/lib/utils/external-system-readiness-display.js +186 -0
  291. package/lib/utils/external-system-system-test-tty-overview.js +120 -0
  292. package/lib/utils/external-system-system-test-tty.js +417 -0
  293. package/lib/utils/external-system-test-helpers.js +24 -6
  294. package/lib/utils/external-system-validators.js +30 -12
  295. package/lib/utils/health-check-url.js +119 -0
  296. package/lib/utils/health-check.js +59 -25
  297. package/lib/utils/help-builder.js +11 -8
  298. package/lib/utils/image-version.js +4 -8
  299. package/lib/utils/infra-containers.js +4 -7
  300. package/lib/utils/infra-env-defaults.js +162 -0
  301. package/lib/utils/infra-status-display.js +167 -0
  302. package/lib/utils/infra-status.js +16 -8
  303. package/lib/utils/local-secrets.js +3 -4
  304. package/lib/utils/paths.js +148 -47
  305. package/lib/utils/port-resolver.js +10 -23
  306. package/lib/utils/redis-env-scope.js +62 -0
  307. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  308. package/lib/utils/remote-builder-validation.js +99 -0
  309. package/lib/utils/remote-dev-auth.js +117 -21
  310. package/lib/utils/remote-docker-env.js +67 -15
  311. package/lib/utils/remote-secrets-loader.js +13 -4
  312. package/lib/utils/resolve-docker-image-ref.js +124 -0
  313. package/lib/utils/schema-loader.js +22 -9
  314. package/lib/utils/secrets-bash-kv.js +25 -0
  315. package/lib/utils/secrets-generator.js +169 -49
  316. package/lib/utils/secrets-helpers.js +70 -59
  317. package/lib/utils/secrets-kv-scope.js +60 -0
  318. package/lib/utils/secrets-utils.js +32 -38
  319. package/lib/utils/secrets-validation.js +3 -1
  320. package/lib/utils/secrets-yaml-preserve.js +109 -0
  321. package/lib/utils/ssh-key-helper.js +4 -2
  322. package/lib/utils/template-helpers.js +2 -2
  323. package/lib/utils/test-log-writer.js +3 -3
  324. package/lib/utils/token-manager.js +1 -2
  325. package/lib/utils/url-declarative-public-base.js +188 -0
  326. package/lib/utils/url-declarative-resolve-build.js +493 -0
  327. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  328. package/lib/utils/url-declarative-resolve.js +220 -0
  329. package/lib/utils/url-declarative-token-parse.js +74 -0
  330. package/lib/utils/url-declarative-url-flags.js +50 -0
  331. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  332. package/lib/utils/url-public-path-prefix.js +34 -0
  333. package/lib/utils/urls-local-registry.js +220 -0
  334. package/lib/utils/validation-report-tty-kit.js +77 -0
  335. package/lib/utils/validation-run-poll.js +112 -0
  336. package/lib/utils/validation-run-post-retry.js +85 -0
  337. package/lib/utils/validation-run-request.js +116 -0
  338. package/lib/utils/variable-transformer.js +21 -4
  339. package/lib/utils/yaml-preserve.js +33 -14
  340. package/lib/validation/datasource-warnings.js +56 -0
  341. package/lib/validation/env-template-auth.js +1 -1
  342. package/lib/validation/external-manifest-validator.js +27 -7
  343. package/lib/validation/validate-display.js +37 -31
  344. package/lib/validation/validate-external-cert-sync.js +23 -0
  345. package/lib/validation/validate.js +8 -14
  346. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  347. package/lib/validation/validator.js +22 -65
  348. package/lib/validation/wizard-config-validator.js +2 -1
  349. package/package.json +9 -4
  350. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  351. package/scripts/diagnose-cli.js +150 -0
  352. package/scripts/install-local.js +307 -55
  353. package/scripts/pnpm-global-remove.js +48 -0
  354. package/templates/README.md +15 -2
  355. package/templates/applications/dataplane/application.yaml +52 -2
  356. package/templates/applications/dataplane/env.template +79 -17
  357. package/templates/applications/dataplane/rbac.yaml +8 -0
  358. package/templates/applications/keycloak/application.yaml +9 -1
  359. package/templates/applications/keycloak/env.template +15 -6
  360. package/templates/applications/miso-controller/application.yaml +10 -2
  361. package/templates/applications/miso-controller/env.template +42 -12
  362. package/templates/applications/miso-controller/rbac.yaml +5 -0
  363. package/templates/external-system/README.md.hbs +20 -7
  364. package/templates/external-system/deploy.js.hbs +5 -5
  365. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  366. package/templates/infra/compose.yaml.hbs +33 -16
  367. package/templates/infra/servers.json.hbs +3 -1
  368. package/templates/python/docker-compose.hbs +16 -0
  369. package/templates/typescript/docker-compose.hbs +16 -0
  370. package/lib/api/external-test.api.js +0 -111
  371. package/lib/schema/env-config.yaml +0 -60
@@ -1,3 +1,4 @@
1
+ const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * CLI developer configuration command setup (dev config, dev set-id, dev init, dev add/update/pin/delete/list).
3
4
  *
@@ -8,10 +9,11 @@
8
9
 
9
10
  const chalk = require('chalk');
10
11
  const config = require('../core/config');
11
- const devConfig = require('../utils/dev-config');
12
12
  const logger = require('../utils/logger');
13
13
  const { handleCommandError } = require('../utils/cli-utils');
14
+ const { setupDevPathAndFormatCommands } = require('./setup-dev-path-commands');
14
15
  const { runDevInit, runDevRefresh } = require('../commands/dev-init');
16
+ const { displayDevConfig } = require('../commands/dev-show-display');
15
17
  const {
16
18
  handleDevList,
17
19
  handleDevAdd,
@@ -20,45 +22,78 @@ const {
20
22
  handleDevDelete
21
23
  } = require('../commands/dev-cli-handlers');
22
24
 
23
- /**
24
- * Display developer configuration (local ports and config; remote/settings keys always shown).
25
- * Always shows environment, controller, and remote keys (value or "(not set)").
26
- * @param {string} devId - Developer ID
27
- * @returns {Promise<void>}
28
- */
29
- async function displayDevConfig(devId) {
30
- const devIdNum = parseInt(devId, 10);
31
- const ports = devConfig.getDevPorts(devIdNum);
32
- const environment = await config.getCurrentEnvironment();
33
- const controller = await config.getControllerUrl();
34
-
35
- const optionalConfigVars = [
36
- { key: 'format', value: (await config.getFormat()) ?? '(not set)' },
37
- { key: 'aifabrix-home', value: await config.getAifabrixHomeOverride() },
38
- { key: 'aifabrix-secrets', value: await config.getAifabrixSecretsPath() },
39
- { key: 'aifabrix-env-config', value: await config.getAifabrixEnvConfigPath() },
40
- { key: 'remote-server', value: await config.getRemoteServer() },
41
- { key: 'docker-endpoint', value: await config.getDockerEndpoint() },
42
- { key: 'user-mutagen-folder', value: await config.getUserMutagenFolder() },
43
- { key: 'sync-ssh-user', value: await config.getSyncSshUser() },
44
- { key: 'sync-ssh-host', value: await config.getSyncSshHost() }
45
- ];
46
-
47
- logger.log('\n🔧 Developer Configuration\n');
48
- logger.log(`Developer ID: ${devId}`);
49
- logger.log('\nPorts:');
50
- logger.log(` App: ${ports.app}`);
51
- logger.log(` Postgres: ${ports.postgres}`);
52
- logger.log(` Redis: ${ports.redis}`);
53
- logger.log(` pgAdmin: ${ports.pgadmin}`);
54
- logger.log(` Redis Commander: ${ports.redisCommander}`);
55
-
56
- logger.log('\nConfiguration:');
57
- logger.log(` environment: '${environment}'`);
58
- logger.log(controller ? ` controller: '${controller}'` : ' controller: (not set)');
59
- optionalConfigVars.forEach(v => logger.log(` ${v.key}: ${v.value || '(not set)'}`));
60
- logger.log('');
61
- }
25
+ /** Appended to `dev update --help` (examples + partial-update behaviour). */
26
+ const DEV_UPDATE_HELP_AFTER = `
27
+ Examples:
28
+ $ aifabrix dev update 02 --name "Jane Doe"
29
+ $ aifabrix dev update --developer-id 02 --email jane@example.com
30
+ $ aifabrix dev update 01 --name "Admin" --groups admin,developer
31
+ $ aifabrix dev update 02 --groups admin,developer,docker
32
+
33
+ Partial update: only flags you pass are sent to the server. Omitted name, email, and groups are left unchanged.
34
+ `;
35
+
36
+ /** Appended to `dev add --help` (examples + workflow). */
37
+ const DEV_ADD_HELP_AFTER = `
38
+ Examples:
39
+ $ aifabrix dev add --developer-id 02 --name "Jane Doe" --email jane@example.com
40
+ $ aifabrix dev add --developer-id 03 --name "Build admin" --email admin@example.com --groups admin,developer
41
+ $ aifabrix dev add --developer-id 04 --name "CI user" --email ci@example.com --groups secret-manager,developer
42
+
43
+ Requires a configured remote Builder Server and an admin client certificate (same machine setup as dev list / dev pin). After add, run dev pin <id> once to create a PIN for aifabrix dev init.
44
+ `;
45
+
46
+ /** Appended to `aifabrix dev --help` (overview; keep subcommand .description lines short). */
47
+ const DEV_GROUP_HELP_AFTER = `
48
+ Categories:
49
+ Local config show, set-id, set-scoped-resources, set-env-config, set-home, set-work, set-format, print-home, print-work
50
+ Onboarding init (PIN onboarding), refresh (sync settings / renew cert)
51
+ Remote admin list, add, update, pin, delete (need remote-server + client cert in ~/.aifabrix)
52
+ Sync / stop down (Mutagen; optional --apps for containers)
53
+
54
+ Use: aifabrix dev <command> --help
55
+ `;
56
+
57
+ /** Appended to `dev init --help`. */
58
+ const DEV_INIT_HELP_AFTER = `
59
+ Examples:
60
+ Full (first machine or no config yet):
61
+ $ aifabrix dev init --developer-id 01 --server https://builder01.local --pin <one-time-pin>
62
+
63
+ When remote-server and developer-id are already in ~/.aifabrix/config.yaml (from settings or dev show):
64
+ $ aifabrix dev init --pin <one-time-pin>
65
+
66
+ Admin issues the PIN with: aifabrix dev pin <developer-id>
67
+ `;
68
+
69
+ /** Appended to `dev refresh --help`. */
70
+ const DEV_REFRESH_HELP_AFTER = `
71
+ Requires remote-server and saved client certificate (after dev init). Use --cert to force a new cert before expiry.
72
+ `;
73
+
74
+ /** Appended to `dev pin --help`. */
75
+ const DEV_PIN_HELP_AFTER = `
76
+ Examples:
77
+ $ aifabrix dev pin 02
78
+ $ aifabrix dev pin 02 --hosts-ip 192.168.1.25
79
+ $ aifabrix dev pin (uses developer-id from config)
80
+
81
+ Prints copy-paste commands for the developer: full dev init, hosts-file variant, and dev init --pin
82
+ when their config already has remote-server + developer-id.
83
+ `;
84
+
85
+ /** Appended to `dev delete --help`. */
86
+ const DEV_DELETE_HELP_AFTER = `
87
+ Example:
88
+ $ aifabrix dev delete 02
89
+ `;
90
+
91
+ /** Appended to `dev down --help`. */
92
+ const DEV_DOWN_HELP_AFTER = `
93
+ Examples:
94
+ $ aifabrix dev down
95
+ $ aifabrix dev down --apps
96
+ `;
62
97
 
63
98
  /**
64
99
  * Handle dev set-format command
@@ -67,7 +102,34 @@ async function displayDevConfig(devId) {
67
102
  */
68
103
  async function handleSetFormat(format) {
69
104
  await config.setFormat(format);
70
- logger.log(chalk.green(`✓ Format set to ${format.toLowerCase()}`));
105
+ logger.log(formatSuccessLine(`Format set to ${format.toLowerCase()}`));
106
+ const devId = await config.getDeveloperId();
107
+ await displayDevConfig(devId);
108
+ }
109
+
110
+ /**
111
+ * Set useEnvironmentScopedResources in ~/.aifabrix/config.yaml
112
+ * @param {string} value - "true" or "false"
113
+ * @returns {Promise<void>}
114
+ */
115
+ async function handleSetScopedResources(value) {
116
+ const b = String(value || '').trim().toLowerCase();
117
+ if (b !== 'true' && b !== 'false') {
118
+ throw new Error('Value must be true or false (example: aifabrix dev set-scoped-resources true)');
119
+ }
120
+ await config.setUseEnvironmentScopedResources(b === 'true');
121
+ if (b === 'true') {
122
+ logger.log(
123
+ formatSuccessLine('Environment-scoped resources activated in ~/.aifabrix/config.yaml')
124
+ );
125
+ } else {
126
+ logger.log(formatSuccessLine('Environment-scoped resources passivated (default local naming)'));
127
+ }
128
+ logger.log(
129
+ chalk.gray(
130
+ ' Apps still need environmentScopedResources: true in application.yaml for prefixing when you run with --env dev or tst.'
131
+ )
132
+ );
71
133
  const devId = await config.getDeveloperId();
72
134
  await displayDevConfig(devId);
73
135
  }
@@ -79,7 +141,7 @@ async function handleSetFormat(format) {
79
141
  function setupDevShowAndSetId(dev) {
80
142
  dev
81
143
  .command('show')
82
- .description('Show developer configuration (ports and config vars)')
144
+ .description('Show dev ports and ~/.aifabrix config')
83
145
  .action(async() => {
84
146
  try {
85
147
  const devId = await config.getDeveloperId();
@@ -92,7 +154,7 @@ function setupDevShowAndSetId(dev) {
92
154
 
93
155
  dev
94
156
  .command('set-id <id>')
95
- .description('Set developer ID (0 = default infra, > 0 = developer-specific)')
157
+ .description('Set developer ID (0 = default infra, >0 = dev-specific ports)')
96
158
  .action(async(id) => {
97
159
  try {
98
160
  const digitsOnly = /^[0-9]+$/.test(id);
@@ -101,56 +163,22 @@ function setupDevShowAndSetId(dev) {
101
163
  }
102
164
  await config.setDeveloperId(id);
103
165
  process.env.AIFABRIX_DEVELOPERID = id;
104
- logger.log(chalk.green(`✓ Developer ID set to ${id}`));
166
+ logger.log(formatSuccessLine(`Developer ID set to ${id}`));
105
167
  await displayDevConfig(id);
106
168
  } catch (error) {
107
169
  handleCommandError(error, 'dev set-id');
108
170
  process.exit(1);
109
171
  }
110
172
  });
111
- }
112
-
113
- /**
114
- * Register dev set-env-config, set-home and set-format commands.
115
- * @param {Command} dev - dev subcommand group
116
- */
117
- function setupDevPathAndFormatCommands(dev) {
118
- dev
119
- .command('set-env-config <filePath>')
120
- .description('Set aifabrix-env-config path in config.yaml (pass empty to clear; path is not checked for existence)')
121
- .action(async(filePath) => {
122
- try {
123
- const trimmed = (filePath || '').trim();
124
- await config.setAifabrixEnvConfigPath(trimmed);
125
- logger.log(trimmed === '' ? chalk.green('✓ Env config path cleared') : chalk.green(`✓ Env config path set to ${trimmed}`));
126
- } catch (error) {
127
- handleCommandError(error, 'dev set-env-config');
128
- process.exit(1);
129
- }
130
- });
131
173
 
132
174
  dev
133
- .command('set-home <path>')
134
- .description('Set aifabrix-home path in config.yaml (pass empty string to clear)')
135
- .action(async(homePath) => {
175
+ .command('set-scoped-resources <value>')
176
+ .description('Set useEnvironmentScopedResources to true|false in ~/.aifabrix/config.yaml')
177
+ .action(async(value) => {
136
178
  try {
137
- const trimmed = (homePath || '').trim();
138
- await config.setAifabrixHomeOverride(trimmed);
139
- logger.log(trimmed === '' ? chalk.green('✓ Home path cleared') : chalk.green(`✓ Home path set to ${trimmed}`));
179
+ await handleSetScopedResources(value);
140
180
  } catch (error) {
141
- handleCommandError(error, 'dev set-home');
142
- process.exit(1);
143
- }
144
- });
145
-
146
- dev
147
- .command('set-format <format>')
148
- .description('Set default output format for download/convert (json | yaml); used when --format not passed')
149
- .action(async(format) => {
150
- try {
151
- await handleSetFormat(format);
152
- } catch (error) {
153
- handleCommandError(error, 'dev set-format');
181
+ handleCommandError(error, 'dev set-scoped-resources');
154
182
  process.exit(1);
155
183
  }
156
184
  });
@@ -162,7 +190,29 @@ function setupDevPathAndFormatCommands(dev) {
162
190
  */
163
191
  function setupDevConfigCommands(dev) {
164
192
  setupDevShowAndSetId(dev);
165
- setupDevPathAndFormatCommands(dev);
193
+ setupDevPathAndFormatCommands(dev, handleSetFormat);
194
+ }
195
+
196
+ /**
197
+ * Shared Commander options for dev init (PIN onboarding).
198
+ * @param {object} cmd - Commander command to attach options to
199
+ * @returns {object} Same command for chaining
200
+ */
201
+ function addDevOnboardingOptions(cmd) {
202
+ return cmd
203
+ .requiredOption('--pin <pin>', 'One-time PIN from your admin (see aifabrix dev pin)')
204
+ .option(
205
+ '--developer-id <id>',
206
+ 'Developer ID (optional if set in ~/.aifabrix/config.yaml and not 0; e.g. 01)'
207
+ )
208
+ .option('--server <url>', 'Builder Server base URL (optional if remote-server is in config)')
209
+ .option('-y, --yes', 'Auto-install development CA without prompt when certificate is untrusted; with --add-hosts, skip hosts-file confirmation')
210
+ .option('--no-install-ca', 'Do not offer CA install; fail with manual instructions on untrusted certificate')
211
+ .option(
212
+ '--add-hosts',
213
+ 'Offer to add the server hostname to this machine\'s hosts file (wildcard DNS must be configured separately; may require admin)'
214
+ )
215
+ .option('--hosts-ip <ip>', 'IPv4 for the hosts entry when using --add-hosts (skips lookup / IP prompt)');
166
216
  }
167
217
 
168
218
  /**
@@ -170,26 +220,26 @@ function setupDevConfigCommands(dev) {
170
220
  * @param {Command} dev - dev subcommand group
171
221
  */
172
222
  function setupDevInitCommand(dev) {
173
- dev
174
- .command('init')
175
- .description('Onboard with Builder Server (issue certificate, fetch settings, register SSH key for Mutagen)')
176
- .requiredOption('--developer-id <id>', 'Developer ID (same as dev add; e.g. 01)')
177
- .requiredOption('--server <url>', 'Builder Server base URL (e.g. https://dev.aifabrix.dev)')
178
- .requiredOption('--pin <pin>', 'One-time PIN from your admin')
179
- .option('-y, --yes', 'Auto-install development CA without prompt when certificate is untrusted')
180
- .option('--no-install-ca', 'Do not offer CA install; fail with manual instructions on untrusted certificate')
181
- .action(async(options) => {
182
- try {
183
- await runDevInit(options);
184
- } catch (error) {
185
- handleCommandError(error, 'dev init');
186
- process.exit(1);
187
- }
188
- });
223
+ const runOnboarding = async(options, label) => {
224
+ try {
225
+ await runDevInit(options);
226
+ } catch (error) {
227
+ handleCommandError(error, label);
228
+ process.exit(1);
229
+ }
230
+ };
231
+
232
+ addDevOnboardingOptions(
233
+ dev
234
+ .command('init')
235
+ .description('Onboard with Builder Server (cert, settings, SSH for Mutagen)')
236
+ .addHelpText('after', DEV_INIT_HELP_AFTER)
237
+ ).action(async(options) => runOnboarding(options, 'dev init'));
189
238
 
190
239
  dev
191
240
  .command('refresh')
192
- .description('Fetch settings from Builder Server and update config; refresh certificate if expiring within 14 days or --cert')
241
+ .description('Pull server settings into config; renew cert if due or --cert')
242
+ .addHelpText('after', DEV_REFRESH_HELP_AFTER)
193
243
  .option('--cert', 'Force certificate refresh (create PIN + issue-cert) even when cert is still valid')
194
244
  .action(async(options) => {
195
245
  try {
@@ -208,7 +258,7 @@ function setupDevInitCommand(dev) {
208
258
  function setupDevListAddCommands(dev) {
209
259
  dev
210
260
  .command('list')
211
- .description('List developer users (remote Builder Server only)')
261
+ .description('List developers (remote Builder Server)')
212
262
  .action(async() => {
213
263
  try {
214
264
  await handleDevList();
@@ -220,11 +270,12 @@ function setupDevListAddCommands(dev) {
220
270
 
221
271
  dev
222
272
  .command('add')
223
- .description('Register a new developer (remote Builder Server only; admin)')
224
- .requiredOption('--developer-id <id>', 'Developer ID (unique, e.g. 01)')
273
+ .description('Create developer on server (admin); then dev pin for onboarding')
274
+ .requiredOption('--developer-id <id>', 'Unique id, digits only (e.g. 02); used with dev init --developer-id')
225
275
  .requiredOption('--name <name>', 'Display name')
226
276
  .requiredOption('--email <email>', 'Email address')
227
- .option('--groups <items>', 'Comma-separated groups (admin, secret-manager, developer)', 'developer')
277
+ .option('--groups <items>', 'Comma-separated roles: admin, secret-manager, developer, docker', 'developer')
278
+ .addHelpText('after', DEV_ADD_HELP_AFTER)
228
279
  .action(async(options) => {
229
280
  try {
230
281
  await handleDevAdd(options);
@@ -242,11 +293,12 @@ function setupDevListAddCommands(dev) {
242
293
  function setupDevUpdatePinDeleteCommands(dev) {
243
294
  dev
244
295
  .command('update [developerId]')
245
- .description('Update a developer (name, email, groups); use --developer-id like dev add')
296
+ .description('Patch name/email/groups (admin); only given flags change')
246
297
  .option('--developer-id <id>', 'Developer ID (same as dev add)')
247
298
  .option('--name <name>', 'Display name')
248
299
  .option('--email <email>', 'Email address')
249
- .option('--groups <items>', 'Comma-separated groups (admin, secret-manager, developer)')
300
+ .option('--groups <items>', 'Comma-separated groups (admin, secret-manager, developer, docker)')
301
+ .addHelpText('after', DEV_UPDATE_HELP_AFTER)
250
302
  .action(async(developerId, options) => {
251
303
  try {
252
304
  await handleDevUpdate(developerId, options);
@@ -258,10 +310,12 @@ function setupDevUpdatePinDeleteCommands(dev) {
258
310
 
259
311
  dev
260
312
  .command('pin [developerId]')
261
- .description('Create or regenerate one-time PIN for onboarding (admin; show once to developer)')
262
- .action(async(developerId) => {
313
+ .description('One-time onboarding PIN for dev init (admin)')
314
+ .option('--hosts-ip <ip>', 'Builder Server LAN IPv4 to embed in the hosts-file init command (optional)')
315
+ .addHelpText('after', DEV_PIN_HELP_AFTER)
316
+ .action(async(developerId, options) => {
263
317
  try {
264
- await handleDevPin(developerId);
318
+ await handleDevPin(developerId, options);
265
319
  } catch (error) {
266
320
  handleCommandError(error, 'dev pin');
267
321
  process.exit(1);
@@ -270,7 +324,8 @@ function setupDevUpdatePinDeleteCommands(dev) {
270
324
 
271
325
  dev
272
326
  .command('delete <developerId>')
273
- .description('Remove a developer (remote Builder Server only; admin)')
327
+ .description('Remove developer from server (admin)')
328
+ .addHelpText('after', DEV_DELETE_HELP_AFTER)
274
329
  .action(async(developerId) => {
275
330
  try {
276
331
  await handleDevDelete(developerId);
@@ -282,7 +337,8 @@ function setupDevUpdatePinDeleteCommands(dev) {
282
337
 
283
338
  dev
284
339
  .command('down')
285
- .description('Stop Mutagen sync sessions for this developer (and optionally app containers)')
340
+ .description('Stop Mutagen sync; --apps also stops app containers')
341
+ .addHelpText('after', DEV_DOWN_HELP_AFTER)
286
342
  .option('--apps', 'Also stop running app containers for this developer')
287
343
  .action(async(options) => {
288
344
  try {
@@ -311,7 +367,8 @@ function setupDevUserCommands(dev) {
311
367
  function setupDevCommands(program) {
312
368
  const dev = program
313
369
  .command('dev')
314
- .description('Developer configuration and isolation');
370
+ .description('Local dev config, Builder onboarding, remote admin, Mutagen/sync')
371
+ .addHelpText('after', DEV_GROUP_HELP_AFTER);
315
372
 
316
373
  setupDevConfigCommands(dev);
317
374
  setupDevInitCommand(dev);
@@ -29,9 +29,15 @@ Examples:
29
29
  $ aifabrix env deploy tst --preset m
30
30
  $ aifabrix env deploy dev --config ./env-config.json --no-poll`;
31
31
 
32
+ const ENV_GROUP_HELP_AFTER = `
33
+ Subcommands:
34
+ deploy <env> Provision/update environment in Miso Controller (see env deploy --help)
35
+ `;
36
+
32
37
  const env = program
33
38
  .command('env')
34
- .description('Deploy and manage Miso Controller environments (dev, tst, pro, miso)');
39
+ .description('Miso Controller environments (primary: env deploy <env>)')
40
+ .addHelpText('after', ENV_GROUP_HELP_AFTER);
35
41
 
36
42
  env
37
43
  .command('deploy <env>')
@@ -2,9 +2,9 @@
2
2
  * CLI external system command setup (download, upload, delete, test-integration).
3
3
  *
4
4
  * Registers these commands on the Commander program:
5
- * - download <system-key> – Download external system from dataplane to integration/<system-key>/
6
- * - upload <system-key> – Upload to dataplane (validate publish; no controller deploy)
7
- * - delete <system-key> – Delete external system and associated datasources from dataplane
5
+ * - download <systemKey> – Download external system from dataplane to integration/<systemKey>/
6
+ * - upload <systemKey> – Upload publishes to dataplane and registers the app with the controller (draft)
7
+ * - delete <systemKey> – Delete external system and associated datasources from dataplane
8
8
  * - test-integration <app> – Run integration tests (builder: in container; external: via dataplane pipeline)
9
9
  *
10
10
  * @fileoverview External system command definitions for AI Fabrix Builder CLI
@@ -15,10 +15,12 @@
15
15
  */
16
16
 
17
17
  const { handleCommandError } = require('../utils/cli-utils');
18
+ const { cliOptsSkipCertSync } = require('../certification/cli-cert-sync-skip');
19
+ const { TEST_INTEGRATION_HELP_AFTER } = require('./setup-app.help');
18
20
 
19
21
  function setupDownloadCommand(program) {
20
- program.command('download <system-key>')
21
- .description('Download external system from dataplane to local development structure')
22
+ program.command('download <systemKey>')
23
+ .description('Pull external system from dataplane into integration/<key>/')
22
24
  .option('--format <format>', 'Output format: json | yaml (default: yaml or config format)')
23
25
  .option('--dry-run', 'Show what would be downloaded without actually downloading')
24
26
  .option('--force', 'Overwrite existing README.md without prompting')
@@ -39,13 +41,29 @@ function setupDownloadCommand(program) {
39
41
  }
40
42
 
41
43
  function setupUploadCommand(program) {
42
- program.command('upload <system-key>')
43
- .description('Upload external system to dataplane (upload validate publish; no controller deploy)')
44
+ program.command('upload <systemKey>')
45
+ .description('Validate, publish to dataplane, and register with controller (draft application)')
44
46
  .option('--dry-run', 'Validate and build payload only; no API calls')
47
+ .option('-v, --verbose', 'Run server-side pipeline validate and print warnings before publish')
48
+ .option('--probe', 'After publish, run dataplane runtime checks (validation/run); slower')
49
+ .option('--minimal', 'Print only a short readiness summary after upload')
50
+ .option('--probe-timeout <ms>', 'Timeout for --probe (default: 120000)', '120000')
51
+ .option(
52
+ '--no-cert-sync',
53
+ 'Skip updating the system file certification block from the dataplane active certificate after publish'
54
+ )
45
55
  .action(async(systemKey, options) => {
46
56
  try {
47
57
  const upload = require('../commands/upload');
48
- await upload.uploadExternalSystem(systemKey, options);
58
+ const probeTimeout =
59
+ options.probeTimeout === undefined || options.probeTimeout === null
60
+ ? 120000
61
+ : Number(options.probeTimeout);
62
+ await upload.uploadExternalSystem(systemKey, {
63
+ ...options,
64
+ noCertSync: cliOptsSkipCertSync(options),
65
+ probeTimeout: Number.isFinite(probeTimeout) ? probeTimeout : 120000
66
+ });
49
67
  } catch (error) {
50
68
  handleCommandError(error, 'upload');
51
69
  process.exit(1);
@@ -54,9 +72,9 @@ function setupUploadCommand(program) {
54
72
  }
55
73
 
56
74
  function setupDeleteCommand(program) {
57
- program.command('delete <system-key>')
58
- .description('Delete external system from dataplane (also deletes all associated datasources)')
59
- .option('--type <type>', 'Application type (default: external; use "external" to target integration/<app>)')
75
+ program.command('delete <systemKey>')
76
+ .description('Remove external system and its datasources from dataplane')
77
+ .option('--type <type>', 'Application type (default: external; use "external" to target integration/<systemKey>)')
60
78
  .option('--yes', 'Skip confirmation prompt')
61
79
  .option('--force', 'Skip confirmation prompt (alias for --yes)')
62
80
  .action(async(systemKey, options) => {
@@ -111,10 +129,25 @@ async function tryBuilderTestIntegration(appName, options) {
111
129
  */
112
130
  async function runExternalSystemTestIntegration(appName, options) {
113
131
  const test = require('../external-system/test');
114
- const opts = { ...options, environment: options.env || options.environment, debug: options.debug };
132
+ const opts = {
133
+ ...options,
134
+ environment: options.env || options.environment,
135
+ debug: options.debug,
136
+ perDatasource: options.perDatasource,
137
+ sync: options.sync === true
138
+ };
115
139
  const results = await test.testExternalSystemIntegration(appName, opts);
116
- test.displayIntegrationTestResults(results, options.verbose);
117
- if (!results.success) process.exit(1);
140
+ test.displayIntegrationTestResults(results, options.verbose, { debug: options.debug, runType: 'integration' });
141
+ const { computeSystemExitCodeFromDatasourceRows } = require('../utils/datasource-test-run-exit');
142
+ const rows = Array.isArray(results.datasourceResults) ? results.datasourceResults : [];
143
+ const exitCode = computeSystemExitCodeFromDatasourceRows(rows, {
144
+ warningsAsErrors: options.warningsAsErrors === true,
145
+ requireCert: options.requireCert === true
146
+ });
147
+ if (exitCode !== 0) process.exit(exitCode);
148
+ if (cliOptsSkipCertSync(options)) return;
149
+ const { trySyncCertificationFromDataplaneForExternalApp } = require('../certification/sync-after-external-command');
150
+ await trySyncCertificationFromDataplaneForExternalApp(appName, 'test-integration');
118
151
  }
119
152
 
120
153
  /**
@@ -126,6 +159,12 @@ async function runExternalSystemTestIntegration(appName, options) {
126
159
  async function runTestIntegrationCommand(appName, options) {
127
160
  const pathsUtil = require('../utils/paths');
128
161
  const appType = await pathsUtil.detectAppType(appName).catch(() => null);
162
+ if (options.sync === true && appType && appType.baseDir === 'builder') {
163
+ throw new Error(
164
+ 'Option --sync applies only to external integration tests (integration/<systemKey>/). ' +
165
+ 'For a builder app use aifabrix upload <systemKey> from the integration folder, or run test-integration without --sync.'
166
+ );
167
+ }
129
168
  if (appType && appType.baseDir === 'builder') {
130
169
  const { runAppTestIntegration } = require('../commands/app-test');
131
170
  const opts = { env: options.env || options.environment || 'dev' };
@@ -133,23 +172,45 @@ async function runTestIntegrationCommand(appName, options) {
133
172
  return;
134
173
  }
135
174
  const ranBuilder = await tryBuilderTestIntegration(appName, options);
136
- if (ranBuilder) return;
175
+ if (ranBuilder) {
176
+ if (options.sync === true) {
177
+ throw new Error(
178
+ 'Option --sync applies only when test-integration runs against an external integration folder on the dataplane. ' +
179
+ 'This run used a builder-style path instead. Remove --sync or use an integration/<systemKey>/ app.'
180
+ );
181
+ }
182
+ return;
183
+ }
137
184
  await runExternalSystemTestIntegration(appName, options);
138
185
  }
139
186
 
140
187
  function setupExternalSystemTestCommands(program) {
141
188
  // 'test <app>' is registered in setup-app.js and dispatches by app type (builder vs external)
142
189
  program.command('test-integration <app>')
143
- .description('Run integration tests (builder/docker app: in container; external system: via dataplane pipeline API)')
144
- .option('-d, --datasource <key>', 'Test specific datasource only')
145
- .option('-p, --payload <file>', 'Path to custom test payload file')
146
- .option('-e, --env <env>', 'Environment: dev, tst, or pro (default: from aifabrix auth config)')
190
+ .description('Integration tests: builder in container; external via dataplane')
191
+ .option('-e, --env <env>', 'Environment: dev, tst, or pro (builder: dev/tst for container)', 'dev')
147
192
  .option('-v, --verbose', 'Show detailed test output')
148
- .option('--debug', 'Include debug output and write log to integration/<app>/logs/')
149
- .option('--timeout <ms>', 'Request timeout in milliseconds', '30000')
150
- .action(async(appName, options) => {
193
+ .option('-d, --debug', 'Include debug output and write log to integration/<systemKey>/logs/')
194
+ .option(
195
+ '--sync',
196
+ 'Publish local system and datasource files to the dataplane before running tests (same as aifabrix upload <systemKey>)'
197
+ )
198
+ .option('--warnings-as-errors', 'Treat aggregate warn as failure (exit 1)')
199
+ .option('--require-cert', 'Require certification passed on every datasource (exit 2 if not)')
200
+ .option(
201
+ '--no-cert-sync',
202
+ 'Skip updating the system file certification block from the dataplane after a successful run'
203
+ )
204
+ .addHelpText('after', TEST_INTEGRATION_HELP_AFTER)
205
+ .action(async(appName, options, cmd) => {
151
206
  try {
152
- await runTestIntegrationCommand(appName, options);
207
+ const rawArgs = Array.isArray(cmd?.rawArgs) ? cmd.rawArgs : [];
208
+ const envExplicit = rawArgs.includes('-e') || rawArgs.includes('--env');
209
+ const opts = {
210
+ ...options,
211
+ env: envExplicit ? options.env : undefined
212
+ };
213
+ await runTestIntegrationCommand(appName, opts);
153
214
  } catch (error) {
154
215
  handleCommandError(error, 'test-integration');
155
216
  process.exit(1);