@aifabrix/builder 2.53.1 → 2.54.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. package/bin/aifabrix.js +2 -2
  2. package/lib/api/assistants.api.js +8 -5
  3. package/lib/api/channel-identity.api.js +41 -0
  4. package/lib/api/evidence-authoring.api.js +5 -1
  5. package/lib/api/evidence.api.js +2 -0
  6. package/lib/api/types/evidence.types.js +2 -0
  7. package/lib/api/work-search.api.js +136 -0
  8. package/lib/channels/add-channel.js +163 -126
  9. package/lib/channels/approval-guides/chatgpt.js +14 -18
  10. package/lib/channels/approval-guides/claude.js +29 -0
  11. package/lib/channels/approval-guides/index.js +88 -22
  12. package/lib/channels/approval-guides/mcp-client.js +27 -0
  13. package/lib/channels/approval-guides/microsoft-copilot.js +52 -3
  14. package/lib/channels/approval-guides/slack.js +10 -10
  15. package/lib/channels/approval-guides/teams-bot.js +8 -12
  16. package/lib/channels/channel-add-continuations.js +91 -0
  17. package/lib/channels/channel-add-ensure.js +124 -27
  18. package/lib/channels/channel-add-existing.js +160 -28
  19. package/lib/channels/channel-add-failure.js +60 -0
  20. package/lib/channels/channel-add-remaining.js +486 -0
  21. package/lib/channels/channel-add-tty.js +190 -0
  22. package/lib/channels/channel-add-wizard-config.js +138 -0
  23. package/lib/channels/channel-add-wizard.js +250 -0
  24. package/lib/channels/channel-artifact-generator.js +27 -13
  25. package/lib/channels/channel-cardinality.js +83 -0
  26. package/lib/channels/channel-catalog-icon.js +45 -0
  27. package/lib/channels/channel-cli-instructions.js +75 -0
  28. package/lib/channels/channel-configuration-map.js +213 -0
  29. package/lib/channels/channel-credential.js +11 -14
  30. package/lib/channels/channel-definition-project.js +101 -0
  31. package/lib/channels/channel-definition-registry.js +154 -0
  32. package/lib/channels/channel-description.js +59 -2
  33. package/lib/channels/channel-discovery.js +16 -2
  34. package/lib/channels/channel-external-system.js +86 -9
  35. package/lib/channels/channel-install-envelope-actions.js +88 -0
  36. package/lib/channels/channel-install-envelope-microsoft.js +155 -0
  37. package/lib/channels/channel-install-envelope.js +356 -0
  38. package/lib/channels/channel-install-help-md.js +172 -0
  39. package/lib/channels/channel-install-http-payload.js +62 -0
  40. package/lib/channels/channel-install-inventory.js +115 -0
  41. package/lib/channels/channel-install-profiles.js +90 -0
  42. package/lib/channels/channel-instance-collision.js +118 -0
  43. package/lib/channels/channel-instance-key.js +100 -0
  44. package/lib/channels/channel-instance-materialize.js +240 -0
  45. package/lib/channels/channel-integration-generator.js +16 -9
  46. package/lib/channels/channel-integration-template.js +101 -22
  47. package/lib/channels/channel-inventory-fetch.js +79 -0
  48. package/lib/channels/channel-oauth-preflight.js +104 -0
  49. package/lib/channels/channel-package-version.js +76 -0
  50. package/lib/channels/channel-predefined-client.js +154 -0
  51. package/lib/channels/channel-probe.js +7 -2
  52. package/lib/channels/channel-runtime-resolver.js +180 -72
  53. package/lib/channels/channel-status-display.js +86 -16
  54. package/lib/channels/channel-targets.js +106 -92
  55. package/lib/channels/chatgpt-callback.js +318 -0
  56. package/lib/channels/chatgpt-channel-add.js +229 -0
  57. package/lib/channels/chatgpt-preflight.js +396 -0
  58. package/lib/channels/chatgpt-runtime-contract.js +17 -0
  59. package/lib/channels/chatgpt-setup-values.js +124 -0
  60. package/lib/channels/claude-callback.js +67 -0
  61. package/lib/channels/claude-channel-add.js +254 -0
  62. package/lib/channels/claude-runtime-contract.js +40 -0
  63. package/lib/channels/claude-runtime.js +58 -0
  64. package/lib/channels/claude-setup-values.js +89 -0
  65. package/lib/channels/mcp-client/config-merge.js +148 -0
  66. package/lib/channels/mcp-client/ensure-client.js +231 -0
  67. package/lib/channels/mcp-client/paths.js +53 -0
  68. package/lib/channels/mcp-client/profiles.js +122 -0
  69. package/lib/channels/mcp-client/redirect-uris.js +99 -0
  70. package/lib/channels/mcp-client/runtime.js +59 -0
  71. package/lib/channels/mcp-client-channel-add.js +186 -0
  72. package/lib/channels/microsoft-copilot-channel-add.js +117 -7
  73. package/lib/channels/microsoft-copilot-entra-identifier-uris.js +187 -0
  74. package/lib/channels/microsoft-copilot-entra-sso-form.js +106 -18
  75. package/lib/channels/microsoft-copilot-entra-sso.js +31 -2
  76. package/lib/channels/microsoft-copilot-package-prior.js +107 -0
  77. package/lib/channels/microsoft-copilot-package.js +29 -28
  78. package/lib/channels/microsoft-provisioning/a365.js +80 -0
  79. package/lib/channels/microsoft-provisioning/auth-config.js +240 -0
  80. package/lib/channels/microsoft-provisioning/auth.js +179 -0
  81. package/lib/channels/microsoft-provisioning/cli.js +71 -0
  82. package/lib/channels/microsoft-provisioning/constants.js +75 -0
  83. package/lib/channels/microsoft-provisioning/errors.js +117 -0
  84. package/lib/channels/microsoft-provisioning/index.js +55 -0
  85. package/lib/channels/microsoft-provisioning/install-atk.js +158 -0
  86. package/lib/channels/microsoft-provisioning/install-teams.js +115 -0
  87. package/lib/channels/microsoft-provisioning/login-portal-device.js +236 -0
  88. package/lib/channels/microsoft-provisioning/login-portal-parse.js +71 -0
  89. package/lib/channels/microsoft-provisioning/login-portal-teams.js +193 -0
  90. package/lib/channels/microsoft-provisioning/login-portal.js +230 -0
  91. package/lib/channels/microsoft-provisioning/persist.js +110 -0
  92. package/lib/channels/microsoft-provisioning/teams-bot-args.js +119 -0
  93. package/lib/channels/microsoft-provisioning/teams-bot-controller.js +123 -0
  94. package/lib/channels/microsoft-provisioning/teams-bot-parse.js +134 -0
  95. package/lib/channels/microsoft-provisioning/teams-bot-persist.js +113 -0
  96. package/lib/channels/microsoft-provisioning/teams-bot-provision.js +234 -0
  97. package/lib/channels/microsoft-provisioning/teams-bot-secrets.js +45 -0
  98. package/lib/channels/microsoft-provisioning/teams-cli.js +82 -0
  99. package/lib/channels/runtime-tool-catalog.js +5 -2
  100. package/lib/channels/slack-channel-add-portal.js +130 -0
  101. package/lib/channels/slack-channel-add-tty-auth.js +95 -0
  102. package/lib/channels/slack-channel-add.js +258 -0
  103. package/lib/channels/slack-provisioning/apps.js +181 -0
  104. package/lib/channels/slack-provisioning/auth-store.js +110 -0
  105. package/lib/channels/slack-provisioning/auth-ticket.js +185 -0
  106. package/lib/channels/slack-provisioning/auth.js +115 -0
  107. package/lib/channels/slack-provisioning/callbacks.js +41 -0
  108. package/lib/channels/slack-provisioning/cli.js +226 -0
  109. package/lib/channels/slack-provisioning/constants.js +37 -0
  110. package/lib/channels/slack-provisioning/credentials.js +169 -0
  111. package/lib/channels/slack-provisioning/curl-shim.js +132 -0
  112. package/lib/channels/slack-provisioning/developer-install.js +118 -0
  113. package/lib/channels/slack-provisioning/env-file.js +120 -0
  114. package/lib/channels/slack-provisioning/errors.js +47 -0
  115. package/lib/channels/slack-provisioning/go-ca-bundle.js +137 -0
  116. package/lib/channels/slack-provisioning/index.js +250 -0
  117. package/lib/channels/slack-provisioning/install-cli.js +323 -0
  118. package/lib/channels/slack-provisioning/manifest.js +89 -0
  119. package/lib/channels/slack-provisioning/oauth-lock.js +33 -0
  120. package/lib/channels/slack-provisioning/offer-cli.js +113 -0
  121. package/lib/channels/slack-provisioning/onboard-members.js +122 -0
  122. package/lib/channels/slack-provisioning/onboard.js +89 -0
  123. package/lib/channels/slack-provisioning/persist.js +95 -0
  124. package/lib/channels/slack-provisioning/remaining-urls.js +158 -0
  125. package/lib/channels/slack-provisioning/with-curl-on-path.js +48 -0
  126. package/lib/channels/teams-bot-channel-add.js +94 -0
  127. package/lib/channels/vendor-dataplane-url.js +249 -0
  128. package/lib/cli/setup-certification.help.js +2 -0
  129. package/lib/cli/setup-external-system-help.js +2 -0
  130. package/lib/cli/setup-external-system.js +1 -1
  131. package/lib/commands/channel-add-help.js +366 -0
  132. package/lib/commands/channel-add-setup.js +162 -80
  133. package/lib/commands/channel-configure.js +118 -0
  134. package/lib/commands/channel.js +10 -1
  135. package/lib/commands/governance-upload-external.js +6 -3
  136. package/lib/commands/lifecycle-command-action.js +2 -5
  137. package/lib/commands/lifecycle-external.js +93 -21
  138. package/lib/commands/repair-datasource-test-payload.js +4 -2
  139. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +23 -2
  140. package/lib/commands/repair-datasource.js +3 -0
  141. package/lib/commands/repair-external-run.js +59 -25
  142. package/lib/commands/repair-openapi-rest-runtime.js +127 -0
  143. package/lib/commands/repair-orchestration-tag-merge.js +339 -0
  144. package/lib/commands/repair-rbac-catalog-defaults.js +96 -0
  145. package/lib/commands/repair-rbac-platform-preset.js +26 -15
  146. package/lib/commands/repair-rbac-reader-roles.js +8 -21
  147. package/lib/commands/repair-rbac.js +10 -34
  148. package/lib/commands/repair-system-permissions.js +24 -22
  149. package/lib/commands/role-assistant-test-output.js +14 -0
  150. package/lib/commands/role-assistant.js +59 -21
  151. package/lib/commands/test-e2e-external.js +148 -21
  152. package/lib/commands/upload-credential-push-log.js +2 -1
  153. package/lib/commands/upload-publish-context.js +1 -1
  154. package/lib/commands/upload-role-assistant-shell.js +124 -0
  155. package/lib/commands/upload-sidecar-followups.js +6 -3
  156. package/lib/commands/upload.js +18 -3
  157. package/lib/core/secrets-docker-env.js +4 -1
  158. package/lib/core/secrets-env-content.js +17 -3
  159. package/lib/datasource/capability/capability-manifest.js +0 -3
  160. package/lib/datasource/capability/copy-test-payload.js +3 -0
  161. package/lib/external-system/deploy-helpers.js +26 -1
  162. package/lib/external-system/deploy.js +10 -6
  163. package/lib/external-system/download-helpers.js +29 -2
  164. package/lib/external-system/download-role-assistant.js +83 -4
  165. package/lib/external-system/download.js +40 -30
  166. package/lib/external-system/sync-deploy-manifest.js +3 -2
  167. package/lib/external-system/upload-identity.js +42 -0
  168. package/lib/generator/index.js +19 -15
  169. package/lib/generator/split.js +13 -2
  170. package/lib/lifecycle/role-assistant-governance.js +146 -0
  171. package/lib/lifecycle/scenario-upload.js +181 -30
  172. package/lib/programmatic/builder-api-cors.js +143 -0
  173. package/lib/programmatic/builder-api-request.js +6 -0
  174. package/lib/programmatic/builder-api-route-dispatch.js +56 -42
  175. package/lib/programmatic/builder-api-server.js +8 -1
  176. package/lib/programmatic/capability-registry.js +54 -0
  177. package/lib/programmatic/channel-install-help-resolve.js +359 -0
  178. package/lib/programmatic/channel-install-session.js +218 -0
  179. package/lib/programmatic/help-content/channel-onboarding.md +2 -0
  180. package/lib/programmatic/help-content/cip-overview.md +3 -1
  181. package/lib/programmatic/http-raw-response.js +62 -0
  182. package/lib/programmatic/openapi-channel-install-bindings.js +179 -0
  183. package/lib/programmatic/openapi-channel-install-schemas.js +286 -0
  184. package/lib/programmatic/openapi-component-schemas.js +18 -1
  185. package/lib/programmatic/openapi-description-enricher.js +3 -1
  186. package/lib/programmatic/openapi-descriptions.js +74 -3
  187. package/lib/programmatic/openapi-envelope-examples.js +117 -0
  188. package/lib/programmatic/openapi-operation-bindings.js +4 -1
  189. package/lib/programmatic/openapi-schema-descriptions-channel.js +316 -0
  190. package/lib/programmatic/openapi-spec.js +12 -8
  191. package/lib/programmatic/platform-rbac-catalog.js +36 -18
  192. package/lib/programmatic/route-handler-map.js +51 -1
  193. package/lib/programmatic/route-handlers-context.js +2 -1
  194. package/lib/programmatic/run-auth-permissions.js +54 -0
  195. package/lib/programmatic/run-channel-catalog.js +196 -0
  196. package/lib/programmatic/run-channel-install-artifacts.js +137 -0
  197. package/lib/programmatic/run-channel-install-copilot.js +353 -0
  198. package/lib/programmatic/run-channel-install-options.js +232 -0
  199. package/lib/programmatic/run-channel-install-teams-bot.js +204 -0
  200. package/lib/programmatic/run-channel-install.js +346 -0
  201. package/lib/programmatic/run-channel-package.js +87 -7
  202. package/lib/programmatic/workspace-context.js +2 -0
  203. package/lib/role-assistant/evidence-sync.js +4 -2
  204. package/lib/role-assistant/evidence-validation-issues.js +51 -0
  205. package/lib/role-assistant/knowledge-sync.js +10 -4
  206. package/lib/role-assistant/settings.js +49 -2
  207. package/lib/role-assistant/test-cases-evaluate.js +30 -2
  208. package/lib/role-assistant/test-cases-evidence.js +175 -0
  209. package/lib/role-assistant/test-cases-search.js +229 -0
  210. package/lib/role-assistant/test-cases.js +37 -4
  211. package/lib/role-assistant/test-runner-search.js +149 -0
  212. package/lib/role-assistant/test-runner-workhub-helpers.js +40 -2
  213. package/lib/role-assistant/test-runner-workhub-soft.js +9 -3
  214. package/lib/role-assistant/test-runner-workhub.js +29 -11
  215. package/lib/role-assistant/test-runner.js +16 -1
  216. package/lib/schema/external-datasource.schema.json +112 -18
  217. package/lib/schema/external-system.schema.json +159 -2
  218. package/lib/schema/mcp-client-profile.schema.json +103 -0
  219. package/lib/utils/app-path-resolve.js +4 -0
  220. package/lib/utils/authentication-env-template.js +44 -6
  221. package/lib/utils/credential-secrets-env.js +6 -1
  222. package/lib/utils/env-copy.js +19 -7
  223. package/lib/utils/external-env-template.js +20 -2
  224. package/lib/utils/paths.js +18 -1
  225. package/lib/utils/platform-shell-package.js +69 -0
  226. package/lib/utils/port-resolver.js +50 -1
  227. package/lib/utils/rewrite-name-flag.js +20 -0
  228. package/lib/utils/role-assistant-paths.js +13 -10
  229. package/lib/utils/schema-resolver.js +11 -1
  230. package/lib/utils/secrets-helpers.js +12 -21
  231. package/lib/utils/token-manager.js +10 -5
  232. package/lib/validation/validate.js +40 -0
  233. package/package.json +1 -1
  234. package/templates/README.md +1 -1
  235. package/templates/applications/builder-api/Dockerfile +1 -1
  236. package/templates/applications/builder-api/env.template +7 -0
  237. package/templates/applications/dataplane/application.yaml +6 -5
  238. package/templates/applications/dataplane/env.template +2 -2
  239. package/templates/applications/dataplane/rbac.yaml +7 -2
  240. package/templates/applications/keycloak/Dockerfile +30 -4
  241. package/templates/applications/keycloak/application.yaml +2 -2
  242. package/templates/applications/keycloak/cimd-lenient-parse/AbstractClientIdMetadataDocumentExecutor.java +896 -0
  243. package/templates/applications/keycloak/cimd-lenient-parse/SOURCE.md +19 -0
  244. package/templates/applications/keycloak/env.template +3 -0
  245. package/templates/applications/miso-controller/application.yaml +1 -2
  246. package/templates/applications/miso-controller/env.template +2 -0
  247. package/templates/channels/README.md +5 -5
  248. package/templates/channels/chatgpt/TROUBLESHOOTING.md +51 -0
  249. package/templates/channels/chatgpt/channel.json +59 -0
  250. package/templates/channels/chatgpt/icon.svg +1 -0
  251. package/templates/channels/chatgpt/install.template.md.hbs +20 -95
  252. package/templates/channels/chatgpt/integration/README.md +1 -1
  253. package/templates/channels/chatgpt/integration/application.json +2 -2
  254. package/templates/channels/chatgpt/integration/chatgpt-system.json +49 -4
  255. package/templates/channels/chatgpt/integration/env.template +2 -4
  256. package/templates/channels/chatgpt/integration/rbac.json +13 -0
  257. package/templates/channels/claude/TROUBLESHOOTING.md +41 -0
  258. package/templates/channels/claude/channel.json +59 -0
  259. package/templates/channels/claude/icon.svg +1 -0
  260. package/templates/channels/claude/install.template.md.hbs +21 -0
  261. package/templates/channels/claude/integration/README.md +14 -0
  262. package/templates/channels/claude/integration/application.json +15 -0
  263. package/templates/channels/claude/integration/claude-system.json +59 -0
  264. package/templates/channels/claude/integration/env.template +2 -0
  265. package/templates/channels/claude/integration/rbac.json +13 -0
  266. package/templates/channels/claude/manifest.template.json.hbs +40 -0
  267. package/templates/channels/mcp-client/channel.json +72 -0
  268. package/templates/channels/mcp-client/icon.svg +1 -0
  269. package/templates/channels/mcp-client/install.template.md.hbs +24 -0
  270. package/templates/channels/mcp-client/integration/README.md +13 -0
  271. package/templates/channels/mcp-client/integration/application.json +15 -0
  272. package/templates/channels/mcp-client/integration/env.template +2 -0
  273. package/templates/channels/mcp-client/integration/mcp-client-system.json +72 -0
  274. package/templates/channels/mcp-client/integration/rbac.json +13 -0
  275. package/templates/channels/mcp-client/manifest.template.json.hbs +41 -0
  276. package/templates/channels/mcp-client/profiles/cursor.json +26 -0
  277. package/templates/channels/mcp-client/profiles/github-copilot.json +29 -0
  278. package/templates/channels/mcp-client/profiles/vscode.json +29 -0
  279. package/templates/channels/microsoft-copilot/channel.json +73 -0
  280. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +8 -4
  281. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +65 -5
  282. package/templates/channels/microsoft-copilot/icon.svg +1 -0
  283. package/templates/channels/microsoft-copilot/install.template.md.hbs +9 -9
  284. package/templates/channels/microsoft-copilot/integration/README.md +1 -1
  285. package/templates/channels/microsoft-copilot/integration/application.json +2 -2
  286. package/templates/channels/microsoft-copilot/integration/env.template +3 -6
  287. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +63 -4
  288. package/templates/channels/microsoft-copilot/integration/rbac.json +13 -0
  289. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +5 -5
  290. package/templates/channels/slack/channel.json +223 -0
  291. package/templates/channels/slack/icon.svg +1 -0
  292. package/templates/channels/slack/install.template.md.hbs +36 -28
  293. package/templates/channels/slack/integration/README.md +245 -22
  294. package/templates/channels/slack/integration/application.json +44 -7
  295. package/templates/channels/slack/integration/env.template +15 -6
  296. package/templates/channels/slack/integration/openapi/openapi.json +126 -0
  297. package/templates/channels/slack/integration/rbac.json +84 -0
  298. package/templates/channels/slack/integration/slack-datasource-commands.json +154 -0
  299. package/templates/channels/slack/integration/slack-datasource-conversations.json +28 -3
  300. package/templates/channels/slack/integration/slack-datasource-events.json +154 -0
  301. package/templates/channels/slack/integration/slack-datasource-interactive.json +154 -0
  302. package/templates/channels/slack/integration/slack-datasource-messages.json +40 -2
  303. package/templates/channels/slack/integration/slack-system.json +155 -77
  304. package/templates/channels/slack/manifest.template.json.hbs +5 -2
  305. package/templates/channels/teams-bot/channel.json +161 -0
  306. package/templates/channels/teams-bot/icon.svg +1 -0
  307. package/templates/channels/teams-bot/install.template.md.hbs +12 -13
  308. package/templates/channels/teams-bot/integration/README.md +5 -4
  309. package/templates/channels/teams-bot/integration/application.json +6 -4
  310. package/templates/channels/teams-bot/integration/env.template +5 -4
  311. package/templates/channels/teams-bot/integration/openapi/openapi.json +68 -0
  312. package/templates/channels/teams-bot/integration/rbac.json +21 -0
  313. package/templates/channels/teams-bot/integration/teams-bot-datasource-activities.json +154 -0
  314. package/templates/channels/teams-bot/integration/teams-bot-system.json +128 -23
  315. package/templates/channels/web-embed/channel.json +60 -0
  316. package/templates/channels/web-embed/install.template.md.hbs +1 -1
  317. package/templates/channels/web-embed/integration/README.md +2 -2
  318. package/templates/channels/web-embed/integration/application.json +2 -2
  319. package/templates/channels/web-embed/integration/env.template +1 -1
  320. package/templates/channels/web-embed/integration/rbac.json +13 -0
  321. package/templates/channels/web-embed/integration/web-embed-system.json +50 -4
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Channel integration templates — copied from templates/channels/<target>/integration/.
3
- * SSOT for slack: aifabrix-dataplane/integration/slack (make sync-json in dataplane).
3
+ * SSOT: aifabrix-builder/templates/channels (not dataplane integration/).
4
4
  *
5
5
  * @fileoverview Template resolution and copy for channel scaffold (plan 152)
6
6
  * @author AI Fabrix Team
@@ -42,53 +42,132 @@ function shouldCopyTemplateFile(name) {
42
42
 
43
43
  /**
44
44
  * @param {string} templateDir
45
- * @returns {string[]}
45
+ * @returns {string[]} Relative file paths under the template dir
46
46
  */
47
47
  function listChannelIntegrationTemplateFiles(templateDir) {
48
48
  if (!fs.existsSync(templateDir)) {
49
49
  return [];
50
50
  }
51
- return fs
52
- .readdirSync(templateDir)
53
- .filter((name) => {
54
- const full = path.join(templateDir, name);
55
- return fs.statSync(full).isFile() && shouldCopyTemplateFile(name);
56
- })
57
- .sort();
51
+ return listTemplateFilesRecursive(templateDir, '').sort();
58
52
  }
59
53
 
60
54
  /**
61
- * @param {string} channelTarget
55
+ * @param {string} dir
56
+ * @param {string} prefix
57
+ * @returns {string[]}
58
+ */
59
+ function listTemplateFilesRecursive(dir, prefix) {
60
+ const names = [];
61
+ for (const name of fs.readdirSync(dir)) {
62
+ const rel = prefix ? `${prefix}/${name}` : name;
63
+ const full = path.join(dir, name);
64
+ const stat = fs.statSync(full);
65
+ if (stat.isDirectory()) {
66
+ names.push(...listTemplateFilesRecursive(full, rel));
67
+ continue;
68
+ }
69
+ if (stat.isFile() && shouldCopyTemplateFile(name)) {
70
+ names.push(rel);
71
+ }
72
+ }
73
+ return names;
74
+ }
75
+
76
+ const APPLICATION_CONFIG_NAMES = [
77
+ 'application.yaml',
78
+ 'application.yml',
79
+ 'application.json',
80
+ 'variables.yaml'
81
+ ];
82
+
83
+ /**
84
+ * @param {string} dirPath
85
+ * @returns {boolean}
86
+ */
87
+ function isExistingDirectory(dirPath) {
88
+ try {
89
+ return fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory();
90
+ } catch {
91
+ return false;
92
+ }
93
+ }
94
+
95
+ /**
96
+ * True when the folder has application config and `<target>-system.json`.
97
+ * Empty leftover directories are not a usable channel scaffold.
98
+ *
62
99
  * @param {string} integrationDir
63
- * @returns {string[]} Copied file paths
100
+ * @param {string} channelTarget
101
+ * @returns {boolean}
64
102
  */
65
- function copyChannelIntegrationTemplate(channelTarget, integrationDir) {
66
- const templateDir = getChannelIntegrationTemplateDir(channelTarget);
67
- const names = listChannelIntegrationTemplateFiles(templateDir);
68
- if (names.length === 0) {
69
- throw new Error(
70
- `Channel integration template missing for "${channelTarget}" (${templateDir}). ` +
71
- 'For slack: edit aifabrix-dataplane/integration/slack and run make sync-json. ' +
72
- 'For other targets: add templates/channels/<target>/integration/ until dataplane SSOT exists.'
73
- );
103
+ function hasChannelIntegrationFiles(integrationDir, channelTarget) {
104
+ if (!integrationDir || typeof integrationDir !== 'string') {
105
+ return false;
106
+ }
107
+ if (!channelTarget || typeof channelTarget !== 'string') {
108
+ return false;
74
109
  }
110
+ if (!isExistingDirectory(integrationDir)) {
111
+ return false;
112
+ }
113
+ const hasAppConfig = APPLICATION_CONFIG_NAMES.some((name) =>
114
+ fs.existsSync(path.join(integrationDir, name))
115
+ );
116
+ const systemFile = path.join(integrationDir, `${channelTarget}-system.json`);
117
+ return hasAppConfig && fs.existsSync(systemFile);
118
+ }
75
119
 
120
+ /**
121
+ * @param {string} templateDir
122
+ * @param {string[]} names
123
+ * @param {string} integrationDir
124
+ * @param {boolean} overwrite
125
+ * @returns {string[]} Copied file paths
126
+ */
127
+ function copyNamedTemplateFiles(templateDir, names, integrationDir, overwrite) {
76
128
  fs.mkdirSync(integrationDir, { recursive: true });
77
129
  const copied = [];
78
130
  for (const name of names) {
79
- const src = path.join(templateDir, name);
80
131
  const dest = path.join(integrationDir, name);
81
- fs.copyFileSync(src, dest);
132
+ if (!overwrite && fs.existsSync(dest)) {
133
+ continue;
134
+ }
135
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
136
+ fs.copyFileSync(path.join(templateDir, name), dest);
82
137
  copied.push(dest);
83
138
  }
84
139
  return copied;
85
140
  }
86
141
 
142
+ /**
143
+ * @param {string} channelTarget
144
+ * @param {string} integrationDir
145
+ * @param {{ overwrite?: boolean }} [options]
146
+ * @returns {string[]} Copied file paths
147
+ */
148
+ function copyChannelIntegrationTemplate(channelTarget, integrationDir, options = {}) {
149
+ const templateDir = getChannelIntegrationTemplateDir(channelTarget);
150
+ const names = listChannelIntegrationTemplateFiles(templateDir);
151
+ if (names.length === 0) {
152
+ throw new Error(
153
+ `Channel integration template missing for "${channelTarget}" (${templateDir}). ` +
154
+ 'Add files under templates/channels/<target>/integration/.'
155
+ );
156
+ }
157
+ return copyNamedTemplateFiles(
158
+ templateDir,
159
+ names,
160
+ integrationDir,
161
+ options.overwrite === true
162
+ );
163
+ }
164
+
87
165
  module.exports = {
88
166
  BUILDER_ROOT,
89
167
  SKIP_TEMPLATE_FILE,
90
168
  getChannelIntegrationTemplateDir,
91
169
  shouldCopyTemplateFile,
92
170
  listChannelIntegrationTemplateFiles,
171
+ hasChannelIntegrationFiles,
93
172
  copyChannelIntegrationTemplate
94
173
  };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * List Dataplane Connected Systems for channel inventory projection.
3
+ *
4
+ * @fileoverview Builder-side Dataplane list — fail closed
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { listExternalSystems } = require('../api/external-systems.api');
12
+ const { unwrapApiData } = require('../utils/external-system-readiness-core');
13
+ const { httpError } = require('../programmatic/channel-install-session');
14
+
15
+ /** Dataplane listExternalSystems pageSize maximum is 100. */
16
+ const INVENTORY_PAGE_SIZE = 100;
17
+ const INVENTORY_MAX_PAGES = 50;
18
+
19
+ /**
20
+ * @param {Object} res
21
+ * @returns {Object[]}
22
+ */
23
+ function systemsFromListResponse(res) {
24
+ const data = unwrapApiData(res);
25
+ if (Array.isArray(data)) {
26
+ return data;
27
+ }
28
+ if (data && Array.isArray(data.items)) {
29
+ return data.items;
30
+ }
31
+ if (data && Array.isArray(data.data)) {
32
+ return data.data;
33
+ }
34
+ return [];
35
+ }
36
+
37
+ /**
38
+ * Channel identity lives on config.extensions.channel / system.channel.
39
+ * Slim list drops those unless includeConfig is true.
40
+ *
41
+ * @param {import('../programmatic/workspace-context').WorkspaceContext} ctx
42
+ * @param {Object} [deps]
43
+ * @returns {Promise<Object[]>}
44
+ */
45
+ async function listConnectedSystemsForInventory(ctx, deps = {}) {
46
+ const list = deps.listExternalSystems || listExternalSystems;
47
+ const auth = {
48
+ type: 'bearer',
49
+ token: ctx.bearerToken,
50
+ preserveBearer: true
51
+ };
52
+ const systems = [];
53
+ try {
54
+ for (let page = 1; page <= INVENTORY_MAX_PAGES; page += 1) {
55
+ const res = await list(ctx.dataplaneUrl, auth, {
56
+ page,
57
+ pageSize: INVENTORY_PAGE_SIZE,
58
+ includeConfig: true
59
+ });
60
+ const chunk = systemsFromListResponse(res);
61
+ systems.push(...chunk);
62
+ if (chunk.length < INVENTORY_PAGE_SIZE) {
63
+ return systems;
64
+ }
65
+ }
66
+ return systems;
67
+ } catch (err) {
68
+ throw httpError(
69
+ `Unable to list Connected Systems for channel inventory: ${err.message}`,
70
+ err.statusCode || 502
71
+ );
72
+ }
73
+ }
74
+
75
+ module.exports = {
76
+ listConnectedSystemsForInventory,
77
+ systemsFromListResponse,
78
+ INVENTORY_PAGE_SIZE
79
+ };
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Authorization preflight for Predefined Client channel installs.
3
+ *
4
+ * @fileoverview GET /api/v1/auth/permissions only — never probe create/update
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { getAuthPermissions } = require('../api/auth.api');
12
+ const { httpError } = require('../programmatic/channel-install-session');
13
+
14
+ const PREDEFINED_CLIENT_DEFINITIONS = new Set(['microsoft-copilot', 'mcp-client']);
15
+ const REQUIRED_SLUGS = Object.freeze(['integration-client:read', 'integration-client:create']);
16
+
17
+ /**
18
+ * @param {string} definitionKey
19
+ * @returns {boolean}
20
+ */
21
+ function needsIntegrationClientPreflight(definitionKey) {
22
+ return PREDEFINED_CLIENT_DEFINITIONS.has(definitionKey);
23
+ }
24
+
25
+ /**
26
+ * @param {unknown} response
27
+ * @returns {string[]}
28
+ */
29
+ function permissionSlugsFromResponse(response) {
30
+ const body = response && response.data !== undefined ? response.data : response;
31
+ const inner = body && body.data !== undefined && body.data !== null ? body.data : body;
32
+ if (Array.isArray(inner)) {
33
+ return inner.filter((item) => typeof item === 'string');
34
+ }
35
+ if (inner && Array.isArray(inner.permissions)) {
36
+ return inner.permissions.filter((item) => typeof item === 'string');
37
+ }
38
+ if (body && Array.isArray(body.permissions)) {
39
+ return body.permissions.filter((item) => typeof item === 'string');
40
+ }
41
+ return [];
42
+ }
43
+
44
+ /**
45
+ * @param {unknown} errOrResponse
46
+ * @returns {Error}
47
+ */
48
+ function toForbiddenError(errOrResponse) {
49
+ const status = Number(
50
+ errOrResponse && (errOrResponse.statusCode || errOrResponse.status)
51
+ );
52
+ const message =
53
+ (errOrResponse && (errOrResponse.formattedError || errOrResponse.message)) ||
54
+ 'Missing integration-client:read. Cannot start channel install.';
55
+ if (status === 403 || /integration-client:/i.test(String(message))) {
56
+ return httpError(String(message), 403);
57
+ }
58
+ return httpError(String(message), status >= 400 && status < 600 ? status : 502);
59
+ }
60
+
61
+ /**
62
+ * Fail closed before wizard/install when Integration Client permissions are missing.
63
+ * Does not attempt create/update. Does not invent a Builder permission catalog.
64
+ * @param {import('../programmatic/workspace-context').WorkspaceContext} ctx
65
+ * @param {string} definitionKey
66
+ * @param {Object} [deps]
67
+ * @returns {Promise<void>}
68
+ */
69
+ async function assertIntegrationClientPermissions(ctx, definitionKey, deps = {}) {
70
+ if (!needsIntegrationClientPreflight(definitionKey)) {
71
+ return;
72
+ }
73
+ const getPerms = deps.getAuthPermissions || getAuthPermissions;
74
+ let response;
75
+ try {
76
+ response = await getPerms(
77
+ ctx.controllerUrl,
78
+ { type: 'bearer', token: ctx.bearerToken, preserveBearer: true },
79
+ ctx.environment
80
+ );
81
+ } catch (err) {
82
+ throw toForbiddenError(err);
83
+ }
84
+ if (response && (response.success === false || Number(response.status) === 403)) {
85
+ throw toForbiddenError(response);
86
+ }
87
+ const slugs = permissionSlugsFromResponse(response);
88
+ const missing = REQUIRED_SLUGS.filter((slug) => !slugs.includes(slug));
89
+ if (missing.length === 0) {
90
+ return;
91
+ }
92
+ throw httpError(
93
+ `Missing ${missing.join(', ')}. Cannot start channel install.`,
94
+ 403
95
+ );
96
+ }
97
+
98
+ module.exports = {
99
+ PREDEFINED_CLIENT_DEFINITIONS,
100
+ REQUIRED_SLUGS,
101
+ needsIntegrationClientPreflight,
102
+ permissionSlugsFromResponse,
103
+ assertIntegrationClientPermissions
104
+ };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Channel package semver for in-place vendor updates.
3
+ *
4
+ * @fileoverview First write is 1.0.0; later writes bump minor (1.0.0 → 1.1.0)
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ /**
10
+ * @param {string} version
11
+ * @returns {{ major: number, minor: number, patch: number }|null}
12
+ */
13
+ function parseSemverTriple(version) {
14
+ const match = String(version || '')
15
+ .trim()
16
+ .match(/^(\d+)\.(\d+)\.(\d+)$/);
17
+ if (!match) {
18
+ return null;
19
+ }
20
+ return {
21
+ major: Number(match[1]),
22
+ minor: Number(match[2]),
23
+ patch: Number(match[3])
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Vendor updates need a higher package version — bump minor (1.0.0 → 1.1.0).
29
+ * @param {string} version
30
+ * @returns {string}
31
+ */
32
+ function bumpMinorPackageVersion(version) {
33
+ const parts = parseSemverTriple(version);
34
+ if (!parts) {
35
+ return '1.1.0';
36
+ }
37
+ return `${parts.major}.${parts.minor + 1}.0`;
38
+ }
39
+
40
+ /**
41
+ * @param {string|null|undefined} explicitVersion
42
+ * @param {string|null} priorVersion
43
+ * @returns {string}
44
+ */
45
+ function resolvePackageVersionForWrite(explicitVersion, priorVersion) {
46
+ if (typeof explicitVersion === 'string' && explicitVersion.trim()) {
47
+ return explicitVersion.trim();
48
+ }
49
+ if (priorVersion) {
50
+ return bumpMinorPackageVersion(priorVersion);
51
+ }
52
+ return '1.0.0';
53
+ }
54
+
55
+ /**
56
+ * Slack re-install writes a new package version unless the caller set one.
57
+ * @param {string} channelTarget
58
+ * @param {Object} options
59
+ * @param {Object|null} existing
60
+ * @returns {void}
61
+ */
62
+ function applySlackPackageVersion(channelTarget, options, existing) {
63
+ if (channelTarget !== 'slack' || !options || typeof options !== 'object') {
64
+ return;
65
+ }
66
+ const prior =
67
+ existing && typeof existing.packageVersion === 'string' ? existing.packageVersion : null;
68
+ options.packageVersion = resolvePackageVersionForWrite(options.packageVersion, prior);
69
+ }
70
+
71
+ module.exports = {
72
+ parseSemverTriple,
73
+ bumpMinorPackageVersion,
74
+ resolvePackageVersionForWrite,
75
+ applySlackPackageVersion
76
+ };
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Per-install Predefined Client clone (Copilot / mcp-client pattern).
3
+ *
4
+ * @fileoverview Create/reuse instance Integration Client; never rotate catalog
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { slugDisplayName, clipInstanceKey } = require('./channel-instance-key');
12
+ const { ensureMcpClientIntegrationClient } = require('./mcp-client/ensure-client');
13
+
14
+ const MS_COPILOT_CATALOG_KEY = 'ms-copilot';
15
+ const MS_COPILOT_REDIRECT_URIS = Object.freeze([
16
+ 'https://copilot.microsoft.com/oauth/callback',
17
+ 'https://global.consent.azure-apim.net/redirect',
18
+ 'https://global.consent.azure-apim.net/redirect/*',
19
+ 'https://europe.consent.azure-apim.net/redirect',
20
+ 'https://europe.consent.azure-apim.net/redirect/*'
21
+ ]);
22
+
23
+ /**
24
+ * Controller environment infix. Production omits the segment.
25
+ * @param {string} [environment]
26
+ * @returns {string}
27
+ */
28
+ function environmentInfix(environment) {
29
+ const raw = String(environment || '').trim().toLowerCase();
30
+ if (!raw || raw === 'prod' || raw === 'production' || raw === 'live') {
31
+ return '';
32
+ }
33
+ if (raw === 'test') {
34
+ return 'tst';
35
+ }
36
+ return raw.replace(/[^a-z0-9]+/g, '').slice(0, 8);
37
+ }
38
+
39
+ /**
40
+ * Instance Integration Client key. key and keycloakClientId match.
41
+ * @param {string} catalogKey
42
+ * @param {string} [environment]
43
+ * @param {string} slug
44
+ * @returns {string}
45
+ */
46
+ function predefinedClientInstanceKey(catalogKey, environment, slug) {
47
+ const infix = environmentInfix(environment);
48
+ const parts = infix ? [catalogKey, infix, slug] : [catalogKey, slug];
49
+ return clipInstanceKey(parts.join('-'));
50
+ }
51
+
52
+ /**
53
+ * @param {Object} params
54
+ * @returns {string}
55
+ */
56
+ function copilotInstallClientKey(params) {
57
+ const slug = slugDisplayName(params.baseName || params.name || params.appName);
58
+ return predefinedClientInstanceKey(MS_COPILOT_CATALOG_KEY, params.environment, slug);
59
+ }
60
+
61
+ /**
62
+ * @param {string} [controllerUrl]
63
+ * @param {string} clientKey
64
+ * @returns {{ oauth2ProfileId: string, oauth2ProfilePath: string, oauth2ProfileUrl?: string }}
65
+ */
66
+ function oauth2ProfileFromClientKey(controllerUrl, clientKey) {
67
+ const oauth2ProfilePath = `/external-access/oauth2-profiles/${clientKey}`;
68
+ const resolved = { oauth2ProfileId: clientKey, oauth2ProfilePath };
69
+ if (typeof controllerUrl === 'string' && controllerUrl.trim()) {
70
+ resolved.oauth2ProfileUrl = `${controllerUrl.replace(/\/$/, '')}${oauth2ProfilePath}`;
71
+ }
72
+ return resolved;
73
+ }
74
+
75
+ function applyCopilotRuntimeDomain(resolved) {
76
+ resolved.runtimeDomain = '';
77
+ try {
78
+ resolved.runtimeDomain = new URL(resolved.mcpUrl).hostname;
79
+ } catch {
80
+ try {
81
+ resolved.runtimeDomain = new URL(resolved.dataplaneBaseUrl).hostname;
82
+ } catch {
83
+ resolved.runtimeDomain = '';
84
+ }
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Apply instance OAuth2 profile URLs on Copilot runtime values (deterministic key).
90
+ * @param {Object} resolved
91
+ * @param {Object} params
92
+ * @returns {void}
93
+ */
94
+ function applyCopilotOauthProfile(resolved, params) {
95
+ const slug = slugDisplayName(params.baseName || params.appName);
96
+ if (!slug) {
97
+ return;
98
+ }
99
+ Object.assign(
100
+ resolved,
101
+ oauth2ProfileFromClientKey(params.controllerUrl, copilotInstallClientKey({
102
+ baseName: params.baseName,
103
+ appName: params.appName,
104
+ environment: params.environment || resolved.environment
105
+ }))
106
+ );
107
+ }
108
+
109
+ /**
110
+ * Create or reuse the per-install client. Never regenerate-secret. Never touch catalog miso-ms-copilot.
111
+ * @param {Object} params
112
+ * @returns {Promise<{ client: Object, created: boolean, added: boolean, clientKey: string }|null>}
113
+ */
114
+ async function ensureCopilotInstallClient(params) {
115
+ if (params.options && params.options.dryRun === true) {
116
+ return null;
117
+ }
118
+ const ctx = params.ctx;
119
+ if (!ctx || !ctx.controllerUrl || !ctx.authConfig) {
120
+ return null;
121
+ }
122
+ const clientKey = copilotInstallClientKey({
123
+ name: params.name,
124
+ baseName: params.baseName,
125
+ environment: ctx.environment
126
+ });
127
+ const profile = {
128
+ key: clientKey,
129
+ displayName: `MS Copilot (${params.name || clientKey})`,
130
+ oauth: {
131
+ integrationClientKey: clientKey,
132
+ keycloakClientId: clientKey,
133
+ redirectUris: [...MS_COPILOT_REDIRECT_URIS]
134
+ }
135
+ };
136
+ const ensured = await ensureMcpClientIntegrationClient({
137
+ ctx,
138
+ profile,
139
+ deps: params.deps || {}
140
+ });
141
+ return { ...ensured, clientKey };
142
+ }
143
+
144
+ module.exports = {
145
+ MS_COPILOT_CATALOG_KEY,
146
+ MS_COPILOT_REDIRECT_URIS,
147
+ environmentInfix,
148
+ predefinedClientInstanceKey,
149
+ copilotInstallClientKey,
150
+ oauth2ProfileFromClientKey,
151
+ applyCopilotOauthProfile,
152
+ applyCopilotRuntimeDomain,
153
+ ensureCopilotInstallClient
154
+ };
@@ -11,6 +11,7 @@
11
11
  const { ApiClient, createDataplaneApiClient } = require('../api/index');
12
12
  const { fetchDataplaneGeneralHealth } = require('../api/dataplane-health.api');
13
13
  const { resolveChannelRuntimeValues } = require('./channel-runtime-resolver');
14
+ const { vendorFacingUrlsFromCtx } = require('./vendor-dataplane-url');
14
15
  const {
15
16
  fetchRuntimeLayerBToolNames,
16
17
  isRuntimeMcpGatewayReachable
@@ -149,8 +150,10 @@ async function buildChatGptProbeDetails(
149
150
  layerBToolNames,
150
151
  catalogItems = []
151
152
  ) {
153
+ const vendor = vendorFacingUrlsFromCtx(ctx);
152
154
  const runtime = resolveChannelRuntimeValues({
153
- dataplaneBaseUrl: ctx.dataplaneUrl,
155
+ dataplaneBaseUrl: vendor.dataplaneBaseUrl,
156
+ controllerUrl: vendor.controllerUrl,
154
157
  channelTarget: 'chatgpt',
155
158
  appName: channelExt?.name || 'chatgpt',
156
159
  baseName: channelExt?.baseName || channelExt?.name || 'chatgpt',
@@ -181,8 +184,10 @@ async function buildChatGptProbeDetails(
181
184
  * @returns {Promise<{ probeTiers: Object, runtimeChecks: Object }>}
182
185
  */
183
186
  async function buildMicrosoftCopilotProbeDetails(ctx, channelExt, catalogOk, layerBToolNames) {
187
+ const vendor = vendorFacingUrlsFromCtx(ctx);
184
188
  const runtime = resolveChannelRuntimeValues({
185
- dataplaneBaseUrl: ctx.dataplaneUrl,
189
+ dataplaneBaseUrl: vendor.dataplaneBaseUrl,
190
+ controllerUrl: vendor.controllerUrl,
186
191
  channelTarget: 'microsoft-copilot',
187
192
  appName: channelExt?.name || 'microsoft-copilot',
188
193
  baseName: channelExt?.baseName || channelExt?.name || 'microsoft-copilot',