@aifabrix/builder 2.42.1 → 2.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (392) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/README.md +2 -2
  3. package/anchor-docs/README.md +10 -0
  4. package/anchor-docs/_TEMPLATE +24 -0
  5. package/bin/aifabrix.js +13 -4
  6. package/integration/hubspot-test/README.md +157 -0
  7. package/integration/{hubspot → hubspot-test}/application.json +6 -6
  8. package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
  9. package/integration/hubspot-test/env.template +4 -0
  10. package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
  11. package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
  12. package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
  13. package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
  14. package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
  15. package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
  16. package/integration/hubspot-test/rbac.json +166 -0
  17. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
  18. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
  19. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
  20. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
  21. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
  22. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
  23. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
  24. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
  25. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
  26. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
  27. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
  28. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
  29. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
  30. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
  31. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
  32. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
  33. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
  34. package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
  35. package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
  36. package/integration/{hubspot → hubspot-test}/test.js +137 -102
  37. package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
  38. package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
  39. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  40. package/integration/roundtrip-test-local/README.md +144 -0
  41. package/integration/roundtrip-test-local/application.yaml +13 -0
  42. package/integration/roundtrip-test-local/env.template +15 -0
  43. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  44. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  45. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  46. package/integration/roundtrip-test-local2/README.md +144 -0
  47. package/integration/roundtrip-test-local2/application.yaml +13 -0
  48. package/integration/roundtrip-test-local2/env.template +15 -0
  49. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  50. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  51. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  52. package/integration/test/wizard.yaml +8 -0
  53. package/jest.config.default.js +10 -0
  54. package/jest.config.integration.fixtures.js +22 -0
  55. package/jest.config.integration.js +21 -18
  56. package/jest.config.isolated.js +10 -0
  57. package/jest.projects.js +288 -0
  58. package/lib/api/datasources-core.api.js +3 -3
  59. package/lib/api/dev-mtls-request.js +110 -0
  60. package/lib/api/dev-server-https.js +145 -0
  61. package/lib/api/dev.api.js +133 -144
  62. package/lib/api/index.js +0 -1
  63. package/lib/api/pipeline.api.js +67 -20
  64. package/lib/api/service-users.api.js +111 -2
  65. package/lib/api/types/dev.types.js +4 -3
  66. package/lib/api/types/pipeline.types.js +8 -5
  67. package/lib/api/types/service-users.types.js +41 -0
  68. package/lib/api/types/validation-run.types.js +56 -0
  69. package/lib/api/validation-run.api.js +99 -0
  70. package/lib/api/validation-runner.js +99 -0
  71. package/lib/app/config.js +1 -1
  72. package/lib/app/deploy-status-display.js +2 -2
  73. package/lib/app/deploy.js +7 -6
  74. package/lib/app/display.js +2 -1
  75. package/lib/app/dockerfile.js +3 -2
  76. package/lib/app/down.js +2 -1
  77. package/lib/app/helpers.js +6 -5
  78. package/lib/app/index.js +27 -8
  79. package/lib/app/list.js +7 -6
  80. package/lib/app/push.js +4 -3
  81. package/lib/app/register.js +19 -8
  82. package/lib/app/rotate-secret.js +17 -13
  83. package/lib/app/run-container-start.js +184 -0
  84. package/lib/app/run-docker-fallback.js +108 -0
  85. package/lib/app/run-env-compose.js +30 -42
  86. package/lib/app/run-helpers.js +49 -126
  87. package/lib/app/run-infra-requirements.js +30 -0
  88. package/lib/app/run-resolve-image.js +21 -0
  89. package/lib/app/run.js +74 -21
  90. package/lib/app/show-display.js +1 -1
  91. package/lib/app/show.js +1 -1
  92. package/lib/build/index.js +13 -10
  93. package/lib/cli/index.js +2 -0
  94. package/lib/cli/setup-app.help.js +67 -0
  95. package/lib/cli/setup-app.js +59 -123
  96. package/lib/cli/setup-app.test-commands.js +179 -0
  97. package/lib/cli/setup-auth.js +36 -14
  98. package/lib/cli/setup-credential-deployment.js +22 -8
  99. package/lib/cli/setup-dev-path-commands.js +124 -0
  100. package/lib/cli/setup-dev.js +190 -103
  101. package/lib/cli/setup-environment.js +11 -20
  102. package/lib/cli/setup-external-system.js +62 -22
  103. package/lib/cli/setup-infra.js +139 -47
  104. package/lib/cli/setup-parameters.js +32 -0
  105. package/lib/cli/setup-secrets.js +147 -10
  106. package/lib/cli/setup-service-user.js +146 -20
  107. package/lib/cli/setup-utility.js +47 -19
  108. package/lib/commands/app-down.js +5 -7
  109. package/lib/commands/app-install.js +14 -7
  110. package/lib/commands/app-logs.js +13 -10
  111. package/lib/commands/app-shell.js +4 -1
  112. package/lib/commands/app-test.js +25 -19
  113. package/lib/commands/app.js +22 -10
  114. package/lib/commands/auth-config.js +10 -14
  115. package/lib/commands/auth-status.js +4 -3
  116. package/lib/commands/credential-env.js +4 -3
  117. package/lib/commands/credential-list.js +5 -4
  118. package/lib/commands/credential-push.js +4 -3
  119. package/lib/commands/datasource-unified-test-cli.js +495 -0
  120. package/lib/commands/datasource-unified-test-cli.options.js +149 -0
  121. package/lib/commands/datasource-validation-cli.js +129 -0
  122. package/lib/commands/datasource.js +123 -71
  123. package/lib/commands/deployment-list.js +6 -5
  124. package/lib/commands/dev-cli-handlers.js +122 -18
  125. package/lib/commands/dev-down.js +4 -3
  126. package/lib/commands/dev-init.js +231 -116
  127. package/lib/commands/dev-show-display.js +473 -0
  128. package/lib/commands/login-credentials.js +3 -2
  129. package/lib/commands/login-device.js +4 -3
  130. package/lib/commands/login.js +5 -4
  131. package/lib/commands/logout.js +8 -7
  132. package/lib/commands/parameters-validate.js +54 -0
  133. package/lib/commands/repair-datasource.js +314 -68
  134. package/lib/commands/repair-env-template.js +16 -10
  135. package/lib/commands/repair-rbac.js +25 -19
  136. package/lib/commands/repair.js +116 -32
  137. package/lib/commands/secrets-list.js +23 -12
  138. package/lib/commands/secrets-remove-all.js +220 -0
  139. package/lib/commands/secrets-remove.js +22 -13
  140. package/lib/commands/secrets-set.js +21 -12
  141. package/lib/commands/secrets-validate.js +20 -7
  142. package/lib/commands/secure.js +10 -9
  143. package/lib/commands/service-user.js +243 -13
  144. package/lib/commands/test-e2e-external.js +27 -1
  145. package/lib/commands/up-common.js +28 -2
  146. package/lib/commands/up-dataplane.js +31 -18
  147. package/lib/commands/up-miso.js +19 -29
  148. package/lib/commands/upload.js +138 -39
  149. package/lib/commands/wizard-core-helpers.js +1 -1
  150. package/lib/commands/wizard-dataplane.js +4 -3
  151. package/lib/commands/wizard-helpers.js +3 -3
  152. package/lib/commands/wizard.js +2 -2
  153. package/lib/core/admin-secrets.js +16 -5
  154. package/lib/core/audit-logger.js +12 -4
  155. package/lib/core/config-attach-extensions.js +46 -0
  156. package/lib/core/config-runtime-paths.js +29 -0
  157. package/lib/core/config.js +59 -58
  158. package/lib/core/diff.js +3 -2
  159. package/lib/core/ensure-encryption-key.js +2 -4
  160. package/lib/core/secrets-ensure-infra.js +77 -0
  161. package/lib/core/secrets-ensure.js +120 -64
  162. package/lib/core/secrets-env-write.js +35 -7
  163. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  164. package/lib/core/secrets.js +228 -42
  165. package/lib/core/templates-env.js +4 -3
  166. package/lib/core/templates.js +1 -1
  167. package/lib/datasource/abac-validator.js +148 -0
  168. package/lib/datasource/deploy.js +75 -53
  169. package/lib/datasource/field-reference-validator.js +77 -36
  170. package/lib/datasource/integration-context.js +63 -0
  171. package/lib/datasource/list.js +8 -7
  172. package/lib/datasource/log-viewer.js +252 -0
  173. package/lib/datasource/resolve-app.js +109 -0
  174. package/lib/datasource/test-e2e.js +95 -155
  175. package/lib/datasource/test-integration.js +121 -109
  176. package/lib/datasource/unified-validation-run-body.js +65 -0
  177. package/lib/datasource/unified-validation-run-post.js +23 -0
  178. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  179. package/lib/datasource/unified-validation-run.js +92 -0
  180. package/lib/datasource/validate.js +162 -15
  181. package/lib/deployment/deployer.js +4 -3
  182. package/lib/deployment/environment.js +7 -6
  183. package/lib/deployment/push.js +17 -8
  184. package/lib/external-system/delete.js +4 -3
  185. package/lib/external-system/deploy.js +131 -53
  186. package/lib/external-system/download-helpers.js +1 -1
  187. package/lib/external-system/download.js +7 -6
  188. package/lib/external-system/generator.js +104 -14
  189. package/lib/external-system/integration-test-dispatch.js +26 -0
  190. package/lib/external-system/test-execution.js +5 -1
  191. package/lib/external-system/test-helpers.js +0 -4
  192. package/lib/external-system/test-system-level-helpers.js +110 -0
  193. package/lib/external-system/test-system-level.js +83 -44
  194. package/lib/external-system/test.js +59 -8
  195. package/lib/generator/builders.js +23 -11
  196. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  197. package/lib/generator/external-controller-manifest.js +3 -3
  198. package/lib/generator/external.js +23 -11
  199. package/lib/generator/helpers.js +71 -12
  200. package/lib/generator/index.js +8 -4
  201. package/lib/generator/split-readme.js +12 -7
  202. package/lib/generator/split-variables.js +2 -1
  203. package/lib/generator/split.js +46 -11
  204. package/lib/generator/wizard-readme.js +3 -3
  205. package/lib/generator/wizard.js +16 -13
  206. package/lib/infrastructure/compose.js +60 -6
  207. package/lib/infrastructure/helpers.js +238 -51
  208. package/lib/infrastructure/index.js +64 -37
  209. package/lib/infrastructure/services.js +21 -15
  210. package/lib/internal/fs-real-sync.js +104 -0
  211. package/lib/internal/node-fs.js +98 -0
  212. package/lib/parameters/database-secret-values.js +173 -0
  213. package/lib/parameters/infra-kv-discovery.js +121 -0
  214. package/lib/parameters/infra-parameter-catalog.js +458 -0
  215. package/lib/parameters/infra-parameter-validate.js +64 -0
  216. package/lib/schema/application-schema.json +37 -17
  217. package/lib/schema/datasource-test-run.schema.json +493 -0
  218. package/lib/schema/deployment-rules.yaml +102 -63
  219. package/lib/schema/external-datasource.schema.json +1201 -433
  220. package/lib/schema/external-system.schema.json +181 -5
  221. package/lib/schema/flag-map-validation-run.json +31 -0
  222. package/lib/schema/infra-parameter.schema.json +106 -0
  223. package/lib/schema/infra.parameter.yaml +421 -0
  224. package/lib/schema/type/credential-auth-templates.json +40 -0
  225. package/lib/schema/type/document-storage.json +213 -0
  226. package/lib/schema/type/message-service.json +123 -0
  227. package/lib/schema/type/vector-store.json +88 -0
  228. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  229. package/lib/utils/api-error-handler.js +2 -2
  230. package/lib/utils/api.js +49 -14
  231. package/lib/utils/app-config-resolver.js +23 -1
  232. package/lib/utils/app-register-api.js +3 -2
  233. package/lib/utils/app-register-auth.js +1 -1
  234. package/lib/utils/app-register-config.js +4 -4
  235. package/lib/utils/app-register-display.js +3 -2
  236. package/lib/utils/app-register-validator.js +3 -2
  237. package/lib/utils/app-run-containers.js +26 -22
  238. package/lib/utils/app-scoped-config.js +31 -0
  239. package/lib/utils/app-service-env-from-builder.js +164 -0
  240. package/lib/utils/build-copy.js +1 -1
  241. package/lib/utils/build-helpers.js +20 -20
  242. package/lib/utils/build-resolve-image.js +165 -0
  243. package/lib/utils/cli-layout-chalk.js +8 -0
  244. package/lib/utils/cli-test-layout-chalk.js +267 -0
  245. package/lib/utils/cli-utils.js +88 -11
  246. package/lib/utils/compose-db-passwords.js +138 -0
  247. package/lib/utils/compose-generate-docker-compose.js +216 -0
  248. package/lib/utils/compose-generator.js +197 -291
  249. package/lib/utils/compose-miso-env.js +18 -0
  250. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  251. package/lib/utils/config-paths.js +209 -6
  252. package/lib/utils/config-scoped-resources-preference.js +41 -0
  253. package/lib/utils/controller-deployment-outcome.js +68 -0
  254. package/lib/utils/credential-display.js +2 -2
  255. package/lib/utils/credential-secrets-env.js +16 -1
  256. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  257. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  258. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  259. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  260. package/lib/utils/datasource-test-run-display.js +442 -0
  261. package/lib/utils/datasource-test-run-exit.js +58 -0
  262. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  263. package/lib/utils/datasource-test-run-report-version.js +51 -0
  264. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  265. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  266. package/lib/utils/datasource-validation-watch.js +266 -0
  267. package/lib/utils/declarative-url-ports.js +47 -0
  268. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  269. package/lib/utils/dev-ca-install.js +185 -23
  270. package/lib/utils/dev-cert-helper.js +266 -17
  271. package/lib/utils/dev-hosts-helper.js +307 -0
  272. package/lib/utils/dev-init-cert-hints.js +37 -0
  273. package/lib/utils/dev-init-health-messages.js +52 -0
  274. package/lib/utils/dev-init-resolve.js +86 -0
  275. package/lib/utils/dev-init-ssh-merge.js +65 -0
  276. package/lib/utils/dev-ssh-config-helper.js +196 -0
  277. package/lib/utils/dev-user-groups.js +93 -0
  278. package/lib/utils/docker-build.js +42 -17
  279. package/lib/utils/docker-exec.js +28 -0
  280. package/lib/utils/docker-manifest-public-port.js +116 -0
  281. package/lib/utils/docker-not-running-hint.js +52 -0
  282. package/lib/utils/docker.js +98 -11
  283. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  284. package/lib/utils/env-config-loader.js +10 -91
  285. package/lib/utils/env-copy.js +19 -10
  286. package/lib/utils/env-map.js +42 -11
  287. package/lib/utils/env-template.js +2 -2
  288. package/lib/utils/environment-scoped-resources.js +144 -0
  289. package/lib/utils/error-formatter.js +125 -9
  290. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  291. package/lib/utils/error-formatters/network-errors.js +2 -1
  292. package/lib/utils/error-formatters/permission-errors.js +2 -1
  293. package/lib/utils/error-formatters/validation-errors.js +2 -1
  294. package/lib/utils/external-env-template.js +180 -0
  295. package/lib/utils/external-readme.js +8 -1
  296. package/lib/utils/external-system-display.js +277 -136
  297. package/lib/utils/external-system-local-test-tty.js +389 -0
  298. package/lib/utils/external-system-readiness-core.js +377 -0
  299. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  300. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  301. package/lib/utils/external-system-readiness-display.js +186 -0
  302. package/lib/utils/external-system-test-helpers.js +24 -6
  303. package/lib/utils/external-system-validators.js +32 -14
  304. package/lib/utils/health-check-url.js +119 -0
  305. package/lib/utils/health-check.js +59 -25
  306. package/lib/utils/help-builder.js +14 -13
  307. package/lib/utils/image-version.js +4 -8
  308. package/lib/utils/infra-containers.js +4 -7
  309. package/lib/utils/infra-env-defaults.js +162 -0
  310. package/lib/utils/infra-status-display.js +167 -0
  311. package/lib/utils/infra-status.js +16 -8
  312. package/lib/utils/local-secrets.js +29 -7
  313. package/lib/utils/paths.js +136 -48
  314. package/lib/utils/port-resolver.js +10 -23
  315. package/lib/utils/redis-env-scope.js +62 -0
  316. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  317. package/lib/utils/remote-builder-validation.js +99 -0
  318. package/lib/utils/remote-dev-auth.js +117 -21
  319. package/lib/utils/remote-docker-env.js +67 -15
  320. package/lib/utils/remote-secrets-loader.js +13 -4
  321. package/lib/utils/resolve-docker-image-ref.js +124 -0
  322. package/lib/utils/schema-loader.js +22 -9
  323. package/lib/utils/secrets-bash-kv.js +25 -0
  324. package/lib/utils/secrets-generator.js +171 -51
  325. package/lib/utils/secrets-helpers.js +70 -59
  326. package/lib/utils/secrets-kv-scope.js +60 -0
  327. package/lib/utils/secrets-utils.js +35 -37
  328. package/lib/utils/secrets-validation.js +3 -1
  329. package/lib/utils/secrets-yaml-preserve.js +109 -0
  330. package/lib/utils/secure-file-permissions.js +91 -0
  331. package/lib/utils/ssh-key-helper.js +4 -2
  332. package/lib/utils/template-helpers.js +2 -2
  333. package/lib/utils/test-log-writer.js +3 -3
  334. package/lib/utils/token-manager.js +37 -5
  335. package/lib/utils/url-declarative-public-base.js +188 -0
  336. package/lib/utils/url-declarative-resolve-build.js +493 -0
  337. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  338. package/lib/utils/url-declarative-resolve.js +220 -0
  339. package/lib/utils/url-declarative-token-parse.js +74 -0
  340. package/lib/utils/url-declarative-url-flags.js +50 -0
  341. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  342. package/lib/utils/url-public-path-prefix.js +34 -0
  343. package/lib/utils/urls-local-registry.js +220 -0
  344. package/lib/utils/validation-report-tty-kit.js +77 -0
  345. package/lib/utils/validation-run-poll.js +89 -0
  346. package/lib/utils/validation-run-post-retry.js +73 -0
  347. package/lib/utils/validation-run-request.js +98 -0
  348. package/lib/utils/variable-transformer.js +21 -4
  349. package/lib/utils/yaml-preserve.js +78 -1
  350. package/lib/validation/datasource-warnings.js +56 -0
  351. package/lib/validation/env-template-auth.js +50 -2
  352. package/lib/validation/external-manifest-validator.js +35 -7
  353. package/lib/validation/validate-display.js +37 -31
  354. package/lib/validation/validate.js +9 -10
  355. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  356. package/lib/validation/validator.js +32 -78
  357. package/lib/validation/wizard-config-validator.js +2 -1
  358. package/package.json +11 -3
  359. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  360. package/scripts/diagnose-cli.js +150 -0
  361. package/scripts/install-local.js +304 -55
  362. package/templates/README.md +15 -2
  363. package/templates/applications/dataplane/application.yaml +52 -2
  364. package/templates/applications/dataplane/env.template +80 -18
  365. package/templates/applications/dataplane/rbac.yaml +8 -0
  366. package/templates/applications/keycloak/application.yaml +9 -1
  367. package/templates/applications/keycloak/env.template +15 -6
  368. package/templates/applications/miso-controller/application.yaml +10 -2
  369. package/templates/applications/miso-controller/env.template +55 -14
  370. package/templates/applications/miso-controller/rbac.yaml +5 -0
  371. package/templates/external-system/README.md.hbs +20 -7
  372. package/templates/external-system/deploy.js.hbs +5 -5
  373. package/templates/external-system/env.template.hbs +22 -0
  374. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  375. package/templates/infra/compose.yaml.hbs +20 -4
  376. package/templates/python/docker-compose.hbs +16 -0
  377. package/templates/typescript/docker-compose.hbs +16 -0
  378. package/integration/hubspot/README.md +0 -102
  379. package/integration/hubspot/env.template +0 -4
  380. package/integration/hubspot/hubspot-datasource-company.json +0 -541
  381. package/integration/hubspot/hubspot-datasource-contact.json +0 -639
  382. package/integration/hubspot/hubspot-datasource-deal.json +0 -588
  383. package/integration/hubspot/hubspot-datasource-users.json +0 -116
  384. package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
  385. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
  386. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
  387. package/lib/api/external-test.api.js +0 -111
  388. package/lib/schema/env-config.yaml +0 -43
  389. /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
  390. /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
  391. /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
  392. /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
@@ -1,3 +1,4 @@
1
+ const { formatSuccessLine, formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * AI Fabrix Builder Build Functions
3
4
  *
@@ -127,7 +128,9 @@ async function generateDockerfile(appNameOrPath, language, config, buildConfig =
127
128
 
128
129
  const template = dockerfileUtils.loadDockerfileTemplate(language);
129
130
  const isAppFlag = buildConfig.context === '../..';
130
- const appSourcePath = isAppFlag ? `apps/${appName}/` : '.';
131
+ // Use "./" (not ".") so Dockerfile lines are "COPY ./requirements*.txt" — a bare "."
132
+ // concatenates with "requirements" and becomes ".requirements*.txt", which matches nothing.
133
+ const appSourcePath = isAppFlag ? `apps/${appName}/` : './';
131
134
 
132
135
  const templateVars = {
133
136
  port: config.port || 3000,
@@ -185,11 +188,11 @@ async function generateDockerfile(appNameOrPath, language, config, buildConfig =
185
188
  async function postBuildTasks(appName, buildConfig) {
186
189
  try {
187
190
  const envPath = await secrets.generateEnvFile(appName, buildConfig.secrets, 'docker');
188
- logger.log(chalk.green(`✓ Generated .env file: ${envPath}`));
191
+ logger.log(formatSuccessLine(`Generated .env file: ${envPath}`));
189
192
  // Note: processEnvVariables is already called by generateEnvFile to generate local .env
190
193
  // at the envOutputPath, so we don't need to manually copy the docker .env file
191
194
  } catch (error) {
192
- logger.log(chalk.yellow(`⚠️ Warning: Could not generate .env file: ${error.message}`));
195
+ logger.log(chalk.yellow(`⚠ Warning: Could not generate .env file: ${error.message}`));
193
196
  }
194
197
  }
195
198
 
@@ -229,7 +232,7 @@ async function copyApplicationSourceFiles(appName, devDir) {
229
232
  const appsPath = path.join(process.cwd(), 'apps', appName);
230
233
  if (fsSync.existsSync(appsPath)) {
231
234
  await buildCopy.copyAppSourceFiles(appsPath, devDir);
232
- logger.log(chalk.green(`✓ Copied application source files from apps/${appName}`));
235
+ logger.log(formatSuccessLine(`Copied application source files from apps/${appName}`));
233
236
  return true;
234
237
  }
235
238
  return false;
@@ -253,12 +256,12 @@ async function copyTemplateFilesIfNeeded(devDir, language, buildConfig, options)
253
256
  const projectRoot = getProjectRoot();
254
257
  const templatePath = path.join(projectRoot, 'templates', 'typescript');
255
258
  await buildCopy.copyTemplateFilesToDevDir(templatePath, devDir, detectedLanguage);
256
- logger.log(chalk.green(`✓ Generated application files from ${detectedLanguage} template`));
259
+ logger.log(formatSuccessLine(`Generated application files from ${detectedLanguage} template`));
257
260
  } else if (detectedLanguage === 'python' && !fsSync.existsSync(requirementsPath)) {
258
261
  const projectRoot = getProjectRoot();
259
262
  const templatePath = path.join(projectRoot, 'templates', 'python');
260
263
  await buildCopy.copyTemplateFilesToDevDir(templatePath, devDir, detectedLanguage);
261
- logger.log(chalk.green(`✓ Generated application files from ${detectedLanguage} template`));
264
+ logger.log(formatSuccessLine(`Generated application files from ${detectedLanguage} template`));
262
265
  }
263
266
  }
264
267
 
@@ -268,7 +271,7 @@ async function prepareDevDirectory(appName, buildConfig, options) {
268
271
  const directoryName = idNum === 0 ? 'applications' : `dev-${developerId}`;
269
272
  logger.log(chalk.blue(`Copying files to developer-specific directory (${directoryName})...`));
270
273
  const devDir = await buildCopy.copyBuilderToDevDirectory(appName, developerId);
271
- logger.log(chalk.green(`✓ Files copied to: ${devDir}`));
274
+ logger.log(formatSuccessLine(`Files copied to: ${devDir}`));
272
275
 
273
276
  const { config: appConfig, imageName } = await buildHelpers.loadAndValidateConfig(appName);
274
277
  const effectiveImageName = buildDevImageName(imageName, developerId);
@@ -294,7 +297,7 @@ function prepareBuildContext(buildConfig, devDir) {
294
297
  // Check if context is using old format (../appName) - these are incompatible with dev directory structure
295
298
  if (buildConfig.context && buildConfig.context.startsWith('../') && buildConfig.context !== '../..') {
296
299
  // Old format detected - always use devDir instead
297
- logger.log(chalk.yellow(`⚠️ Warning: Build context uses old format: ${buildConfig.context}`));
300
+ logger.log(chalk.yellow(`⚠ Warning: Build context uses old format: ${buildConfig.context}`));
298
301
  logger.log(chalk.yellow(` Using dev directory instead: ${devDir}`));
299
302
  contextPath = devDir;
300
303
  } else if (buildConfig.context && buildConfig.context !== '../..') {
@@ -353,7 +356,7 @@ async function handleDockerfileGeneration(appName, params, options, buildHelpers
353
356
  language = 'typescript';
354
357
  }
355
358
  if (!hasExistingDockerfile) {
356
- logger.log(chalk.green(`✓ Detected language: ${language}`));
359
+ logger.log(formatSuccessLine(`Detected language: ${language}`));
357
360
  }
358
361
 
359
362
  // Determine Dockerfile (needs context path to generate in correct location)
@@ -425,7 +428,7 @@ async function buildApp(appName, options = {}) {
425
428
  // 7. Post-build tasks
426
429
  await postBuildTasks(appName, buildConfig);
427
430
 
428
- logger.log(chalk.green('\n✅ Build completed successfully!'));
431
+ logger.log(formatSuccessParagraph('Build completed successfully!'));
429
432
  return `${imageName}:${tag}`;
430
433
 
431
434
  } catch (error) {
package/lib/cli/index.js CHANGED
@@ -17,6 +17,7 @@ const { setupEnvironmentCommands } = require('./setup-environment');
17
17
  const { setupUtilityCommands } = require('./setup-utility');
18
18
  const { setupDevCommands } = require('./setup-dev');
19
19
  const { setupSecretsCommands } = require('./setup-secrets');
20
+ const { setupParametersCommands } = require('./setup-parameters');
20
21
  const { setupExternalSystemCommands } = require('./setup-external-system');
21
22
  const { setupAppCommands: setupAppManagementCommands } = require('../commands/app');
22
23
  const { setupDatasourceCommands } = require('../commands/datasource');
@@ -40,6 +41,7 @@ function setupCommands(program) {
40
41
  setupExternalSystemCommands(program);
41
42
  setupDevCommands(program);
42
43
  setupSecretsCommands(program);
44
+ setupParametersCommands(program);
43
45
  }
44
46
 
45
47
  module.exports = {
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @fileoverview Help text blocks for app-level CLI commands.
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const TEST_HELP_AFTER = `
8
+ Examples:
9
+ # External system (integration/<systemKey>/) — local validation
10
+ $ aifabrix test hubspot
11
+ $ aifabrix test hubspot -v
12
+ $ aifabrix test hubspot -d
13
+
14
+ # Builder app (builder/<app>/) — runs in container
15
+ $ aifabrix test myapp -e dev
16
+ $ aifabrix test myapp -e tst
17
+
18
+ Notes:
19
+ - To run unit test for one datasource, use:
20
+ aifabrix datasource test <datasourceKey>
21
+ - To run integration test, use:
22
+ aifabrix test-integration <app>
23
+ - Option --sync is not supported here (local validation only); use upload or dataplane test commands with --sync.
24
+ `;
25
+
26
+ const TEST_INTEGRATION_HELP_AFTER = `
27
+ Examples:
28
+ # External system (integration/<systemKey>/) — integration health across datasources via dataplane
29
+ $ aifabrix test-integration hubspot
30
+ $ aifabrix test-integration hubspot -v
31
+ $ aifabrix test-integration hubspot -d
32
+
33
+ # Builder app (builder/<app>/) — runs in container
34
+ $ aifabrix test-integration myapp -e dev
35
+ $ aifabrix test-integration myapp -e tst
36
+
37
+ Notes:
38
+ - To run integration test for one datasource, use:
39
+ aifabrix datasource test-integration <datasourceKey>
40
+ - To run E2E test, use:
41
+ aifabrix test-e2e <app>
42
+ - Optional --sync publishes local files to the dataplane first (external integration under integration/<systemKey>/ only).
43
+ `;
44
+
45
+ const TEST_E2E_HELP_AFTER = `
46
+ Examples:
47
+ # External system (integration/<systemKey>/) — E2E across datasources via dataplane
48
+ $ aifabrix test-e2e hubspot
49
+ $ aifabrix test-e2e hubspot -v
50
+ $ aifabrix test-e2e hubspot -d
51
+
52
+ # Builder app (builder/<app>/) — runs in container
53
+ $ aifabrix test-e2e myapp -e dev
54
+ $ aifabrix test-e2e myapp -e tst
55
+
56
+ Notes:
57
+ - To run E2E for one datasource, use:
58
+ aifabrix datasource test-e2e <datasourceKey>
59
+ - Optional --sync publishes local files to the dataplane first (external integration only).
60
+ `;
61
+
62
+ module.exports = {
63
+ TEST_HELP_AFTER,
64
+ TEST_INTEGRATION_HELP_AFTER,
65
+ TEST_E2E_HELP_AFTER
66
+ };
67
+
@@ -1,3 +1,4 @@
1
+ const { formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * CLI application lifecycle command setup (create, wizard, build, run, push, deploy, dockerfile).
3
4
  *
@@ -11,6 +12,24 @@ const path = require('path');
11
12
  const app = require('../app');
12
13
  const logger = require('../utils/logger');
13
14
  const { handleCommandError } = require('../utils/cli-utils');
15
+ const { setupInstallTestE2eLintCommands } = require('./setup-app.test-commands');
16
+
17
+ const CREATE_HELP_AFTER = `
18
+ Examples:
19
+ $ aifabrix create myapi --type webapp -l typescript
20
+ $ aifabrix create mycrm --wizard
21
+ `;
22
+
23
+ const DEPLOY_HELP_AFTER = `
24
+ Examples:
25
+ $ aifabrix deploy myapp
26
+ $ aifabrix deploy myext --local
27
+ `;
28
+
29
+ const PUSH_HELP_AFTER = `
30
+ Example:
31
+ $ aifabrix push myapp -t v1.0.0
32
+ `;
14
33
 
15
34
  /**
16
35
  * Normalize options for external system creation
@@ -102,7 +121,8 @@ async function handleCreateCommand(appName, options) {
102
121
 
103
122
  function setupCreateCommand(program) {
104
123
  program.command('create <app>')
105
- .description('Create new application with configuration files')
124
+ .description('Scaffold builder or external app (flags or --wizard)')
125
+ .addHelpText('after', CREATE_HELP_AFTER)
106
126
  .option('-p, --port <port>', 'Application port', '3000')
107
127
  .option('-d, --database', 'Requires database')
108
128
  .option('-r, --redis', 'Requires Redis')
@@ -140,17 +160,17 @@ Examples:
140
160
  $ aifabrix wizard my-integration --silent Run headless with integration/my-integration/wizard.yaml (no prompts)
141
161
  $ aifabrix wizard -a my-integration Same as above (app name set)
142
162
  $ aifabrix wizard --config wizard.yaml Run headless from a wizard config file
143
- $ aifabrix wizard hubspot-test-v2 --debug Enable debug output and save debug manifests on validation failure
163
+ $ aifabrix wizard hubspot-test --debug Enable debug output and save debug manifests on validation failure
144
164
 
145
- Config path: When appName is provided, integration/<appName>/wizard.yaml is used for load/save and error.log.
165
+ Config path: When appName is provided, integration/<systemKey>/wizard.yaml is used for load/save and error.log.
146
166
  To change settings after a run, edit that file and run "aifabrix wizard <app>" again.
147
167
  Headless config must include: appName, mode (create-system|add-datasource), source (type + filePath/url/platform).
148
- See integration/hubspot/wizard-hubspot-e2e.yaml for an example.`;
168
+ See integration/hubspot-test/wizard-hubspot-e2e.yaml for an example.`;
149
169
  program.command('wizard [appName]')
150
- .description('Create or extend external systems (OpenAPI, MCP, or known platforms like HubSpot) via guided steps or a config file')
170
+ .description('Guided external system setup (OpenAPI, MCP, HubSpot, ) or headless wizard.yaml')
151
171
  .option('-a, --app <app>', 'Application name (synonym for positional appName)')
152
172
  .option('--config <file>', 'Run headless using a wizard.yaml file (appName, mode, source, credential, preferences)')
153
- .option('--silent', 'Run with saved integration/<app>/wizard.yaml only; no prompts (requires app name and existing wizard.yaml)')
173
+ .option('--silent', 'Run with saved integration/<systemKey>/wizard.yaml only; no prompts (requires app name and existing wizard.yaml)')
154
174
  .option('--debug', 'Enable debug output and save debug manifests on validation failure')
155
175
  .addHelpText('after', wizardHelp)
156
176
  .action(async(positionalAppName, options) => {
@@ -172,9 +192,10 @@ In dev: use --reload for sync and mount (requires remote server with Mutagen, or
172
192
  Examples:
173
193
  $ aifabrix run myapp
174
194
  $ aifabrix run myapp --env tst
195
+ $ aifabrix run myapp --tag v1.0.0
175
196
  $ aifabrix run myapp --reload`;
176
197
  program.command('run <app>')
177
- .description('Run application locally (or remotely on your Docker host)')
198
+ .description('Run app locally or on remote Docker host')
178
199
  .option('-p, --port <port>', 'Override local port')
179
200
  .option('-d, --debug', 'Enable debug output with detailed container information')
180
201
  .option('-t, --tag <tag>', 'Image tag to run (e.g. v1.0.0); overrides application.yaml image.tag')
@@ -193,14 +214,15 @@ Examples:
193
214
 
194
215
  function setupBuildRunLogsDownCommands(program) {
195
216
  program.command('build <app>')
196
- .description('Build container image (auto-detects runtime)')
217
+ .description('Build Docker image (auto-detect runtime)')
197
218
  .option('-l, --language <lang>', 'Override language detection')
198
219
  .option('-f, --force-template', 'Force rebuild from template')
220
+ .option('--no-cache', 'Full Docker rebuild (disable layer cache); use after Dockerfile or context fixes')
199
221
  .option('-t, --tag <tag>', 'Image tag (default: latest). Set image.tag in application.yaml to match for deploy.')
200
222
  .action(async(appName, options) => {
201
223
  try {
202
224
  const imageTag = await app.buildApp(appName, options);
203
- logger.log(`✅ Built image: ${imageTag}`);
225
+ logger.log(`✔ Built image: ${imageTag}`);
204
226
  } catch (error) {
205
227
  handleCommandError(error, 'build');
206
228
  process.exit(1);
@@ -210,7 +232,7 @@ function setupBuildRunLogsDownCommands(program) {
210
232
  registerRunCommand(program);
211
233
 
212
234
  program.command('logs <app>')
213
- .description('Show application container logs (and optional env summary with secrets masked)')
235
+ .description('Tail app container logs (optional env summary; secrets masked)')
214
236
  .option('-f', 'Follow log stream')
215
237
  .option('-t, --tail <lines>', 'Number of lines (default: 100); 0 = full list', '100')
216
238
  .option('-l, --level <level>', 'Show only logs at this level or above (debug|info|warn|error)')
@@ -227,7 +249,7 @@ function setupBuildRunLogsDownCommands(program) {
227
249
  });
228
250
 
229
251
  program.command('down-app <app>')
230
- .description('Stop and remove application container; optionally remove volume and image')
252
+ .description('Stop and remove app container (--volumes removes data volume)')
231
253
  .option('--volumes', 'Remove application Docker volume')
232
254
  .action(async(appName, options) => {
233
255
  try {
@@ -242,7 +264,7 @@ function setupBuildRunLogsDownCommands(program) {
242
264
 
243
265
  function setupShellTestStopCommands(program) {
244
266
  program.command('stop <app>')
245
- .description('Stop and remove application container (alias for down-app)')
267
+ .description('Alias for down-app: stop and remove container')
246
268
  .option('--volumes', 'Remove application Docker volume')
247
269
  .action(async(appName, options) => {
248
270
  try {
@@ -255,7 +277,7 @@ function setupShellTestStopCommands(program) {
255
277
  });
256
278
 
257
279
  program.command('shell <app>')
258
- .description('Open interactive shell in the application container')
280
+ .description('Interactive shell in running or ephemeral container')
259
281
  .option('--env <env>', 'Environment (dev|tst); dev uses running container', 'dev')
260
282
  .action(async(appName, options) => {
261
283
  try {
@@ -266,105 +288,20 @@ function setupShellTestStopCommands(program) {
266
288
  process.exit(1);
267
289
  }
268
290
  });
269
-
270
- program.command('test <app>')
271
- .description('Run tests (builder app: in container; external system: local validation)')
272
- .option('--env <env>', 'For builder app: dev (running container) or tst (ephemeral)', 'dev')
273
- .option('-d, --datasource <key>', 'For external system: test specific datasource only')
274
- .option('-v, --verbose', 'Verbose output')
275
- .action(async(appName, options) => {
276
- try {
277
- const pathsUtil = require('../utils/paths');
278
- const appType = await pathsUtil.detectAppType(appName).catch(() => null);
279
- if (appType && appType.baseDir === 'integration') {
280
- const test = require('../external-system/test');
281
- const results = await test.testExternalSystem(appName, options);
282
- test.displayTestResults(results, options.verbose);
283
- if (!results.valid) process.exit(1);
284
- } else {
285
- const { runAppTest } = require('../commands/app-test');
286
- await runAppTest(appName, { env: options.env });
287
- }
288
- } catch (error) {
289
- handleCommandError(error, 'test');
290
- process.exit(1);
291
- }
292
- });
293
291
  }
294
292
 
295
- async function runTestE2ECommand(appName, options) {
296
- const pathsUtil = require('../utils/paths');
297
- const appType = await pathsUtil.detectAppType(appName).catch(() => null);
298
- if (appType && appType.baseDir === 'integration') {
299
- const { runTestE2EForExternalSystem } = require('../commands/test-e2e-external');
300
- const { success, results } = await runTestE2EForExternalSystem(appName, {
301
- env: options.env,
302
- debug: options.debug,
303
- verbose: options.verbose,
304
- async: options.async !== false
305
- });
306
- results.forEach(r => {
307
- const icon = r.success ? chalk.green('✓') : chalk.red('✗');
308
- const msg = r.error ? `${r.key}: ${r.error}` : r.key;
309
- logger.log(` ${icon} ${msg}`);
310
- });
311
- if (!success) process.exit(1);
312
- return;
313
- }
314
- const { runAppTestE2e } = require('../commands/app-test');
315
- await runAppTestE2e(appName, { env: options.env });
316
- }
317
-
318
- function setupInstallTestE2eLintCommands(program) {
319
- program.command('install <app>')
320
- .description('Install dependencies in container (builder apps only)')
321
- .option('--env <env>', 'dev (running container) or tst (ephemeral with .env)', 'dev')
322
- .action(async(appName, options) => {
323
- try {
324
- const pathsUtil = require('../utils/paths');
325
- const appType = await pathsUtil.detectAppType(appName).catch(() => null);
326
- if (appType && appType.baseDir === 'integration') {
327
- logger.log(chalk.gray('Install is for builder applications only. Use aifabrix shell <app> to run commands in external setups.'));
328
- return;
329
- }
330
- const { runAppInstall } = require('../commands/app-install');
331
- await runAppInstall(appName, { env: options.env });
332
- } catch (error) {
333
- handleCommandError(error, 'install');
334
- process.exit(1);
335
- }
336
- });
337
-
338
- program.command('test-e2e <app>')
339
- .description('Run e2e tests (builder: in container; external system: all datasources via dataplane)')
340
- .option('-e, --env <env>', 'Environment: dev, tst, or pro (builder: dev/tst for container)')
341
- .option('-v, --verbose', 'Show detailed step output and poll progress')
342
- .option('--debug', 'Include debug output and write log to integration/<app>/logs/')
343
- .option('--no-async', 'Use sync mode (no polling); single POST per datasource')
344
- .action(async(appName, options) => {
345
- try {
346
- await runTestE2ECommand(appName, options);
347
- } catch (error) {
348
- handleCommandError(error, 'test-e2e');
349
- process.exit(1);
350
- }
351
- });
352
-
353
- program.command('lint <app>')
354
- .description('Run lint in container (builder apps only)')
355
- .option('--env <env>', 'dev (running container) or tst (ephemeral with .env)', 'dev')
293
+ function setupDockerfileGenerateCommand(program) {
294
+ program.command('dockerfile <app>')
295
+ .description('Generate Dockerfile from detected runtime')
296
+ .option('-l, --language <lang>', 'Override language detection')
297
+ .option('-f, --force', 'Overwrite existing Dockerfile')
356
298
  .action(async(appName, options) => {
357
299
  try {
358
- const pathsUtil = require('../utils/paths');
359
- const appType = await pathsUtil.detectAppType(appName).catch(() => null);
360
- if (appType && appType.baseDir === 'integration') {
361
- logger.log(chalk.gray('lint is for builder applications only. Use aifabrix shell <app> then make lint or pnpm lint.'));
362
- return;
363
- }
364
- const { runAppLint } = require('../commands/app-test');
365
- await runAppLint(appName, { env: options.env });
300
+ const dockerfilePath = await app.generateDockerfileForApp(appName, options);
301
+ logger.log(formatSuccessParagraph('Dockerfile generated successfully!'));
302
+ logger.log(chalk.gray(`Location: ${dockerfilePath}`));
366
303
  } catch (error) {
367
- handleCommandError(error, 'lint');
304
+ handleCommandError(error, 'dockerfile');
368
305
  process.exit(1);
369
306
  }
370
307
  });
@@ -373,6 +310,7 @@ function setupInstallTestE2eLintCommands(program) {
373
310
  function setupPushDeployDockerfileCommands(program) {
374
311
  program.command('push <app>')
375
312
  .description('Push image to Azure Container Registry')
313
+ .addHelpText('after', PUSH_HELP_AFTER)
376
314
  .option('-r, --registry <registry>', 'ACR registry URL (overrides application.yaml)')
377
315
  .option('-t, --tag <tag>', 'Image tag(s) - comma-separated for multiple (default: latest)')
378
316
  .action(async(appName, options) => {
@@ -385,15 +323,26 @@ function setupPushDeployDockerfileCommands(program) {
385
323
  });
386
324
 
387
325
  program.command('deploy <app>')
388
- .description('Deploy to Azure or locally via Miso Controller')
326
+ .description('Deploy via Miso Controller (Azure or --local)')
327
+ .addHelpText('after', DEPLOY_HELP_AFTER)
389
328
  .option('--local', 'Send manifest to controller then run app locally (app: same as aifabrix run <app>; external: restart dataplane)')
390
329
  .option('--client-id <id>', 'Client ID (overrides config)')
391
330
  .option('--client-secret <secret>', 'Client Secret (overrides config)')
392
331
  .option('--poll', 'Poll for deployment status', true)
393
332
  .option('--no-poll', 'Do not poll for status')
333
+ .option('--probe', 'After external deploy, run dataplane runtime checks (validation/run); slower')
334
+ .option('--probe-timeout <ms>', 'Timeout for --probe on external deploy (default: 120000)', '120000')
394
335
  .action(async(appName, options) => {
395
336
  try {
396
- const opts = { ...options, local: !!options.local };
337
+ const probeTimeout =
338
+ options.probeTimeout === undefined || options.probeTimeout === null
339
+ ? 120000
340
+ : Number(options.probeTimeout);
341
+ const opts = {
342
+ ...options,
343
+ local: !!options.local,
344
+ probeTimeout: Number.isFinite(probeTimeout) ? probeTimeout : 120000
345
+ };
397
346
  const outcome = await app.deployApp(appName, opts);
398
347
  if (opts.local && outcome) {
399
348
  if (outcome.usedExternalDeploy) await app.restartApp('dataplane');
@@ -405,20 +354,7 @@ function setupPushDeployDockerfileCommands(program) {
405
354
  }
406
355
  });
407
356
 
408
- program.command('dockerfile <app>')
409
- .description('Generate Dockerfile for an application')
410
- .option('-l, --language <lang>', 'Override language detection')
411
- .option('-f, --force', 'Overwrite existing Dockerfile')
412
- .action(async(appName, options) => {
413
- try {
414
- const dockerfilePath = await app.generateDockerfileForApp(appName, options);
415
- logger.log(chalk.green('\n✅ Dockerfile generated successfully!'));
416
- logger.log(chalk.gray(`Location: ${dockerfilePath}`));
417
- } catch (error) {
418
- handleCommandError(error, 'dockerfile');
419
- process.exit(1);
420
- }
421
- });
357
+ setupDockerfileGenerateCommand(program);
422
358
  }
423
359
 
424
360
  /**
@@ -0,0 +1,179 @@
1
+ /**
2
+ * @fileoverview CLI test/install/lint command setup (builder app + external integration dispatch).
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const chalk = require('chalk');
8
+ const logger = require('../utils/logger');
9
+ const { handleCommandError } = require('../utils/cli-utils');
10
+ const { TEST_HELP_AFTER, TEST_E2E_HELP_AFTER } = require('./setup-app.help');
11
+
12
+ function setupTestCommand(program) {
13
+ program.command('test <app>')
14
+ .description('Tests: builder in container; external = local validation')
15
+ .option('-e, --env <env>', 'For builder app: dev (running container) or tst (ephemeral)', 'dev')
16
+ .option('-v, --verbose', 'Verbose output')
17
+ .option('-d, --debug', 'Write debug log to integration/<systemKey>/logs/ (external only)')
18
+ .option(
19
+ '--sync',
20
+ 'Not supported for this command (local validation only). Use aifabrix upload <systemKey> or dataplane test commands with --sync.'
21
+ )
22
+ .addHelpText('after', TEST_HELP_AFTER)
23
+ .action(async(appName, options, cmd) => {
24
+ try {
25
+ const rawArgs = Array.isArray(cmd?.rawArgs) ? cmd.rawArgs : [];
26
+ const envExplicit = rawArgs.includes('-e') || rawArgs.includes('--env');
27
+ const pathsUtil = require('../utils/paths');
28
+ const appType = await pathsUtil.detectAppType(appName).catch(() => null);
29
+ if (options.sync === true) {
30
+ throw new Error(
31
+ 'Option --sync is not supported for aifabrix test (local or container runs do not publish to the dataplane). ' +
32
+ 'Use: aifabrix upload <systemKey>, then aifabrix test-integration <systemKey> --sync or aifabrix datasource test-integration <datasourceKey> --sync.'
33
+ );
34
+ }
35
+ if (appType && appType.baseDir === 'integration') {
36
+ const test = require('../external-system/test');
37
+ const externalOpts = {
38
+ ...options,
39
+ // Keep help default but don't override auth/env behavior unless user explicitly set it.
40
+ env: envExplicit ? options.env : undefined
41
+ };
42
+ const results = await test.testExternalSystem(appName, externalOpts);
43
+ test.displayTestResults(results, options.verbose, appName);
44
+ if (!results.valid) process.exit(1);
45
+ return;
46
+ }
47
+ const { runAppTest } = require('../commands/app-test');
48
+ await runAppTest(appName, { env: options.env });
49
+ } catch (error) {
50
+ handleCommandError(error, 'test');
51
+ process.exit(1);
52
+ }
53
+ });
54
+ }
55
+
56
+ async function runTestE2ECommand(appName, options) {
57
+ const pathsUtil = require('../utils/paths');
58
+ const appType = await pathsUtil.detectAppType(appName).catch(() => null);
59
+ if (options.sync === true && appType && appType.baseDir === 'builder') {
60
+ throw new Error(
61
+ 'Option --sync applies only to external integration E2E (integration/<systemKey>/). ' +
62
+ 'Remove --sync for builder app E2E, or use aifabrix upload from the integration folder first.'
63
+ );
64
+ }
65
+ if (appType && appType.baseDir === 'integration') {
66
+ const { runTestE2EForExternalSystem } = require('../commands/test-e2e-external');
67
+ const { success, results } = await runTestE2EForExternalSystem(appName, {
68
+ env: options.env,
69
+ debug: options.debug,
70
+ verbose: options.verbose,
71
+ async: options.async !== false,
72
+ sync: options.sync === true
73
+ });
74
+ const { displayIntegrationTestResults } = require('../utils/external-system-display');
75
+ displayIntegrationTestResults(
76
+ {
77
+ systemKey: appName,
78
+ success,
79
+ datasourceResults: results.map(r => ({
80
+ key: r.key,
81
+ success: r.success,
82
+ error: r.error,
83
+ skipped: false,
84
+ datasourceTestRun: r.datasourceTestRun
85
+ }))
86
+ },
87
+ options.verbose,
88
+ { debug: options.debug, runType: 'e2e' }
89
+ );
90
+ if (!success) process.exit(1);
91
+ return;
92
+ }
93
+ const { runAppTestE2e } = require('../commands/app-test');
94
+ await runAppTestE2e(appName, { env: options.env });
95
+ }
96
+
97
+ function setupInstallCommand(program) {
98
+ program.command('install <app>')
99
+ .description('Install deps in container (builder apps only)')
100
+ .option('--env <env>', 'dev (running container) or tst (ephemeral with .env)', 'dev')
101
+ .action(async(appName, options) => {
102
+ try {
103
+ const pathsUtil = require('../utils/paths');
104
+ const appType = await pathsUtil.detectAppType(appName).catch(() => null);
105
+ if (appType && appType.baseDir === 'integration') {
106
+ logger.log(
107
+ chalk.gray('Install is for builder applications only. Use aifabrix shell <app> to run commands in external setups.')
108
+ );
109
+ return;
110
+ }
111
+ const { runAppInstall } = require('../commands/app-install');
112
+ await runAppInstall(appName, { env: options.env });
113
+ } catch (error) {
114
+ handleCommandError(error, 'install');
115
+ process.exit(1);
116
+ }
117
+ });
118
+ }
119
+
120
+ function setupTestE2eCommand(program) {
121
+ program.command('test-e2e <app>')
122
+ .description('E2E: builder in container; external = all datasources via dataplane')
123
+ .option('-e, --env <env>', 'Environment: dev, tst, or pro (builder: dev/tst for container)', 'dev')
124
+ .option('-v, --verbose', 'Show detailed step output and poll progress')
125
+ .option('-d, --debug', 'Include debug output and write log to integration/<systemKey>/logs/')
126
+ .option(
127
+ '--sync',
128
+ 'Publish local system and datasource files to the dataplane before running E2E (same as aifabrix upload <systemKey>; external integration only)'
129
+ )
130
+ .addHelpText('after', TEST_E2E_HELP_AFTER)
131
+ .action(async(appName, options, cmd) => {
132
+ try {
133
+ const rawArgs = Array.isArray(cmd?.rawArgs) ? cmd.rawArgs : [];
134
+ const envExplicit = rawArgs.includes('-e') || rawArgs.includes('--env');
135
+ const externalOpts = {
136
+ ...options,
137
+ env: envExplicit ? options.env : undefined,
138
+ async: true // system-level command surface omits --no-async; always poll for completeness
139
+ };
140
+ await runTestE2ECommand(appName, externalOpts);
141
+ } catch (error) {
142
+ handleCommandError(error, 'test-e2e');
143
+ process.exit(1);
144
+ }
145
+ });
146
+ }
147
+
148
+ function setupLintCommand(program) {
149
+ program.command('lint <app>')
150
+ .description('Lint in container (builder apps only)')
151
+ .option('--env <env>', 'dev (running container) or tst (ephemeral with .env)', 'dev')
152
+ .action(async(appName, options) => {
153
+ try {
154
+ const pathsUtil = require('../utils/paths');
155
+ const appType = await pathsUtil.detectAppType(appName).catch(() => null);
156
+ if (appType && appType.baseDir === 'integration') {
157
+ logger.log(chalk.gray('lint is for builder applications only. Use aifabrix shell <app> then make lint or pnpm lint.'));
158
+ return;
159
+ }
160
+ const { runAppLint } = require('../commands/app-test');
161
+ await runAppLint(appName, { env: options.env });
162
+ } catch (error) {
163
+ handleCommandError(error, 'lint');
164
+ process.exit(1);
165
+ }
166
+ });
167
+ }
168
+
169
+ function setupInstallTestE2eLintCommands(program) {
170
+ setupInstallCommand(program);
171
+ setupTestCommand(program);
172
+ setupTestE2eCommand(program);
173
+ setupLintCommand(program);
174
+ }
175
+
176
+ module.exports = {
177
+ setupInstallTestE2eLintCommands
178
+ };
179
+