@aifabrix/builder 2.53.0 → 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 +119 -16
  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
@@ -15,7 +15,10 @@ const { buildSlackApprovalGuide } = require('./slack');
15
15
  const { buildTeamsBotApprovalGuide } = require('./teams-bot');
16
16
  const { buildMicrosoftCopilotApprovalGuide } = require('./microsoft-copilot');
17
17
  const { buildChatGptApprovalGuide } = require('./chatgpt');
18
+ const { buildClaudeApprovalGuide } = require('./claude');
18
19
  const { buildWebEmbedInstallGuide } = require('./web-embed');
20
+ const { buildMcpClientInstallGuide } = require('./mcp-client');
21
+ const { vendorFacingUrlsFromCtx } = require('../vendor-dataplane-url');
19
22
  const { buildCredentialPortalUrl } = require('./credential-portal');
20
23
 
21
24
  /** @type {Record<string, (ctx: Object) => { portalUrl: string|null, steps: string[] }>} */
@@ -24,6 +27,8 @@ const GUIDE_BUILDERS = {
24
27
  'teams-bot': buildTeamsBotApprovalGuide,
25
28
  'microsoft-copilot': buildMicrosoftCopilotApprovalGuide,
26
29
  chatgpt: buildChatGptApprovalGuide,
30
+ claude: buildClaudeApprovalGuide,
31
+ 'mcp-client': buildMcpClientInstallGuide,
27
32
  'web-embed': buildWebEmbedInstallGuide
28
33
  };
29
34
 
@@ -51,50 +56,110 @@ function buildResumeCommand(channelTarget, name) {
51
56
 
52
57
  /**
53
58
  * @param {string} channelTarget
54
- * @param {Object} [context]
59
+ * @param {Object} context
60
+ * @param {Object} target
55
61
  * @returns {Object}
56
62
  */
57
- function buildChannelApprovalGuide(channelTarget, context = {}) {
58
- const target = getChannelTarget(channelTarget);
59
- const builder = GUIDE_BUILDERS[channelTarget];
60
- if (!builder) {
61
- throw new Error(`No approval guide for channel target "${channelTarget}"`);
62
- }
63
-
63
+ function approvalGuideContext(channelTarget, context, target) {
64
64
  const projectRoot = context.projectRoot || process.cwd();
65
65
  const name = context.name || '';
66
+ const baseName = context.baseName || name;
66
67
  const artifactPath = resolveArtifactPath(projectRoot, channelTarget, context.artifactPath);
67
- const installGuidePath = path.join(path.dirname(artifactPath), 'INSTALL.md');
68
- const resumeCommand = buildResumeCommand(channelTarget, name);
69
- const credentialPortalUrl = context.dataplaneBaseUrl
70
- ? buildCredentialPortalUrl(context.dataplaneBaseUrl, channelTarget)
71
- : null;
72
- const baseCtx = {
68
+ const resumeName = channelTarget === 'chatgpt' || channelTarget === 'claude' ? baseName : name;
69
+ return {
73
70
  channelTarget,
74
71
  name,
75
- baseName: context.baseName || name,
72
+ baseName,
76
73
  environment: context.environment || 'dev',
77
74
  artifactPath,
78
- resumeCommand,
75
+ installGuidePath: path.join(path.dirname(artifactPath), 'INSTALL.md'),
76
+ resumeCommand: buildResumeCommand(channelTarget, resumeName),
79
77
  credentialKey: target.credentialKey,
80
- credentialPortalUrl
78
+ credentialPortalUrl: context.dataplaneBaseUrl
79
+ ? buildCredentialPortalUrl(context.dataplaneBaseUrl, channelTarget)
80
+ : null,
81
+ controllerUrl: context.controllerUrl,
82
+ oauth2ProfileUrl: context.oauth2ProfileUrl,
83
+ mcpUrl: context.mcpUrl,
84
+ appName: context.appName || name,
85
+ description: context.description,
86
+ authorizationUrl: context.authorizationUrl,
87
+ tokenUrl: context.tokenUrl,
88
+ clientId: context.clientId
81
89
  };
90
+ }
82
91
 
83
- const guide = builder(baseCtx);
92
+ /**
93
+ * @param {Object} context
94
+ * @param {Object} guide
95
+ * @param {string} channelTarget
96
+ * @returns {string|null}
97
+ */
98
+ function approvalGuideCredentialUrl(channelTarget, context, guide) {
99
+ if (guide.credentialPortalUrl !== undefined) {
100
+ return guide.credentialPortalUrl;
101
+ }
102
+ if (!context.dataplaneBaseUrl) {
103
+ return null;
104
+ }
105
+ return buildCredentialPortalUrl(context.dataplaneBaseUrl, channelTarget);
106
+ }
84
107
 
108
+ /**
109
+ * @param {string} channelTarget
110
+ * @param {Object} [context]
111
+ * @returns {Object}
112
+ */
113
+ function buildChannelApprovalGuide(channelTarget, context = {}) {
114
+ const target = getChannelTarget(channelTarget);
115
+ const builder = GUIDE_BUILDERS[channelTarget];
116
+ if (!builder) {
117
+ throw new Error(`No approval guide for channel target "${channelTarget}"`);
118
+ }
119
+ const baseCtx = approvalGuideContext(channelTarget, context, target);
120
+ const guide = builder(baseCtx);
85
121
  return {
86
122
  channelTarget,
123
+ heading: guide.heading,
87
124
  portalUrl: guide.portalUrl,
88
- artifactPath,
89
- installGuidePath,
90
- resumeCommand,
125
+ artifactPath: baseCtx.artifactPath,
126
+ installGuidePath: baseCtx.installGuidePath,
127
+ resumeCommand: baseCtx.resumeCommand,
91
128
  credentialKey: target.credentialKey,
92
- credentialPortalUrl,
129
+ credentialPortalUrl: approvalGuideCredentialUrl(channelTarget, context, guide),
93
130
  steps: guide.steps,
94
131
  approvalRequired: target.approvalRequired === true
95
132
  };
96
133
  }
97
134
 
135
+ /**
136
+ * @param {Object} params
137
+ * @returns {Object|null}
138
+ */
139
+ function buildLiveInstallApprovalGuide(params) {
140
+ const { channelTarget, status, artifact, name, baseName, ctx, options } = params;
141
+ if (status !== 'approvalRequired') {
142
+ return null;
143
+ }
144
+ const runtimeValues = params.runtimeValues || {};
145
+ const asMetadata = params.preflight && params.preflight.asMetadata;
146
+ const vendor = vendorFacingUrlsFromCtx(ctx);
147
+ return buildChannelApprovalGuide(channelTarget, {
148
+ projectRoot: options.projectRoot || process.cwd(),
149
+ name,
150
+ baseName,
151
+ artifactPath: artifact.outputPath,
152
+ dataplaneBaseUrl: vendor.dataplaneBaseUrl,
153
+ controllerUrl: vendor.controllerUrl,
154
+ environment: ctx.environment || options.environment || 'dev',
155
+ oauth2ProfileUrl: runtimeValues.oauth2ProfileUrl,
156
+ mcpUrl: runtimeValues.mcpUrl,
157
+ description: runtimeValues.appDescription,
158
+ authorizationUrl: asMetadata && asMetadata.authorization_endpoint,
159
+ tokenUrl: asMetadata && asMetadata.token_endpoint
160
+ });
161
+ }
162
+
98
163
  /**
99
164
  * @param {string} channelTarget
100
165
  * @param {Object} [context]
@@ -107,6 +172,7 @@ function resolveApprovalPortalUrl(channelTarget, context = {}) {
107
172
  module.exports = {
108
173
  GUIDE_BUILDERS,
109
174
  buildChannelApprovalGuide,
175
+ buildLiveInstallApprovalGuide,
110
176
  resolveApprovalPortalUrl,
111
177
  resolveArtifactPath,
112
178
  buildResumeCommand
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Developer MCP client go-live steps — reload the editor after mcp.json merge.
3
+ *
4
+ * @fileoverview Remaining operator step for mcp-client
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ /**
10
+ * @param {Object} ctx
11
+ * @returns {{ heading: string, portalUrl: null, steps: string[], credentialPortalUrl: null }}
12
+ */
13
+ function buildMcpClientInstallGuide(ctx) {
14
+ const profile = ctx.mcpClientProfileKey || '<profile>';
15
+ return {
16
+ heading: 'Reload the editor',
17
+ portalUrl: null,
18
+ credentialPortalUrl: null,
19
+ steps: [
20
+ 'Reload the editor so it reads the merged MCP client config.',
21
+ 'Sign in with your user account when the editor starts OAuth.',
22
+ `Re-run: aifabrix channel add mcp-client --target ${profile} --name "${ctx.name || ''}"`
23
+ ]
24
+ };
25
+ }
26
+
27
+ module.exports = { buildMcpClientInstallGuide };
@@ -8,8 +8,53 @@
8
8
 
9
9
  'use strict';
10
10
 
11
+ const fs = require('../../internal/fs-real-sync');
12
+ const path = require('path');
13
+
11
14
  const DEVELOPER_PORTAL_URL = 'https://dev.teams.microsoft.com/';
15
+ const DEVELOPER_PORTAL_APPS_URL = 'https://dev.teams.microsoft.com/apps';
12
16
  const TEAMS_ADMIN_APPS_URL = 'https://admin.teams.microsoft.com/policies/manage-apps';
17
+ const TEAMS_APP_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
18
+
19
+ /**
20
+ * Developer Portal publish-to-org page for a packaged Teams app id.
21
+ * @param {string} [appId]
22
+ * @returns {string}
23
+ */
24
+ function developerPortalPublishOrgUrl(appId) {
25
+ const id = typeof appId === 'string' ? appId.trim() : '';
26
+ if (!TEAMS_APP_ID.test(id)) {
27
+ return DEVELOPER_PORTAL_APPS_URL;
28
+ }
29
+ return `${DEVELOPER_PORTAL_APPS_URL}/${id}/publish-org`;
30
+ }
31
+
32
+ /**
33
+ * Packaged Teams app / manifest id from runtime values or the built source manifest.
34
+ * @param {Object|null} ctx
35
+ * @param {Object|null} runtimeValues
36
+ * @returns {string}
37
+ */
38
+ function copilotPackageAppId(ctx, runtimeValues) {
39
+ const fromRuntime =
40
+ runtimeValues && typeof runtimeValues.packageAppId === 'string'
41
+ ? runtimeValues.packageAppId.trim()
42
+ : '';
43
+ if (fromRuntime) {
44
+ return fromRuntime;
45
+ }
46
+ const root = ctx && typeof ctx.projectRoot === 'string' ? ctx.projectRoot.trim() : '';
47
+ if (!root) {
48
+ return '';
49
+ }
50
+ try {
51
+ const manifestPath = path.join(root, 'dist', 'channels', 'microsoft-copilot', 'source', 'manifest.json');
52
+ const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
53
+ return typeof parsed.id === 'string' ? parsed.id.trim() : '';
54
+ } catch {
55
+ return '';
56
+ }
57
+ }
13
58
 
14
59
  /**
15
60
  * @param {Object} ctx
@@ -25,14 +70,15 @@ function buildMicrosoftCopilotApprovalGuide(ctx) {
25
70
  (typeof ctx.baseName === 'string' && ctx.baseName.trim()) ||
26
71
  'your app';
27
72
  return {
28
- portalUrl: DEVELOPER_PORTAL_URL,
73
+ portalUrl: DEVELOPER_PORTAL_APPS_URL,
74
+ heading: 'Organisation publish / Teams admin approval required',
29
75
  steps: [
30
- `Open Teams Developer Portal (${DEVELOPER_PORTAL_URL}).`,
76
+ `Open Teams Developer Portal (${DEVELOPER_PORTAL_APPS_URL}).`,
31
77
  `Click Import an app → import ${zipName}. Preserve the generated stable manifest.json.id. Do not create an unrelated new Teams app.`,
32
78
  'Developer Portal → selected app → Publish to your org → Distribute / submit.',
33
79
  `Teams admin approves in ${TEAMS_ADMIN_APPS_URL} (Manage apps → search → allow). Expect Published / Unblocked per organisation policy. Allow several minutes for propagation.`,
34
80
  `Open Teams → Apps (Built for your org), click "${appName}", Add the application, then choose Open with Copilot.`,
35
- 'In Copilot, click "Show my role assistants" and run the command.',
81
+ 'In Copilot, click a conversation starter titled like "vX.Y.Z — Role Assistants" and run it.',
36
82
  'Confirm Runtime MCP and governed tools using INSTALL.md, then re-run with --probe after organisation publish.',
37
83
  `After the app is available under Built for your org, re-run: ${ctx.resumeCommand}`
38
84
  ]
@@ -41,6 +87,9 @@ function buildMicrosoftCopilotApprovalGuide(ctx) {
41
87
 
42
88
  module.exports = {
43
89
  buildMicrosoftCopilotApprovalGuide,
90
+ copilotPackageAppId,
91
+ developerPortalPublishOrgUrl,
44
92
  DEVELOPER_PORTAL_URL,
93
+ DEVELOPER_PORTAL_APPS_URL,
45
94
  TEAMS_ADMIN_APPS_URL
46
95
  };
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Slack channel admin approval steps (plan 152).
2
+ * Slack channel admin approval steps (plan 152 / 176).
3
3
  *
4
- * @fileoverview Slack app manifest install guide
4
+ * @fileoverview Automated Slack CLI path first; manifest paste is recovery
5
5
  * @author AI Fabrix Team
6
- * @version 1.0.0
6
+ * @version 1.1.0
7
7
  */
8
8
 
9
9
  'use strict';
@@ -17,14 +17,14 @@ const { formatCredentialPortalStep } = require('./credential-portal');
17
17
  function buildSlackApprovalGuide(ctx) {
18
18
  return {
19
19
  portalUrl: 'https://api.slack.com/apps',
20
+ heading: 'Slack workspace approval',
20
21
  steps: [
21
- 'Open https://api.slack.com/apps and sign in as a Slack workspace admin.',
22
- 'Click Create New App → From an app manifest.',
23
- 'Select your workspace, then paste or upload the Slack app manifest (path shown below).',
24
- 'Review callback URLs and OAuth scopes (pre-filled from AI Fabrix), then create the app.',
25
- 'Open Install App → Install to Workspace and approve the installation.',
26
- 'Copy the Bot User OAuth Token and Signing Secret from the Slack app settings.',
27
- formatCredentialPortalStep(ctx, 'the Bot User OAuth Token and Signing Secret'),
22
+ 'Open https://api.slack.com/apps only if channel add could not create the app (recovery).',
23
+ 'Preferred: paste the slash command from Next actions in Slack, then paste the challenge code and continue.',
24
+ 'Approve the Slack workspace install if Slack prompts.',
25
+ 'Recovery: Create New App → From an app manifest, then paste or upload the generated Slack app manifest (path shown below).',
26
+ 'Recovery only: copy the Bot User OAuth Token and Signing Secret from Slack app settings.',
27
+ formatCredentialPortalStep(ctx, 'the Bot User OAuth Token and Signing Secret (recovery only)'),
28
28
  `When Slack shows the app as installed, re-run: ${ctx.resumeCommand}`,
29
29
  'Optional: add --probe to verify callbacks and the assistant catalog.'
30
30
  ]
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Microsoft Teams bot channel admin approval steps (plan 152).
2
+ * Microsoft Teams bot channel admin approval steps.
3
3
  *
4
- * @fileoverview Teams Developer Portal + Azure Bot registration guide
4
+ * @fileoverview Tenant policy / org publish after Azure-managed bot provision
5
5
  * @author AI Fabrix Team
6
6
  * @version 1.0.0
7
7
  */
8
8
 
9
9
  'use strict';
10
10
 
11
- const { formatCredentialPortalStep } = require('./credential-portal');
11
+ const { TEAMS_ADMIN_APPS_URL, TEAMS_OPEN_URL, TEAMS_POLICY_REMAINING } = require('../microsoft-provisioning/constants');
12
12
 
13
13
  /**
14
14
  * @param {Object} ctx
@@ -16,16 +16,12 @@ const { formatCredentialPortalStep } = require('./credential-portal');
16
16
  */
17
17
  function buildTeamsBotApprovalGuide(ctx) {
18
18
  return {
19
- portalUrl: 'https://dev.teams.microsoft.com/',
19
+ portalUrl: TEAMS_OPEN_URL,
20
+ heading: 'Tenant policy / org publish may still be required',
20
21
  steps: [
21
- 'Open the Teams Developer Portal (https://dev.teams.microsoft.com/) as a Teams tenant admin.',
22
- 'Create a new app or import the Bot Framework manifest JSON (path shown below).',
23
- 'Set the bot messaging endpoint to the Bot messages URL in INSTALL.md (your dataplane /messages route).',
24
- 'In Azure Portal, register or link the Azure Bot resource and copy the Microsoft App ID.',
25
- 'Create a client secret (or upload certificate) for the bot app registration in Microsoft Entra.',
26
- 'Enable the Microsoft Teams channel on the Azure Bot resource.',
27
- formatCredentialPortalStep(ctx, 'the Microsoft App ID and client secret'),
28
- 'Publish the app to your org (or sideload for lab) and complete tenant admin approval if prompted.',
22
+ `Open Teams (${TEAMS_OPEN_URL}) and install the generated package if sideloading is allowed.`,
23
+ TEAMS_POLICY_REMAINING,
24
+ `If custom app upload is restricted, approve in Teams admin centre: ${TEAMS_ADMIN_APPS_URL}`,
29
25
  `After the bot is live in Teams, re-run: ${ctx.resumeCommand}`,
30
26
  'Optional: add --probe to verify inbound JWT validation and the assistant catalog.'
31
27
  ]
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Vendor preflight and continuation dispatch for channel add.
3
+ *
4
+ * @fileoverview Keep add-channel.js under the file-size limit
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const {
10
+ maybeAssertChatGptPreflight,
11
+ maybeRunChatGptContinuation
12
+ } = require('./chatgpt-channel-add');
13
+ const {
14
+ maybeAssertMcpClientPreflight,
15
+ maybeRunMcpClientContinuation
16
+ } = require('./mcp-client-channel-add');
17
+ const {
18
+ maybeAssertClaudePreflight,
19
+ maybeRunClaudeContinuation
20
+ } = require('./claude-channel-add');
21
+ const { assertIntegrationClientPermissions } = require('./channel-oauth-preflight');
22
+
23
+ /**
24
+ * @param {Object} params
25
+ * @returns {Promise<void>}
26
+ */
27
+ async function maybeAssertIntegrationClientPermissions(params) {
28
+ const ctx = params.ctx;
29
+ if (!ctx || (params.options && params.options.dryRun === true)) {
30
+ return;
31
+ }
32
+ const token = (ctx.authConfig && ctx.authConfig.token) || ctx.bearerToken;
33
+ if (!token || !ctx.controllerUrl) {
34
+ return;
35
+ }
36
+ await assertIntegrationClientPermissions(
37
+ {
38
+ controllerUrl: ctx.controllerUrl,
39
+ environment: ctx.environment,
40
+ bearerToken: token
41
+ },
42
+ params.channelTarget,
43
+ params.deps || {}
44
+ );
45
+ }
46
+
47
+ /**
48
+ * @param {Object} params
49
+ * @returns {Promise<void>}
50
+ */
51
+ async function runChannelAddPreflights(params) {
52
+ await maybeAssertIntegrationClientPermissions(params);
53
+ await maybeAssertChatGptPreflight(params);
54
+ await maybeAssertMcpClientPreflight(params);
55
+ await maybeAssertClaudePreflight(params);
56
+ }
57
+
58
+ /**
59
+ * @param {Object} params
60
+ * @returns {Promise<void>}
61
+ */
62
+ async function runChannelAddContinuations(params) {
63
+ await maybeRunChatGptContinuation(params);
64
+ await maybeRunMcpClientContinuation(params);
65
+ await maybeRunClaudeContinuation(params);
66
+ }
67
+
68
+ /**
69
+ * Re-run remaining TTY for ChatGPT/Claude without regenerating artifacts.
70
+ * @param {Object} params
71
+ * @returns {Promise<boolean>}
72
+ */
73
+ async function runSkippedRemoteMcpTty(params) {
74
+ if (params.channelTarget === 'chatgpt') {
75
+ await maybeAssertChatGptPreflight(params);
76
+ await maybeRunChatGptContinuation(params);
77
+ return true;
78
+ }
79
+ if (params.channelTarget === 'claude') {
80
+ await maybeAssertClaudePreflight(params);
81
+ await maybeRunClaudeContinuation(params);
82
+ return true;
83
+ }
84
+ return false;
85
+ }
86
+
87
+ module.exports = {
88
+ runChannelAddPreflights,
89
+ runChannelAddContinuations,
90
+ runSkippedRemoteMcpTty
91
+ };
@@ -8,28 +8,87 @@
8
8
 
9
9
  'use strict';
10
10
 
11
- const fs = require('fs');
12
11
  const path = require('path');
12
+ const fs = require('fs');
13
13
  const chalk = require('chalk');
14
14
  const logger = require('../utils/logger');
15
- const { formatSuccessLine, metadata } = require('../utils/cli-test-layout-chalk');
15
+ const { printScaffolded, printUploaded, isChannelAddVerbose } = require('./channel-add-tty');
16
16
  const { getIntegrationPath } = require('../utils/paths');
17
17
  const { getExternalSystem } = require('../api/external-systems.api');
18
18
  const { unwrapApiData } = require('../utils/external-system-readiness-core');
19
- const { scaffoldChannelIntegration } = require('./channel-integration-generator');
19
+ const {
20
+ scaffoldChannelIntegration,
21
+ hasChannelIntegrationFiles
22
+ } = require('./channel-integration-generator');
20
23
  const { resolveChannelAuthContext } = require('./channel-auth-context');
21
24
  const { uploadExternalSystem } = require('../commands/upload');
25
+ const { materializeChannelInstanceSystem } = require('./channel-instance-materialize');
26
+ const { resolveChannelInstanceKey } = require('./channel-instance-key');
27
+ const { isNotFoundError } = require('./channel-instance-collision');
28
+
29
+ /**
30
+ * Default channel-add TTY: Publishing spinner, then one Uploaded line.
31
+ * Compact UPLOAD card and dataplane URL resolve stay on -v.
32
+ * @param {Object} options
33
+ * @param {Object} ctx
34
+ * @returns {Object}
35
+ */
36
+ function buildChannelAddUploadOptions(options, ctx) {
37
+ const verbose = isChannelAddVerbose(options);
38
+ const shared = {
39
+ force: true,
40
+ authConfig: ctx.authConfig,
41
+ dataplaneUrl: ctx.dataplaneUrl,
42
+ environment: ctx.environment
43
+ };
44
+ if (verbose) {
45
+ return { ...shared, minimal: false, verbose: true };
46
+ }
47
+ return {
48
+ ...shared,
49
+ minimal: true,
50
+ verbose: false,
51
+ silentResolve: true,
52
+ suppressSummary: true,
53
+ suppressPipelineSpinner: options.quiet === true
54
+ };
55
+ }
56
+
57
+ function resolveInstanceKey(channelTarget, options = {}) {
58
+ return resolveChannelInstanceKey(channelTarget, options);
59
+ }
60
+
61
+ /**
62
+ * HTTP install already has the caller JWT on options.authContext.
63
+ * Re-resolving via getDeploymentAuth(definitionKey) looks up
64
+ * `{key}-client-idKeyVault` inside builder-api and 500s.
65
+ *
66
+ * @param {string} channelTarget
67
+ * @param {Object} options
68
+ * @returns {Promise<Object>}
69
+ */
70
+ async function resolveEnsureAuthContext(channelTarget, options) {
71
+ if (options.authContext && typeof options.authContext === 'object') {
72
+ return options.authContext;
73
+ }
74
+ const verbose = isChannelAddVerbose(options);
75
+ return resolveChannelAuthContext(channelTarget, {
76
+ silent: options.quiet === true || !verbose
77
+ });
78
+ }
22
79
 
23
80
  /**
24
81
  * @param {string} channelTarget
25
82
  * @param {string} [projectRoot]
83
+ * @param {string} [instanceKey]
26
84
  * @returns {string}
27
85
  */
28
- function resolveIntegrationDir(channelTarget, projectRoot) {
86
+ function resolveIntegrationDir(channelTarget, projectRoot, instanceKey) {
87
+ const folderKey = instanceKey || channelTarget;
29
88
  if (projectRoot) {
30
- return path.join(path.resolve(projectRoot), 'integration', channelTarget);
89
+ return path.join(path.resolve(projectRoot), 'integration', folderKey);
31
90
  }
32
- return getIntegrationPath(channelTarget);
91
+ return getIntegrationPath(folderKey);
33
92
  }
34
93
 
35
94
  /**
@@ -38,31 +97,65 @@ function resolveIntegrationDir(channelTarget, projectRoot) {
38
97
  * @returns {Promise<boolean>}
39
98
  */
40
99
  async function isCommunicationSystemUploaded(ctx, channelTarget) {
41
- const res = await getExternalSystem(ctx.dataplaneUrl, channelTarget, ctx.authConfig);
42
- const system = unwrapApiData(res);
43
- return !!(system && typeof system === 'object');
100
+ try {
101
+ const res = await getExternalSystem(ctx.dataplaneUrl, channelTarget, ctx.authConfig);
102
+ const system = unwrapApiData(res);
103
+ return !!(system && typeof system === 'object');
104
+ } catch (err) {
105
+ if (isNotFoundError(err)) {
106
+ return false;
107
+ }
108
+ throw err;
109
+ }
110
+ }
111
+
112
+ async function maybeRegenerateInstanceDeployJson(integrationDir, instanceKey) {
113
+ const appPath = path.join(integrationDir, 'application.json');
114
+ if (!fs.existsSync(appPath)) {
115
+ return;
116
+ }
117
+ const { generateDeployJson } = require('../generator');
118
+ await generateDeployJson(instanceKey, { appPath: integrationDir });
119
+ }
120
+
121
+ async function finishInstanceScaffold(integrationDir, definitionKey, instanceKey) {
122
+ materializeChannelInstanceSystem(integrationDir, definitionKey, instanceKey);
123
+ await maybeRegenerateInstanceDeployJson(integrationDir, instanceKey);
44
124
  }
45
125
 
46
126
  /**
47
- * Scaffold integration/<target>/ when missing (does not overwrite).
127
+ * Scaffold integration/<target>/ when missing or incomplete.
128
+ * With --force, refresh files from the channel template (same as channel scaffold --force).
48
129
  *
49
130
  * @param {string} channelTarget
50
131
  * @param {Object} options
51
132
  * @returns {Promise<{ scaffolded: boolean, integrationDir: string }>}
52
133
  */
53
134
  async function ensureChannelScaffold(channelTarget, options = {}) {
54
- const integrationDir = resolveIntegrationDir(channelTarget, options.projectRoot);
55
- if (fs.existsSync(integrationDir)) {
135
+ const instanceKey = resolveInstanceKey(channelTarget, options);
136
+ const integrationDir = resolveIntegrationDir(
137
+ channelTarget,
138
+ options.projectRoot,
139
+ instanceKey
140
+ );
141
+ const force = options.force === true;
142
+ if (hasChannelIntegrationFiles(integrationDir, instanceKey) && !force) {
143
+ await finishInstanceScaffold(integrationDir, channelTarget, instanceKey);
56
144
  return { scaffolded: false, integrationDir };
57
145
  }
58
146
  const result = await scaffoldChannelIntegration(channelTarget, {
59
147
  projectRoot: options.projectRoot,
60
- allowExperimental: options.allowExperimental === true
148
+ integrationDir,
149
+ allowExperimental: options.allowExperimental === true,
150
+ force
61
151
  });
152
+ await finishInstanceScaffold(result.integrationDir, channelTarget, instanceKey);
62
153
  if (options.quiet !== true) {
63
- logger.log(formatSuccessLine(`Scaffolded integration at ${result.integrationDir}`));
64
- for (const file of result.files) {
65
- logger.log(metadata(file));
154
+ printScaffolded(result.integrationDir);
155
+ if (isChannelAddVerbose(options) && Array.isArray(result.files)) {
156
+ for (const file of result.files) {
157
+ logger.log(chalk.gray(file));
158
+ }
66
159
  }
67
160
  }
68
161
  return { scaffolded: true, integrationDir: result.integrationDir };
@@ -79,25 +172,28 @@ async function ensureChannelUploaded(channelTarget, options = {}) {
79
172
  if (options.dryRun === true) {
80
173
  return { uploaded: false, skipped: true, ctx: null };
81
174
  }
82
- const ctx = await resolveChannelAuthContext(channelTarget, { silent: options.quiet === true });
175
+ const instanceKey = resolveInstanceKey(channelTarget, options);
176
+ const verbose = isChannelAddVerbose(options);
177
+ const ctx = await resolveEnsureAuthContext(channelTarget, options);
83
178
  const force = options.force === true;
84
- const alreadyUploaded = force ? false : await isCommunicationSystemUploaded(ctx, channelTarget);
179
+ const alreadyUploaded = force ? false : await isCommunicationSystemUploaded(ctx, instanceKey);
85
180
  if (alreadyUploaded) {
86
- if (options.quiet !== true) {
87
- logger.log(chalk.gray(` Communication system "${channelTarget}" already on dataplane`));
181
+ if (verbose && options.quiet !== true) {
182
+ logger.log(chalk.gray(` Communication system "${instanceKey}" already on dataplane`));
88
183
  }
89
184
  return { uploaded: false, skipped: true, ctx };
90
185
  }
91
- if (options.quiet !== true) {
186
+ if (verbose && options.quiet !== true) {
92
187
  const reason = force ? 'force upload' : 'not found on dataplane';
93
- logger.log(chalk.white(`Uploading ${channelTarget} (${reason})…`));
188
+ logger.log(chalk.white(`Uploading ${instanceKey} (${reason})…`));
94
189
  }
95
- await uploadExternalSystem(channelTarget, {
96
- force: true,
97
- minimal: options.quiet === true || options.minimal !== false
190
+ const integrationDir = resolveIntegrationDir(channelTarget, options.projectRoot, instanceKey);
191
+ await uploadExternalSystem(instanceKey, {
192
+ ...buildChannelAddUploadOptions(options, ctx),
193
+ pathOptions: { appPath: integrationDir }
98
194
  });
99
- if (options.quiet !== true) {
100
- logger.log(formatSuccessLine(`Uploaded ${channelTarget}`));
195
+ if (options.quiet !== true && options.suppressUploadedLine !== true) {
196
+ printUploaded(instanceKey);
101
197
  }
102
198
  return { uploaded: true, skipped: false, ctx };
103
199
  }
@@ -122,6 +218,7 @@ async function ensureChannelReadyForAdd(channelTarget, options = {}) {
122
218
  module.exports = {
123
219
  resolveIntegrationDir,
124
220
  isCommunicationSystemUploaded,
221
+ buildChannelAddUploadOptions,
125
222
  ensureChannelScaffold,
126
223
  ensureChannelUploaded,
127
224
  ensureChannelReadyForAdd