@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
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Portal Microsoft login for Teams Bot via `teams login --device-code`.
3
+ *
4
+ * @fileoverview Copilot ATK MSAL is not a Teams Developer CLI session
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { spawn } = require('child_process');
10
+ const { parseMicrosoftLoginOutput } = require('./login-portal-parse');
11
+ const { microsoftProvisioningError } = require('./errors');
12
+ const { resolveTeamsBinary, isTeamsCliLoggedIn } = require('./teams-cli');
13
+ const { shouldSkipLiveToolkit } = require('./cli');
14
+ const { atkInstallEnv } = require('./install-atk');
15
+
16
+ /**
17
+ * @param {string} message
18
+ * @returns {Error}
19
+ */
20
+ function deviceCodeStartError(message) {
21
+ const error = microsoftProvisioningError(message, 'TEAMS_CLI');
22
+ error.statusCode = 409;
23
+ return error;
24
+ }
25
+
26
+ /**
27
+ * @param {import('child_process').ChildProcess} child
28
+ * @param {Map} inflight
29
+ * @param {string} key
30
+ * @returns {Promise<void>}
31
+ */
32
+ function tokenPromiseFromChild(child, inflight, key) {
33
+ return new Promise((resolve, reject) => {
34
+ child.on('error', reject);
35
+ child.on('close', (code) => {
36
+ if (code === 0) {
37
+ const job = inflight.get(key);
38
+ if (job) {
39
+ job.authenticated = true;
40
+ }
41
+ resolve();
42
+ return;
43
+ }
44
+ reject(new Error('Microsoft sign-in did not finish.'));
45
+ });
46
+ });
47
+ }
48
+
49
+ /**
50
+ * @param {Object} state
51
+ * @param {string} chunk
52
+ * @returns {{ waiting: boolean, loginUrl?: string, userCode?: string|null, authenticated?: boolean }|null}
53
+ */
54
+ function consumeTeamsLoginChunk(state, chunk) {
55
+ state.buf += String(chunk);
56
+ if (/already logged in/i.test(state.buf)) {
57
+ return { waiting: false, authenticated: true };
58
+ }
59
+ const parsed = parseMicrosoftLoginOutput(state.buf);
60
+ if (!parsed.loginUrl) {
61
+ return null;
62
+ }
63
+ return { waiting: true, loginUrl: parsed.loginUrl, userCode: parsed.userCode };
64
+ }
65
+
66
+ /**
67
+ * @param {Map} inflight
68
+ * @param {string} key
69
+ * @param {Object} child
70
+ * @param {Promise<void>} tokenPromise
71
+ * @param {Object} parsed
72
+ * @returns {Object}
73
+ */
74
+ function rememberTeamsLoginJob(inflight, key, child, tokenPromise, parsed) {
75
+ inflight.set(key, {
76
+ cli: 'teams',
77
+ child,
78
+ tokenPromise,
79
+ authenticated: parsed.authenticated === true,
80
+ loginUrl: parsed.loginUrl,
81
+ userCode: parsed.userCode
82
+ });
83
+ return parsed;
84
+ }
85
+
86
+ /**
87
+ * @param {Object} child
88
+ * @param {Object} ctx
89
+ * @returns {void}
90
+ */
91
+ function bindTeamsLoginStreams(child, ctx) {
92
+ const onData = (chunk) => {
93
+ const parsed = consumeTeamsLoginChunk(ctx.state, chunk);
94
+ if (parsed) {
95
+ ctx.finish(parsed);
96
+ }
97
+ };
98
+ if (child.stdout) {
99
+ child.stdout.on('data', onData);
100
+ }
101
+ if (child.stderr) {
102
+ child.stderr.on('data', onData);
103
+ }
104
+ child.on('error', (err) => {
105
+ if (!ctx.state.settled) {
106
+ ctx.state.settled = true;
107
+ clearTimeout(ctx.timer);
108
+ ctx.reject(err);
109
+ }
110
+ });
111
+ }
112
+
113
+ /**
114
+ * @param {Object} params
115
+ * @param {string} key
116
+ * @param {Map} inflight
117
+ * @param {string} bin
118
+ * @returns {Promise<Object>}
119
+ */
120
+ function startTeamsCliDeviceLogin(params, key, inflight, bin) {
121
+ const deps = params.deps || {};
122
+ const spawnImpl = deps.spawnImpl || spawn;
123
+ return new Promise((resolve, reject) => {
124
+ const child = spawnImpl(bin, ['login', '--device-code'], {
125
+ env: { ...atkInstallEnv(deps.env || process.env), TEAMS_NO_INTERACTIVE: '1' },
126
+ stdio: ['ignore', 'pipe', 'pipe']
127
+ });
128
+ const tokenPromise = tokenPromiseFromChild(child, inflight, key);
129
+ tokenPromise.catch(() => undefined);
130
+ const state = { buf: '', settled: false };
131
+ const timer = setTimeout(() => {
132
+ if (!state.settled) {
133
+ state.settled = true;
134
+ child.kill();
135
+ reject(deviceCodeStartError(
136
+ 'Microsoft sign-in timed out before a device code was issued. Use Get a new code.'
137
+ ));
138
+ }
139
+ }, 20000);
140
+ bindTeamsLoginStreams(child, {
141
+ state,
142
+ timer,
143
+ reject,
144
+ finish: (parsed) => {
145
+ if (state.settled) {
146
+ return;
147
+ }
148
+ state.settled = true;
149
+ clearTimeout(timer);
150
+ resolve(rememberTeamsLoginJob(inflight, key, child, tokenPromise, parsed));
151
+ }
152
+ });
153
+ });
154
+ }
155
+
156
+ /**
157
+ * @param {Object} params
158
+ * @param {string} key
159
+ * @param {Map} inflight
160
+ * @returns {Promise<Object>}
161
+ */
162
+ async function startTeamsPortalLogin(params, key, inflight) {
163
+ const deps = params.deps || {};
164
+ if (params.retryLogin !== true && await isTeamsCliLoggedIn(deps)) {
165
+ inflight.set(key, { cli: 'teams', authenticated: true });
166
+ return { waiting: false, authenticated: true };
167
+ }
168
+ if (shouldSkipLiveToolkit(deps)) {
169
+ return { waiting: true };
170
+ }
171
+ const bin = await resolveTeamsBinary(deps);
172
+ if (!bin) {
173
+ return { waiting: true };
174
+ }
175
+ return startTeamsCliDeviceLogin(params, key, inflight, bin);
176
+ }
177
+
178
+ /**
179
+ * @param {Object} params
180
+ * @param {Object|null} job
181
+ * @returns {boolean}
182
+ */
183
+ function loginJobMatches(params, job) {
184
+ const want = params.loginCli === 'teams' ? 'teams' : 'atk';
185
+ const got = job && job.cli === 'teams' ? 'teams' : 'atk';
186
+ return want === got;
187
+ }
188
+
189
+ module.exports = {
190
+ startTeamsPortalLogin,
191
+ startTeamsCliDeviceLogin,
192
+ loginJobMatches
193
+ };
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Portal Microsoft login: device-code URL for the UI; keep MSAL polling alive.
3
+ *
4
+ * @fileoverview Remote browsers cannot complete Toolkit localhost redirects
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { ensureMicrosoftSession } = require('./auth');
10
+ const { resolveAtkBinary, shouldSkipLiveToolkit } = require('./cli');
11
+ const { findOrInstallAtkBinary } = require('./install-atk');
12
+ const {
13
+ parseMicrosoftLoginOutput,
14
+ isMicrosoftLoginUrl,
15
+ isLoopbackAuthorizeUrl
16
+ } = require('./login-portal-parse');
17
+ const { startMsalDeviceCode } = require('./login-portal-device');
18
+ const { startTeamsPortalLogin, loginJobMatches } = require('./login-portal-teams');
19
+
20
+ const inflight = new Map();
21
+
22
+ /**
23
+ * @param {string} key
24
+ * @returns {void}
25
+ */
26
+ function stopPortalMicrosoftLogin(key) {
27
+ const job = inflight.get(key);
28
+ if (!job) {
29
+ return;
30
+ }
31
+ inflight.delete(key);
32
+ if (job.request && typeof job.request === 'object') {
33
+ job.request.cancel = true;
34
+ }
35
+ if (job.child && typeof job.child.kill === 'function') {
36
+ try {
37
+ job.child.kill();
38
+ } catch {
39
+ // best-effort
40
+ }
41
+ }
42
+ }
43
+
44
+ /**
45
+ * @param {string} key
46
+ * @returns {{ loginUrl?: string, userCode?: string|null, authenticated?: boolean }|null}
47
+ */
48
+ function peekPortalMicrosoftLogin(key) {
49
+ const job = inflight.get(String(key || '').trim());
50
+ if (!job) {
51
+ return null;
52
+ }
53
+ return {
54
+ loginUrl: job.loginUrl,
55
+ userCode: job.userCode || null,
56
+ authenticated: job.authenticated === true
57
+ };
58
+ }
59
+
60
+ /**
61
+ * @param {Object} job
62
+ * @param {number} timeoutMs
63
+ * @returns {Promise<'ok'|'none'|'timeout'|'error'>}
64
+ */
65
+ function settleTokenPromise(job, timeoutMs) {
66
+ if (job.authenticated === true) {
67
+ return Promise.resolve('ok');
68
+ }
69
+ if (!job.tokenPromise || typeof job.tokenPromise.then !== 'function') {
70
+ return Promise.resolve('none');
71
+ }
72
+ return new Promise((resolve) => {
73
+ const timer = setTimeout(() => resolve('timeout'), timeoutMs);
74
+ job.tokenPromise.then(
75
+ () => {
76
+ clearTimeout(timer);
77
+ resolve('ok');
78
+ },
79
+ () => {
80
+ clearTimeout(timer);
81
+ resolve('error');
82
+ }
83
+ );
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Wait for an in-flight device-code poll. Does not issue a new code.
89
+ * @param {string} key
90
+ * @param {number} [timeoutMs]
91
+ * @returns {Promise<{ loginUrl?: string, userCode?: string|null, authenticated?: boolean }|null>}
92
+ */
93
+ async function awaitPortalMicrosoftLogin(key, timeoutMs = 120000) {
94
+ const normalized = String(key || '').trim();
95
+ const job = inflight.get(normalized);
96
+ if (!job) {
97
+ return null;
98
+ }
99
+ const settled = await settleTokenPromise(job, timeoutMs);
100
+ if (settled === 'ok') {
101
+ job.authenticated = true;
102
+ }
103
+ return peekPortalMicrosoftLogin(normalized);
104
+ }
105
+
106
+ /**
107
+ * @param {string} key
108
+ * @param {Object|null} result
109
+ * @returns {void}
110
+ */
111
+ function rememberInflightLogin(key, result) {
112
+ if (!key || !result) {
113
+ return;
114
+ }
115
+ const existing = inflight.get(key) || {};
116
+ inflight.set(key, {
117
+ ...existing,
118
+ cli: result.cli || existing.cli,
119
+ loginUrl: result.loginUrl || existing.loginUrl,
120
+ userCode: result.userCode || existing.userCode,
121
+ authenticated: result.authenticated === true || existing.authenticated === true
122
+ });
123
+ }
124
+
125
+ /**
126
+ * @param {Object} deps
127
+ * @returns {Promise<string|null>}
128
+ */
129
+ async function resolvePortalLoginBinary(deps) {
130
+ try {
131
+ return (await findOrInstallAtkBinary(deps)) || (await resolveAtkBinary(deps));
132
+ } catch {
133
+ return null;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Probe an existing Toolkit session. Missing tenant means "not signed in yet".
139
+ * @param {string|undefined} expectedTenantId
140
+ * @param {Object} deps
141
+ * @returns {Promise<{ binary: string, tenantId: string }|null>}
142
+ */
143
+ async function existingMicrosoftSession(expectedTenantId, deps) {
144
+ try {
145
+ return await ensureMicrosoftSession(expectedTenantId, deps);
146
+ } catch (err) {
147
+ if (err && err.code === 'TENANT') {
148
+ return null;
149
+ }
150
+ throw err;
151
+ }
152
+ }
153
+
154
+ /**
155
+ * @param {Object} params
156
+ * @param {string} key
157
+ * @returns {Promise<{ waiting: boolean, authenticated?: boolean, loginUrl?: string, userCode?: string|null }>}
158
+ */
159
+ async function startFreshLogin(params, key) {
160
+ const deps = params.deps || {};
161
+ if (typeof deps.startLoginImpl === 'function') {
162
+ return deps.startLoginImpl(params);
163
+ }
164
+ if (params.loginCli === 'teams') {
165
+ return startTeamsPortalLogin(params, key, inflight);
166
+ }
167
+ if (params.retryLogin !== true) {
168
+ const session = await existingMicrosoftSession(params.expectedTenantId, deps);
169
+ if (session && session.tenantId) {
170
+ const authenticated = { waiting: false, authenticated: true, cli: 'atk' };
171
+ rememberInflightLogin(key, authenticated);
172
+ return authenticated;
173
+ }
174
+ }
175
+ if (shouldSkipLiveToolkit(deps)) {
176
+ return { waiting: true };
177
+ }
178
+ const binary = await resolvePortalLoginBinary(deps);
179
+ if (!binary) {
180
+ return { waiting: true };
181
+ }
182
+ return startMsalDeviceCode({ ...params, atkBinary: binary }, key, inflight);
183
+ }
184
+
185
+ /**
186
+ * @param {Object} params
187
+ * @returns {Promise<{ waiting: boolean, authenticated?: boolean, loginUrl?: string, userCode?: string|null }>}
188
+ */
189
+ async function reuseOrStartLogin(params) {
190
+ const key = String(params.installationKey || '').trim();
191
+ if (params.retryLogin === true && key) {
192
+ stopPortalMicrosoftLogin(key);
193
+ }
194
+ const existing = key ? inflight.get(key) : null;
195
+ if (existing && !loginJobMatches(params, existing)) {
196
+ stopPortalMicrosoftLogin(key);
197
+ return startFreshLogin(params, key);
198
+ }
199
+ if (existing && existing.authenticated === true) {
200
+ return {
201
+ waiting: false,
202
+ authenticated: true,
203
+ loginUrl: existing.loginUrl,
204
+ userCode: existing.userCode
205
+ };
206
+ }
207
+ if (existing && existing.loginUrl && !isLoopbackAuthorizeUrl(existing.loginUrl)) {
208
+ return { waiting: true, loginUrl: existing.loginUrl, userCode: existing.userCode };
209
+ }
210
+ return startFreshLogin(params, key);
211
+ }
212
+
213
+ /**
214
+ * Start or reuse Microsoft login for a portal install. Does not persist tokens.
215
+ * @param {Object} params
216
+ * @returns {Promise<{ waiting: boolean, authenticated?: boolean, loginUrl?: string, userCode?: string|null }>}
217
+ */
218
+ async function startPortalMicrosoftLogin(params = {}) {
219
+ return reuseOrStartLogin(params);
220
+ }
221
+
222
+ module.exports = {
223
+ parseMicrosoftLoginOutput,
224
+ isMicrosoftLoginUrl,
225
+ isLoopbackAuthorizeUrl,
226
+ stopPortalMicrosoftLogin,
227
+ startPortalMicrosoftLogin,
228
+ peekPortalMicrosoftLogin,
229
+ awaitPortalMicrosoftLogin
230
+ };
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Persist non-secret Microsoft Copilot correlation IDs only.
3
+ *
4
+ * @fileoverview Auth-config id + Application ID URI; never tokens
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const path = require('path');
10
+ const fs = require('../../internal/fs-real-sync');
11
+ const { STATE_FILE, STATE_KIND, SECRET_KEY_RE } = require('./constants');
12
+ const { microsoftProvisioningError } = require('./errors');
13
+
14
+ /**
15
+ * @param {string} projectRoot
16
+ * @returns {string}
17
+ */
18
+ function provisioningStatePath(projectRoot) {
19
+ const root = projectRoot || process.cwd();
20
+ return path.join(root, 'dist', 'channels', 'microsoft-copilot', STATE_FILE);
21
+ }
22
+
23
+ /**
24
+ * @param {Object} record
25
+ * @returns {void}
26
+ */
27
+ function assertNoSecrets(record) {
28
+ const keys = record && typeof record === 'object' ? Object.keys(record) : [];
29
+ const hit = keys.find((key) => SECRET_KEY_RE.test(key));
30
+ if (hit) {
31
+ throw microsoftProvisioningError(
32
+ `Refusing to persist Microsoft secret field "${hit}".`,
33
+ 'SECRET'
34
+ );
35
+ }
36
+ }
37
+
38
+ /**
39
+ * @param {string} projectRoot
40
+ * @returns {Object|null}
41
+ */
42
+ function readProvisioningState(projectRoot) {
43
+ const filePath = provisioningStatePath(projectRoot);
44
+ if (!fs.existsSync(filePath)) {
45
+ return null;
46
+ }
47
+ try {
48
+ const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
49
+ if (!parsed || parsed.kind !== STATE_KIND) {
50
+ return null;
51
+ }
52
+ assertNoSecrets(parsed);
53
+ return parsed;
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * @param {Object} current
61
+ * @param {Object} next
62
+ * @returns {boolean}
63
+ */
64
+ function isReusableAuthConfig(current, next) {
65
+ if (!current || typeof current.authConfigId !== 'string' || !current.authConfigId.trim()) {
66
+ return false;
67
+ }
68
+ if (current.environment !== next.environment || current.mcpServerUrl !== next.mcpServerUrl) {
69
+ return false;
70
+ }
71
+ if (next.teamsAppId) {
72
+ const bound = typeof current.teamsAppId === 'string' ? current.teamsAppId.trim() : '';
73
+ if (bound.toLowerCase() !== String(next.teamsAppId).trim().toLowerCase()) {
74
+ return false;
75
+ }
76
+ }
77
+ if (current.tenantId && next.tenantId) {
78
+ return String(current.tenantId).toLowerCase() === String(next.tenantId).toLowerCase();
79
+ }
80
+ return true;
81
+ }
82
+
83
+ /**
84
+ * @param {string} projectRoot
85
+ * @param {Object} state
86
+ * @returns {void}
87
+ */
88
+ function writeProvisioningState(projectRoot, state) {
89
+ const record = {
90
+ kind: STATE_KIND,
91
+ environment: state.environment,
92
+ tenantId: state.tenantId,
93
+ mcpServerUrl: state.mcpServerUrl,
94
+ teamsAppId: state.teamsAppId || null,
95
+ authConfigId: state.authConfigId,
96
+ applicationIdUri: state.applicationIdUri || null
97
+ };
98
+ assertNoSecrets(record);
99
+ const filePath = provisioningStatePath(projectRoot);
100
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
101
+ fs.writeFileSync(filePath, `${JSON.stringify(record, null, 2)}\n`, 'utf8');
102
+ }
103
+
104
+ module.exports = {
105
+ provisioningStatePath,
106
+ readProvisioningState,
107
+ writeProvisioningState,
108
+ isReusableAuthConfig,
109
+ assertNoSecrets
110
+ };
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Build Teams Developer CLI argv for Azure-managed bots.
3
+ *
4
+ * @fileoverview Never scaffold a Teams SDK project; always --azure + existing endpoint
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { microsoftProvisioningError } = require('./errors');
10
+
11
+ /**
12
+ * @param {string} [value]
13
+ * @returns {string}
14
+ */
15
+ function trimFlag(value) {
16
+ return typeof value === 'string' ? value.trim() : '';
17
+ }
18
+
19
+ /**
20
+ * @param {string[]} args
21
+ * @returns {void}
22
+ */
23
+ function assertNoScaffoldArgs(args) {
24
+ const list = Array.isArray(args) ? args : [];
25
+ if (/\bproject\s+new\b/.test(list.join(' '))) {
26
+ throw microsoftProvisioningError(
27
+ 'Teams Bot provisioning must not run teams project new or scaffold a bot.',
28
+ 'SCAFFOLD'
29
+ );
30
+ }
31
+ if (list.includes('--teams-managed')) {
32
+ throw microsoftProvisioningError(
33
+ 'Teams-managed bot is not supported. Azure-managed is required for OAuth/SSO.',
34
+ 'TEAMS_MANAGED'
35
+ );
36
+ }
37
+ }
38
+
39
+ /**
40
+ * @param {Object} [options]
41
+ * @returns {{ subscription: string, resourceGroup: string }}
42
+ */
43
+ function resolveAzureFlags(options = {}) {
44
+ return {
45
+ subscription: trimFlag(options.azureSubscription),
46
+ resourceGroup: trimFlag(options.azureResourceGroup)
47
+ };
48
+ }
49
+
50
+ /**
51
+ * @param {{ subscription: string, resourceGroup: string }} flags
52
+ * @returns {void}
53
+ */
54
+ function requireAzureFlags(flags) {
55
+ if (!flags || !flags.subscription || !flags.resourceGroup) {
56
+ throw microsoftProvisioningError(
57
+ 'Azure subscription and resource group were not found on the controller environment. ' +
58
+ 'Deploy the environment first.',
59
+ 'MISSING_AZURE'
60
+ );
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @param {string} [url]
66
+ * @returns {void}
67
+ */
68
+ function assertHttpsEndpoint(url) {
69
+ const endpoint = trimFlag(url);
70
+ if (!endpoint) {
71
+ throw microsoftProvisioningError('Teams Bot messages URL is missing.', 'ENDPOINT');
72
+ }
73
+ if (!/^https:\/\//i.test(endpoint)) {
74
+ throw microsoftProvisioningError(
75
+ 'Teams Bot messaging endpoint must be a public HTTPS URL.',
76
+ 'ENDPOINT'
77
+ );
78
+ }
79
+ }
80
+
81
+ /**
82
+ * @param {Object} params
83
+ * @returns {string[]}
84
+ */
85
+ function buildAppCreateArgs(params) {
86
+ const args = [
87
+ 'app',
88
+ 'create',
89
+ '--azure',
90
+ '--name',
91
+ trimFlag(params.name) || 'AI Fabrix',
92
+ '--endpoint',
93
+ trimFlag(params.endpoint),
94
+ '--subscription',
95
+ trimFlag(params.subscription),
96
+ '--resource-group',
97
+ trimFlag(params.resourceGroup),
98
+ '--env',
99
+ trimFlag(params.envPath),
100
+ '--json'
101
+ ];
102
+ assertNoScaffoldArgs(args);
103
+ if (!args.includes('--azure') || !args.includes('--endpoint')) {
104
+ throw microsoftProvisioningError(
105
+ 'Teams app create must pass --azure and --endpoint.',
106
+ 'TEAMS_CLI'
107
+ );
108
+ }
109
+ return args;
110
+ }
111
+
112
+ module.exports = {
113
+ trimFlag,
114
+ assertNoScaffoldArgs,
115
+ resolveAzureFlags,
116
+ requireAzureFlags,
117
+ assertHttpsEndpoint,
118
+ buildAppCreateArgs
119
+ };