@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
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CI helper: fail when Builder lib/schema/datasource-test-run.schema.json drifts from Dataplane copy.
4
+ * @fileoverview Schema sync gate (plan §8.1)
5
+ */
6
+ /* eslint-disable no-console -- CLI script */
7
+
8
+ const path = require('path');
9
+ const { assertDatasourceTestRunSchemasInSync } = require('../lib/utils/datasource-test-run-schema-sync');
10
+
11
+ const root = path.join(__dirname, '..');
12
+ const builderSchema = path.join(root, 'lib/schema/datasource-test-run.schema.json');
13
+ const dpRoot = process.env.AIFABRIX_DATAPLANE_ROOT || path.join(root, '..', 'aifabrix-dataplane');
14
+ const dataplaneSchema = path.join(dpRoot, 'app/schemas/json/datasource-test-run.schema.json');
15
+
16
+ const strict = process.env.AIFABRIX_SCHEMA_SYNC_STRICT === '1';
17
+
18
+ try {
19
+ const result = assertDatasourceTestRunSchemasInSync(builderSchema, dataplaneSchema);
20
+ if (result.skipped) {
21
+ const msg = result.reason || 'Dataplane schema path missing';
22
+ if (strict) {
23
+ console.error(`Schema sync failed (strict): ${msg}`);
24
+ process.exit(1);
25
+ }
26
+ console.warn(`Schema sync skipped: ${msg}`);
27
+ process.exit(0);
28
+ }
29
+ console.log(`DatasourceTestRun schema OK (sha256 ${result.builderSha})`);
30
+ process.exit(0);
31
+ } catch (e) {
32
+ console.error(e.message || String(e));
33
+ process.exit(1);
34
+ }
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ /**
5
+ * List every PATH hit for aifabrix / af and each --version (find duplicate installs).
6
+ *
7
+ * @fileoverview CLI path diagnostic for @aifabrix/builder
8
+ */
9
+
10
+ const { execFileSync, execSync } = require('child_process');
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+
14
+ /**
15
+ * Reads package.json `bin` field.
16
+ * @returns {Record<string, string>|string} Bin map or single path string
17
+ */
18
+ function readBins() {
19
+ const pkgPath = path.join(__dirname, '..', 'package.json');
20
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
21
+ return pkg.bin || { aifabrix: 'bin/aifabrix.js' };
22
+ }
23
+
24
+ /**
25
+ * Resolves every PATH directory that exposes an executable named `binName`.
26
+ * @param {string} binName - CLI name (e.g. aifabrix)
27
+ * @returns {Array<{ path: string, real: string }>} Deduped hits with real paths
28
+ */
29
+ function locationsOnPath(binName) {
30
+ if (process.platform === 'win32') {
31
+ try {
32
+ const out = execSync(`where ${binName}`, {
33
+ encoding: 'utf8',
34
+ stdio: ['ignore', 'pipe', 'ignore']
35
+ }).trim();
36
+ return out.split(/\r?\n/).filter(Boolean).map((p) => ({ path: p, real: p }));
37
+ } catch {
38
+ return [];
39
+ }
40
+ }
41
+
42
+ const dirs = (process.env.PATH || '').split(path.delimiter).filter(Boolean);
43
+ const out = [];
44
+ const seenReal = new Set();
45
+ for (const dir of dirs) {
46
+ const candidate = path.join(dir, binName);
47
+ try {
48
+ const st = fs.lstatSync(candidate);
49
+ if (!st.isFile() && !st.isSymbolicLink()) continue;
50
+ fs.accessSync(candidate, fs.constants.X_OK);
51
+ const real = fs.realpathSync(candidate);
52
+ if (seenReal.has(real)) continue;
53
+ seenReal.add(real);
54
+ out.push({ path: candidate, real });
55
+ } catch {
56
+ // not found or not executable
57
+ }
58
+ }
59
+ return out;
60
+ }
61
+
62
+ /**
63
+ * Runs `executablePath --version` and returns stdout or null on failure.
64
+ * @param {string} executablePath - Absolute path to the binary
65
+ * @returns {string|null} Trimmed version output
66
+ */
67
+ function versionAt(executablePath) {
68
+ try {
69
+ return execFileSync(executablePath, ['--version'], {
70
+ encoding: 'utf8',
71
+ stdio: ['ignore', 'pipe', 'ignore']
72
+ }).trim();
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Prints PNPM_HOME and npm prefix for debugging PATH issues.
80
+ * @returns {void}
81
+ */
82
+ function printEnvironment() {
83
+ console.log('Environment (relevant to global CLIs)\n');
84
+ console.log(` PNPM_HOME ${process.env.PNPM_HOME || '(not set)'}`);
85
+ try {
86
+ const prefix = execSync('npm config get prefix', {
87
+ encoding: 'utf8',
88
+ stdio: ['ignore', 'pipe', 'ignore']
89
+ }).trim();
90
+ console.log(` npm prefix ${prefix}`);
91
+ } catch {
92
+ console.log(' npm prefix (could not read)');
93
+ }
94
+ console.log('');
95
+ }
96
+
97
+ /**
98
+ * @param {string[]} names - Bin names from package.json
99
+ * @returns {void}
100
+ */
101
+ function printBinReports(names) {
102
+ for (const name of names) {
103
+ console.log(`── ${name} ──`);
104
+ const hits = locationsOnPath(name);
105
+ if (!hits.length) {
106
+ console.log(' (not found on PATH)\n');
107
+ continue;
108
+ }
109
+ hits.forEach((h, i) => {
110
+ const ver = versionAt(h.path);
111
+ const marker = i === 0 ? ' ← first on PATH (what your shell runs)' : '';
112
+ console.log(` [${i + 1}] ${h.path}`);
113
+ if (h.real !== h.path) console.log(` → ${h.real}`);
114
+ console.log(` --version: ${ver ?? '(failed to run)'}${marker}`);
115
+ });
116
+ console.log('');
117
+ }
118
+ }
119
+
120
+ /**
121
+ * @param {string[]} names - Bin names from package.json
122
+ * @returns {void}
123
+ */
124
+ function warnIfMultipleVersions(names) {
125
+ const uniqVersions = new Set();
126
+ for (const name of names) {
127
+ for (const h of locationsOnPath(name)) {
128
+ const v = versionAt(h.path);
129
+ if (v) uniqVersions.add(v);
130
+ }
131
+ }
132
+ if (uniqVersions.size > 1) {
133
+ console.log('⚠ Multiple distinct --version values above: remove or reorder PATH so only one install remains.');
134
+ console.log(' Often: npm uninstall -g @aifabrix/builder, then ensure PNPM_HOME is before /usr/local/bin in PATH.\n');
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Entry: list PATH hits and versions for each package bin.
140
+ * @returns {void}
141
+ */
142
+ function main() {
143
+ const binField = readBins();
144
+ const names = typeof binField === 'string' ? ['aifabrix'] : Object.keys(binField);
145
+ printEnvironment();
146
+ printBinReports(names);
147
+ warnIfMultipleVersions(names);
148
+ }
149
+
150
+ main();
@@ -10,38 +10,157 @@
10
10
  * @version 2.0.0
11
11
  */
12
12
 
13
- const { execSync } = require('child_process');
13
+ const { execSync, execFileSync } = require('child_process');
14
14
  const fs = require('fs');
15
+ const os = require('os');
15
16
  const path = require('path');
16
17
 
18
+ const PACKAGE_NAME = '@aifabrix/builder';
19
+ /** Primary CLI name used for “current version” before link */
20
+ const PRIMARY_BIN = 'aifabrix';
21
+
22
+ /**
23
+ * Default PNPM_HOME when not set in the environment (matches `pnpm setup` on Linux/macOS; Windows uses LOCALAPPDATA).
24
+ * @returns {string} Resolved PNPM global bin home directory
25
+ */
26
+ function defaultPnpmHome() {
27
+ if (process.env.PNPM_HOME) {
28
+ return process.env.PNPM_HOME;
29
+ }
30
+ if (process.platform === 'win32' && process.env.LOCALAPPDATA) {
31
+ return path.join(process.env.LOCALAPPDATA, 'pnpm');
32
+ }
33
+ return path.join(os.homedir(), '.local', 'share', 'pnpm');
34
+ }
35
+
36
+ /**
37
+ * Environment with PNPM_HOME and PATH set so `pnpm link --global` can find the global bin dir
38
+ * (same idea as aifabrix-setup/scripts/install-local.js).
39
+ * @returns {NodeJS.ProcessEnv} Copy of process.env with pnpm paths prepended
40
+ */
41
+ function pnpmEnv() {
42
+ const env = { ...process.env };
43
+ const pnpmHome = defaultPnpmHome();
44
+ env.PNPM_HOME = pnpmHome;
45
+ env.PATH = [pnpmHome, env.PATH].filter(Boolean).join(path.delimiter);
46
+ return env;
47
+ }
48
+
17
49
  /**
18
50
  * Detect which package manager is being used (pnpm or npm)
19
51
  * @returns {string} 'pnpm' or 'npm'
20
52
  */
21
53
  function detectPackageManager() {
22
54
  try {
23
- // Check if pnpm is available
24
55
  execSync('which pnpm', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
25
56
  return 'pnpm';
26
57
  } catch {
27
- // Fall back to npm
28
58
  return 'npm';
29
59
  }
30
60
  }
31
61
 
32
62
  /**
33
- * Get currently installed version of aifabrix CLI
34
- * @returns {string|null} Version string or null if not installed
63
+ * Reads package.json `bin` keys (or default primary bin).
64
+ * @returns {string[]} CLI executable names published by this package
65
+ */
66
+ function listCliBinNames() {
67
+ try {
68
+ const packageJsonPath = path.join(__dirname, '..', 'package.json');
69
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
70
+ const bin = packageJson.bin;
71
+ if (!bin) return [PRIMARY_BIN];
72
+ if (typeof bin === 'string') return [PRIMARY_BIN];
73
+ return Object.keys(bin);
74
+ } catch {
75
+ return [PRIMARY_BIN];
76
+ }
77
+ }
78
+
79
+ /**
80
+ * @param {string} binName - CLI name on PATH
81
+ * @param {NodeJS.ProcessEnv} [env] - Optional env (e.g. pnpm-adjusted PATH)
82
+ * @returns {string|null} Trimmed `--version` output or null if command fails
83
+ */
84
+ function getBinVersion(binName, env) {
85
+ try {
86
+ return execSync(`${binName} --version`, {
87
+ encoding: 'utf8',
88
+ stdio: ['ignore', 'pipe', 'ignore'],
89
+ env: env || process.env
90
+ }).trim();
91
+ } catch {
92
+ return null;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * @param {string} binName - CLI name on PATH
98
+ * @param {NodeJS.ProcessEnv} [env] - Optional env for `which`
99
+ * @returns {string|null} First resolved path or null
100
+ */
101
+ function getBinPath(binName, env) {
102
+ try {
103
+ const which = execSync(`which ${binName}`, {
104
+ encoding: 'utf8',
105
+ stdio: ['ignore', 'pipe', 'ignore'],
106
+ env: env || process.env
107
+ }).trim();
108
+ return which || null;
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * First executable `binName` on PATH (same resolution order as a POSIX shell).
116
+ * @param {string} binName - CLI name
117
+ * @param {string} pathString - PATH value (e.g. process.env.PATH)
118
+ * @returns {{ candidate: string, real: string }|null} First hit or null
119
+ */
120
+ function firstExecutableOnPath(binName, pathString) {
121
+ if (process.platform === 'win32') {
122
+ return null;
123
+ }
124
+ const dirs = (pathString || '').split(path.delimiter).filter(Boolean);
125
+ for (const dir of dirs) {
126
+ const candidate = path.join(dir, binName);
127
+ try {
128
+ const st = fs.lstatSync(candidate);
129
+ if (!st.isFile() && !st.isSymbolicLink()) continue;
130
+ fs.accessSync(candidate, fs.constants.X_OK);
131
+ const real = fs.realpathSync(candidate);
132
+ return { candidate, real };
133
+ } catch {
134
+ // continue
135
+ }
136
+ }
137
+ return null;
138
+ }
139
+
140
+ /**
141
+ * @param {string} executablePath - Absolute path to CLI
142
+ * @returns {string|null} Trimmed --version or null
35
143
  */
36
- function getCurrentVersion() {
144
+ function versionAtExecutablePath(executablePath) {
37
145
  try {
38
- const version = execSync('aifabrix --version', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
39
- return version;
146
+ return execFileSync(executablePath, ['--version'], {
147
+ encoding: 'utf8',
148
+ stdio: ['ignore', 'pipe', 'ignore']
149
+ }).trim();
40
150
  } catch {
41
151
  return null;
42
152
  }
43
153
  }
44
154
 
155
+ /**
156
+ * Get currently installed version of primary CLI (aifabrix)
157
+ * @param {NodeJS.ProcessEnv} [env] - Optional env for the version probe
158
+ * @returns {string|null} Trimmed version or null if not on PATH
159
+ */
160
+ function getCurrentVersion(env) {
161
+ return getBinVersion(PRIMARY_BIN, env);
162
+ }
163
+
45
164
  /**
46
165
  * Get version from local package.json
47
166
  * @returns {string|null} Version string or null if not found
@@ -81,53 +200,192 @@ function displayVersionInfo(currentVersion, packageVersion) {
81
200
  }
82
201
  }
83
202
 
203
+ /**
204
+ * @typedef {{ name: string, path: string|null, real: string|null, version: string|null }} PathBinRow
205
+ */
206
+
207
+ /**
208
+ * @param {string[]} binNames - CLI names from package.json
209
+ * @returns {PathBinRow[]} Resolution rows for current PATH
210
+ */
211
+ function collectPathResolutionRows(binNames) {
212
+ const rows = [];
213
+ if (process.platform === 'win32') {
214
+ for (const name of binNames) {
215
+ const p = getBinPath(name, process.env);
216
+ const version = p
217
+ ? versionAtExecutablePath(p) || getBinVersion(name, process.env)
218
+ : getBinVersion(name, process.env);
219
+ rows.push({ name, path: p, real: p, version });
220
+ }
221
+ return rows;
222
+ }
223
+ for (const name of binNames) {
224
+ const hit = firstExecutableOnPath(name, process.env.PATH);
225
+ if (!hit) {
226
+ rows.push({ name, path: null, real: null, version: null });
227
+ continue;
228
+ }
229
+ const version =
230
+ versionAtExecutablePath(hit.candidate) || getBinVersion(name, process.env);
231
+ rows.push({ name, path: hit.candidate, real: hit.real, version });
232
+ }
233
+ return rows;
234
+ }
235
+
236
+ /**
237
+ * @param {PathBinRow[]} rows - Rows from collectPathResolutionRows
238
+ * @param {boolean} multipleBins - Whether package exposes more than one CLI name
239
+ * @returns {void}
240
+ */
241
+ function printPathResolutionTable(rows, multipleBins) {
242
+ const label = multipleBins
243
+ ? 'First match on your PATH for each command (what new programs see):'
244
+ : 'First match on your PATH (what new programs see):';
245
+ console.log(`\n${label}`);
246
+ for (const r of rows) {
247
+ if (!r.path) {
248
+ console.log(` ${r.name}: (not found on PATH)`);
249
+ continue;
250
+ }
251
+ const ver = r.version !== null && r.version !== undefined ? r.version : '(could not run --version)';
252
+ const arrow = r.real !== r.path ? ` → ${r.real}` : '';
253
+ console.log(` ${r.name}: ${r.path}${arrow} → ${ver}`);
254
+ }
255
+ }
256
+
257
+ /**
258
+ * @param {PathBinRow[]} rows - Rows from collectPathResolutionRows
259
+ * @param {string|null} expectedVersion - Linked package version
260
+ * @param {string[]} binNames - Bin names (length for multi-alias tip)
261
+ * @returns {void}
262
+ */
263
+ function printPathResolutionWarnings(rows, expectedVersion, binNames) {
264
+ const versions = rows
265
+ .map((r) => r.version)
266
+ .filter((v) => v !== null && v !== undefined && v !== '(could not run --version)');
267
+ const uniq = [...new Set(versions)];
268
+ const mismatchAliases = uniq.length > 1;
269
+ const hasStaleVers =
270
+ Boolean(expectedVersion) &&
271
+ rows.some(
272
+ (r) => r.version !== null && r.version !== undefined && r.version !== expectedVersion
273
+ );
274
+
275
+ if (hasStaleVers) {
276
+ console.log(`\n⚠️ At least one command above is not ${expectedVersion} (linked package version).`);
277
+ console.log(' Another install is winning on PATH for that name — often an old npm global copy.');
278
+ console.log(' Try: pnpm run diagnose:cli');
279
+ console.log(` Then: npm uninstall -g ${PACKAGE_NAME}`);
280
+ console.log(' Put PNPM_HOME (or ~/.local/share/pnpm) before other global bin dirs in PATH if needed.');
281
+ }
282
+
283
+ if (mismatchAliases) {
284
+ console.log('\n⚠️ `af` and `aifabrix` resolve to different installs on PATH.');
285
+ console.log(' Fix PATH as above, or if PATH looks correct, your shell may be using a stale location for one of them.');
286
+ console.log(' Bash: hash -r Zsh: rehash Then run both with --version again.');
287
+ } else if (binNames.length > 1 && expectedVersion && uniq.length === 1 && uniq[0] === expectedVersion) {
288
+ console.log('\nTip: Bash caches `af` and `aifabrix` separately. If your terminal shows a wrong version for only one, run: hash -r');
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Report first PATH hit per bin (matches new subprocesses). Warn on mismatch vs link or between aliases.
294
+ * Bash/zsh cache each command name separately — `af` can stay stale while `aifabrix` updates; suggest hash -r.
295
+ * @param {string|null} expectedVersion - Version from the linked package (pnpm env probe)
296
+ * @param {string[]} binNames - All bin entries from package.json
297
+ * @returns {void}
298
+ */
299
+ function reportCliAliasesOnPath(expectedVersion, binNames) {
300
+ if (!binNames.length) return;
301
+ const rows = collectPathResolutionRows(binNames);
302
+ printPathResolutionTable(rows, binNames.length > 1);
303
+ printPathResolutionWarnings(rows, expectedVersion, binNames);
304
+ }
305
+
306
+ /**
307
+ * Prints pnpm-specific hints when shell PATH still resolves an old binary.
308
+ * @param {boolean} usedPnpm - Whether link used pnpm
309
+ * @param {string|null} newVersion - Version after link
310
+ * @param {Object} [pathInfo] - Shell vs linked path probe
311
+ * @param {string|null} [pathInfo.versionInShell] - Version from default shell env
312
+ * @param {string|null} [pathInfo.linkedPath] - Path under pnpm env
313
+ * @returns {void}
314
+ */
315
+ function printPnpmPathHints(usedPnpm, newVersion, pathInfo) {
316
+ if (!usedPnpm) return;
317
+ const shellVersion = pathInfo && pathInfo.versionInShell;
318
+ const linkedPath = pathInfo && pathInfo.linkedPath;
319
+ if (newVersion && shellVersion !== newVersion) {
320
+ console.log(`\n⚠️ Your shell is still running an older ${PRIMARY_BIN} (${shellVersion || 'unknown'}).`);
321
+ console.log(` The linked binary is at: ${linkedPath || 'unknown'}`);
322
+ console.log(' Fix: run source ~/.bashrc (or open a new terminal).');
323
+ console.log(' If it still shows the old version, put pnpm\'s global bin first in PATH, or run:');
324
+ console.log(` npm uninstall -g ${PACKAGE_NAME}`);
325
+ } else {
326
+ console.log('If you still see an old version, run: source ~/.bashrc (or open a new terminal)');
327
+ }
328
+ }
329
+
84
330
  /**
85
331
  * Display success message with version information
86
332
  * @param {string|null} currentVersion - Version before linking
87
333
  * @param {string|null} newVersion - Version after linking
334
+ * @param {boolean} [usedPnpm] - Link used pnpm
335
+ * @param {Object} [pathInfo] - Optional shell vs linked path info
336
+ * @param {string|null} [pathInfo.versionInShell] - Version from default shell env
337
+ * @param {string|null} [pathInfo.linkedPath] - Path under pnpm env
338
+ * @param {string[]} [binNames] - Bin names from package.json
88
339
  * @returns {void}
89
340
  */
90
- function displaySuccessMessage(currentVersion, newVersion) {
91
- console.log('\n✅ Successfully linked!');
341
+ function displaySuccessMessage(currentVersion, newVersion, usedPnpm, pathInfo, binNames) {
342
+ const bins = binNames && binNames.length ? binNames : [PRIMARY_BIN];
343
+ console.log('\n✔ Successfully linked!');
92
344
  if (currentVersion && newVersion && currentVersion !== newVersion) {
93
345
  console.log(`📊 Version updated: ${currentVersion} → ${newVersion}`);
94
346
  } else if (newVersion) {
95
347
  console.log(`📊 Installed version: ${newVersion}`);
96
348
  }
97
- console.log('Run "aifabrix --version" to verify.');
349
+ const verifyHint =
350
+ bins.length > 1
351
+ ? bins.map((b) => `${b} --version`).join('" or "')
352
+ : `${bins[0]} --version`;
353
+ console.log(`Run "${verifyHint}" to verify.`);
354
+ if (bins.length > 1) {
355
+ console.log(
356
+ 'If only one alias shows the wrong version in your terminal, clear the shell command cache (bash: hash -r, zsh: rehash).'
357
+ );
358
+ }
359
+
360
+ printPnpmPathHints(usedPnpm, newVersion, pathInfo);
361
+ reportCliAliasesOnPath(newVersion, bins);
98
362
  }
99
363
 
100
364
  /**
101
- * Run pnpm link --global and npm link from project root (handles pnpm global bin not set).
102
- * @param {string} projectRoot - Path to project root
365
+ * Runs global link and reports success (throws on failure).
366
+ * @param {string} pm - 'pnpm' or 'npm'
367
+ * @param {string|null} currentVersion - Version before link
368
+ * @param {string[]} binNames - CLI bin names
103
369
  * @returns {void}
104
- * @throws {Error} If linking fails when pnpm global bin is not configured
105
370
  */
106
- function runPnpmLink(projectRoot) {
107
- let pnpmLinked = false;
108
- try {
109
- execSync('pnpm link --global', { stdio: 'inherit', cwd: projectRoot });
110
- pnpmLinked = true;
111
- } catch (pnpmErr) {
112
- const msg = (pnpmErr.message || String(pnpmErr));
113
- if (msg.includes('global bin directory') || msg.includes('ERR_PNPM_NO_GLOBAL_BIN_DIR')) {
114
- console.log(
115
- '⚠️ pnpm global bin is not set up. Run "pnpm setup" and add PNPM_HOME to PATH, or we will use npm link.\n'
116
- );
117
- } else {
118
- throw pnpmErr;
119
- }
120
- }
121
- try {
371
+ function runGlobalLink(pm, currentVersion, binNames) {
372
+ const projectRoot = path.join(__dirname, '..');
373
+ const env = pm === 'pnpm' ? pnpmEnv() : undefined;
374
+ if (pm === 'pnpm') {
375
+ execSync('pnpm link --global', { stdio: 'inherit', cwd: projectRoot, env });
376
+ } else {
122
377
  execSync('npm link', { stdio: 'inherit', cwd: projectRoot });
123
- } catch {
124
- if (!pnpmLinked) {
125
- console.error(
126
- '\n💡 To fix: run "pnpm setup" and add the suggested line to your shell config, then run install:local again.'
127
- );
128
- throw new Error('Linking failed. pnpm global bin not configured and npm link failed.');
129
- }
130
378
  }
379
+
380
+ const newVersion = getCurrentVersion(env);
381
+ let pathInfo;
382
+ if (pm === 'pnpm') {
383
+ pathInfo = {
384
+ versionInShell: getCurrentVersion(),
385
+ linkedPath: getBinPath(PRIMARY_BIN, env)
386
+ };
387
+ }
388
+ displaySuccessMessage(currentVersion, newVersion, pm === 'pnpm', pathInfo, binNames);
131
389
  }
132
390
 
133
391
  /**
@@ -137,23 +395,17 @@ function runPnpmLink(projectRoot) {
137
395
  function installLocal() {
138
396
  const pm = detectPackageManager();
139
397
  const packageVersion = getPackageVersion();
398
+ const binNames = listCliBinNames();
140
399
  const currentVersion = getCurrentVersion();
141
400
 
142
401
  console.log(`Detected package manager: ${pm}\n`);
143
402
  displayVersionInfo(currentVersion, packageVersion);
144
- console.log('Linking @aifabrix/builder globally...\n');
403
+ console.log(`Linking ${PACKAGE_NAME} globally...\n`);
145
404
 
146
405
  try {
147
- const projectRoot = path.join(__dirname, '..');
148
- if (pm === 'pnpm') {
149
- runPnpmLink(projectRoot);
150
- } else {
151
- execSync('npm link', { stdio: 'inherit', cwd: projectRoot });
152
- }
153
- const newVersion = getCurrentVersion();
154
- displaySuccessMessage(currentVersion, newVersion);
406
+ runGlobalLink(pm, currentVersion, binNames);
155
407
  } catch (error) {
156
- console.error('\n Failed to link package:', error.message);
408
+ console.error('\n Failed to link package:', error.message);
157
409
  process.exit(1);
158
410
  }
159
411
  }
@@ -192,7 +444,7 @@ function displayUninstallVersionInfo(currentVersion, packageVersion) {
192
444
  * @returns {void}
193
445
  */
194
446
  function displayUninstallSuccess(pm, currentVersion) {
195
- console.log(`\n Successfully unlinked with ${pm}!`);
447
+ console.log(`\n Successfully unlinked with ${pm}!`);
196
448
  if (currentVersion) {
197
449
  console.log(`📊 Uninstalled version: ${currentVersion}`);
198
450
  }
@@ -208,22 +460,19 @@ function uninstallLocal() {
208
460
  const packageVersion = getPackageVersion();
209
461
 
210
462
  console.log(`Detected package manager: ${pm}\n`);
211
-
212
- // Show version information before unlinking
213
463
  displayUninstallVersionInfo(currentVersion, packageVersion);
214
-
215
- console.log('Unlinking @aifabrix/builder globally...\n');
464
+ console.log(`Unlinking ${PACKAGE_NAME} globally...\n`);
216
465
 
217
466
  try {
218
467
  if (pm === 'pnpm') {
219
- execSync('pnpm unlink --global @aifabrix/builder', { stdio: 'inherit' });
468
+ execSync(`pnpm unlink --global ${PACKAGE_NAME}`, { stdio: 'inherit', env: pnpmEnv() });
220
469
  displayUninstallSuccess(pm, currentVersion);
221
470
  } else {
222
- execSync('npm unlink -g @aifabrix/builder', { stdio: 'inherit' });
471
+ execSync(`npm unlink -g ${PACKAGE_NAME}`, { stdio: 'inherit' });
223
472
  displayUninstallSuccess(pm, currentVersion);
224
473
  }
225
474
  } catch (error) {
226
- console.error('\n Failed to unlink package:', error.message);
475
+ console.error('\n Failed to unlink package:', error.message);
227
476
  process.exit(1);
228
477
  }
229
478
  }
@@ -8,7 +8,7 @@ The templates directory is organized as follows:
8
8
 
9
9
  ### Application Templates (for `--template` flag)
10
10
 
11
- Application templates are folder-based and located under `templates/applications/`. When you use `--template <name>`, the tool looks for `templates/applications/<name>/` and copies all files from that folder to `builder/<app>/`.
11
+ Application templates are folder-based and located under `templates/applications/`. When you use `--template <name>`, the tool looks for `templates/applications/<name>/` and copies all files from that folder to `builder/<appKey>/`.
12
12
 
13
13
  **Example:**
14
14
  - `templates/applications/miso-controller/` - Miso Controller application template
@@ -18,7 +18,7 @@ Application templates are folder-based and located under `templates/applications
18
18
  - Template folder must exist in `templates/applications/<name>/`
19
19
  - Template folder must contain at least one file
20
20
  - Hidden files (starting with `.`) are skipped
21
- - If a template includes a `Dockerfile`, it will be copied to `builder/<app>/Dockerfile` along with other files
21
+ - If a template includes a `Dockerfile`, it will be copied to `builder/<appKey>/Dockerfile` along with other files
22
22
 
23
23
  ### Language Templates
24
24
 
@@ -63,6 +63,19 @@ Extra workflow steps are located in `templates/github/steps/`. When you use `--g
63
63
  ### Health Check Configuration
64
64
  - `{{healthCheck.path}}` - Health check endpoint path (e.g., "/health")
65
65
  - `{{healthCheck.interval}}` - Health check interval in seconds
66
+ - `{{healthCheck.bashProbe}}` - When true, generated Docker Compose uses a bash TCP probe (no `curl` dependency) instead of `curl -f`.
67
+
68
+ **Why `bashProbe` exists**
69
+
70
+ Some application images intentionally do not ship with `curl` (for smaller images or stricter runtime environments). If Compose uses a `curl`-based healthcheck in those images, Docker will mark the container as **unhealthy** even when the app is actually serving traffic.
71
+
72
+ Set `healthCheck.bashProbe: true` to make Compose healthchecks work without `curl` by performing a minimal HTTP request over `/dev/tcp`.
73
+
74
+ ### Traefik (Docker Compose labels)
75
+
76
+ Generated compose includes `traefik.http.routers.<app>.service=<app>` so Traefik’s Docker provider always binds the router to the in-compose service (required for HTTP-only routers when TLS terminates at nginx).
77
+
78
+ Infra Traefik is started with `--providers.docker.allowEmptyServices=true` so routes are published while a container is still in Docker’s `starting` / `unhealthy` health state (common during slow boots or when a health probe differs from real readiness).
66
79
 
67
80
  ### Service Requirements
68
81
  - `{{requiresDatabase}}` - Database requirement flag (conditional db-init service)