@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,274 @@
1
+ /**
2
+ * Generate integration/<channelTarget>/ for communication external systems (plan 152).
3
+ *
4
+ * @fileoverview Builder generator for channel deploy step 1 scaffolds
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const { getChannelTarget } = require('./channel-targets');
14
+ const { getIntegrationPath } = require('../utils/paths');
15
+
16
+ /** @type {Record<string, Object>} */
17
+ const AUTH_BLOCKS = {
18
+ slack: {
19
+ authType: 'credential',
20
+ credential: {
21
+ credentialKey: 'slack-app',
22
+ displayName: 'Slack assistant channel',
23
+ method: 'hmac',
24
+ variables: {},
25
+ security: {
26
+ signingSecret: 'kv://slack/signingSecret',
27
+ clientId: 'kv://slack/clientId',
28
+ clientSecret: 'kv://slack/clientSecret'
29
+ },
30
+ writeOnce: true
31
+ }
32
+ },
33
+ 'teams-bot': {
34
+ authType: 'credential',
35
+ credential: {
36
+ credentialKey: 'teams-bot',
37
+ displayName: 'Microsoft Teams assistant bot',
38
+ method: 'oidc',
39
+ variables: {
40
+ openIdConfigUrl: 'https://login.botframework.com/v1/.well-known/openid_configuration',
41
+ clientId: 'kv://teams-bot/botAppId',
42
+ expectedIssuer: 'https://api.botframework.com'
43
+ },
44
+ security: {},
45
+ writeOnce: true
46
+ }
47
+ },
48
+ 'microsoft-copilot': {
49
+ authType: 'credential',
50
+ credential: {
51
+ credentialKey: 'microsoft-copilot-channel',
52
+ displayName: 'Microsoft Copilot assistant channel',
53
+ method: 'oauth2',
54
+ variables: {
55
+ tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
56
+ grantType: 'client_credentials'
57
+ },
58
+ security: {
59
+ clientId: 'kv://microsoft-copilot/clientId',
60
+ clientSecret: 'kv://microsoft-copilot/clientSecret'
61
+ },
62
+ writeOnce: true
63
+ }
64
+ },
65
+ chatgpt: {
66
+ authType: 'credential',
67
+ credential: {
68
+ credentialKey: 'chatgpt-channel',
69
+ displayName: 'ChatGPT assistant channel',
70
+ method: 'apikey',
71
+ variables: {},
72
+ security: {
73
+ apiKey: 'kv://chatgpt/apiKey'
74
+ },
75
+ writeOnce: true
76
+ }
77
+ },
78
+ 'web-embed': {
79
+ authType: 'credential',
80
+ credential: {
81
+ credentialKey: 'web-embed-channel',
82
+ displayName: 'Web embed assistant channel',
83
+ method: 'apikey',
84
+ variables: {},
85
+ security: {
86
+ apiKey: 'kv://web-embed/apiKey'
87
+ },
88
+ writeOnce: true
89
+ }
90
+ }
91
+ };
92
+
93
+ /**
94
+ * @param {string} channelTarget
95
+ * @param {typeof import('./channel-targets').CHANNEL_TARGETS[string]} target
96
+ * @returns {Object}
97
+ */
98
+ function buildAuthenticationBlock(channelTarget, target) {
99
+ const block = AUTH_BLOCKS[channelTarget];
100
+ if (!block) {
101
+ throw new Error(`No authentication block for channel target "${channelTarget}"`);
102
+ }
103
+ const auth = JSON.parse(JSON.stringify(block));
104
+ auth.credential.credentialKey = target.credentialKey;
105
+ return auth;
106
+ }
107
+
108
+ /**
109
+ * @param {string} channelTarget
110
+ * @returns {Object}
111
+ */
112
+ function buildSystemJson(channelTarget) {
113
+ const target = getChannelTarget(channelTarget);
114
+ const system = {
115
+ key: channelTarget,
116
+ displayName: 'Microsoft Teams assistant bot',
117
+ description: 'Bot Framework assistant channel (not full Teams / Graph integration)',
118
+ type: 'custom',
119
+ systemKind: 'communication',
120
+ enabled: true,
121
+ authentication: buildAuthenticationBlock(channelTarget, target),
122
+ configuration: [],
123
+ dataSources: []
124
+ };
125
+
126
+ if (channelTarget === 'teams-bot') {
127
+ system.displayName = 'Microsoft Teams assistant bot';
128
+ system.endpoints = [
129
+ {
130
+ type: 'messages',
131
+ path: '/messages',
132
+ router: 'teams_bot_router',
133
+ description: 'Bot Framework messaging endpoint',
134
+ active: true
135
+ },
136
+ {
137
+ type: 'notifications',
138
+ path: '/notifications',
139
+ router: 'teams_notifications_router',
140
+ description: 'Proactive notification endpoint',
141
+ active: true
142
+ },
143
+ {
144
+ type: 'config',
145
+ path: '/bot-config',
146
+ router: 'teams_config_router',
147
+ description: 'Bot configuration endpoint',
148
+ active: true
149
+ }
150
+ ];
151
+ system.endpointsActive = true;
152
+ } else {
153
+ system.displayName = `${target.key} assistant channel`;
154
+ system.description = 'Communication external system for assistant channel install (plan 152)';
155
+ }
156
+
157
+ return system;
158
+ }
159
+
160
+ /**
161
+ * @param {string} channelTarget
162
+ * @returns {Object}
163
+ */
164
+ function buildApplicationJson(channelTarget) {
165
+ const target = getChannelTarget(channelTarget);
166
+ const systemFile = `${channelTarget}-system.json`;
167
+ return {
168
+ app: {
169
+ key: channelTarget,
170
+ displayName: `${target.key} assistant channel`,
171
+ description: 'Assistant communication channel — deploy then app add-channel',
172
+ type: 'external'
173
+ },
174
+ externalIntegration: {
175
+ schemaBasePath: './',
176
+ systems: [systemFile],
177
+ dataSources: [],
178
+ autopublish: true,
179
+ version: '1.0.0'
180
+ }
181
+ };
182
+ }
183
+
184
+ /**
185
+ * @param {string} channelTarget
186
+ * @returns {string}
187
+ */
188
+ function buildEnvTemplate(channelTarget) {
189
+ const kvPrefix = channelTarget === 'web-embed' ? 'web-embed' : channelTarget;
190
+ const lines = [
191
+ `# ${channelTarget} assistant channel — resolve secrets before deploy/add-channel`,
192
+ '# kv:// paths are pushed via aifabrix credential push or add-channel secret sync',
193
+ ''
194
+ ];
195
+ if (channelTarget === 'slack') {
196
+ lines.push('KV_SLACK_SIGNINGSECRET=kv://slack/signingSecret');
197
+ lines.push('KV_SLACK_CLIENTID=kv://slack/clientId');
198
+ lines.push('KV_SLACK_CLIENTSECRET=kv://slack/clientSecret');
199
+ } else if (channelTarget === 'teams-bot') {
200
+ lines.push('KV_TEAMS_BOT_BOTAPPID=kv://teams-bot/botAppId');
201
+ } else if (channelTarget === 'microsoft-copilot') {
202
+ lines.push('KV_MICROSOFT_COPILOT_CLIENTID=kv://microsoft-copilot/clientId');
203
+ lines.push('KV_MICROSOFT_COPILOT_CLIENTSECRET=kv://microsoft-copilot/clientSecret');
204
+ } else {
205
+ lines.push(`KV_${kvPrefix.toUpperCase().replace(/-/g, '_')}_APIKEY=kv://${kvPrefix}/apiKey`);
206
+ }
207
+ lines.push('');
208
+ return lines.join('\n');
209
+ }
210
+
211
+ /**
212
+ * @param {string} channelTarget
213
+ * @param {Object} [options]
214
+ * @param {boolean} [options.force]
215
+ * @param {boolean} [options.allowExperimental]
216
+ * @param {string} [options.projectRoot]
217
+ * @returns {{ integrationDir: string, files: string[] }}
218
+ */
219
+ function scaffoldChannelIntegration(channelTarget, options = {}) {
220
+ const target = getChannelTarget(channelTarget);
221
+ if (target.experimental && !options.allowExperimental) {
222
+ throw new Error(
223
+ `Channel target "${channelTarget}" is experimental. Pass --allow-experimental to scaffold.`
224
+ );
225
+ }
226
+
227
+ const integrationDir = options.projectRoot
228
+ ? path.join(path.resolve(options.projectRoot), 'integration', channelTarget)
229
+ : getIntegrationPath(channelTarget);
230
+ if (fs.existsSync(integrationDir) && !options.force) {
231
+ throw new Error(
232
+ `Integration folder already exists: ${integrationDir}. Use --force to overwrite generated files.`
233
+ );
234
+ }
235
+
236
+ fs.mkdirSync(integrationDir, { recursive: true });
237
+ const systemPath = path.join(integrationDir, `${channelTarget}-system.json`);
238
+ const appPath = path.join(integrationDir, 'application.json');
239
+ const envPath = path.join(integrationDir, 'env.template');
240
+ const readmePath = path.join(integrationDir, 'README.md');
241
+
242
+ fs.writeFileSync(systemPath, `${JSON.stringify(buildSystemJson(channelTarget), null, 2)}\n`, 'utf8');
243
+ fs.writeFileSync(appPath, `${JSON.stringify(buildApplicationJson(channelTarget), null, 2)}\n`, 'utf8');
244
+ fs.writeFileSync(envPath, buildEnvTemplate(channelTarget), 'utf8');
245
+ fs.writeFileSync(
246
+ readmePath,
247
+ [
248
+ `# ${channelTarget} assistant channel`,
249
+ '',
250
+ '## Two-step install',
251
+ '',
252
+ '```bash',
253
+ `aifabrix deploy ${channelTarget}`,
254
+ `aifabrix app add-channel ${channelTarget} --name "Your Assistant"`,
255
+ '```',
256
+ '',
257
+ 'Generated by `aifabrix channel scaffold`. Secrets belong in kv:// env.template only.',
258
+ ''
259
+ ].join('\n'),
260
+ 'utf8'
261
+ );
262
+
263
+ return {
264
+ integrationDir,
265
+ files: [systemPath, appPath, envPath, readmePath]
266
+ };
267
+ }
268
+
269
+ module.exports = {
270
+ buildSystemJson,
271
+ buildApplicationJson,
272
+ buildEnvTemplate,
273
+ scaffoldChannelIntegration
274
+ };
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Channel install probe checks (plan 152).
3
+ *
4
+ * @fileoverview Callback, assistant catalog, and inbound verification probes
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { ApiClient } = require('../api/index');
12
+ const { fetchDataplaneGeneralHealth } = require('../api/dataplane-health.api');
13
+
14
+ /**
15
+ * @async
16
+ * @param {string} url
17
+ * @returns {Promise<boolean>}
18
+ */
19
+ async function isUrlReachable(url) {
20
+ if (!url) return false;
21
+ const client = new ApiClient(url.split('/api/')[0] || url);
22
+ try {
23
+ const pathPart = url.includes('/api/') ? url.substring(url.indexOf('/api/')) : '/health';
24
+ const res = await client.get(pathPart, { timeoutMs: 8000 });
25
+ return res && res.success !== false;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * @async
33
+ * @param {string} dataplaneUrl
34
+ * @param {Object} authConfig
35
+ * @returns {Promise<boolean>}
36
+ */
37
+ async function isAssistantCatalogReachable(dataplaneUrl, authConfig) {
38
+ const client = require('../api/index').createDataplaneApiClient(dataplaneUrl, authConfig);
39
+ try {
40
+ const res = await client.get('/api/v1/workers/available', { timeoutMs: 10000 });
41
+ return res && res.success !== false;
42
+ } catch {
43
+ return false;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * @param {Object|null} channelExt
49
+ * @returns {Object}
50
+ */
51
+ function evaluateInboundVerification(channelExt) {
52
+ const credentialKey = channelExt?.credentialKey || '';
53
+ return {
54
+ slackSigningSecretConfigured: credentialKey.includes('slack'),
55
+ teamsBotOidcValidationConfigured: credentialKey.includes('teams-bot'),
56
+ issuerAudienceConfigured: Boolean(channelExt?.type),
57
+ replayProtectionConfigured: Boolean(channelExt?.status === 'installed' || channelExt?.status === 'validated')
58
+ };
59
+ }
60
+
61
+ /**
62
+ * @async
63
+ * @param {Object} ctx
64
+ * @param {Object|null} channelExt
65
+ * @returns {Promise<Object>}
66
+ */
67
+ async function runChannelProbe(ctx, channelExt) {
68
+ const health = await fetchDataplaneGeneralHealth(ctx.dataplaneUrl, { timeoutMs: 8000 });
69
+ const catalogOk = await isAssistantCatalogReachable(ctx.dataplaneUrl, ctx.authConfig);
70
+ const callbackOk = health?.status === 'healthy' || health?.status === 'ok';
71
+
72
+ const inbound = evaluateInboundVerification(channelExt);
73
+
74
+ return {
75
+ dataplaneHealth: health?.status || 'unknown',
76
+ callbackReachable: callbackOk,
77
+ assistantCatalogReachable: catalogOk,
78
+ credentialValid: Boolean(channelExt?.credentialKey),
79
+ inboundVerification: inbound,
80
+ passed: callbackOk && catalogOk && Boolean(channelExt?.credentialKey)
81
+ };
82
+ }
83
+
84
+ module.exports = {
85
+ isUrlReachable,
86
+ isAssistantCatalogReachable,
87
+ evaluateInboundVerification,
88
+ runChannelProbe
89
+ };
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Resolve runtime URLs for channel templates (no hardcoded env URLs).
3
+ *
4
+ * @fileoverview Channel runtime value resolution (plan 152)
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { getChannelTarget } = require('./channel-targets');
12
+
13
+ /**
14
+ * Normalize dataplane base URL (no trailing slash).
15
+ * @param {string} dataplaneBaseUrl
16
+ * @returns {string}
17
+ */
18
+ function normalizeBaseUrl(dataplaneBaseUrl) {
19
+ if (!dataplaneBaseUrl || typeof dataplaneBaseUrl !== 'string') {
20
+ throw new Error('dataplaneBaseUrl is required');
21
+ }
22
+ return dataplaneBaseUrl.trim().replace(/\/+$/, '');
23
+ }
24
+
25
+ /**
26
+ * @param {string} base
27
+ * @param {string} path
28
+ * @returns {string}
29
+ */
30
+ function joinUrl(base, path) {
31
+ return `${normalizeBaseUrl(base)}${path.startsWith('/') ? path : `/${path}`}`;
32
+ }
33
+
34
+ /**
35
+ * Dataplane external-system route prefix for webhook URLs.
36
+ * @param {string} routeSystemKey
37
+ * @returns {string}
38
+ */
39
+ function externalSystemsPrefix(routeSystemKey) {
40
+ return `/api/v1/external/systems/${routeSystemKey}`;
41
+ }
42
+
43
+ /**
44
+ * Relative endpoint paths per channel target (under external/systems/{routeSystemKey}).
45
+ * @param {string} channelTarget
46
+ * @returns {Record<string, string>}
47
+ */
48
+ function getEndpointPathSuffixes(channelTarget) {
49
+ const maps = {
50
+ slack: {
51
+ eventsUrl: '/events',
52
+ interactionUrl: '/interactive',
53
+ oauthCallbackUrl: '/oauth/callback',
54
+ commandUrl: '/commands'
55
+ },
56
+ 'teams-bot': {
57
+ messagesUrl: '/messages',
58
+ notificationsUrl: '/notifications',
59
+ botConfigUrl: '/bot-config'
60
+ },
61
+ 'microsoft-copilot': {
62
+ openapiUrl: '/openapi.yaml',
63
+ actionsBaseUrl: '/actions'
64
+ },
65
+ chatgpt: {
66
+ openapiUrl: '/openapi.yaml',
67
+ mcpUrl: '/mcp',
68
+ actionsBaseUrl: '/actions'
69
+ },
70
+ 'web-embed': {
71
+ configUrl: '/config'
72
+ }
73
+ };
74
+ return maps[channelTarget] || {};
75
+ }
76
+
77
+ /**
78
+ * Legacy / non-external-system paths (Copilot/ChatGPT until dataplane routes exist).
79
+ * @param {string} channelTarget
80
+ * @returns {Record<string, string>}
81
+ */
82
+ function getLegacyApiPaths(channelTarget) {
83
+ const legacy = {
84
+ 'microsoft-copilot': {
85
+ openapiUrl: '/api/v1/copilot/openapi.yaml',
86
+ actionsBaseUrl: '/api/v1/copilot/actions'
87
+ },
88
+ chatgpt: {
89
+ openapiUrl: '/api/v1/chatgpt/openapi.yaml',
90
+ mcpUrl: '/api/v1/chatgpt/mcp',
91
+ actionsBaseUrl: '/api/v1/chatgpt/actions'
92
+ },
93
+ 'web-embed': {
94
+ configUrl: '/api/v1/web-embed/config'
95
+ }
96
+ };
97
+ return legacy[channelTarget] || {};
98
+ }
99
+
100
+ /**
101
+ * @param {Object} params
102
+ * @param {string} params.dataplaneBaseUrl
103
+ * @param {string} params.channelTarget
104
+ * @param {string} params.appName
105
+ * @param {string} [params.baseName]
106
+ * @param {string} [params.environment]
107
+ * @param {string} params.appDescription
108
+ * @param {string} [params.icon]
109
+ * @returns {Object}
110
+ */
111
+ function resolveChannelRuntimeValues(params) {
112
+ const target = getChannelTarget(params.channelTarget);
113
+ const base = normalizeBaseUrl(params.dataplaneBaseUrl);
114
+ const routeKey = target.routeSystemKey || target.key;
115
+ const systemPrefix = externalSystemsPrefix(routeKey);
116
+ const suffixes = getEndpointPathSuffixes(params.channelTarget);
117
+ const legacy = getLegacyApiPaths(params.channelTarget);
118
+
119
+ const resolved = {
120
+ dataplaneBaseUrl: base,
121
+ channelTarget: params.channelTarget,
122
+ routeSystemKey: routeKey,
123
+ appName: params.appName,
124
+ baseName: params.baseName || params.appName,
125
+ environment: params.environment || 'dev',
126
+ appDescription: params.appDescription,
127
+ icon: params.icon || '',
128
+ credentialKey: target.credentialKey,
129
+ assistantCatalogUrl: joinUrl(base, '/api/v1/workers/available'),
130
+ scopes: []
131
+ };
132
+
133
+ for (const [key, suffix] of Object.entries(suffixes)) {
134
+ resolved[key] = joinUrl(base, `${systemPrefix}${suffix}`);
135
+ }
136
+
137
+ for (const [key, legacyPath] of Object.entries(legacy)) {
138
+ if (!resolved[key]) {
139
+ resolved[key] = joinUrl(base, legacyPath);
140
+ }
141
+ }
142
+
143
+ return resolved;
144
+ }
145
+
146
+ module.exports = {
147
+ normalizeBaseUrl,
148
+ joinUrl,
149
+ externalSystemsPrefix,
150
+ getEndpointPathSuffixes,
151
+ resolveChannelRuntimeValues
152
+ };
@@ -0,0 +1,141 @@
1
+ /**
2
+ * TTY output for app add-channel (plan 152).
3
+ *
4
+ * @fileoverview Channel install status display — customer language: Assistant
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const chalk = require('chalk');
12
+ const logger = require('../utils/logger');
13
+ const {
14
+ formatSuccessLine,
15
+ formatWarningLine,
16
+ formatBlockingError,
17
+ sectionTitle,
18
+ metadata
19
+ } = require('../utils/cli-test-layout-chalk');
20
+
21
+ /** @returns {string} */
22
+ function separatorLine() {
23
+ const gray = chalk.gray;
24
+ return typeof gray === 'function'
25
+ ? gray('────────────────────────────────────────')
26
+ : '────────────────────────────────────────';
27
+ }
28
+
29
+ /**
30
+ * @param {Object} params
31
+ * @param {string} params.channelTarget
32
+ * @param {string} params.name
33
+ * @param {Object|null} params.channelExt
34
+ * @param {string} [params.approvalUrl]
35
+ */
36
+ function displayExistingChannelStatus(params) {
37
+ logger.log(sectionTitle(`${params.channelTarget} channel: ${params.name}`));
38
+ logger.log('');
39
+ logger.log(metadata(`Status: ${params.channelExt?.status || 'unknown'}`));
40
+ if (params.channelExt?.baseName && params.channelExt.baseName !== params.name) {
41
+ logger.log(metadata(`Base name: ${params.channelExt.baseName}`));
42
+ }
43
+ logger.log(metadata(`External System: ${params.channelTarget}`));
44
+ logger.log(metadata(`Credential: ${params.channelExt?.credentialKey || '—'}`));
45
+ if (params.channelExt?.capabilities?.length) {
46
+ logger.log(metadata('Capabilities:'));
47
+ for (const cap of params.channelExt.capabilities) {
48
+ logger.log(` - ${cap}`);
49
+ }
50
+ }
51
+ logger.log('');
52
+ logger.log(formatWarningLine('Channel install already configured. Use --force to regenerate artifacts.'));
53
+ if (params.approvalUrl) {
54
+ logger.log(metadata(`Approval URL: ${params.approvalUrl}`));
55
+ }
56
+ logger.log(separatorLine());
57
+ }
58
+
59
+ /**
60
+ * @param {Object} result
61
+ */
62
+ function displayChannelCoreFields(result) {
63
+ logger.log(sectionTitle(`${result.channelTarget} channel: ${result.name}`));
64
+ logger.log('');
65
+ logger.log(metadata(`Status: ${result.statusLabel}`));
66
+ if (result.baseName && result.baseName !== result.name) {
67
+ logger.log(metadata(`Base name: ${result.baseName}`));
68
+ }
69
+ logger.log(metadata(`External System: ${result.channelTarget}`));
70
+ logger.log(metadata(`Credential: ${result.credentialKey}`));
71
+ if (result.capabilities?.length) {
72
+ logger.log(metadata('Capabilities:'));
73
+ for (const cap of result.capabilities) {
74
+ logger.log(` - ${cap}`);
75
+ }
76
+ }
77
+ if (result.artifactPath) {
78
+ logger.log(metadata(`Artifact: ${result.artifactPath}`));
79
+ }
80
+ if (result.installGuidePath) {
81
+ logger.log(metadata(`Install guide: ${result.installGuidePath}`));
82
+ }
83
+ }
84
+
85
+ /**
86
+ * @param {Object|null} validation
87
+ */
88
+ function displayValidationSection(validation) {
89
+ if (!validation) return;
90
+ logger.log('');
91
+ logger.log(metadata('Validation:'));
92
+ if (validation.callbackReachable) {
93
+ logger.log(formatSuccessLine('Callback reachable'));
94
+ }
95
+ if (validation.credentialValid) {
96
+ logger.log(formatSuccessLine('Credential valid'));
97
+ }
98
+ if (validation.assistantCatalogReachable) {
99
+ logger.log(formatSuccessLine('Assistant catalog reachable'));
100
+ }
101
+ if (validation.inboundVerification) {
102
+ logger.log(formatSuccessLine('Inbound verification configured'));
103
+ }
104
+ }
105
+
106
+ /**
107
+ * @param {Object} result
108
+ */
109
+ function displayApprovalSection(result) {
110
+ if (!result.approvalUrl) return;
111
+ logger.log('');
112
+ logger.log(formatWarningLine('Approval required'));
113
+ logger.log(metadata('Open this URL as platform admin:'));
114
+ logger.log(chalk.cyan(result.approvalUrl));
115
+ logger.log('');
116
+ logger.log(metadata('After approval, run:'));
117
+ logger.log(chalk.white(` aifabrix app add-channel ${result.channelTarget} --name "${result.name}"`));
118
+ }
119
+
120
+ /**
121
+ * @param {Object} result
122
+ */
123
+ function displayChannelInstallResult(result) {
124
+ displayChannelCoreFields(result);
125
+ displayValidationSection(result.validation);
126
+ displayApprovalSection(result);
127
+ logger.log(separatorLine());
128
+ }
129
+
130
+ /**
131
+ * @param {string} message
132
+ */
133
+ function displayChannelError(message) {
134
+ logger.error(formatBlockingError(message));
135
+ }
136
+
137
+ module.exports = {
138
+ displayExistingChannelStatus,
139
+ displayChannelInstallResult,
140
+ displayChannelError
141
+ };