@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
@@ -0,0 +1,197 @@
1
+ /**
2
+ * @fileoverview Sync `certification` on *-system.json|yaml from dataplane active certificate(s).
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const path = require('path');
10
+ const chalk = require('chalk');
11
+ const logger = require('../utils/logger');
12
+ const { getIntegrationPath } = require('../utils/paths');
13
+ const { discoverIntegrationFiles } = require('../commands/repair-internal');
14
+ const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
15
+ const { unwrapApiData } = require('../utils/external-system-readiness-core');
16
+ const { getActiveIntegrationCertificate } = require('../api/certificates.api');
17
+ const {
18
+ buildCertificationFromArtifact,
19
+ pickArtifactForCertificationMerge
20
+ } = require('./merge-certification-from-artifact');
21
+
22
+ /**
23
+ * @param {string} systemKey
24
+ * @returns {{ systemFilePath: string }|null}
25
+ */
26
+ function resolvePrimarySystemFilePath(systemKey) {
27
+ const appPath = getIntegrationPath(systemKey);
28
+ const { systemFiles } = discoverIntegrationFiles(appPath);
29
+ if (!systemFiles || systemFiles.length === 0) return null;
30
+ return { systemFilePath: path.join(appPath, systemFiles[0]) };
31
+ }
32
+
33
+ /**
34
+ * @async
35
+ * @param {Object} ctx
36
+ * @returns {Promise<Array<import('../api/types/certificates.types').CertificateArtifactResponse>>}
37
+ */
38
+ async function collectActiveArtifacts(ctx) {
39
+ const { dataplaneUrl, authConfig, systemKey, datasourceKeys } = ctx;
40
+ const out = [];
41
+ for (const dk of datasourceKeys || []) {
42
+ if (!dk || typeof dk !== 'string') continue;
43
+ try {
44
+ const res = await getActiveIntegrationCertificate(dataplaneUrl, authConfig, systemKey, dk);
45
+ if (res && res.success === false) continue;
46
+ const art = unwrapApiData(res);
47
+ if (art && typeof art === 'object') out.push(art);
48
+ } catch {
49
+ /* skip datasource */
50
+ }
51
+ }
52
+ return out;
53
+ }
54
+
55
+ /**
56
+ * @param {string} systemFilePath
57
+ * @returns {Object|null}
58
+ */
59
+ function readSystemObject(systemFilePath) {
60
+ try {
61
+ return loadConfigFile(systemFilePath);
62
+ } catch (e) {
63
+ logger.log(chalk.yellow(`⚠ Certification sync: could not read system file: ${e.message}`));
64
+ return null;
65
+ }
66
+ }
67
+
68
+ /**
69
+ * @param {string} systemFilePath
70
+ * @param {Object} systemObj
71
+ * @param {Object} nextCert
72
+ * @returns {{ ok: true } | { ok: false }}
73
+ */
74
+ function tryWriteSystemCertification(systemFilePath, systemObj, nextCert) {
75
+ try {
76
+ writeConfigFile(systemFilePath, { ...systemObj, certification: nextCert });
77
+ return { ok: true };
78
+ } catch (e) {
79
+ logger.log(chalk.yellow(`⚠ Certification sync: could not write system file: ${e.message}`));
80
+ return { ok: false };
81
+ }
82
+ }
83
+
84
+ /**
85
+ * @param {Object|null} chosen
86
+ * @param {'no_active'|'no_public_key'} detail
87
+ */
88
+ function logSkippedCertification(chosen, detail) {
89
+ if (detail === 'no_active' || !chosen) {
90
+ logger.log(
91
+ chalk.yellow(
92
+ '⚠ Certification not written: dataplane has no active trusted certificate for this system/datasource scope yet. ' +
93
+ 'Run a successful validation or E2E that issues a certificate, then upload or run cert sync again.'
94
+ )
95
+ );
96
+ return;
97
+ }
98
+ logger.log(
99
+ chalk.yellow(
100
+ '⚠ Certification not written: active certificate has no publicKey and your system file has none to merge. ' +
101
+ 'The dataplane must return publicKey (or add certification.publicKey locally once) to satisfy the schema.'
102
+ )
103
+ );
104
+ }
105
+
106
+ /**
107
+ * Read system file, merge **certification** from dataplane, write back. Does not modify other top-level keys.
108
+ * @async
109
+ * @param {Object} params
110
+ * @param {string} params.systemKey
111
+ * @param {string} params.dataplaneUrl
112
+ * @param {Object} params.authConfig
113
+ * @param {string[]} params.datasourceKeys
114
+ * @returns {Promise<{ written: boolean, reason?: string }>}
115
+ */
116
+ async function syncSystemCertificationFromDataplane(params) {
117
+ const { systemKey, dataplaneUrl, authConfig, datasourceKeys } = params;
118
+ const resolved = resolvePrimarySystemFilePath(systemKey);
119
+ if (!resolved) return { written: false, reason: 'no_system_file' };
120
+ if (!dataplaneUrl || !authConfig || !authConfig.token) {
121
+ return { written: false, reason: 'no_auth' };
122
+ }
123
+
124
+ const systemObj = readSystemObject(resolved.systemFilePath);
125
+ if (!systemObj || typeof systemObj !== 'object') {
126
+ return { written: false, reason: 'invalid_system' };
127
+ }
128
+
129
+ const existing = systemObj.certification;
130
+ const artifacts = await collectActiveArtifacts({
131
+ dataplaneUrl,
132
+ authConfig,
133
+ systemKey,
134
+ datasourceKeys
135
+ });
136
+ const chosen = pickArtifactForCertificationMerge(artifacts);
137
+ const nextCert = buildCertificationFromArtifact(chosen, existing);
138
+ if (!nextCert) {
139
+ const detail = chosen ? 'no_public_key' : 'no_active';
140
+ logSkippedCertification(chosen, detail);
141
+ return { written: false, reason: 'incomplete_certification', detail };
142
+ }
143
+
144
+ const writeResult = tryWriteSystemCertification(resolved.systemFilePath, systemObj, nextCert);
145
+ if (!writeResult.ok) return { written: false, reason: 'write_error' };
146
+ return { written: true };
147
+ }
148
+
149
+ /**
150
+ * Non-throwing entry for upload/deploy: failures are warnings only.
151
+ * @async
152
+ * @param {Object} params
153
+ * @param {string} [params.label] - e.g. "upload"
154
+ * @param {boolean} [params.noCertSync]
155
+ * @returns {Promise<void>}
156
+ */
157
+ function logCertificationSyncNotWritten(r, label) {
158
+ const prefix = label ? ` (${label})` : '';
159
+ const map = {
160
+ no_system_file: `No *-system* file found under integration folder for this key${prefix}.`,
161
+ no_auth: `No Bearer token for dataplane${prefix}; run aifabrix login.`,
162
+ invalid_system: `Could not read or parse the primary system file${prefix}.`,
163
+ incomplete_certification: 'Could not build certification (see message above).',
164
+ write_error: 'Write to system file failed (see message above).'
165
+ };
166
+ const msg = (r && r.reason && map[r.reason]) || `Certification block not updated${prefix}.`;
167
+ logger.log(chalk.yellow(`⚠ ${msg}`));
168
+ }
169
+
170
+ async function maybeSyncSystemCertificationFromDataplane(params) {
171
+ const { label, noCertSync, systemKey, dataplaneUrl, authConfig, datasourceKeys } = params;
172
+ if (noCertSync === true) return;
173
+ try {
174
+ const r = await syncSystemCertificationFromDataplane({
175
+ systemKey,
176
+ dataplaneUrl,
177
+ authConfig,
178
+ datasourceKeys
179
+ });
180
+ if (r.written) {
181
+ logger.log(
182
+ chalk.gray(`Updated certification block from dataplane${label ? ` (${label})` : ''} in system file.`)
183
+ );
184
+ } else if (r.reason) {
185
+ logCertificationSyncNotWritten(r, label);
186
+ }
187
+ } catch (e) {
188
+ logger.log(chalk.yellow(`⚠ Certification sync skipped: ${e.message}`));
189
+ }
190
+ }
191
+
192
+ module.exports = {
193
+ syncSystemCertificationFromDataplane,
194
+ maybeSyncSystemCertificationFromDataplane,
195
+ resolvePrimarySystemFilePath,
196
+ collectActiveArtifacts
197
+ };
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')
@@ -142,15 +162,15 @@ Examples:
142
162
  $ aifabrix wizard --config wizard.yaml Run headless from a wizard config file
143
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
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,30 @@ 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')
335
+ .option(
336
+ '--no-cert-sync',
337
+ 'Skip updating integration certification in the system file from the dataplane after external deploy'
338
+ )
394
339
  .action(async(appName, options) => {
395
340
  try {
396
- const opts = { ...options, local: !!options.local };
341
+ const probeTimeout =
342
+ options.probeTimeout === undefined || options.probeTimeout === null
343
+ ? 120000
344
+ : Number(options.probeTimeout);
345
+ const opts = {
346
+ ...options,
347
+ local: !!options.local,
348
+ probeTimeout: Number.isFinite(probeTimeout) ? probeTimeout : 120000
349
+ };
397
350
  const outcome = await app.deployApp(appName, opts);
398
351
  if (opts.local && outcome) {
399
352
  if (outcome.usedExternalDeploy) await app.restartApp('dataplane');
@@ -405,20 +358,7 @@ function setupPushDeployDockerfileCommands(program) {
405
358
  }
406
359
  });
407
360
 
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
- });
361
+ setupDockerfileGenerateCommand(program);
422
362
  }
423
363
 
424
364
  /**