@aifabrix/builder 2.43.0 → 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 (346) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/README.md +1 -1
  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 +31 -0
  7. package/integration/hubspot-test/create-hubspot.js +5 -5
  8. package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
  9. package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
  10. package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
  11. package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
  12. package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
  13. package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
  14. package/integration/hubspot-test/test-dataplane-down.js +3 -3
  15. package/integration/hubspot-test/test.js +35 -43
  16. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  17. package/integration/roundtrip-test-local/README.md +144 -0
  18. package/integration/roundtrip-test-local/application.yaml +13 -0
  19. package/integration/roundtrip-test-local/env.template +15 -0
  20. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  21. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  22. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  23. package/integration/roundtrip-test-local2/README.md +144 -0
  24. package/integration/roundtrip-test-local2/application.yaml +13 -0
  25. package/integration/roundtrip-test-local2/env.template +15 -0
  26. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  27. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  28. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  29. package/integration/test/wizard.yaml +8 -0
  30. package/jest.config.default.js +10 -0
  31. package/jest.config.integration.fixtures.js +22 -0
  32. package/jest.config.integration.js +21 -18
  33. package/jest.config.isolated.js +10 -0
  34. package/jest.projects.js +288 -0
  35. package/lib/api/datasources-core.api.js +3 -3
  36. package/lib/api/dev-mtls-request.js +110 -0
  37. package/lib/api/dev-server-https.js +145 -0
  38. package/lib/api/dev.api.js +133 -144
  39. package/lib/api/index.js +0 -1
  40. package/lib/api/pipeline.api.js +67 -20
  41. package/lib/api/types/dev.types.js +4 -3
  42. package/lib/api/types/pipeline.types.js +8 -5
  43. package/lib/api/types/validation-run.types.js +56 -0
  44. package/lib/api/validation-run.api.js +99 -0
  45. package/lib/api/validation-runner.js +99 -0
  46. package/lib/app/config.js +1 -1
  47. package/lib/app/deploy-status-display.js +2 -2
  48. package/lib/app/deploy.js +7 -6
  49. package/lib/app/display.js +2 -1
  50. package/lib/app/dockerfile.js +3 -2
  51. package/lib/app/down.js +2 -1
  52. package/lib/app/helpers.js +6 -5
  53. package/lib/app/index.js +27 -8
  54. package/lib/app/list.js +7 -6
  55. package/lib/app/push.js +4 -3
  56. package/lib/app/register.js +16 -7
  57. package/lib/app/rotate-secret.js +14 -13
  58. package/lib/app/run-container-start.js +184 -0
  59. package/lib/app/run-docker-fallback.js +108 -0
  60. package/lib/app/run-env-compose.js +30 -42
  61. package/lib/app/run-helpers.js +49 -126
  62. package/lib/app/run-infra-requirements.js +30 -0
  63. package/lib/app/run-resolve-image.js +21 -0
  64. package/lib/app/run.js +74 -21
  65. package/lib/app/show-display.js +1 -1
  66. package/lib/app/show.js +1 -1
  67. package/lib/build/index.js +13 -10
  68. package/lib/cli/index.js +2 -0
  69. package/lib/cli/setup-app.help.js +67 -0
  70. package/lib/cli/setup-app.js +57 -121
  71. package/lib/cli/setup-app.test-commands.js +179 -0
  72. package/lib/cli/setup-auth.js +19 -5
  73. package/lib/cli/setup-credential-deployment.js +22 -8
  74. package/lib/cli/setup-dev-path-commands.js +124 -0
  75. package/lib/cli/setup-dev.js +170 -113
  76. package/lib/cli/setup-environment.js +7 -1
  77. package/lib/cli/setup-external-system.js +62 -22
  78. package/lib/cli/setup-infra.js +126 -47
  79. package/lib/cli/setup-parameters.js +32 -0
  80. package/lib/cli/setup-secrets.js +106 -8
  81. package/lib/cli/setup-service-user.js +1 -1
  82. package/lib/cli/setup-utility.js +36 -20
  83. package/lib/commands/app-down.js +5 -7
  84. package/lib/commands/app-install.js +14 -7
  85. package/lib/commands/app-logs.js +13 -10
  86. package/lib/commands/app-shell.js +4 -1
  87. package/lib/commands/app-test.js +25 -19
  88. package/lib/commands/app.js +22 -10
  89. package/lib/commands/auth-config.js +6 -6
  90. package/lib/commands/auth-status.js +4 -3
  91. package/lib/commands/credential-env.js +4 -3
  92. package/lib/commands/credential-list.js +5 -4
  93. package/lib/commands/credential-push.js +4 -3
  94. package/lib/commands/datasource-unified-test-cli.js +495 -0
  95. package/lib/commands/datasource-unified-test-cli.options.js +149 -0
  96. package/lib/commands/datasource-validation-cli.js +129 -0
  97. package/lib/commands/datasource.js +105 -98
  98. package/lib/commands/deployment-list.js +6 -5
  99. package/lib/commands/dev-cli-handlers.js +122 -18
  100. package/lib/commands/dev-down.js +4 -3
  101. package/lib/commands/dev-init.js +231 -116
  102. package/lib/commands/dev-show-display.js +473 -0
  103. package/lib/commands/login-credentials.js +3 -2
  104. package/lib/commands/login-device.js +4 -3
  105. package/lib/commands/login.js +5 -4
  106. package/lib/commands/logout.js +8 -7
  107. package/lib/commands/parameters-validate.js +54 -0
  108. package/lib/commands/repair-datasource.js +314 -68
  109. package/lib/commands/repair-env-template.js +2 -2
  110. package/lib/commands/repair.js +21 -3
  111. package/lib/commands/secrets-list.js +23 -12
  112. package/lib/commands/secrets-remove-all.js +220 -0
  113. package/lib/commands/secrets-remove.js +21 -12
  114. package/lib/commands/secrets-set.js +21 -12
  115. package/lib/commands/secrets-validate.js +4 -4
  116. package/lib/commands/secure.js +10 -9
  117. package/lib/commands/service-user.js +26 -25
  118. package/lib/commands/test-e2e-external.js +27 -1
  119. package/lib/commands/up-common.js +3 -2
  120. package/lib/commands/up-dataplane.js +29 -16
  121. package/lib/commands/up-miso.js +19 -29
  122. package/lib/commands/upload.js +138 -39
  123. package/lib/commands/wizard-core-helpers.js +1 -1
  124. package/lib/commands/wizard-dataplane.js +4 -3
  125. package/lib/commands/wizard-helpers.js +3 -3
  126. package/lib/commands/wizard.js +2 -2
  127. package/lib/core/admin-secrets.js +14 -5
  128. package/lib/core/audit-logger.js +12 -4
  129. package/lib/core/config-attach-extensions.js +46 -0
  130. package/lib/core/config-runtime-paths.js +29 -0
  131. package/lib/core/config.js +55 -56
  132. package/lib/core/diff.js +3 -2
  133. package/lib/core/ensure-encryption-key.js +1 -1
  134. package/lib/core/secrets-ensure-infra.js +77 -0
  135. package/lib/core/secrets-ensure.js +120 -64
  136. package/lib/core/secrets-env-write.js +35 -7
  137. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  138. package/lib/core/secrets.js +200 -37
  139. package/lib/core/templates-env.js +4 -3
  140. package/lib/datasource/abac-validator.js +1 -10
  141. package/lib/datasource/deploy.js +75 -53
  142. package/lib/datasource/field-reference-validator.js +9 -6
  143. package/lib/datasource/integration-context.js +63 -0
  144. package/lib/datasource/list.js +8 -7
  145. package/lib/datasource/log-viewer.js +84 -53
  146. package/lib/datasource/resolve-app.js +4 -4
  147. package/lib/datasource/test-e2e.js +95 -146
  148. package/lib/datasource/test-integration.js +114 -122
  149. package/lib/datasource/unified-validation-run-body.js +65 -0
  150. package/lib/datasource/unified-validation-run-post.js +23 -0
  151. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  152. package/lib/datasource/unified-validation-run.js +92 -0
  153. package/lib/datasource/validate.js +157 -13
  154. package/lib/deployment/deployer.js +4 -3
  155. package/lib/deployment/environment.js +7 -6
  156. package/lib/deployment/push.js +17 -8
  157. package/lib/external-system/delete.js +4 -3
  158. package/lib/external-system/deploy.js +131 -53
  159. package/lib/external-system/download-helpers.js +1 -1
  160. package/lib/external-system/download.js +7 -6
  161. package/lib/external-system/generator.js +92 -6
  162. package/lib/external-system/integration-test-dispatch.js +26 -0
  163. package/lib/external-system/test-execution.js +5 -1
  164. package/lib/external-system/test-helpers.js +0 -4
  165. package/lib/external-system/test-system-level-helpers.js +110 -0
  166. package/lib/external-system/test-system-level.js +83 -44
  167. package/lib/external-system/test.js +59 -8
  168. package/lib/generator/builders.js +23 -11
  169. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  170. package/lib/generator/external.js +16 -4
  171. package/lib/generator/helpers.js +58 -3
  172. package/lib/generator/index.js +4 -0
  173. package/lib/generator/split-readme.js +12 -7
  174. package/lib/generator/split-variables.js +2 -1
  175. package/lib/generator/split.js +1 -1
  176. package/lib/generator/wizard-readme.js +3 -3
  177. package/lib/generator/wizard.js +8 -8
  178. package/lib/infrastructure/compose.js +60 -6
  179. package/lib/infrastructure/helpers.js +201 -29
  180. package/lib/infrastructure/index.js +28 -17
  181. package/lib/infrastructure/services.js +21 -15
  182. package/lib/internal/fs-real-sync.js +104 -0
  183. package/lib/internal/node-fs.js +98 -0
  184. package/lib/parameters/database-secret-values.js +173 -0
  185. package/lib/parameters/infra-kv-discovery.js +121 -0
  186. package/lib/parameters/infra-parameter-catalog.js +458 -0
  187. package/lib/parameters/infra-parameter-validate.js +64 -0
  188. package/lib/schema/application-schema.json +37 -17
  189. package/lib/schema/datasource-test-run.schema.json +493 -0
  190. package/lib/schema/deployment-rules.yaml +102 -63
  191. package/lib/schema/external-datasource.schema.json +1200 -442
  192. package/lib/schema/external-system.schema.json +181 -5
  193. package/lib/schema/flag-map-validation-run.json +31 -0
  194. package/lib/schema/infra-parameter.schema.json +106 -0
  195. package/lib/schema/infra.parameter.yaml +421 -0
  196. package/lib/schema/type/credential-auth-templates.json +40 -0
  197. package/lib/schema/type/document-storage.json +213 -0
  198. package/lib/schema/type/message-service.json +123 -0
  199. package/lib/schema/type/vector-store.json +88 -0
  200. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  201. package/lib/utils/api-error-handler.js +2 -2
  202. package/lib/utils/api.js +49 -14
  203. package/lib/utils/app-register-api.js +3 -2
  204. package/lib/utils/app-register-auth.js +1 -1
  205. package/lib/utils/app-register-config.js +4 -4
  206. package/lib/utils/app-register-display.js +3 -2
  207. package/lib/utils/app-register-validator.js +3 -2
  208. package/lib/utils/app-run-containers.js +26 -22
  209. package/lib/utils/app-scoped-config.js +31 -0
  210. package/lib/utils/app-service-env-from-builder.js +164 -0
  211. package/lib/utils/build-copy.js +1 -1
  212. package/lib/utils/build-helpers.js +20 -20
  213. package/lib/utils/build-resolve-image.js +165 -0
  214. package/lib/utils/cli-layout-chalk.js +8 -0
  215. package/lib/utils/cli-test-layout-chalk.js +267 -0
  216. package/lib/utils/cli-utils.js +88 -11
  217. package/lib/utils/compose-db-passwords.js +138 -0
  218. package/lib/utils/compose-generate-docker-compose.js +216 -0
  219. package/lib/utils/compose-generator.js +197 -291
  220. package/lib/utils/compose-miso-env.js +18 -0
  221. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  222. package/lib/utils/config-paths.js +166 -7
  223. package/lib/utils/config-scoped-resources-preference.js +41 -0
  224. package/lib/utils/controller-deployment-outcome.js +68 -0
  225. package/lib/utils/credential-display.js +2 -2
  226. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  227. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  228. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  229. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  230. package/lib/utils/datasource-test-run-display.js +442 -0
  231. package/lib/utils/datasource-test-run-exit.js +58 -0
  232. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  233. package/lib/utils/datasource-test-run-report-version.js +51 -0
  234. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  235. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  236. package/lib/utils/datasource-validation-watch.js +266 -0
  237. package/lib/utils/declarative-url-ports.js +47 -0
  238. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  239. package/lib/utils/dev-ca-install.js +185 -23
  240. package/lib/utils/dev-cert-helper.js +266 -17
  241. package/lib/utils/dev-hosts-helper.js +307 -0
  242. package/lib/utils/dev-init-cert-hints.js +37 -0
  243. package/lib/utils/dev-init-health-messages.js +52 -0
  244. package/lib/utils/dev-init-resolve.js +86 -0
  245. package/lib/utils/dev-init-ssh-merge.js +65 -0
  246. package/lib/utils/dev-ssh-config-helper.js +196 -0
  247. package/lib/utils/dev-user-groups.js +93 -0
  248. package/lib/utils/docker-build.js +42 -17
  249. package/lib/utils/docker-exec.js +28 -0
  250. package/lib/utils/docker-manifest-public-port.js +116 -0
  251. package/lib/utils/docker-not-running-hint.js +52 -0
  252. package/lib/utils/docker.js +98 -11
  253. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  254. package/lib/utils/env-config-loader.js +10 -91
  255. package/lib/utils/env-copy.js +19 -10
  256. package/lib/utils/env-map.js +35 -8
  257. package/lib/utils/env-template.js +2 -2
  258. package/lib/utils/environment-scoped-resources.js +144 -0
  259. package/lib/utils/error-formatter.js +92 -13
  260. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  261. package/lib/utils/error-formatters/network-errors.js +2 -1
  262. package/lib/utils/error-formatters/permission-errors.js +2 -1
  263. package/lib/utils/error-formatters/validation-errors.js +2 -1
  264. package/lib/utils/external-readme.js +8 -1
  265. package/lib/utils/external-system-display.js +234 -136
  266. package/lib/utils/external-system-local-test-tty.js +389 -0
  267. package/lib/utils/external-system-readiness-core.js +377 -0
  268. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  269. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  270. package/lib/utils/external-system-readiness-display.js +186 -0
  271. package/lib/utils/external-system-test-helpers.js +24 -6
  272. package/lib/utils/external-system-validators.js +30 -12
  273. package/lib/utils/health-check-url.js +119 -0
  274. package/lib/utils/health-check.js +59 -25
  275. package/lib/utils/help-builder.js +11 -8
  276. package/lib/utils/image-version.js +4 -8
  277. package/lib/utils/infra-containers.js +4 -7
  278. package/lib/utils/infra-env-defaults.js +162 -0
  279. package/lib/utils/infra-status-display.js +167 -0
  280. package/lib/utils/infra-status.js +16 -8
  281. package/lib/utils/local-secrets.js +3 -4
  282. package/lib/utils/paths.js +134 -47
  283. package/lib/utils/port-resolver.js +10 -23
  284. package/lib/utils/redis-env-scope.js +62 -0
  285. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  286. package/lib/utils/remote-builder-validation.js +99 -0
  287. package/lib/utils/remote-dev-auth.js +117 -21
  288. package/lib/utils/remote-docker-env.js +67 -15
  289. package/lib/utils/remote-secrets-loader.js +13 -4
  290. package/lib/utils/resolve-docker-image-ref.js +124 -0
  291. package/lib/utils/schema-loader.js +22 -9
  292. package/lib/utils/secrets-bash-kv.js +25 -0
  293. package/lib/utils/secrets-generator.js +169 -49
  294. package/lib/utils/secrets-helpers.js +70 -59
  295. package/lib/utils/secrets-kv-scope.js +60 -0
  296. package/lib/utils/secrets-utils.js +32 -38
  297. package/lib/utils/secrets-validation.js +3 -1
  298. package/lib/utils/secrets-yaml-preserve.js +109 -0
  299. package/lib/utils/ssh-key-helper.js +4 -2
  300. package/lib/utils/template-helpers.js +2 -2
  301. package/lib/utils/test-log-writer.js +3 -3
  302. package/lib/utils/token-manager.js +1 -2
  303. package/lib/utils/url-declarative-public-base.js +188 -0
  304. package/lib/utils/url-declarative-resolve-build.js +493 -0
  305. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  306. package/lib/utils/url-declarative-resolve.js +220 -0
  307. package/lib/utils/url-declarative-token-parse.js +74 -0
  308. package/lib/utils/url-declarative-url-flags.js +50 -0
  309. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  310. package/lib/utils/url-public-path-prefix.js +34 -0
  311. package/lib/utils/urls-local-registry.js +220 -0
  312. package/lib/utils/validation-report-tty-kit.js +77 -0
  313. package/lib/utils/validation-run-poll.js +89 -0
  314. package/lib/utils/validation-run-post-retry.js +73 -0
  315. package/lib/utils/validation-run-request.js +98 -0
  316. package/lib/utils/variable-transformer.js +21 -4
  317. package/lib/utils/yaml-preserve.js +33 -14
  318. package/lib/validation/datasource-warnings.js +56 -0
  319. package/lib/validation/env-template-auth.js +1 -1
  320. package/lib/validation/external-manifest-validator.js +27 -7
  321. package/lib/validation/validate-display.js +37 -31
  322. package/lib/validation/validate.js +4 -13
  323. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  324. package/lib/validation/validator.js +22 -65
  325. package/lib/validation/wizard-config-validator.js +2 -1
  326. package/package.json +7 -3
  327. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  328. package/scripts/diagnose-cli.js +150 -0
  329. package/scripts/install-local.js +304 -55
  330. package/templates/README.md +15 -2
  331. package/templates/applications/dataplane/application.yaml +52 -2
  332. package/templates/applications/dataplane/env.template +75 -17
  333. package/templates/applications/dataplane/rbac.yaml +8 -0
  334. package/templates/applications/keycloak/application.yaml +9 -1
  335. package/templates/applications/keycloak/env.template +15 -6
  336. package/templates/applications/miso-controller/application.yaml +10 -2
  337. package/templates/applications/miso-controller/env.template +42 -12
  338. package/templates/applications/miso-controller/rbac.yaml +5 -0
  339. package/templates/external-system/README.md.hbs +20 -7
  340. package/templates/external-system/deploy.js.hbs +5 -5
  341. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  342. package/templates/infra/compose.yaml.hbs +20 -4
  343. package/templates/python/docker-compose.hbs +16 -0
  344. package/templates/typescript/docker-compose.hbs +16 -0
  345. package/lib/api/external-test.api.js +0 -111
  346. package/lib/schema/env-config.yaml +0 -60
@@ -2,9 +2,9 @@
2
2
  * CLI external system command setup (download, upload, delete, test-integration).
3
3
  *
4
4
  * Registers these commands on the Commander program:
5
- * - download <system-key> – Download external system from dataplane to integration/<system-key>/
6
- * - upload <system-key> – Upload to dataplane (validate publish; no controller deploy)
7
- * - delete <system-key> – Delete external system and associated datasources from dataplane
5
+ * - download <systemKey> – Download external system from dataplane to integration/<systemKey>/
6
+ * - upload <systemKey> – Upload publishes to dataplane and registers the app with the controller (draft)
7
+ * - delete <systemKey> – Delete external system and associated datasources from dataplane
8
8
  * - test-integration <app> – Run integration tests (builder: in container; external: via dataplane pipeline)
9
9
  *
10
10
  * @fileoverview External system command definitions for AI Fabrix Builder CLI
@@ -15,10 +15,11 @@
15
15
  */
16
16
 
17
17
  const { handleCommandError } = require('../utils/cli-utils');
18
+ const { TEST_INTEGRATION_HELP_AFTER } = require('./setup-app.help');
18
19
 
19
20
  function setupDownloadCommand(program) {
20
- program.command('download <system-key>')
21
- .description('Download external system from dataplane to local development structure')
21
+ program.command('download <systemKey>')
22
+ .description('Pull external system from dataplane into integration/<key>/')
22
23
  .option('--format <format>', 'Output format: json | yaml (default: yaml or config format)')
23
24
  .option('--dry-run', 'Show what would be downloaded without actually downloading')
24
25
  .option('--force', 'Overwrite existing README.md without prompting')
@@ -39,13 +40,24 @@ function setupDownloadCommand(program) {
39
40
  }
40
41
 
41
42
  function setupUploadCommand(program) {
42
- program.command('upload <system-key>')
43
- .description('Upload external system to dataplane (upload validate publish; no controller deploy)')
43
+ program.command('upload <systemKey>')
44
+ .description('Validate, publish to dataplane, and register with controller (draft application)')
44
45
  .option('--dry-run', 'Validate and build payload only; no API calls')
46
+ .option('-v, --verbose', 'Run server-side pipeline validate and print warnings before publish')
47
+ .option('--probe', 'After publish, run dataplane runtime checks (validation/run); slower')
48
+ .option('--minimal', 'Print only a short readiness summary after upload')
49
+ .option('--probe-timeout <ms>', 'Timeout for --probe (default: 120000)', '120000')
45
50
  .action(async(systemKey, options) => {
46
51
  try {
47
52
  const upload = require('../commands/upload');
48
- await upload.uploadExternalSystem(systemKey, options);
53
+ const probeTimeout =
54
+ options.probeTimeout === undefined || options.probeTimeout === null
55
+ ? 120000
56
+ : Number(options.probeTimeout);
57
+ await upload.uploadExternalSystem(systemKey, {
58
+ ...options,
59
+ probeTimeout: Number.isFinite(probeTimeout) ? probeTimeout : 120000
60
+ });
49
61
  } catch (error) {
50
62
  handleCommandError(error, 'upload');
51
63
  process.exit(1);
@@ -54,9 +66,9 @@ function setupUploadCommand(program) {
54
66
  }
55
67
 
56
68
  function setupDeleteCommand(program) {
57
- program.command('delete <system-key>')
58
- .description('Delete external system from dataplane (also deletes all associated datasources)')
59
- .option('--type <type>', 'Application type (default: external; use "external" to target integration/<app>)')
69
+ program.command('delete <systemKey>')
70
+ .description('Remove external system and its datasources from dataplane')
71
+ .option('--type <type>', 'Application type (default: external; use "external" to target integration/<systemKey>)')
60
72
  .option('--yes', 'Skip confirmation prompt')
61
73
  .option('--force', 'Skip confirmation prompt (alias for --yes)')
62
74
  .action(async(systemKey, options) => {
@@ -111,9 +123,15 @@ async function tryBuilderTestIntegration(appName, options) {
111
123
  */
112
124
  async function runExternalSystemTestIntegration(appName, options) {
113
125
  const test = require('../external-system/test');
114
- const opts = { ...options, environment: options.env || options.environment, debug: options.debug };
126
+ const opts = {
127
+ ...options,
128
+ environment: options.env || options.environment,
129
+ debug: options.debug,
130
+ perDatasource: options.perDatasource,
131
+ sync: options.sync === true
132
+ };
115
133
  const results = await test.testExternalSystemIntegration(appName, opts);
116
- test.displayIntegrationTestResults(results, options.verbose);
134
+ test.displayIntegrationTestResults(results, options.verbose, { debug: options.debug, runType: 'integration' });
117
135
  if (!results.success) process.exit(1);
118
136
  }
119
137
 
@@ -126,6 +144,12 @@ async function runExternalSystemTestIntegration(appName, options) {
126
144
  async function runTestIntegrationCommand(appName, options) {
127
145
  const pathsUtil = require('../utils/paths');
128
146
  const appType = await pathsUtil.detectAppType(appName).catch(() => null);
147
+ if (options.sync === true && appType && appType.baseDir === 'builder') {
148
+ throw new Error(
149
+ 'Option --sync applies only to external integration tests (integration/<systemKey>/). ' +
150
+ 'For a builder app use aifabrix upload <systemKey> from the integration folder, or run test-integration without --sync.'
151
+ );
152
+ }
129
153
  if (appType && appType.baseDir === 'builder') {
130
154
  const { runAppTestIntegration } = require('../commands/app-test');
131
155
  const opts = { env: options.env || options.environment || 'dev' };
@@ -133,23 +157,39 @@ async function runTestIntegrationCommand(appName, options) {
133
157
  return;
134
158
  }
135
159
  const ranBuilder = await tryBuilderTestIntegration(appName, options);
136
- if (ranBuilder) return;
160
+ if (ranBuilder) {
161
+ if (options.sync === true) {
162
+ throw new Error(
163
+ 'Option --sync applies only when test-integration runs against an external integration folder on the dataplane. ' +
164
+ 'This run used a builder-style path instead. Remove --sync or use an integration/<systemKey>/ app.'
165
+ );
166
+ }
167
+ return;
168
+ }
137
169
  await runExternalSystemTestIntegration(appName, options);
138
170
  }
139
171
 
140
172
  function setupExternalSystemTestCommands(program) {
141
173
  // 'test <app>' is registered in setup-app.js and dispatches by app type (builder vs external)
142
174
  program.command('test-integration <app>')
143
- .description('Run integration tests (builder/docker app: in container; external system: via dataplane pipeline API)')
144
- .option('-d, --datasource <key>', 'Test specific datasource only')
145
- .option('-p, --payload <file>', 'Path to custom test payload file')
146
- .option('-e, --env <env>', 'Environment: dev, tst, or pro (default: from aifabrix auth config)')
175
+ .description('Integration tests: builder in container; external via dataplane')
176
+ .option('-e, --env <env>', 'Environment: dev, tst, or pro (builder: dev/tst for container)', 'dev')
147
177
  .option('-v, --verbose', 'Show detailed test output')
148
- .option('--debug', 'Include debug output and write log to integration/<app>/logs/')
149
- .option('--timeout <ms>', 'Request timeout in milliseconds', '30000')
150
- .action(async(appName, options) => {
178
+ .option('-d, --debug', 'Include debug output and write log to integration/<systemKey>/logs/')
179
+ .option(
180
+ '--sync',
181
+ 'Publish local system and datasource files to the dataplane before running tests (same as aifabrix upload <systemKey>)'
182
+ )
183
+ .addHelpText('after', TEST_INTEGRATION_HELP_AFTER)
184
+ .action(async(appName, options, cmd) => {
151
185
  try {
152
- await runTestIntegrationCommand(appName, options);
186
+ const rawArgs = Array.isArray(cmd?.rawArgs) ? cmd.rawArgs : [];
187
+ const envExplicit = rawArgs.includes('-e') || rawArgs.includes('--env');
188
+ const opts = {
189
+ ...options,
190
+ env: envExplicit ? options.env : undefined
191
+ };
192
+ await runTestIntegrationCommand(appName, opts);
153
193
  } catch (error) {
154
194
  handleCommandError(error, 'test-integration');
155
195
  process.exit(1);
@@ -1,3 +1,4 @@
1
+ const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * CLI infrastructure command setup (up-infra, up-platform, up-miso, up-dataplane, down-infra, doctor, status, restart).
3
4
  *
@@ -18,6 +19,22 @@ const { handleLogin } = require('../commands/login');
18
19
  const { handleUpMiso } = require('../commands/up-miso');
19
20
  const { handleUpDataplane } = require('../commands/up-dataplane');
20
21
  const { cleanBuilderAppDirs } = require('../commands/up-common');
22
+ const {
23
+ loadInfraStatusSummary,
24
+ formatInfraStatusTitleLine,
25
+ logInfraStatusConfigurationSummary,
26
+ logPaddedFieldRow
27
+ } = require('../utils/infra-status-display');
28
+
29
+ const UP_INFRA_HELP_AFTER = `
30
+ Typical sequence:
31
+ $ aifabrix up-infra
32
+ $ aifabrix up-platform
33
+ Or: aifabrix up-miso, then aifabrix up-dataplane (login required for dataplane)
34
+
35
+ Full bootstrap example (Traefik, TLS flag, pgAdmin, catalog overrides — matches shipped defaults in infra.parameter.yaml):
36
+ $ aifabrix up-infra --traefik --tls --adminPassword admin123 --adminEmail admin@aifabrix.dev --userPassword user123 --pgAdmin
37
+ `;
21
38
 
22
39
  /**
23
40
  * Persists optional service flag to config when explicitly set.
@@ -29,7 +46,29 @@ const { cleanBuilderAppDirs } = require('../commands/up-common');
29
46
  async function persistOptionalServiceFlag(cfg, key, value, label) {
30
47
  cfg[key] = value;
31
48
  await config.saveConfig(cfg);
32
- logger.log(chalk.green(`✓ ${label} ${value ? 'enabled' : 'disabled'} and saved to config`));
49
+ logger.log(formatSuccessLine(`${label} ${value ? 'enabled' : 'disabled'} and saved to config`));
50
+ }
51
+
52
+ /**
53
+ * Persists TLS mode for ${TLS_ENABLED} / ${HTTP_ENABLED} in application.yaml / deployment manifest interpolation.
54
+ * @param {Object} cfg - Config object (mutated)
55
+ * @param {boolean} value - Whether TLS mode is on
56
+ */
57
+ async function persistTlsEnabledFlag(cfg, value) {
58
+ cfg.tlsEnabled = value;
59
+ await config.saveConfig(cfg);
60
+ const tlsStr = value ? 'true' : 'false';
61
+ const httpStr = value ? 'false' : 'true';
62
+ logger.log(
63
+ chalk.green(
64
+ `✔ TLS mode ${value ? 'enabled' : 'disabled'} and saved to config (` +
65
+ '${TLS_ENABLED}=' +
66
+ tlsStr +
67
+ ', ${HTTP_ENABLED}=' +
68
+ httpStr +
69
+ ' when generating deployment JSON)'
70
+ )
71
+ );
33
72
  }
34
73
 
35
74
  /**
@@ -46,24 +85,26 @@ function resolveFlag(optValue, cfgValue, defaultWhenUndef = true) {
46
85
  }
47
86
 
48
87
  /**
49
- * Runs the up-infra command: resolves developer ID, traefik, pgAdmin, redisAdmin, and starts infra.
50
- * @param {Object} options - Commander options (developer, traefik, pgAdmin, redisAdmin)
51
- * @returns {Promise<void>}
88
+ * @param {Object} options - Commander options
89
+ * @returns {Promise<number|null>} Developer ID or null
52
90
  */
53
- async function runUpInfraCommand(options) {
54
- await config.ensureSecretsEncryptionKey();
55
- let developerId = null;
56
- if (options.developer) {
57
- const id = parseInt(options.developer, 10);
58
- if (isNaN(id) || id < 0) {
59
- throw new Error('Developer ID must be a non-negative number (0 = default infra, > 0 = developer-specific)');
60
- }
61
- await config.setDeveloperId(id);
62
- process.env.AIFABRIX_DEVELOPERID = id.toString();
63
- developerId = id;
64
- logger.log(chalk.green(`✓ Developer ID set to ${id}`));
91
+ async function applyDeveloperIdFromUpInfra(options) {
92
+ if (!options.developer) return null;
93
+ const id = parseInt(options.developer, 10);
94
+ if (isNaN(id) || id < 0) {
95
+ throw new Error('Developer ID must be a non-negative number (0 = default infra, > 0 = developer-specific)');
65
96
  }
66
- const cfg = await config.getConfig();
97
+ await config.setDeveloperId(id);
98
+ process.env.AIFABRIX_DEVELOPERID = id.toString();
99
+ logger.log(formatSuccessLine(`Developer ID set to ${id}`));
100
+ return id;
101
+ }
102
+
103
+ /**
104
+ * @param {Object} options
105
+ * @param {Object} cfg - Mutable config from getConfig()
106
+ */
107
+ async function persistOptionalInfraFlagsFromCli(options, cfg) {
67
108
  const flagSpecs = [
68
109
  { opt: options.traefik, key: 'traefik', label: 'Traefik' },
69
110
  { opt: options.pgAdmin, key: 'pgadmin', label: 'pgAdmin' },
@@ -74,25 +115,59 @@ async function runUpInfraCommand(options) {
74
115
  await persistOptionalServiceFlag(cfg, key, opt, label);
75
116
  }
76
117
  }
118
+ }
119
+
120
+ /**
121
+ * @param {Object} options
122
+ * @param {Object} cfg
123
+ */
124
+ async function maybePersistTlsFromUpInfra(options, cfg) {
125
+ // Commander maps --no-tls to options.tls === false (not a separate notls flag).
126
+ if (options.tls === true) await persistTlsEnabledFlag(cfg, true);
127
+ else if (options.tls === false) await persistTlsEnabledFlag(cfg, false);
128
+ }
129
+
130
+ /**
131
+ * Runs the up-infra command: resolves developer ID, traefik, pgAdmin, redisAdmin, and starts infra.
132
+ * @param {Object} options - Commander options (developer, traefik, pgAdmin, redisAdmin)
133
+ * @returns {Promise<void>}
134
+ */
135
+ async function runUpInfraCommand(options) {
136
+ await config.ensureSecretsEncryptionKey();
137
+ const developerId = await applyDeveloperIdFromUpInfra(options);
138
+ const cfg = await config.getConfig();
139
+ await persistOptionalInfraFlagsFromCli(options, cfg);
140
+ await maybePersistTlsFromUpInfra(options, cfg);
141
+ const adminPass = options.adminPassword || options.adminPwd;
142
+ const tlsEnabledEffective = cfg.tlsEnabled === true;
77
143
  await infra.startInfra(developerId, {
78
144
  traefik: resolveFlag(options.traefik, cfg.traefik, false),
79
145
  pgadmin: resolveFlag(options.pgAdmin, cfg.pgadmin, true),
80
146
  redisCommander: resolveFlag(options.redisAdmin, cfg.redisCommander, true),
81
- adminPwd: options.adminPwd
147
+ adminPassword: adminPass,
148
+ adminPwd: adminPass,
149
+ adminEmail: options.adminEmail,
150
+ userPassword: options.userPassword,
151
+ tlsEnabled: tlsEnabledEffective
82
152
  });
83
153
  }
84
154
 
85
155
  function setupUpInfraCommand(program) {
86
156
  program.command('up-infra')
87
- .description('Start local infrastructure: Postgres, Redis, optional pgAdmin, Redis Commander, Traefik')
157
+ .description('Start Postgres, Redis; optional pgAdmin, Redis Commander, Traefik')
158
+ .addHelpText('after', UP_INFRA_HELP_AFTER)
88
159
  .option('-d, --developer <id>', 'Set developer ID and start infrastructure')
89
- .option('--adminPwd <password>', 'Override default admin password for new install (Postgres, pgAdmin, Redis Commander)')
160
+ .option('--adminPassword <password>', 'Override {{adminPassword}} defaults (Postgres, pgAdmin, Redis Commander, catalog literals)')
161
+ .option('--adminEmail <email>', 'Override {{adminEmail}} default (e.g. pgAdmin login email)')
162
+ .option('--userPassword <password>', 'Override {{userPassword}} default (e.g. Keycloak default user password)')
90
163
  .option('--pgAdmin', 'Include pgAdmin web UI and save to config')
91
164
  .option('--no-pgAdmin', 'Exclude pgAdmin and save to config')
92
165
  .option('--redisAdmin', 'Include Redis Commander web UI and save to config')
93
166
  .option('--no-redisAdmin', 'Exclude Redis Commander and save to config')
94
167
  .option('--traefik', 'Include Traefik reverse proxy and save to config')
95
168
  .option('--no-traefik', 'Exclude Traefik and save to config')
169
+ .option('--tls', 'Enable TLS mode; save tlsEnabled (${TLS_ENABLED}=true, ${HTTP_ENABLED}=false in application.yaml)')
170
+ .option('--no-tls', 'Disable TLS mode (${TLS_ENABLED}=false, ${HTTP_ENABLED}=true)')
96
171
  .action(async(options) => {
97
172
  try {
98
173
  await runUpInfraCommand(options);
@@ -105,7 +180,7 @@ function setupUpInfraCommand(program) {
105
180
 
106
181
  function setupUpPlatformCommand(program) {
107
182
  program.command('up-platform')
108
- .description('Start platform (Keycloak, Miso Controller, Dataplane) from community images; infra must be up')
183
+ .description('Start Keycloak, Miso Controller, dataplane from images (needs up-infra)')
109
184
  .option('-r, --registry <url>', 'Override registry for all apps (e.g. myacr.azurecr.io)')
110
185
  .option('--registry-mode <mode>', 'Override registry mode (acr|external)')
111
186
  .option('-i, --image <key>=<value>', 'Override image (e.g. keycloak=myreg/k:v1, miso-controller=myreg/m:v1, dataplane=myreg/d:v1); can be repeated', (v, prev) => (prev || []).concat([v]))
@@ -138,7 +213,7 @@ function setupUpPlatformCommand(program) {
138
213
 
139
214
  function setupUpMisoCommand(program) {
140
215
  program.command('up-miso')
141
- .description('Install keycloak and miso-controller from images (no build). Infra must be up. For dataplane use up-dataplane. Uses auto-generated secrets for testing.')
216
+ .description('Start Keycloak + Miso Controller from images only (no dataplane; needs up-infra)')
142
217
  .option('-r, --registry <url>', 'Override registry for all apps (e.g. myacr.azurecr.io)')
143
218
  .option('--registry-mode <mode>', 'Override registry mode (acr|external)')
144
219
  .option('-i, --image <key>=<value>', 'Override image (e.g. keycloak=myreg/k:v1, miso-controller=myreg/m:v1); can be repeated', (v, prev) => (prev || []).concat([v]))
@@ -158,7 +233,7 @@ function setupUpMisoCommand(program) {
158
233
 
159
234
  function setupUpDataplaneCommand(program) {
160
235
  program.command('up-dataplane')
161
- .description('Register, deploy, then run dataplane app locally in dev (always local deployment; requires login, environment must be dev)')
236
+ .description('Register, deploy, run dataplane locally (dev env; login required)')
162
237
  .option('-r, --registry <url>', 'Override registry for dataplane image')
163
238
  .option('--registry-mode <mode>', 'Override registry mode (acr|external)')
164
239
  .option('-i, --image <ref>', 'Override dataplane image reference (e.g. myreg/dataplane:latest)')
@@ -189,8 +264,8 @@ function setupUpDataplaneCommand(program) {
189
264
  }
190
265
 
191
266
  function setupDownInfraCommand(program) {
192
- program.command('down-infra [app]')
193
- .description('Stop and remove local infrastructure services or a specific application')
267
+ program.command('down-infra [service|app]')
268
+ .description('Stop all infra, or stop one app; use -v to remove volumes')
194
269
  .option('-v, --volumes', 'Remove volumes (deletes all data)')
195
270
  .action(async(appName, options) => {
196
271
  try {
@@ -209,14 +284,14 @@ function setupDownInfraCommand(program) {
209
284
 
210
285
  function setupDoctorCommand(program) {
211
286
  program.command('doctor')
212
- .description('Check environment and configuration')
287
+ .description('Check Docker, ports, secrets, and infra health')
213
288
  .action(async() => {
214
289
  try {
215
290
  const result = await validator.checkEnvironment();
216
291
  logger.log('\n🔍 AI Fabrix Environment Check\n');
217
- logger.log(`Docker: ${result.docker === 'ok' ? ' Running' : ' Not available'}`);
218
- logger.log(`Ports: ${result.ports === 'ok' ? ' Available' : '⚠️ Some ports in use'}`);
219
- logger.log(`Secrets: ${result.secrets === 'ok' ? ' Configured' : ' Missing'}`);
292
+ logger.log(`Docker: ${result.docker === 'ok' ? ' Running' : ' Not available'}`);
293
+ logger.log(`Ports: ${result.ports === 'ok' ? ' Available' : ' Some ports in use'}`);
294
+ logger.log(`Secrets: ${result.secrets === 'ok' ? ' Configured' : ' Missing'}`);
220
295
  if (result.recommendations.length > 0) {
221
296
  logger.log('\n📋 Recommendations:');
222
297
  result.recommendations.forEach(rec => logger.log(` • ${rec}`));
@@ -231,7 +306,7 @@ function setupDoctorCommand(program) {
231
306
  });
232
307
  logger.log('\n🏥 Infrastructure Health:');
233
308
  Object.entries(health).forEach(([service, status]) => {
234
- const icon = status === 'healthy' ? '' : status === 'unknown' ? '❓' : '';
309
+ const icon = status === 'healthy' ? '' : status === 'unknown' ? '❓' : '';
235
310
  logger.log(` ${icon} ${service}: ${status}`);
236
311
  });
237
312
  } catch (error) {
@@ -248,17 +323,21 @@ function setupDoctorCommand(program) {
248
323
 
249
324
  function setupStatusCommand(program) {
250
325
  program.command('status')
251
- .description('Show detailed infrastructure service status and running applications')
326
+ .description('Show infra services and running apps (ports, URLs)')
252
327
  .action(async() => {
253
328
  try {
329
+ const summary = await loadInfraStatusSummary();
254
330
  const status = await infra.getInfraStatus();
255
- logger.log('\n📊 Infrastructure Status\n');
331
+ logger.log('');
332
+ logger.log(formatInfraStatusTitleLine(summary.devIdStr, summary.remoteServer));
333
+ logger.log('');
334
+ logInfraStatusConfigurationSummary(summary);
256
335
  Object.entries(status).forEach(([service, info]) => {
257
- const icon = String(info.status).trim().toLowerCase() === 'running' ? '' : '';
258
- logger.log(`${icon} ${service}:`);
259
- logger.log(` Status: ${info.status}`);
260
- logger.log(` Port: ${info.port}`);
261
- logger.log(` URL: ${info.url}`);
336
+ const icon = String(info.status).trim().toLowerCase() === 'running' ? '' : '';
337
+ logger.log(`${icon} ${service}`);
338
+ logPaddedFieldRow('Status', info.status);
339
+ logPaddedFieldRow('Port', info.port);
340
+ logPaddedFieldRow('URL', info.url);
262
341
  logger.log('');
263
342
  });
264
343
  const apps = await infra.getAppStatus();
@@ -266,12 +345,12 @@ function setupStatusCommand(program) {
266
345
  logger.log('📱 Running Applications\n');
267
346
  apps.forEach((appInfo) => {
268
347
  const s = String(appInfo.status).trim().toLowerCase();
269
- const icon = s.includes('running') || s.includes('up') ? '' : '';
270
- logger.log(`${icon} ${appInfo.name}:`);
271
- logger.log(` Container: ${appInfo.container}`);
272
- logger.log(` Port: ${appInfo.port}`);
273
- logger.log(` Status: ${appInfo.status}`);
274
- logger.log(` URL: ${appInfo.url}`);
348
+ const icon = s.includes('running') || s.includes('up') ? '' : '';
349
+ logger.log(`${icon} ${appInfo.name}`);
350
+ logPaddedFieldRow('Container', appInfo.container);
351
+ logPaddedFieldRow('Port', appInfo.port);
352
+ logPaddedFieldRow('Status', appInfo.status);
353
+ logPaddedFieldRow('URL', appInfo.url);
275
354
  logger.log('');
276
355
  });
277
356
  }
@@ -285,16 +364,16 @@ function setupStatusCommand(program) {
285
364
  const INFRA_SERVICES = ['postgres', 'redis', 'pgadmin', 'redis-commander', 'traefik'];
286
365
 
287
366
  function setupRestartCommand(program) {
288
- program.command('restart <service>')
289
- .description('Restart an infrastructure service or a Docker application (builder/<app>)')
367
+ program.command('restart <service|app>')
368
+ .description('Restart infra service (postgres, redis, …) or a builder/<app> container')
290
369
  .action(async(service) => {
291
370
  try {
292
371
  if (INFRA_SERVICES.includes(service)) {
293
372
  await infra.restartService(service);
294
- logger.log(`✅ ${service} service restarted successfully`);
373
+ logger.log(`✔ ${service} service restarted successfully`);
295
374
  } else {
296
375
  await appLib.restartApp(service);
297
- logger.log(`✅ ${service} restarted successfully`);
376
+ logger.log(`✔ ${service} restarted successfully`);
298
377
  }
299
378
  } catch (error) {
300
379
  handleCommandError(error, 'restart');
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview parameters subcommand (validate kv:// catalog coverage)
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ const { handleCommandError } = require('../utils/cli-utils');
8
+ const { handleParametersValidate } = require('../commands/parameters-validate');
9
+
10
+ /**
11
+ * @param {import('commander').Command} program - Commander program
12
+ */
13
+ function setupParametersCommands(program) {
14
+ const parameters = program
15
+ .command('parameters')
16
+ .description('Infra parameter catalog (kv:// keys, generators, Azure naming hints)');
17
+
18
+ parameters
19
+ .command('validate')
20
+ .description('Check env.template kv:// references against lib/schema/infra.parameter.yaml')
21
+ .option('--catalog <path>', 'Override path to infra.parameter.yaml')
22
+ .action(async(opts) => {
23
+ try {
24
+ const result = await handleParametersValidate({ catalogPath: opts.catalog });
25
+ if (!result.valid) process.exit(1);
26
+ } catch (error) {
27
+ handleCommandError(error, 'parameters validate');
28
+ }
29
+ });
30
+ }
31
+
32
+ module.exports = { setupParametersCommands };
@@ -6,7 +6,7 @@
6
6
  * @version 2.0.0
7
7
  */
8
8
 
9
- const chalk = require('chalk');
9
+ const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
10
10
  const { handleCommandError } = require('../utils/cli-utils');
11
11
  const { handleSecretsSet } = require('../commands/secrets-set');
12
12
  const { handleSecretsList } = require('../commands/secrets-list');
@@ -16,10 +16,101 @@ const { handleSecure } = require('../commands/secure');
16
16
  const config = require('../core/config');
17
17
  const logger = require('../utils/logger');
18
18
 
19
+ const SECRET_GROUP_HELP_AFTER = `
20
+ Subcommands:
21
+ list, set, remove, remove-all User secrets.local.yaml (add --shared for shared/remote)
22
+ set-secrets-file Point config at a shared secrets file or https URL
23
+ validate YAML structure (+ optional --naming)
24
+
25
+ Also: aifabrix secure Encrypt secrets.local.yaml (ISO 27001)
26
+
27
+ Examples:
28
+ $ aifabrix secret list
29
+ $ aifabrix secret set myapp/clientSecret "your-value"
30
+ $ aifabrix secret remove old-key
31
+ $ aifabrix secret remove-all
32
+ $ aifabrix secret validate
33
+
34
+ Shared over https: key BASH_NPM_TOKEN --shared → NPM_TOKEN available in terminal (exported).
35
+ `;
36
+
37
+ const SECRET_LIST_HELP_AFTER = `
38
+ Examples:
39
+ $ aifabrix secret list
40
+ $ aifabrix secret list --shared
41
+ `;
42
+
43
+ const SECRET_SET_HELP_AFTER = `
44
+ Examples:
45
+ $ aifabrix secret set myapp/clientSecret "your-secret"
46
+ $ aifabrix secret set hubspot/apiKey "$HUBSPOT_KEY"
47
+ $ aifabrix secret set team/shared-token "value" --shared
48
+ $ aifabrix secret set BASH_NPM_TOKEN "$NPM_TOKEN" --shared
49
+
50
+ With https aifabrix-secrets: keys named BASH_<NAME> --shared expose <NAME> in your
51
+ terminal as an exported env var (e.g. BASH_NPM_TOKEN → NPM_TOKEN).
52
+ `;
53
+
54
+ const SECRET_REMOVE_HELP_AFTER = `
55
+ Examples:
56
+ $ aifabrix secret remove deprecated-key
57
+ $ aifabrix secret remove shared-key --shared
58
+ `;
59
+
60
+ const SECRET_REMOVE_ALL_HELP_AFTER = `
61
+ You will be asked to type "yes" to confirm unless you pass --yes.
62
+
63
+ Examples:
64
+ $ aifabrix secret remove-all
65
+ $ aifabrix secret remove-all --yes
66
+ $ aifabrix secret remove-all --shared
67
+ $ aifabrix secret remove-all --shared --yes
68
+ `;
69
+
70
+ const SECRET_SET_SECRETS_FILE_HELP_AFTER = `
71
+ Examples:
72
+ $ aifabrix secret set-secrets-file ./shared-secrets.yaml
73
+ $ aifabrix secret set-secrets-file https://dev.example.com/api/secrets
74
+ $ aifabrix secret set-secrets-file ""
75
+ `;
76
+
77
+ const SECRET_VALIDATE_HELP_AFTER = `
78
+ Examples:
79
+ $ aifabrix secret validate
80
+ $ aifabrix secret validate ./secrets.local.yaml
81
+ $ aifabrix secret validate --naming
82
+ `;
83
+
84
+ const SECURE_HELP_AFTER = `
85
+ Examples:
86
+ $ aifabrix secure
87
+ $ aifabrix secure --secrets-encryption <32-byte-hex-or-base64>
88
+ `;
89
+
90
+ function setupSecretRemoveAllCommand(secretCmd) {
91
+ const { handleSecretsRemoveAll } = require('../commands/secrets-remove-all');
92
+ secretCmd
93
+ .command('remove-all')
94
+ .description('Remove all secret keys (requires typing "yes" unless --yes)')
95
+ .addHelpText('after', SECRET_REMOVE_ALL_HELP_AFTER)
96
+ .option('--shared', 'Remove all from shared secrets (file or remote API)')
97
+ .option('-y, --yes', 'Skip confirmation prompt (non-interactive / scripts)')
98
+ .action(async options => {
99
+ try {
100
+ await config.ensureSecretsEncryptionKey();
101
+ await handleSecretsRemoveAll(options);
102
+ } catch (error) {
103
+ handleCommandError(error, 'secret remove-all');
104
+ process.exit(1);
105
+ }
106
+ });
107
+ }
108
+
19
109
  function setupSecretValidateCommand(secretCmd) {
20
110
  secretCmd
21
111
  .command('validate [path]')
22
112
  .description('Validate secrets file (YAML structure and optional naming convention)')
113
+ .addHelpText('after', SECRET_VALIDATE_HELP_AFTER)
23
114
  .option('--naming', 'Check key names against *KeyVault convention')
24
115
  .action(async(pathArg, options) => {
25
116
  try {
@@ -39,7 +130,8 @@ function setupSecretValidateCommand(secretCmd) {
39
130
  */
40
131
  function setupSecureCommand(program) {
41
132
  program.command('secure')
42
- .description('Encrypt secrets in secrets.local.yaml files for ISO 27001 compliance')
133
+ .description('Encrypt secrets.local.yaml at rest (ISO 27001)')
134
+ .addHelpText('after', SECURE_HELP_AFTER)
43
135
  .option('--secrets-encryption <key>', 'Encryption key (32 bytes, hex or base64)')
44
136
  .action(async(options) => {
45
137
  try {
@@ -59,11 +151,13 @@ function setupSecureCommand(program) {
59
151
  function setupSecretsCommands(program) {
60
152
  const secretCmd = program
61
153
  .command('secret')
62
- .description('Manage secrets in secrets files');
154
+ .description('User and shared secrets (list, set, remove, remove-all, validate)')
155
+ .addHelpText('after', SECRET_GROUP_HELP_AFTER);
63
156
 
64
157
  secretCmd
65
158
  .command('list')
66
- .description('List secret keys (user or shared; use --shared for shared)')
159
+ .description('List secret keys (--shared for shared/remote)')
160
+ .addHelpText('after', SECRET_LIST_HELP_AFTER)
67
161
  .option('--shared', 'List shared secrets (from config aifabrix-secrets or remote API)')
68
162
  .action(async(options) => {
69
163
  try {
@@ -77,7 +171,8 @@ function setupSecretsCommands(program) {
77
171
 
78
172
  secretCmd
79
173
  .command('set <key> <value>')
80
- .description('Set a secret value in secrets file')
174
+ .description('Set a secret value')
175
+ .addHelpText('after', SECRET_SET_HELP_AFTER)
81
176
  .option('--shared', 'Save to general secrets file (from config.yaml aifabrix-secrets) instead of user secrets')
82
177
  .action(async(key, value, options) => {
83
178
  try {
@@ -91,7 +186,8 @@ function setupSecretsCommands(program) {
91
186
 
92
187
  secretCmd
93
188
  .command('remove <key>')
94
- .description('Remove a secret by key')
189
+ .description('Remove a secret key')
190
+ .addHelpText('after', SECRET_REMOVE_HELP_AFTER)
95
191
  .option('--shared', 'Remove from shared secrets (file or remote API)')
96
192
  .action(async(key, options) => {
97
193
  try {
@@ -103,6 +199,7 @@ function setupSecretsCommands(program) {
103
199
  }
104
200
  });
105
201
 
202
+ setupSecretRemoveAllCommand(secretCmd);
106
203
  setupSecretSetSecretsFileCommand(secretCmd);
107
204
  setupSecretValidateCommand(secretCmd);
108
205
  setupSecureCommand(program);
@@ -115,7 +212,8 @@ function setupSecretsCommands(program) {
115
212
  function setupSecretSetSecretsFileCommand(secretCmd) {
116
213
  secretCmd
117
214
  .command('set-secrets-file <path>')
118
- .description('Set aifabrix-secrets path in config (local file or https URL; pass empty to clear; path/URL is not checked for existence)')
215
+ .description('Set shared secrets path in config (file or https; empty clears; not validated)')
216
+ .addHelpText('after', SECRET_SET_SECRETS_FILE_HELP_AFTER)
119
217
  .action(async(secretsPath) => {
120
218
  try {
121
219
  const trimmed = (secretsPath || '').trim();
@@ -123,7 +221,7 @@ function setupSecretSetSecretsFileCommand(secretCmd) {
123
221
  throw new Error('Only https URLs are allowed for remote secrets');
124
222
  }
125
223
  await config.setSecretsPath(trimmed);
126
- logger.log(trimmed === '' ? chalk.green('Secrets file path cleared') : chalk.green(`✓ Secrets file path set to ${trimmed}`));
224
+ logger.log(trimmed === '' ? formatSuccessLine('Secrets file path cleared') : formatSuccessLine(`Secrets file path set to ${trimmed}`));
127
225
  } catch (error) {
128
226
  handleCommandError(error, 'secret set-secrets-file');
129
227
  process.exit(1);