@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
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Copilot waiting install and channel-install envelope persistence.
3
+ *
4
+ * @fileoverview Entra SSO wait path plus help payload for generic channel install
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { toChannelInstallEnvelope } = require('../channels/channel-install-envelope');
12
+ const { toChannelInstallHttpPayload } = require('../channels/channel-install-http-payload');
13
+ const { resolveChannelRuntimeValues } = require('../channels/channel-runtime-resolver');
14
+ const { vendorFacingUrlsFromCtx } = require('../channels/vendor-dataplane-url');
15
+ const {
16
+ startPortalMicrosoftLogin,
17
+ isLoopbackAuthorizeUrl
18
+ } = require('../channels/microsoft-provisioning');
19
+ const { writeChannelInstallSession, httpError } = require('./channel-install-session');
20
+ const { attachInstallIdentity } = require('./channel-install-help-resolve');
21
+
22
+ /**
23
+ * Missing Teams Entra SSO id is a remaining step, not a publish failure.
24
+ * @param {unknown} err
25
+ * @returns {boolean}
26
+ */
27
+ function isCopilotEntraWaitingError(err) {
28
+ if (!err || Number(err.statusCode) !== 409) {
29
+ return false;
30
+ }
31
+ return /Entra SSO registration is stored on this install/i.test(String(err.message || ''));
32
+ }
33
+
34
+ /**
35
+ * @param {import('./workspace-context').WorkspaceContext} ctx
36
+ * @param {Object} addOptions
37
+ * @param {string} definitionKey
38
+ * @returns {Object}
39
+ */
40
+ function copilotWaitingRuntimeValues(ctx, addOptions, definitionKey) {
41
+ const vendor = vendorFacingUrlsFromCtx(ctx);
42
+ return resolveChannelRuntimeValues({
43
+ dataplaneBaseUrl: vendor.dataplaneBaseUrl,
44
+ controllerUrl: vendor.controllerUrl,
45
+ channelTarget: definitionKey,
46
+ appName: addOptions.name,
47
+ instanceSystemKey: addOptions.systemKey || ctx.instanceSystemKey || ctx.systemKey,
48
+ environment: ctx.environment,
49
+ appDescription: typeof addOptions.description === 'string' ? addOptions.description : ''
50
+ });
51
+ }
52
+
53
+ function applyPortalMicrosoftLogin(runtimeValues, login) {
54
+ const loginUrl = login && login.loginUrl ? String(login.loginUrl).trim() : '';
55
+ if (loginUrl && !isLoopbackAuthorizeUrl(loginUrl)) {
56
+ runtimeValues.microsoftLoginUrl = loginUrl;
57
+ }
58
+ if (login && login.userCode) {
59
+ runtimeValues.microsoftLoginUserCode = login.userCode;
60
+ }
61
+ return runtimeValues;
62
+ }
63
+
64
+ /**
65
+ * @param {import('./workspace-context').WorkspaceContext} ctx
66
+ * @param {Object} addOptions
67
+ * @param {string} definitionKey
68
+ * @param {Object} [deps]
69
+ * @returns {Promise<Object>}
70
+ */
71
+ async function retryCopilotCaptureIfAuthenticated(ctx, addOptions, definitionKey, deps, login) {
72
+ if (!login || login.authenticated !== true || addOptions.copilotCaptureRetry === true) {
73
+ return null;
74
+ }
75
+ try {
76
+ const result = await deps.executeAddChannel(
77
+ ctx,
78
+ { ...addOptions, copilotCaptureRetry: true },
79
+ deps,
80
+ definitionKey
81
+ );
82
+ if (copilotInstallStillWaiting(definitionKey, result)) {
83
+ return null;
84
+ }
85
+ const envelope = envelopeFromInstall(ctx, addOptions, result, definitionKey);
86
+ return persistHelpPayload(ctx, addOptions, envelope, definitionKey, result);
87
+ } catch (err) {
88
+ if (!isCopilotEntraWaitingError(err)) {
89
+ throw err;
90
+ }
91
+ return null;
92
+ }
93
+ }
94
+
95
+ function copilotWaitingWithoutSignInError(login) {
96
+ if (login && login.authenticated === true) {
97
+ return httpError(
98
+ 'Microsoft sign-in succeeded, but Copilot setup still needs Entra SSO. ' +
99
+ 'This environment needs an Entra application id and a public MCP URL.',
100
+ 400
101
+ );
102
+ }
103
+ return httpError(
104
+ 'Could not start Microsoft sign-in. Use Get a new code, complete sign-in, then click Continue.',
105
+ 409
106
+ );
107
+ }
108
+
109
+ /**
110
+ * Add-channel can skip/succeed without Entra SSO landing on the install result.
111
+ * @param {string} definitionKey
112
+ * @param {Object|null} result
113
+ * @returns {boolean}
114
+ */
115
+ function copilotInstallStillWaiting(definitionKey, result) {
116
+ if (definitionKey !== 'microsoft-copilot') {
117
+ return false;
118
+ }
119
+ const vault =
120
+ result &&
121
+ result.runtimeValues &&
122
+ typeof result.runtimeValues.oauthPluginVaultReferenceId === 'string'
123
+ ? result.runtimeValues.oauthPluginVaultReferenceId.trim()
124
+ : '';
125
+ return !vault;
126
+ }
127
+
128
+ function persistCopilotWaitingEnvelope(ctx, addOptions, definitionKey, runtimeValues, login) {
129
+ applyPortalMicrosoftLogin(runtimeValues, login);
130
+ const loginUrl =
131
+ typeof runtimeValues.microsoftLoginUrl === 'string' ? runtimeValues.microsoftLoginUrl.trim() : '';
132
+ if (!loginUrl) {
133
+ throw copilotWaitingWithoutSignInError(login);
134
+ }
135
+ const envelope = toChannelInstallEnvelope({
136
+ channelTarget: definitionKey,
137
+ displayName: addOptions.name,
138
+ ctx: remainingCtxFromResult(ctx, null, addOptions),
139
+ runtimeValues,
140
+ verdicts: {
141
+ runtime: { ok: true, label: 'Deployed' },
142
+ oauth: { ok: true, label: 'Connected' },
143
+ vendorSession: { ok: false, label: 'Approval required' }
144
+ }
145
+ });
146
+ return persistHelpPayload(ctx, addOptions, envelope, definitionKey, { runtimeValues });
147
+ }
148
+
149
+ async function persistWaitingCopilotInstall(ctx, addOptions, definitionKey, deps = {}) {
150
+ const runtimeValues = copilotWaitingRuntimeValues(ctx, addOptions, definitionKey);
151
+ let login = { waiting: true };
152
+ try {
153
+ login = await startPortalMicrosoftLogin({
154
+ installationKey: addOptions.systemKey || ctx.instanceSystemKey || ctx.systemKey,
155
+ expectedTenantId: runtimeValues.entraTenantId,
156
+ retryLogin: addOptions.retryLogin === true,
157
+ deps: (deps && deps.microsoftProvisioningDeps) || {}
158
+ });
159
+ } catch (err) {
160
+ if (err && (err.statusCode || err.code === 'WRONG_TENANT' || err.code === 'TOOLKIT')) {
161
+ throw err;
162
+ }
163
+ throw httpError(
164
+ (err && err.message) || 'Could not start Microsoft sign-in.',
165
+ 409
166
+ );
167
+ }
168
+ const captured = await retryCopilotCaptureIfAuthenticated(
169
+ ctx,
170
+ addOptions,
171
+ definitionKey,
172
+ deps,
173
+ login
174
+ );
175
+ if (captured) {
176
+ return captured;
177
+ }
178
+ return persistCopilotWaitingEnvelope(ctx, addOptions, definitionKey, runtimeValues, login);
179
+ }
180
+
181
+ /**
182
+ * @param {Object|null} result
183
+ * @returns {Object}
184
+ */
185
+ function teamsBotOauthOk(definitionKey, result, blocker) {
186
+ if (blocker) {
187
+ return false;
188
+ }
189
+ if (definitionKey !== 'teams-bot') {
190
+ return true;
191
+ }
192
+ const bot = result && result.teamsBotProvision;
193
+ return Boolean(bot && bot.connected === true && bot.skipped !== true);
194
+ }
195
+
196
+ /**
197
+ * @param {Object|null} result
198
+ * @param {string} [definitionKey]
199
+ * @returns {Object}
200
+ */
201
+ function verdictsFromInstallResult(result, definitionKey) {
202
+ const runtimeValues = (result && result.runtimeValues) || {};
203
+ const blocker = runtimeValues.discoveryBlocker;
204
+ const slack = result && result.slackProvision;
205
+ const connected = Boolean(slack && slack.connected === true);
206
+ const oauthOk = teamsBotOauthOk(definitionKey, result, blocker);
207
+ const teamsConnected = teamsBotOauthOk('teams-bot', result, blocker);
208
+ return {
209
+ runtime: {
210
+ ok: !blocker,
211
+ label: blocker ? 'Unavailable' : 'Deployed'
212
+ },
213
+ oauth: { ok: oauthOk, label: oauthOk ? 'Connected' : 'Not connected' },
214
+ vendorSession: {
215
+ ok: definitionKey === 'teams-bot' ? teamsConnected : connected,
216
+ label: (definitionKey === 'teams-bot' ? teamsConnected : connected)
217
+ ? 'Connected'
218
+ : 'Approval required'
219
+ }
220
+ };
221
+ }
222
+
223
+ /**
224
+ * @param {import('./workspace-context').WorkspaceContext} ctx
225
+ * @param {Object} result
226
+ * @param {Object} [addOptions]
227
+ * @returns {Object}
228
+ */
229
+ function remainingCtxFromResult(ctx, result, addOptions) {
230
+ const slack = (result && result.slackProvision) || {};
231
+ const teamsBot = (result && result.teamsBotProvision) || {};
232
+ const runtime = (result && result.runtimeValues) || {};
233
+ return {
234
+ dataplaneUrl: ctx.dataplaneUrl,
235
+ publicOrigin: ctx.publicOrigin,
236
+ environment: ctx.environment,
237
+ projectRoot: ctx.getUserRoot(),
238
+ instanceSystemKey:
239
+ (addOptions && addOptions.systemKey) || ctx.instanceSystemKey || runtime.instanceSystemKey,
240
+ slackConnected: slack.connected === true,
241
+ slackAppSettingsUrl: slack.slackAppSettingsUrl || slack.appSettingsUrl,
242
+ slackInstallAppUrl: slack.slackInstallAppUrl || slack.installUrl,
243
+ slackWorkspaceApproveUrl: slack.slackWorkspaceApproveUrl,
244
+ slackRemaining: slack.remaining,
245
+ slackSlashCommand: slack.slashCommand,
246
+ slackHandshakeFailed: slack.handshakeFailed === true,
247
+ teamsBotSkipped: teamsBot.skipped === true,
248
+ teamsBotOpenUrl: teamsBot.openUrl,
249
+ teamsBotRemaining: teamsBot.remaining,
250
+ microsoftLoginUrl: runtime.microsoftLoginUrl
251
+ };
252
+ }
253
+
254
+ /**
255
+ * @param {import('./workspace-context').WorkspaceContext} ctx
256
+ * @param {Object} addOptions
257
+ * @param {Object|null} result
258
+ * @returns {Object}
259
+ */
260
+ function envelopeFromInstall(ctx, addOptions, result, definitionKey) {
261
+ const runtimeValues = (result && result.runtimeValues) || { appName: addOptions.name };
262
+ return toChannelInstallEnvelope({
263
+ channelTarget: definitionKey || ctx.systemKey,
264
+ displayName: runtimeValues.appName || addOptions.name,
265
+ ctx: remainingCtxFromResult(ctx, result, addOptions),
266
+ runtimeValues,
267
+ verdicts: verdictsFromInstallResult(result, definitionKey || ctx.systemKey)
268
+ });
269
+ }
270
+
271
+ /**
272
+ * @param {Object} addOptions
273
+ * @param {Object|null} [result]
274
+ * @returns {string|undefined}
275
+ */
276
+ function persistableCommandPrefix(addOptions, result) {
277
+ const fromOptions =
278
+ typeof addOptions.commandPrefix === 'string' ? addOptions.commandPrefix.trim() : '';
279
+ if (fromOptions) {
280
+ return fromOptions;
281
+ }
282
+ const runtime = (result && result.runtimeValues) || {};
283
+ return typeof runtime.commandPrefix === 'string' ? runtime.commandPrefix.trim() : undefined;
284
+ }
285
+
286
+ /**
287
+ * @param {Object} addOptions
288
+ * @param {Object|null} [result]
289
+ * @returns {string|undefined}
290
+ */
291
+ function persistablePackageVersion(addOptions, result) {
292
+ const fromOptions =
293
+ typeof addOptions.packageVersion === 'string' ? addOptions.packageVersion.trim() : '';
294
+ if (fromOptions) {
295
+ return fromOptions;
296
+ }
297
+ const runtime = (result && result.runtimeValues) || {};
298
+ return typeof runtime.packageVersion === 'string' ? runtime.packageVersion.trim() : undefined;
299
+ }
300
+
301
+ /**
302
+ * @param {Object|null} [result]
303
+ * @param {string} key
304
+ * @returns {*|undefined}
305
+ */
306
+ function persistableRuntimeValue(result, key) {
307
+ const runtime = (result && result.runtimeValues) || {};
308
+ return runtime[key];
309
+ }
310
+
311
+ /**
312
+ * @param {import('./workspace-context').WorkspaceContext} ctx
313
+ * @param {Object} addOptions
314
+ * @param {Object} envelope
315
+ * @param {string} [definitionKey]
316
+ * @param {Object|null} [result]
317
+ * @returns {Object}
318
+ */
319
+ function persistHelpPayload(ctx, addOptions, envelope, definitionKey, result) {
320
+ const payload = toChannelInstallHttpPayload(envelope);
321
+ const installationKey = addOptions.systemKey || ctx.instanceSystemKey || ctx.systemKey;
322
+ const catalogKey = definitionKey || ctx.systemKey;
323
+ const slack = (result && result.slackProvision) || {};
324
+ writeChannelInstallSession(ctx, {
325
+ name: addOptions.name,
326
+ displayName: envelope.displayName,
327
+ profile: addOptions.profile || null,
328
+ allowExperimental: addOptions.allowExperimental === true,
329
+ phase: envelope.phase,
330
+ envelope,
331
+ definitionKey: catalogKey,
332
+ installationKey,
333
+ slackAuthTicket: slack.slackAuthTicket,
334
+ commandPrefix: persistableCommandPrefix(addOptions, result),
335
+ packageVersion: persistablePackageVersion(addOptions, result),
336
+ packageAppId: persistableRuntimeValue(result, 'packageAppId'),
337
+ oauthPluginVaultReferenceId: persistableRuntimeValue(result, 'oauthPluginVaultReferenceId'),
338
+ microsoftLoginUrl: persistableRuntimeValue(result, 'microsoftLoginUrl'),
339
+ microsoftLoginUserCode: persistableRuntimeValue(result, 'microsoftLoginUserCode'),
340
+ microsoftAuthConfigFallback: persistableRuntimeValue(result, 'microsoftAuthConfigFallback') === true
341
+ });
342
+ return attachInstallIdentity(payload, catalogKey, installationKey);
343
+ }
344
+
345
+ module.exports = {
346
+ isCopilotEntraWaitingError,
347
+ copilotInstallStillWaiting,
348
+ persistWaitingCopilotInstall,
349
+ envelopeFromInstall,
350
+ persistHelpPayload,
351
+ remainingCtxFromResult,
352
+ verdictsFromInstallResult
353
+ };
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Validate and map generic channel install POST body to add-channel options.
3
+ *
4
+ * @fileoverview Shared by HTTP install and continue
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const {
12
+ formatUnknownChannelTargetError,
13
+ listLiveChannelTargetKeys,
14
+ assertChannelTargetInstallable
15
+ } = require('../channels/channel-targets');
16
+ const { getChannelDefinition } = require('../channels/channel-definition-registry');
17
+ const {
18
+ unknownConfigurationKeys,
19
+ missingRequiredConfigurationKeys,
20
+ applyConfigurationToAddOptions
21
+ } = require('../channels/channel-configuration-map');
22
+ const { deriveChannelInstanceKey } = require('../channels/channel-instance-key');
23
+ const {
24
+ installRequiresProfile,
25
+ isAllowedInstallProfile,
26
+ profilesForInstall
27
+ } = require('../channels/channel-install-profiles');
28
+ const { httpError } = require('./channel-install-session');
29
+
30
+ /**
31
+ * @param {string} systemKey
32
+ * @param {Object} body
33
+ * @returns {void}
34
+ */
35
+ function assertInstallProfile(systemKey, body) {
36
+ if (!installRequiresProfile(systemKey)) {
37
+ return;
38
+ }
39
+ const profile = typeof body.profile === 'string' ? body.profile.trim() : '';
40
+ if (!profile) {
41
+ const keys = profilesForInstall(systemKey).map((row) => row.key).join(', ');
42
+ throw httpError(`profile is required for ${systemKey} (${keys}).`, 400);
43
+ }
44
+ if (!isAllowedInstallProfile(systemKey, profile)) {
45
+ const keys = profilesForInstall(systemKey).map((row) => row.key).join(', ');
46
+ throw httpError(`Unknown profile "${profile}" for ${systemKey}. Allowed: ${keys}.`, 400);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * @param {string} systemKey
52
+ * @param {Object} body
53
+ * @returns {void}
54
+ */
55
+ function assertChannelInstallTarget(systemKey, body) {
56
+ assertInstallProfile(systemKey, body || {});
57
+ try {
58
+ assertChannelTargetInstallable(systemKey, {
59
+ allowExperimental: body && body.allowExperimental === true
60
+ });
61
+ } catch (err) {
62
+ const live = listLiveChannelTargetKeys({
63
+ allowExperimental: body && body.allowExperimental === true
64
+ }).join(', ');
65
+ throw httpError(`${err.message}\nLive channels: ${live}`, 400);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @param {Object} body
71
+ * @returns {string}
72
+ */
73
+ function requireInstallName(body) {
74
+ const name = body && typeof body.name === 'string' ? body.name.trim() : '';
75
+ if (!name) {
76
+ throw httpError('name is required.', 400);
77
+ }
78
+ return name;
79
+ }
80
+
81
+ /**
82
+ * @param {unknown} value
83
+ * @returns {boolean}
84
+ */
85
+ function isRetryLoginFlag(value) {
86
+ return value === true || value === 'true' || value === '1';
87
+ }
88
+
89
+ /**
90
+ * @param {Object} options
91
+ * @param {Object} body
92
+ * @param {Object|null} def
93
+ * @returns {Object}
94
+ */
95
+ function mergeInstallConfiguration(body) {
96
+ const source = body && typeof body === 'object' ? body : {};
97
+ const configuration = {
98
+ ...(source.configuration && typeof source.configuration === 'object' ? source.configuration : {})
99
+ };
100
+ for (const key of ['commandPrefix', 'packageVersion', 'oauthPluginVaultReferenceId']) {
101
+ if (configuration[key] === undefined && typeof source[key] === 'string' && source[key].trim()) {
102
+ configuration[key] = source[key].trim();
103
+ }
104
+ }
105
+ return configuration;
106
+ }
107
+
108
+ /**
109
+ * @param {Object} options
110
+ * @param {Object} body
111
+ * @param {Object|null} def
112
+ * @returns {Object}
113
+ */
114
+ function applyInstallConfiguration(options, body, def) {
115
+ const configuration = mergeInstallConfiguration(body);
116
+ if (def) {
117
+ const unknown = unknownConfigurationKeys(def, configuration);
118
+ if (unknown.length > 0) {
119
+ throw httpError(`Unknown configuration key(s): ${unknown.join(', ')}.`, 400);
120
+ }
121
+ const missing = missingRequiredConfigurationKeys(def, configuration);
122
+ if (missing.length > 0) {
123
+ throw httpError(`Missing required configuration: ${missing.join(', ')}.`, 400);
124
+ }
125
+ } else if (Object.keys(configuration).length > 0) {
126
+ throw httpError('Unknown configuration keys cannot be validated without a Channel Definition.', 400);
127
+ }
128
+ return applyConfigurationToAddOptions(options, configuration);
129
+ }
130
+
131
+ /**
132
+ * @param {Object} body
133
+ * @param {Object|null} def
134
+ * @returns {Object}
135
+ */
136
+ function applyVendorSessionToken(options, body) {
137
+ if (isRetryLoginFlag(body && body.retryLogin)) {
138
+ options.retryLogin = true;
139
+ return options;
140
+ }
141
+ const token = body && typeof body.token === 'string' ? body.token.trim() : '';
142
+ if (token) {
143
+ options.vendorSessionToken = token;
144
+ }
145
+ const ticket = body && typeof body.slackAuthTicket === 'string' ? body.slackAuthTicket.trim() : '';
146
+ if (ticket) {
147
+ options.slackAuthTicket = ticket;
148
+ }
149
+ return options;
150
+ }
151
+
152
+ /**
153
+ * @param {Object} options
154
+ * @param {Object} body
155
+ * @param {Object|null} def
156
+ * @returns {Object}
157
+ */
158
+ function applyInstallBodyOptions(body, def) {
159
+ const options = applyVendorSessionToken(applyInstallConfiguration({
160
+ name: requireInstallName(body),
161
+ force: body.force === true,
162
+ probe: body.probe === true,
163
+ dryRun: body.dryRun === true,
164
+ allowExperimental: body.allowExperimental === true,
165
+ continueInstall: body.continueInstall === true,
166
+ quiet: true
167
+ }, body, def), body);
168
+ if (body.onboardUsers === true) {
169
+ options.onboardUsers = true;
170
+ }
171
+ if (body.onboardUsers === false) {
172
+ options.onboardUsers = false;
173
+ }
174
+ if (typeof body.profile === 'string' && body.profile.trim()) {
175
+ const profile = body.profile.trim();
176
+ options.profile = profile;
177
+ options.target = profile;
178
+ options.mcpClientProfile = profile;
179
+ }
180
+ return options;
181
+ }
182
+
183
+ /**
184
+ * @param {Object} options
185
+ * @param {Object} body
186
+ * @param {Object|null} def
187
+ * @returns {Object}
188
+ */
189
+ function assignDerivedSystemKey(options, body, def) {
190
+ const explicitKey = typeof body.systemKey === 'string' ? body.systemKey : '';
191
+ if (!(def && def.key) && !explicitKey) {
192
+ return options;
193
+ }
194
+ try {
195
+ options.systemKey = deriveChannelInstanceKey(
196
+ (def && def.key) || 'channel',
197
+ options.name,
198
+ explicitKey
199
+ );
200
+ } catch (err) {
201
+ throw httpError(err.message, 400);
202
+ }
203
+ return options;
204
+ }
205
+
206
+ /**
207
+ * Map HTTP body to runAddChannel options (same flags as `channel add --name`).
208
+ * @param {Object} body
209
+ * @param {Object} [definition]
210
+ * @returns {Object}
211
+ */
212
+ function toChannelAddOptionsFromBody(body, definition) {
213
+ const def = definition || getChannelDefinition(body && body.definitionKey) || null;
214
+ return assignDerivedSystemKey(applyInstallBodyOptions(body, def), body, def);
215
+ }
216
+
217
+ /**
218
+ * @param {string} systemKey
219
+ * @returns {Error}
220
+ */
221
+ function unknownChannelError(systemKey) {
222
+ return httpError(formatUnknownChannelTargetError(systemKey), 400);
223
+ }
224
+
225
+ module.exports = {
226
+ assertChannelInstallTarget,
227
+ assertInstallProfile,
228
+ requireInstallName,
229
+ toChannelAddOptionsFromBody,
230
+ unknownChannelError,
231
+ isRetryLoginFlag
232
+ };