@aifabrix/builder 2.45.5 → 2.47.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 (355) hide show
  1. package/.cursor/rules/cli-layout.mdc +2 -0
  2. package/.cursor/rules/cli-product-neutral.mdc +43 -0
  3. package/.cursor/rules/project-rules.mdc +1 -0
  4. package/.npmrc.token +1 -0
  5. package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
  6. package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
  7. package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
  8. package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
  9. package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
  10. package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
  11. package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
  12. package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
  13. package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
  14. package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
  15. package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
  16. package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
  17. package/.temp/validation/summary.txt +5 -0
  18. package/README.md +43 -17
  19. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
  20. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
  21. package/jest.config.default.js +2 -1
  22. package/jest.config.isolated.js +2 -1
  23. package/jest.global-live-fabrix-hooks.js +36 -0
  24. package/jest.isolated-projects.js +146 -0
  25. package/jest.projects.js +65 -136
  26. package/lib/api/api-response-errors.js +124 -0
  27. package/lib/api/dataplane-health.api.js +19 -7
  28. package/lib/api/governance-scenario-pack.api.js +159 -0
  29. package/lib/api/index.js +43 -3
  30. package/lib/api/lifecycle.api.js +98 -0
  31. package/lib/api/pipeline.api.js +3 -1
  32. package/lib/api/records-bulk.api.js +14 -1
  33. package/lib/api/resource-types.api.js +107 -0
  34. package/lib/api/runtime-configuration.api.js +72 -0
  35. package/lib/api/types/resource-types.types.js +45 -0
  36. package/lib/api/user-groups.api.js +9 -9
  37. package/lib/api/users.api.js +8 -8
  38. package/lib/api/validation-runner.js +3 -1
  39. package/lib/api/wizard.api.js +10 -2
  40. package/lib/app/deploy-config.js +4 -1
  41. package/lib/app/down.js +78 -27
  42. package/lib/app/index.js +2 -2
  43. package/lib/app/push.js +4 -5
  44. package/lib/app/register.js +7 -4
  45. package/lib/app/run-env-compose.js +84 -30
  46. package/lib/app/run-resolve-image.js +2 -1
  47. package/lib/app/run-stop-containers.js +113 -0
  48. package/lib/app/run.js +1 -31
  49. package/lib/app/show-display.js +35 -0
  50. package/lib/app/show.js +32 -1
  51. package/lib/build/index.js +22 -5
  52. package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
  53. package/lib/certification/sync-system-certification.js +13 -6
  54. package/lib/channels/add-channel.js +348 -0
  55. package/lib/channels/channel-artifact-generator.js +141 -0
  56. package/lib/channels/channel-audit.js +101 -0
  57. package/lib/channels/channel-auth-context.js +37 -0
  58. package/lib/channels/channel-credential.js +200 -0
  59. package/lib/channels/channel-display-name.js +64 -0
  60. package/lib/channels/channel-external-system.js +106 -0
  61. package/lib/channels/channel-integration-generator.js +274 -0
  62. package/lib/channels/channel-probe.js +89 -0
  63. package/lib/channels/channel-runtime-resolver.js +152 -0
  64. package/lib/channels/channel-status-display.js +141 -0
  65. package/lib/channels/channel-targets.js +115 -0
  66. package/lib/cli/index.js +20 -4
  67. package/lib/cli/infra-guided-auth.js +109 -0
  68. package/lib/cli/infra-guided.js +84 -81
  69. package/lib/cli/setup-app.help.js +0 -31
  70. package/lib/cli/setup-app.js +82 -5
  71. package/lib/cli/setup-app.test-commands.js +5 -57
  72. package/lib/cli/setup-auth.js +25 -0
  73. package/lib/cli/setup-certification-commands.js +147 -0
  74. package/lib/cli/setup-certification.help.js +141 -0
  75. package/lib/cli/setup-environment.js +19 -2
  76. package/lib/cli/setup-external-system-help.js +62 -0
  77. package/lib/cli/setup-external-system.js +25 -3
  78. package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
  79. package/lib/cli/setup-infra-up-platform-action.js +2 -1
  80. package/lib/cli/setup-infra.js +9 -1
  81. package/lib/cli/setup-platform.js +6 -1
  82. package/lib/cli/setup-secrets.js +33 -1
  83. package/lib/cli/setup-utility-help-after.js +25 -2
  84. package/lib/cli/setup-utility-repair.js +198 -0
  85. package/lib/cli/setup-utility-resolve.js +44 -5
  86. package/lib/cli/setup-utility-validate.js +197 -0
  87. package/lib/cli/setup-utility.js +4 -239
  88. package/lib/commands/app-logs.js +54 -26
  89. package/lib/commands/app.js +41 -0
  90. package/lib/commands/auth-status-client-tokens.js +214 -0
  91. package/lib/commands/auth-status-dataplane-version.js +142 -68
  92. package/lib/commands/auth-status.js +43 -54
  93. package/lib/commands/channel.js +58 -0
  94. package/lib/commands/datasource-test-trust-cli.js +27 -23
  95. package/lib/commands/datasource-unified-test-cli.js +6 -3
  96. package/lib/commands/datasource-unified-test-cli.options.js +5 -1
  97. package/lib/commands/datasource.js +8 -8
  98. package/lib/commands/dev-show-display.js +8 -1
  99. package/lib/commands/governance-cli-shared.js +94 -0
  100. package/lib/commands/governance-command-action.js +132 -0
  101. package/lib/commands/governance-download-external.js +34 -0
  102. package/lib/commands/governance-generate-external.js +71 -0
  103. package/lib/commands/governance-upload-external.js +36 -0
  104. package/lib/commands/governance-verify-external.js +64 -0
  105. package/lib/commands/governance.js +144 -0
  106. package/lib/commands/identity-apply-sync.js +49 -8
  107. package/lib/commands/identity-group-cli.js +66 -26
  108. package/lib/commands/identity-membership-role-cache.js +58 -37
  109. package/lib/commands/identity-shared.js +22 -1
  110. package/lib/commands/identity-user-cli.js +80 -34
  111. package/lib/commands/lifecycle-command-action.js +123 -0
  112. package/lib/commands/lifecycle-external.js +268 -0
  113. package/lib/commands/login.js +11 -2
  114. package/lib/commands/repair-auth-apply.js +153 -0
  115. package/lib/commands/repair-auth-config.js +8 -13
  116. package/lib/commands/repair-changed-files.js +41 -0
  117. package/lib/commands/repair-datasource-com-v2.js +15 -0
  118. package/lib/commands/repair-datasource-keys.js +4 -1
  119. package/lib/commands/repair-datasource-run.js +59 -0
  120. package/lib/commands/repair-datasource-service-contract.js +206 -0
  121. package/lib/commands/repair-datasource-test-payload.js +259 -0
  122. package/lib/commands/repair-datasource.js +49 -64
  123. package/lib/commands/repair-env-template.js +76 -25
  124. package/lib/commands/repair-external-run.js +216 -0
  125. package/lib/commands/repair-openapi-sync.js +49 -4
  126. package/lib/commands/repair-persist.js +4 -0
  127. package/lib/commands/repair-rbac.js +52 -1
  128. package/lib/commands/repair-steps.js +160 -0
  129. package/lib/commands/repair-system-alignment.js +7 -4
  130. package/lib/commands/repair.js +29 -296
  131. package/lib/commands/resource-type.js +371 -0
  132. package/lib/commands/secrets-get.js +184 -0
  133. package/lib/commands/secrets-remove-all.js +3 -1
  134. package/lib/commands/setup-image-refresh.js +146 -0
  135. package/lib/commands/setup-modes.js +158 -162
  136. package/lib/commands/setup-platform-auth.js +76 -0
  137. package/lib/commands/setup-prompts-admin.js +244 -0
  138. package/lib/commands/setup-prompts-platform-mode.js +70 -0
  139. package/lib/commands/setup-prompts-validators.js +36 -0
  140. package/lib/commands/setup-prompts.js +24 -76
  141. package/lib/commands/setup-run-context.js +45 -0
  142. package/lib/commands/setup-spinners.js +39 -0
  143. package/lib/commands/setup.js +27 -5
  144. package/lib/commands/teardown.js +39 -0
  145. package/lib/commands/test-e2e-external.js +24 -8
  146. package/lib/commands/test-governance-external.js +3 -24
  147. package/lib/commands/test-trust-external.js +48 -100
  148. package/lib/commands/up-common.js +57 -13
  149. package/lib/commands/up-dataplane.js +56 -15
  150. package/lib/commands/upload-publish-context.js +75 -0
  151. package/lib/commands/upload-sidecar-followups.js +89 -0
  152. package/lib/commands/upload.js +113 -110
  153. package/lib/commands/verify-governance-combined-external.js +61 -0
  154. package/lib/commands/verify-governance-command-action.js +64 -0
  155. package/lib/commands/verify-governance-db.js +102 -0
  156. package/lib/commands/verify-governance-external.js +77 -0
  157. package/lib/commands/verify-governance-result-builders.js +71 -0
  158. package/lib/commands/verify-operations-command-action.js +68 -0
  159. package/lib/commands/verify-operations-external.js +268 -0
  160. package/lib/commands/verify-operations-persist.js +75 -0
  161. package/lib/commands/verify-operations-step-plan.js +68 -0
  162. package/lib/commands/verify-operations-steps.js +111 -0
  163. package/lib/commands/verify-trust-command-action.js +73 -0
  164. package/lib/commands/verify-trust-external.js +59 -0
  165. package/lib/commands/wizard-config-normalizer.js +43 -23
  166. package/lib/commands/wizard-core.js +2 -0
  167. package/lib/core/admin-password-generator.js +38 -0
  168. package/lib/core/admin-secrets-bundle.js +111 -0
  169. package/lib/core/admin-secrets-env-overlay.js +62 -0
  170. package/lib/core/admin-secrets.js +32 -4
  171. package/lib/core/config-attach-extensions.js +3 -0
  172. package/lib/core/config-platform-controller.js +44 -0
  173. package/lib/core/config-setup-installation-profile.js +42 -0
  174. package/lib/core/config-setup-platform-mode.js +46 -0
  175. package/lib/core/config.js +46 -36
  176. package/lib/core/secrets-admin-env.js +6 -2
  177. package/lib/core/secrets-ensure.js +4 -0
  178. package/lib/core/secrets-env-content.js +54 -48
  179. package/lib/core/secrets-env-write.js +10 -1
  180. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  181. package/lib/core/setup-installation-profile.js +43 -0
  182. package/lib/core/setup-platform-mode.js +90 -0
  183. package/lib/datasource/agent-trust-debug-log.js +1 -1
  184. package/lib/datasource/agent-trust-run.js +5 -3
  185. package/lib/datasource/audit-evidence-extract-debug.js +30 -18
  186. package/lib/datasource/audit-evidence-extract.js +7 -4
  187. package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
  188. package/lib/datasource/bulk-loader-run-batches.js +15 -3
  189. package/lib/datasource/capability/capability-diff-slice.js +2 -2
  190. package/lib/datasource/capability/capability-manifest.js +254 -0
  191. package/lib/datasource/capability/capability-resolve.js +3 -4
  192. package/lib/datasource/capability/copy-operations.js +5 -3
  193. package/lib/datasource/capability/remove-operations.js +2 -1
  194. package/lib/datasource/capability/run-capability-copy.js +32 -4
  195. package/lib/datasource/capability/run-capability-diff.js +3 -3
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -4
  197. package/lib/datasource/capability/run-capability-edit.js +4 -7
  198. package/lib/datasource/capability/run-capability-relate.js +2 -4
  199. package/lib/datasource/capability/run-capability-remove.js +2 -4
  200. package/lib/datasource/capability/validate-capability-slice.js +2 -1
  201. package/lib/datasource/datasource-identifier.js +2 -1
  202. package/lib/datasource/datasource-load-export-context.js +3 -0
  203. package/lib/datasource/datasource-validate-display.js +1 -1
  204. package/lib/datasource/field-reference-validator.js +24 -3
  205. package/lib/datasource/log-cleaner.js +2 -2
  206. package/lib/datasource/log-viewer.js +8 -8
  207. package/lib/datasource/orphan-profiles-validator.js +98 -0
  208. package/lib/datasource/test-e2e.js +4 -1
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run.js +5 -2
  211. package/lib/datasource/validate.js +41 -23
  212. package/lib/deployment/environment-poll-status.js +138 -0
  213. package/lib/deployment/environment.js +42 -34
  214. package/lib/external-system/download-helpers.js +87 -0
  215. package/lib/external-system/download.js +78 -138
  216. package/lib/external-system/generator.js +1 -55
  217. package/lib/external-system/integration-auth-context.js +45 -0
  218. package/lib/external-system/test-auth.js +12 -5
  219. package/lib/external-system/test.js +16 -21
  220. package/lib/generator/builders.js +11 -1
  221. package/lib/generator/external-controller-manifest.js +18 -0
  222. package/lib/generator/split.js +3 -1
  223. package/lib/generator/wizard.js +1 -28
  224. package/lib/governance/governance-cli-errors.js +96 -0
  225. package/lib/governance/governance-download-display.js +38 -0
  226. package/lib/governance/governance-run-display.js +215 -25
  227. package/lib/identity/fk-reference.js +65 -0
  228. package/lib/identity/identity-apply-core.js +13 -58
  229. package/lib/identity/identity-apply-phases.js +5 -1
  230. package/lib/identity/identity-display.js +243 -0
  231. package/lib/identity/identity-response-helpers.js +52 -0
  232. package/lib/identity/identity-sync-errors.js +62 -0
  233. package/lib/identity/resolve-user-id.js +129 -0
  234. package/lib/identity/username-default.js +31 -0
  235. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  236. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  237. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  238. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  239. package/lib/infrastructure/helpers.js +23 -129
  240. package/lib/infrastructure/index.js +5 -6
  241. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  242. package/lib/lifecycle/certification-progress.js +231 -0
  243. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  244. package/lib/lifecycle/exit-codes.js +24 -0
  245. package/lib/lifecycle/json-envelope.js +25 -0
  246. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  247. package/lib/lifecycle/logger-quiet.js +29 -0
  248. package/lib/lifecycle/open-api-published.js +59 -0
  249. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  250. package/lib/lifecycle/product-model.js +196 -0
  251. package/lib/lifecycle/report-display-trust.js +70 -0
  252. package/lib/lifecycle/report-display.js +472 -0
  253. package/lib/lifecycle/scenario-upload.js +191 -0
  254. package/lib/lifecycle/verify-step-progress.js +87 -0
  255. package/lib/parameters/infra-kv-discovery.js +27 -2
  256. package/lib/protection/auth-context.js +10 -4
  257. package/lib/resolvers/datasource-resolver.js +2 -3
  258. package/lib/resolvers/resource-type-file.js +159 -0
  259. package/lib/schema/application-schema.json +17 -1
  260. package/lib/schema/datasource-test-run.schema.json +89 -6
  261. package/lib/schema/deployment-rules.yaml +2 -1
  262. package/lib/schema/external-datasource.schema.json +2947 -2619
  263. package/lib/schema/external-system.schema.json +1418 -761
  264. package/lib/schema/infra.parameter.yaml +45 -0
  265. package/lib/schema/type/credential-field-registry.json +103 -97
  266. package/lib/schema/type/document-storage.json +9 -5
  267. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  268. package/lib/utils/api.js +55 -31
  269. package/lib/utils/app-relative-path-env.js +112 -0
  270. package/lib/utils/app-run-containers.js +25 -2
  271. package/lib/utils/authentication-shape.js +224 -0
  272. package/lib/utils/build-copy.js +36 -5
  273. package/lib/utils/build-resolve-image.js +66 -12
  274. package/lib/utils/celery-companion-apps.js +53 -0
  275. package/lib/utils/cli-secrets-error-format.js +83 -21
  276. package/lib/utils/cli-utils.js +20 -4
  277. package/lib/utils/compose-celery-worker.js +23 -0
  278. package/lib/utils/compose-generate-docker-compose.js +13 -1
  279. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  280. package/lib/utils/config-secrets-path.js +46 -0
  281. package/lib/utils/configuration-env-resolver.js +36 -0
  282. package/lib/utils/controller-url.js +88 -1
  283. package/lib/utils/credential-secrets-env-kv.js +216 -0
  284. package/lib/utils/credential-secrets-env.js +175 -257
  285. package/lib/utils/dataplane-resolver.js +18 -2
  286. package/lib/utils/declarative-url-ports.js +27 -4
  287. package/lib/utils/deployment-auth-mode.js +41 -0
  288. package/lib/utils/developer-volume-id.js +33 -0
  289. package/lib/utils/docker-build.js +1 -4
  290. package/lib/utils/env-copy.js +14 -9
  291. package/lib/utils/env-kv-orphan-lines.js +43 -0
  292. package/lib/utils/error-formatters/network-errors.js +13 -4
  293. package/lib/utils/external-env-template.js +11 -3
  294. package/lib/utils/external-system-readiness-core.js +10 -0
  295. package/lib/utils/external-system-readiness-display.js +80 -23
  296. package/lib/utils/external-system-validators.js +8 -2
  297. package/lib/utils/health-check.js +4 -1
  298. package/lib/utils/help-builder.js +13 -8
  299. package/lib/utils/keycloak-realm-ready.js +101 -0
  300. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  301. package/lib/utils/manifest-source-emit.js +2 -0
  302. package/lib/utils/paths.js +25 -0
  303. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  304. package/lib/utils/platform-controller-url.js +157 -0
  305. package/lib/utils/platform-kv-ref.js +57 -0
  306. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  307. package/lib/utils/postgres-wipe.js +9 -2
  308. package/lib/utils/resolve-env-mode.js +47 -0
  309. package/lib/utils/runtime-configuration-download.js +189 -0
  310. package/lib/utils/runtime-configuration-values.js +119 -0
  311. package/lib/utils/schema-loader.js +19 -4
  312. package/lib/utils/secrets-generator.js +31 -25
  313. package/lib/utils/secrets-missing-error.js +164 -0
  314. package/lib/utils/service-url-label.js +81 -0
  315. package/lib/utils/setup-quiet-output.js +25 -0
  316. package/lib/utils/template-helpers.js +15 -0
  317. package/lib/utils/token-manager-client-credentials.js +201 -0
  318. package/lib/utils/token-manager-messages.js +8 -0
  319. package/lib/utils/token-manager-refresh.js +12 -2
  320. package/lib/utils/token-manager.js +86 -105
  321. package/lib/utils/upload-pipeline-ui.js +12 -5
  322. package/lib/utils/upload-sync-options.js +42 -0
  323. package/lib/utils/url-declarative-public-base.js +21 -3
  324. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  325. package/lib/utils/validation-poll-ui.js +8 -0
  326. package/lib/utils/validation-run-stage.js +45 -0
  327. package/lib/utils/worker-sidecars.js +142 -0
  328. package/lib/validation/external-manifest-validator.js +2 -0
  329. package/lib/validation/runtime-configuration-rules.js +98 -0
  330. package/lib/validation/validate-display-dimensions.js +154 -0
  331. package/lib/validation/validate-display-sections.js +276 -0
  332. package/lib/validation/validate-display-steps.js +67 -0
  333. package/lib/validation/validate-display.js +24 -402
  334. package/package.json +1 -1
  335. package/templates/applications/dataplane/application.yaml +7 -1
  336. package/templates/applications/dataplane/env.template +50 -14
  337. package/templates/applications/dataplane/rbac.yaml +108 -1
  338. package/templates/applications/miso-controller/application.yaml +2 -2
  339. package/templates/applications/miso-controller/env.template +53 -122
  340. package/templates/applications/miso-controller/rbac.yaml +28 -13
  341. package/templates/channels/chatgpt/install.template.md.hbs +49 -0
  342. package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
  343. package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
  344. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
  345. package/templates/channels/slack/install.template.md.hbs +49 -0
  346. package/templates/channels/slack/manifest.template.json.hbs +66 -0
  347. package/templates/channels/teams-bot/install.template.md.hbs +49 -0
  348. package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
  349. package/templates/channels/web-embed/install.template.md.hbs +49 -0
  350. package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
  351. package/templates/external-system/README.md.hbs +74 -17
  352. package/templates/python/docker-compose.hbs +75 -18
  353. package/templates/typescript/docker-compose.hbs +70 -17
  354. package/lib/commands/test-governance-command-action.js +0 -55
  355. package/lib/commands/test-trust-command-action.js +0 -118
@@ -0,0 +1,197 @@
1
+ /**
2
+ * `aifabrix validate` and `diff` command wiring (split from setup-utility for size limits).
3
+ *
4
+ * @fileoverview Validate and diff CLI commands
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('fs');
12
+ const chalk = require('chalk');
13
+ const logger = require('../utils/logger');
14
+ const { handleCommandError } = require('../utils/cli-utils');
15
+ const { VALIDATE_HELP_AFTER } = require('./setup-utility-help-after');
16
+
17
+ /**
18
+ * @param {string} appOrFile
19
+ * @param {object} result
20
+ * @param {string} outFormat
21
+ */
22
+ function emitManifestAfterValidateIfApplicable(appOrFile, result, outFormat) {
23
+ if (outFormat === 'json' || !result?.appPath || !appOrFile || typeof appOrFile !== 'string') {
24
+ return;
25
+ }
26
+ try {
27
+ if (fs.existsSync(appOrFile) && fs.statSync(appOrFile).isFile()) {
28
+ return;
29
+ }
30
+ const { emitManifestMetadataLineIfTTY } = require('../utils/manifest-source-emit');
31
+ emitManifestMetadataLineIfTTY(logger, {
32
+ appKey: appOrFile,
33
+ appPath: result.appPath,
34
+ envOnly: false,
35
+ json: false
36
+ });
37
+ } catch {
38
+ /* ignore emit failures */
39
+ }
40
+ }
41
+
42
+ /**
43
+ * @param {object} validate
44
+ * @param {object} opts
45
+ * @returns {Promise<boolean>}
46
+ */
47
+ async function runValidateBatchBranch(validate, opts) {
48
+ const integration = opts.integration === true;
49
+ const builder = opts.builder === true;
50
+ if (!integration && !builder) {
51
+ return false;
52
+ }
53
+ const outFormat = (opts.format || 'default').toLowerCase();
54
+ const batchResult = integration && builder
55
+ ? await validate.validateAll(opts)
56
+ : integration
57
+ ? await validate.validateAllIntegrations(opts)
58
+ : await validate.validateAllBuilderApps(opts);
59
+ if (outFormat === 'json') {
60
+ logger.log(JSON.stringify(batchResult, null, 2));
61
+ } else {
62
+ validate.displayBatchValidationResults(batchResult);
63
+ }
64
+ if (!batchResult.valid) process.exit(1);
65
+ return true;
66
+ }
67
+
68
+ /**
69
+ * @param {string} appOrFile
70
+ * @param {object} opts
71
+ * @returns {Promise<void>}
72
+ */
73
+ async function runProtectionValidateBranch(appOrFile, opts) {
74
+ const { validateProtectionBatchCommand } = require('../protection/validate-batch');
75
+ const code = await validateProtectionBatchCommand(
76
+ {
77
+ env: opts.env,
78
+ json: (opts.format || '').toLowerCase() === 'json',
79
+ warningsAsErrors: opts.warningsAsErrors === true,
80
+ simulate: opts.simulate === true,
81
+ verbose: opts.verbose === true
82
+ },
83
+ logger
84
+ );
85
+ if (code !== 0) {
86
+ process.exit(code);
87
+ }
88
+ }
89
+
90
+ /**
91
+ * @param {object} result
92
+ * @param {string} appOrFile
93
+ * @returns {object}
94
+ */
95
+ function buildValidateJsonPayload(result, appOrFile) {
96
+ let payload = result;
97
+ try {
98
+ if (result?.appPath && appOrFile && typeof appOrFile === 'string') {
99
+ if (!(fs.existsSync(appOrFile) && fs.statSync(appOrFile).isFile())) {
100
+ const { getManifestSourcePayload } = require('../utils/manifest-source-emit');
101
+ payload = { ...result, manifestSource: getManifestSourcePayload(appOrFile, result.appPath) };
102
+ }
103
+ }
104
+ } catch {
105
+ /* keep plain result */
106
+ }
107
+ return payload;
108
+ }
109
+
110
+ /**
111
+ * @param {string} appOrFile
112
+ * @param {object} result
113
+ * @param {string} outFormat
114
+ * @param {object} validate
115
+ */
116
+ function displaySingleValidateResult(appOrFile, result, outFormat, validate) {
117
+ emitManifestAfterValidateIfApplicable(appOrFile, result, outFormat);
118
+ if (outFormat === 'json') {
119
+ logger.log(JSON.stringify(buildValidateJsonPayload(result, appOrFile), null, 2));
120
+ return;
121
+ }
122
+ validate.displayValidationResults(result);
123
+ }
124
+
125
+ /**
126
+ * @param {string} appOrFile
127
+ * @param {object} options
128
+ * @returns {Promise<void>}
129
+ */
130
+ async function runValidateCommand(appOrFile, options) {
131
+ const validate = require('../validation/validate');
132
+ const opts = options.opts ? options.opts() : options;
133
+ const { isProtectionScope } = require('../protection/scope');
134
+ if (isProtectionScope(appOrFile)) {
135
+ await runProtectionValidateBranch(appOrFile, opts);
136
+ return;
137
+ }
138
+ if (await runValidateBatchBranch(validate, opts)) {
139
+ return;
140
+ }
141
+ const outFormat = (opts.format || 'default').toLowerCase();
142
+ if (!appOrFile || typeof appOrFile !== 'string') {
143
+ logger.log(chalk.red('App name or file path is required, or use --integration / --builder'));
144
+ process.exit(1);
145
+ }
146
+ const result = await validate.validateAppOrFile(appOrFile, {
147
+ ...opts,
148
+ certSync: opts.certSync === true
149
+ });
150
+ displaySingleValidateResult(appOrFile, result, outFormat, validate);
151
+ if (!result.valid) process.exit(1);
152
+ }
153
+
154
+ /**
155
+ * @param {import('commander').Command} program
156
+ */
157
+ function setupValidateDiffCommands(program) {
158
+ program.command('validate [appKey|systemKey|file]')
159
+ .description('Validate appKey, systemKey, file path, .protection batch, or all under integration/ and builder/')
160
+ .addHelpText('after', VALIDATE_HELP_AFTER)
161
+ .option('--format <format>', 'Output format: json | default (human-readable)')
162
+ .option('--integration', 'Validate all applications under integration/')
163
+ .option('--builder', 'Validate all applications under builder/')
164
+ .option('--warnings-as-errors', 'For .protection: pass strict=true to dataplane validate')
165
+ .option('--simulate', 'For .protection: run simulate after validate')
166
+ .option(
167
+ '--cert-sync',
168
+ 'After successful validation of an external integration, refresh the system file certification block from the dataplane (requires login)'
169
+ )
170
+ .action((appOrFile, options) => {
171
+ runValidateCommand(appOrFile, options).catch((error) => {
172
+ handleCommandError(error, 'validate');
173
+ process.exit(1);
174
+ });
175
+ });
176
+
177
+ program.command('diff <file1> <file2>')
178
+ .description('Diff two config files (optional schema validate)')
179
+ .option('--no-validate', 'Skip schema validation (type check still applied)')
180
+ .action(async(file1, file2, cmd) => {
181
+ try {
182
+ const diff = require('../core/diff');
183
+ const opts = cmd.opts();
184
+ const result = await diff.compareFiles(file1, file2, { validate: opts.validate !== false });
185
+ diff.formatDiffOutput(result);
186
+ if (!result.identical) process.exit(1);
187
+ } catch (error) {
188
+ handleCommandError(error, 'diff');
189
+ process.exit(1);
190
+ }
191
+ });
192
+ }
193
+
194
+ module.exports = {
195
+ setupValidateDiffCommands,
196
+ runValidateCommand
197
+ };
@@ -1,4 +1,3 @@
1
- const { formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
2
1
  /**
3
2
  * CLI utility command setup (resolve, json, split-json, show, validate, diff).
4
3
  *
@@ -10,12 +9,15 @@ const { formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
10
9
  const path = require('path');
11
10
  const fs = require('fs');
12
11
  const chalk = require('chalk');
12
+ const { formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
13
13
  const generator = require('../generator');
14
14
  const logger = require('../utils/logger');
15
15
  const { handleCommandError, logOfflinePathWhenType } = require('../utils/cli-utils');
16
16
  const { detectAppType, getDeployJsonPath, getResolveAppPath } = require('../utils/paths');
17
17
  const { setupResolveCommand } = require('./setup-utility-resolve');
18
- const { JSON_HELP_AFTER, VALIDATE_HELP_AFTER, REPAIR_HELP_AFTER } = require('./setup-utility-help-after');
18
+ const { setupRepairCommand } = require('./setup-utility-repair');
19
+ const { setupValidateDiffCommands } = require('./setup-utility-validate');
20
+ const { JSON_HELP_AFTER } = require('./setup-utility-help-after');
19
21
 
20
22
  /**
21
23
  * Resolve app path and type for split-json (integration first, then builder).
@@ -136,100 +138,6 @@ function setupSplitJsonCommand(program) {
136
138
  });
137
139
  }
138
140
 
139
- function buildRepairExternalIntegrationOptions(appName, options, format) {
140
- const all = options.all === true;
141
- return {
142
- auth: options.auth,
143
- doc: options.doc || all,
144
- dryRun: options.dryRun,
145
- format,
146
- rbac: options.rbac || all,
147
- expose: options.expose || all,
148
- sync: options.sync || all,
149
- api: options.api || all,
150
- test: options.test || all,
151
- backup: options.backup,
152
- noBackup: options.noBackup
153
- };
154
- }
155
-
156
- function logRepairResult(options, result) {
157
- if (options.dryRun && result.updated && result.changes.length > 0) {
158
- logger.log(chalk.yellow('\nWould apply:'));
159
- result.changes.forEach(c => logger.log(chalk.gray(` ${c}`)));
160
- return;
161
- }
162
- if (Array.isArray(result.backupPaths) && result.backupPaths.length > 0) {
163
- result.backupPaths.forEach((p) => logger.log(chalk.gray(`Backup: ${p}`)));
164
- }
165
- if (result.updated) {
166
- logger.log(formatSuccessParagraph('Repaired external integration config.'));
167
- return;
168
- }
169
- if (Array.isArray(result.changes) && result.changes.length > 0) {
170
- logger.log(formatSuccessParagraph('Repair actions completed.'));
171
- result.changes.forEach(c => logger.log(chalk.gray(` ${c}`)));
172
- return;
173
- }
174
- if (result.readmeRegenerated) {
175
- logger.log(formatSuccessParagraph('Regenerated README.md from deployment manifest.'));
176
- return;
177
- }
178
- logger.log(chalk.gray('No changes needed; config already matches files on disk.'));
179
- }
180
-
181
- /**
182
- * Handler for `aifabrix repair <systemKey>`.
183
- * @param {string} appName
184
- * @param {object} options - Commander options
185
- * @returns {Promise<void>}
186
- */
187
- async function handleRepairCommand(appName, options) {
188
- const { repairExternalIntegration } = require('../commands/repair');
189
- const { detectAppType } = require('../utils/paths');
190
- const { appPath } = await detectAppType(appName);
191
- logOfflinePathWhenType(appPath);
192
- let format = 'yaml';
193
- try {
194
- const config = require('../core/config');
195
- format = (await config.getFormat()) || format;
196
- } catch (_) {
197
- /* default yaml when config unavailable */
198
- }
199
- const result = await repairExternalIntegration(
200
- appName,
201
- buildRepairExternalIntegrationOptions(appName, options, format)
202
- );
203
- logRepairResult(options, result);
204
- }
205
-
206
- function setupRepairCommand(program) {
207
- program.command('repair <systemKey>')
208
- .description('Fix external integration drift (files, RBAC, manifest, …)')
209
- .option('--all', 'Run all repair actions (api, doc, expose, rbac, sync, test)')
210
- .option(
211
- '--api',
212
- 'Validate and sync API contracts needed for OpenAPI/MCP (uses local OpenAPI specs at integration/<systemKey>/openapi/*.json when present)'
213
- )
214
- .option('--auth <method>', 'Set authentication method (oauth2, aad, apikey, basic, queryParam, oidc, hmac, none); updates system file and env.template')
215
- .option('--doc', 'Regenerate README.md from deployment manifest')
216
- .option('--expose', 'Set exposed.schema on each datasource from all fieldMappings.attributes keys (metadata.<key>); removes deprecated exposed.attributes if present')
217
- .option('--rbac', 'Ensure RBAC permissions per datasource and add default Admin/Reader roles if none exist')
218
- .option('--sync', 'Add default sync section to datasources that lack it')
219
- .option('--test', 'Generate testPayload.payloadTemplate and testPayload.expectedResult from attributes')
220
- .option('--no-backup', 'Skip timestamped copies under integration/<systemKey>/backup/')
221
- .option('--dry-run', 'Report changes only; do not write')
222
- .addHelpText('after', REPAIR_HELP_AFTER)
223
- .action(async(appName, options) => {
224
- try {
225
- await handleRepairCommand(appName, options);
226
- } catch (error) {
227
- handleCommandError(error, 'repair');
228
- process.exit(1);
229
- }
230
- });
231
- }
232
-
233
141
  async function resolveConvertTargetFormat(options) {
234
142
  const config = require('../core/config');
235
143
  const effectiveFormat = options.format || (await config.getFormat());
@@ -316,149 +224,6 @@ function setupSplitJsonConvertShowCommands(program) {
316
224
  setupShowCommand(program);
317
225
  }
318
226
 
319
- function emitManifestAfterValidateIfApplicable(appOrFile, result, outFormat) {
320
- if (outFormat === 'json' || !result?.appPath || !appOrFile || typeof appOrFile !== 'string') {
321
- return;
322
- }
323
- try {
324
- if (fs.existsSync(appOrFile) && fs.statSync(appOrFile).isFile()) {
325
- return;
326
- }
327
- const { emitManifestMetadataLineIfTTY } = require('../utils/manifest-source-emit');
328
- emitManifestMetadataLineIfTTY(logger, {
329
- appKey: appOrFile,
330
- appPath: result.appPath,
331
- envOnly: false,
332
- json: false
333
- });
334
- } catch {
335
- /* ignore emit failures */
336
- }
337
- }
338
-
339
- async function runValidateBatchBranch(validate, opts) {
340
- const integration = opts.integration === true;
341
- const builder = opts.builder === true;
342
- if (!integration && !builder) {
343
- return false;
344
- }
345
- const outFormat = (opts.format || 'default').toLowerCase();
346
- const batchResult = integration && builder
347
- ? await validate.validateAll(opts)
348
- : integration
349
- ? await validate.validateAllIntegrations(opts)
350
- : await validate.validateAllBuilderApps(opts);
351
- if (outFormat === 'json') {
352
- logger.log(JSON.stringify(batchResult, null, 2));
353
- } else {
354
- validate.displayBatchValidationResults(batchResult);
355
- }
356
- if (!batchResult.valid) process.exit(1);
357
- return true;
358
- }
359
-
360
- async function runProtectionValidateBranch(appOrFile, opts) {
361
- const { validateProtectionBatchCommand } = require('../protection/validate-batch');
362
- const code = await validateProtectionBatchCommand(
363
- {
364
- env: opts.env,
365
- json: (opts.format || '').toLowerCase() === 'json',
366
- warningsAsErrors: opts.warningsAsErrors === true,
367
- simulate: opts.simulate === true,
368
- verbose: opts.verbose === true
369
- },
370
- logger
371
- );
372
- if (code !== 0) {
373
- process.exit(code);
374
- }
375
- }
376
-
377
- function buildValidateJsonPayload(result, appOrFile) {
378
- let payload = result;
379
- try {
380
- if (result?.appPath && appOrFile && typeof appOrFile === 'string') {
381
- if (!(fs.existsSync(appOrFile) && fs.statSync(appOrFile).isFile())) {
382
- const { getManifestSourcePayload } = require('../utils/manifest-source-emit');
383
- payload = { ...result, manifestSource: getManifestSourcePayload(appOrFile, result.appPath) };
384
- }
385
- }
386
- } catch {
387
- /* keep plain result */
388
- }
389
- return payload;
390
- }
391
-
392
- function displaySingleValidateResult(appOrFile, result, outFormat, validate) {
393
- emitManifestAfterValidateIfApplicable(appOrFile, result, outFormat);
394
- if (outFormat === 'json') {
395
- logger.log(JSON.stringify(buildValidateJsonPayload(result, appOrFile), null, 2));
396
- return;
397
- }
398
- validate.displayValidationResults(result);
399
- }
400
-
401
- async function runValidateCommand(appOrFile, options) {
402
- const validate = require('../validation/validate');
403
- const opts = options.opts ? options.opts() : options;
404
- const { isProtectionScope } = require('../protection/scope');
405
- if (isProtectionScope(appOrFile)) {
406
- await runProtectionValidateBranch(appOrFile, opts);
407
- return;
408
- }
409
- if (await runValidateBatchBranch(validate, opts)) {
410
- return;
411
- }
412
- const outFormat = (opts.format || 'default').toLowerCase();
413
- if (!appOrFile || typeof appOrFile !== 'string') {
414
- logger.log(chalk.red('App name or file path is required, or use --integration / --builder'));
415
- process.exit(1);
416
- }
417
- const result = await validate.validateAppOrFile(appOrFile, {
418
- ...opts,
419
- certSync: opts.certSync === true
420
- });
421
- displaySingleValidateResult(appOrFile, result, outFormat, validate);
422
- if (!result.valid) process.exit(1);
423
- }
424
-
425
- function setupValidateDiffCommands(program) {
426
- program.command('validate [appKey|systemKey|file]')
427
- .description('Validate appKey, systemKey, file path, .protection batch, or all under integration/ and builder/')
428
- .addHelpText('after', VALIDATE_HELP_AFTER)
429
- .option('--format <format>', 'Output format: json | default (human-readable)')
430
- .option('--integration', 'Validate all applications under integration/')
431
- .option('--builder', 'Validate all applications under builder/')
432
- .option('--warnings-as-errors', 'For .protection: pass strict=true to dataplane validate')
433
- .option('--simulate', 'For .protection: run simulate after validate')
434
- .option(
435
- '--cert-sync',
436
- 'After successful validation of an external integration, refresh the system file certification block from the dataplane (requires login)'
437
- )
438
- .action((appOrFile, options) => {
439
- runValidateCommand(appOrFile, options).catch((error) => {
440
- handleCommandError(error, 'validate');
441
- process.exit(1);
442
- });
443
- });
444
-
445
- program.command('diff <file1> <file2>')
446
- .description('Diff two config files (optional schema validate)')
447
- .option('--no-validate', 'Skip schema validation (type check still applied)')
448
- .action(async(file1, file2, cmd) => {
449
- try {
450
- const diff = require('../core/diff');
451
- const opts = cmd.opts();
452
- const result = await diff.compareFiles(file1, file2, { validate: opts.validate !== false });
453
- diff.formatDiffOutput(result);
454
- if (!result.identical) process.exit(1);
455
- } catch (error) {
456
- handleCommandError(error, 'diff');
457
- process.exit(1);
458
- }
459
- });
460
- }
461
-
462
227
  /**
463
228
  * Sets up utility commands
464
229
  * @param {Command} program - Commander program instance
@@ -13,6 +13,10 @@ const logger = require('../utils/logger');
13
13
  const config = require('../core/config');
14
14
  const containerHelpers = require('../utils/app-run-containers');
15
15
  const { validateAppName } = require('../app/push');
16
+ const {
17
+ getCeleryCompanionAppKeys,
18
+ loadBuilderApplicationConfig
19
+ } = require('../utils/celery-companion-apps');
16
20
 
17
21
  const { execWithDockerEnv } = require('../utils/docker-exec');
18
22
  const { maskEnvLine } = require('../utils/log-redaction');
@@ -295,6 +299,36 @@ async function runDockerLogsFollow(containerName, tail, minLevel) {
295
299
  });
296
300
  }
297
301
 
302
+ function parseLogLevelOption(options) {
303
+ const rawLevel =
304
+ options.level !== undefined && options.level !== null && options.level !== ''
305
+ ? String(options.level).trim()
306
+ : undefined;
307
+ const level = rawLevel ? rawLevel.toLowerCase() : undefined;
308
+ if (level !== undefined && level !== null && !LOG_LEVELS.includes(level)) {
309
+ throw new Error(
310
+ `Invalid log level '${rawLevel}'; use one of: ${LOG_LEVELS.join(', ')}`
311
+ );
312
+ }
313
+ return level;
314
+ }
315
+
316
+ async function logFollowStream(companionKeys, containerName, tail, level) {
317
+ await runDockerLogsFollow(containerName, tail, level);
318
+ if (companionKeys.length > 0) {
319
+ const hint = companionKeys.map((key) => `aifabrix logs ${key}`).join(' or ');
320
+ logger.log(chalk.gray(`Tip: sidecar logs — ${hint}`));
321
+ }
322
+ }
323
+
324
+ async function logContainerSnapshot(containerName, tail, level) {
325
+ try {
326
+ await runDockerLogs(containerName, { tail, level });
327
+ } catch (err) {
328
+ logger.log(chalk.yellow(`No logs for ${containerName}: ${err.message}`));
329
+ }
330
+ }
331
+
298
332
  /**
299
333
  * Run app logs command: optional env dump (masked), then docker logs
300
334
  * @async
@@ -307,39 +341,33 @@ async function runDockerLogsFollow(containerName, tail, minLevel) {
307
341
  */
308
342
  async function runAppLogs(appKey, options = {}) {
309
343
  validateAppName(appKey);
310
- const rawLevel =
311
- options.level !== undefined && options.level !== null && options.level !== ''
312
- ? String(options.level).trim()
313
- : undefined;
314
- const level = rawLevel ? rawLevel.toLowerCase() : undefined;
315
- if (level !== undefined && level !== null && !LOG_LEVELS.includes(level)) {
316
- throw new Error(
317
- `Invalid log level '${rawLevel}'; use one of: ${LOG_LEVELS.join(', ')}`
318
- );
319
- }
320
-
344
+ const level = parseLogLevelOption(options);
321
345
  const developerId = await config.getDeveloperId();
322
- const containerName = containerHelpers.getContainerName(appKey, developerId);
323
-
324
346
  const follow = !!options.follow;
325
347
  const tail = typeof options.tail === 'number' ? options.tail : DEFAULT_TAIL_LINES;
348
+ const appConfig = loadBuilderApplicationConfig(appKey);
349
+ const companionKeys = getCeleryCompanionAppKeys(appKey, appConfig);
350
+ const appKeysToLog = follow ? [appKey] : [appKey, ...companionKeys];
326
351
 
327
- logger.log(chalk.blue(`Container: ${containerName}\n`));
352
+ for (const key of appKeysToLog) {
353
+ const containerName = containerHelpers.getContainerName(key, developerId);
328
354
 
329
- if (!follow) {
330
- await dumpMaskedEnv(containerName);
331
- }
355
+ logger.log(chalk.blue(`Container: ${containerName}\n`));
332
356
 
333
- if (follow) {
334
- await runDockerLogsFollow(containerName, tail, level);
335
- return;
336
- }
357
+ if (!follow) {
358
+ await dumpMaskedEnv(containerName);
359
+ }
337
360
 
338
- try {
339
- await runDockerLogs(containerName, { tail, level });
340
- } catch (err) {
341
- logger.log(chalk.red(`Error: ${err.message}`));
342
- throw new Error(`Failed to show logs: ${err.message}`);
361
+ if (follow) {
362
+ await logFollowStream(companionKeys, containerName, tail, level);
363
+ return;
364
+ }
365
+
366
+ await logContainerSnapshot(containerName, tail, level);
367
+
368
+ if (key !== appKeysToLog[appKeysToLog.length - 1]) {
369
+ logger.log('');
370
+ }
343
371
  }
344
372
  }
345
373
 
@@ -17,6 +17,8 @@ const { registerApplication } = require('../app/register');
17
17
  const { rotateSecret } = require('../app/rotate-secret');
18
18
  const { showApp } = require('../app/show');
19
19
  const { runAppDeploymentList } = require('./deployment-list');
20
+ const { isChannelTargetKey } = require('../channels/channel-targets');
21
+ const { addChannelCommand } = require('../channels/add-channel');
20
22
 
21
23
  const APP_HELP_AFTER = `
22
24
  Subcommands:
@@ -25,6 +27,7 @@ Subcommands:
25
27
  rotate-secret <key> New ClientSecret (shown once)
26
28
  show <key> From controller (like show --online)
27
29
  deployment <key> Deployment history for app
30
+ add-channel <target> Configure assistant channel install (after deploy)
28
31
 
29
32
  Requires: aifabrix login
30
33
  `;
@@ -118,6 +121,43 @@ function setupAppDeploymentCommand(app) {
118
121
  });
119
122
  }
120
123
 
124
+ function setupAppAddChannelCommand(app) {
125
+ app.command('add-channel <channelTarget>')
126
+ .description(
127
+ 'Configure assistant channel install (teams-bot, slack, …) after aifabrix deploy <target>'
128
+ )
129
+ .requiredOption('-n, --name <name>', 'Customer-visible channel name')
130
+ .option('-d, --description <text>', 'Channel description (default generated)')
131
+ .option('--icon <path>', 'Path to channel icon asset')
132
+ .option('--template <name>', 'Template override (default from channel target)')
133
+ .option('--dry-run', 'Generate artifacts only; do not patch external system or credentials')
134
+ .option('--force', 'Regenerate artifacts and patch config (does not rotate secrets)')
135
+ .option('--probe', 'After install, validate callbacks and assistant catalog')
136
+ .action(async(channelTarget, options) => {
137
+ try {
138
+ if (!isChannelTargetKey(channelTarget)) {
139
+ throw new Error(
140
+ `Unknown channel target "${channelTarget}". Use teams-bot, slack, microsoft-copilot, or chatgpt.`
141
+ );
142
+ }
143
+ await addChannelCommand(channelTarget, {
144
+ name: options.name,
145
+ description: options.description,
146
+ icon: options.icon,
147
+ template: options.template,
148
+ dryRun: options.dryRun === true,
149
+ force: options.force === true,
150
+ probe: options.probe === true
151
+ });
152
+ } catch (error) {
153
+ if (!error.message?.includes('Authentication required')) {
154
+ logger.error(formatBlockingError('Channel install failed:'), error.message);
155
+ }
156
+ process.exit(1);
157
+ }
158
+ });
159
+ }
160
+
121
161
  /**
122
162
  * Setup application management commands
123
163
  * @param {Command} program - Commander program instance
@@ -129,6 +169,7 @@ function setupAppCommands(program) {
129
169
  setupAppRotateSecretCommand(app);
130
170
  setupAppShowCommand(app);
131
171
  setupAppDeploymentCommand(app);
172
+ setupAppAddChannelCommand(app);
132
173
  }
133
174
 
134
175
  module.exports = { setupAppCommands };