@aifabrix/builder 2.54.1 → 2.55.2

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 (253) hide show
  1. package/README.md +8 -0
  2. package/lib/agent-kit/apply-ops.js +82 -0
  3. package/lib/agent-kit/checksums.js +28 -0
  4. package/lib/agent-kit/classify.js +113 -0
  5. package/lib/agent-kit/claude-shim.js +61 -0
  6. package/lib/agent-kit/constants.js +55 -0
  7. package/lib/agent-kit/file-list.js +103 -0
  8. package/lib/agent-kit/host-approve.js +172 -0
  9. package/lib/agent-kit/hosting/github.js +63 -0
  10. package/lib/agent-kit/hosts.js +71 -0
  11. package/lib/agent-kit/init.js +319 -0
  12. package/lib/agent-kit/kit-root.js +17 -0
  13. package/lib/agent-kit/managed-section.js +79 -0
  14. package/lib/agent-kit/package-load.js +45 -0
  15. package/lib/agent-kit/plan-ops.js +69 -0
  16. package/lib/agent-kit/remote-prompts.js +272 -0
  17. package/lib/agent-kit/render-host-markdown.js +40 -0
  18. package/lib/agent-kit/repo-guard.js +47 -0
  19. package/lib/agent-kit/report.js +107 -0
  20. package/lib/agent-kit/run.js +82 -0
  21. package/lib/agent-kit/scm/git.js +122 -0
  22. package/lib/agent-kit/start.js +310 -0
  23. package/lib/agent-kit/state-file.js +83 -0
  24. package/lib/agent-kit/status.js +50 -0
  25. package/lib/agent-kit/v1-detect.js +81 -0
  26. package/lib/agent-kit/validate-kit.js +87 -0
  27. package/lib/agent-kit/workspace-name.js +40 -0
  28. package/lib/agent-kit/workspace-skeleton.js +103 -0
  29. package/lib/api/role-assistant-test-pack.api.js +86 -0
  30. package/lib/api/work-search.api.js +31 -4
  31. package/lib/api/work.api.js +19 -12
  32. package/lib/app/deploy.js +7 -4
  33. package/lib/app/list-external-systems.js +2 -1
  34. package/lib/app/offer-create-from-template.js +184 -0
  35. package/lib/app/show-display.js +33 -6
  36. package/lib/app/show.js +25 -2
  37. package/lib/channels/add-channel.js +1 -0
  38. package/lib/channels/approval-guides/claude.js +2 -2
  39. package/lib/channels/channel-add-failure.js +1 -0
  40. package/lib/channels/channel-add-remaining.js +15 -9
  41. package/lib/channels/channel-definition-status.js +115 -0
  42. package/lib/channels/channel-description.js +2 -1
  43. package/lib/channels/channel-install-envelope.js +4 -2
  44. package/lib/channels/channel-integration-generator.js +2 -0
  45. package/lib/channels/channel-runtime-resolver.js +14 -0
  46. package/lib/channels/channel-targets.js +31 -5
  47. package/lib/channels/claude-setup-values.js +4 -1
  48. package/lib/channels/slack-channel-add.js +59 -6
  49. package/lib/channels/slack-mcp-callback.js +51 -0
  50. package/lib/channels/slack-mcp-runtime.js +156 -0
  51. package/lib/channels/slack-provisioning/install-cli.js +14 -2
  52. package/lib/channels/slack-provisioning/with-curl-on-path.js +6 -1
  53. package/lib/cli/index.js +4 -0
  54. package/lib/cli/setup-app.js +8 -1
  55. package/lib/cli/setup-auth.js +11 -2
  56. package/lib/cli/setup-certification-commands.js +2 -2
  57. package/lib/cli/setup-certification.help.js +3 -1
  58. package/lib/commands/agent-kit-help.js +149 -0
  59. package/lib/commands/agent-kit.js +417 -0
  60. package/lib/commands/auth-status-user.js +99 -0
  61. package/lib/commands/auth-status.js +14 -4
  62. package/lib/commands/channel-add-help.js +5 -5
  63. package/lib/commands/datasource-capability-relate-cli.js +5 -4
  64. package/lib/commands/datasource-load-export-cli.js +7 -2
  65. package/lib/commands/datasource-test-trust-cli.js +5 -1
  66. package/lib/commands/governance-command-action.js +5 -4
  67. package/lib/commands/identity-membership-role-cache.js +6 -1
  68. package/lib/commands/lifecycle-command-action.js +16 -15
  69. package/lib/commands/login-credentials.js +8 -3
  70. package/lib/commands/login-device.js +14 -5
  71. package/lib/commands/login.js +14 -1
  72. package/lib/commands/logout.js +50 -15
  73. package/lib/commands/repair-auth-apply.js +1 -1
  74. package/lib/commands/repair-datasource-key-skip.js +39 -0
  75. package/lib/commands/repair-datasource-keys.js +24 -12
  76. package/lib/commands/repair-rbac.js +16 -10
  77. package/lib/commands/role-assistant-copy-output.js +61 -0
  78. package/lib/commands/role-assistant-copy.js +155 -0
  79. package/lib/commands/role-assistant-test-output.js +8 -9
  80. package/lib/commands/role-assistant-test-result-rows.js +42 -0
  81. package/lib/commands/role-assistant.js +140 -59
  82. package/lib/commands/search.js +143 -0
  83. package/lib/commands/test-trust-external.js +7 -5
  84. package/lib/commands/upload-sidecar-followups.js +4 -1
  85. package/lib/commands/verify-governance-command-action.js +9 -7
  86. package/lib/commands/verify-operations-command-action.js +9 -8
  87. package/lib/commands/verify-operations-skip-e2e.js +131 -0
  88. package/lib/commands/verify-operations-step-plan.js +6 -33
  89. package/lib/commands/verify-operations-steps.js +3 -1
  90. package/lib/commands/verify-trust-command-action.js +6 -5
  91. package/lib/datasource/capability/relate-operations.js +28 -10
  92. package/lib/datasource/capability/run-capability-relate.js +48 -25
  93. package/lib/datasource/datasource-identifier.js +13 -5
  94. package/lib/deployment/deployer-poll-run.js +117 -35
  95. package/lib/external-system/deploy-dataplane-published.js +70 -0
  96. package/lib/external-system/deploy.js +12 -2
  97. package/lib/external-system/download-role-assistant.js +41 -15
  98. package/lib/external-system/download.js +8 -3
  99. package/lib/generator/helpers.js +12 -1
  100. package/lib/generator/wizard-datasource-key.js +54 -0
  101. package/lib/generator/wizard.js +55 -54
  102. package/lib/integration-definition/apply-datasource-keys.js +75 -0
  103. package/lib/integration-definition/apply-relationships.js +195 -0
  104. package/lib/integration-definition/apply-static-enterprise.js +232 -0
  105. package/lib/integration-definition/apply-system-file.js +71 -0
  106. package/lib/integration-definition/apply-test-endpoint.js +89 -0
  107. package/lib/integration-definition/apply-viewpoint-defaults.js +157 -0
  108. package/lib/integration-definition/apply.js +78 -59
  109. package/lib/integration-definition/enrich-openapi-operations.js +36 -10
  110. package/lib/integration-definition/enrich-openapi-pick.js +87 -0
  111. package/lib/lifecycle/role-assistant-governance.js +56 -21
  112. package/lib/programmatic/capability-registry.js +1 -0
  113. package/lib/programmatic/index.js +2 -0
  114. package/lib/programmatic/openapi-apply-result-schemas.js +8 -0
  115. package/lib/programmatic/openapi-channel-install-schemas.js +4 -1
  116. package/lib/programmatic/openapi-component-schemas.js +1 -0
  117. package/lib/programmatic/openapi-descriptions.js +9 -3
  118. package/lib/programmatic/openapi-envelope-examples.js +7 -0
  119. package/lib/programmatic/openapi-operation-bindings.js +5 -0
  120. package/lib/programmatic/openapi-request-schemas.js +5 -0
  121. package/lib/programmatic/openapi-schema-descriptions-channel.js +8 -5
  122. package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
  123. package/lib/programmatic/openapi-spec.js +1 -0
  124. package/lib/programmatic/request-timeout.js +3 -0
  125. package/lib/programmatic/route-handler-map.js +7 -0
  126. package/lib/programmatic/run-channel-catalog.js +50 -8
  127. package/lib/programmatic/run-channel-install-options.js +5 -1
  128. package/lib/programmatic/run-download.js +41 -0
  129. package/lib/protection/auth-context.js +3 -1
  130. package/lib/protection/protection-display.js +3 -2
  131. package/lib/protection/report-exit.js +50 -0
  132. package/lib/protection/run-commands.js +2 -0
  133. package/lib/role-assistant/knowledge-sync-settings-push.js +172 -0
  134. package/lib/role-assistant/knowledge-sync.js +9 -126
  135. package/lib/role-assistant/package-validate.js +175 -0
  136. package/lib/role-assistant/test-case-assertion-row.js +36 -0
  137. package/lib/role-assistant/test-case-copy-bind.js +77 -0
  138. package/lib/role-assistant/test-case-copy-expected.js +127 -0
  139. package/lib/role-assistant/test-case-copy-from-work.js +90 -0
  140. package/lib/role-assistant/test-case-copy-interactions.js +67 -0
  141. package/lib/role-assistant/test-case-copy.js +119 -0
  142. package/lib/role-assistant/test-case-expected-catalog.js +135 -0
  143. package/lib/role-assistant/test-case-validate.js +88 -0
  144. package/lib/role-assistant/test-cases-bid.js +117 -4
  145. package/lib/role-assistant/test-cases-evaluate.js +149 -31
  146. package/lib/role-assistant/test-cases-evidence.js +44 -5
  147. package/lib/role-assistant/test-cases-honesty.js +155 -6
  148. package/lib/role-assistant/test-cases-lifecycle.js +297 -0
  149. package/lib/role-assistant/test-cases-search-graph.js +122 -0
  150. package/lib/role-assistant/test-cases-search.js +20 -2
  151. package/lib/role-assistant/test-cases.js +34 -168
  152. package/lib/role-assistant/test-pack-map.js +180 -0
  153. package/lib/role-assistant/test-pack-sync.js +187 -0
  154. package/lib/role-assistant/test-runner-debug.js +54 -0
  155. package/lib/role-assistant/test-runner-respond-body.js +36 -0
  156. package/lib/role-assistant/test-runner-search.js +20 -5
  157. package/lib/role-assistant/test-runner-start-payload.js +63 -10
  158. package/lib/role-assistant/test-runner-workhub-answers.js +45 -16
  159. package/lib/role-assistant/test-runner-workhub.js +45 -21
  160. package/lib/role-assistant/test-runner.js +53 -10
  161. package/lib/schema/external-datasource.schema.json +36 -5
  162. package/lib/schema/external-system.schema.json +20 -2
  163. package/lib/schema/infra-parameter.schema.json +51 -3
  164. package/lib/schema/infra.parameter.yaml +476 -40
  165. package/lib/schema/role-assistant-test-case.schema.json +408 -0
  166. package/lib/schema/type/document-storage.json +1 -1
  167. package/lib/search/dataplane-context.js +23 -0
  168. package/lib/search/search-args.js +211 -0
  169. package/lib/search/search-display.js +238 -0
  170. package/lib/search/search-errors.js +50 -0
  171. package/lib/search/search-prompts.js +119 -0
  172. package/lib/search/search-roles.js +85 -0
  173. package/lib/search/search-run.js +241 -0
  174. package/lib/search/search-skills.js +198 -0
  175. package/lib/utils/api-required-permissions.js +271 -0
  176. package/lib/utils/api.js +16 -13
  177. package/lib/utils/authentication-slot-show.js +153 -0
  178. package/lib/utils/cli-json-exit.js +41 -0
  179. package/lib/utils/cli-utils.js +23 -5
  180. package/lib/utils/controller-url.js +78 -4
  181. package/lib/utils/credential-display.js +43 -1
  182. package/lib/utils/deployment-errors.js +15 -0
  183. package/lib/utils/deployment-validation-helpers.js +4 -1
  184. package/lib/utils/device-code.js +31 -10
  185. package/lib/utils/error-formatters/error-parser.js +16 -1
  186. package/lib/utils/error-formatters/permission-errors.js +19 -5
  187. package/lib/utils/external-system-readiness-compact-blocks.js +5 -1
  188. package/lib/utils/external-system-readiness-compact-display.js +30 -1
  189. package/lib/utils/external-system-validators.js +2 -1
  190. package/lib/utils/help-builder.js +3 -1
  191. package/lib/utils/keycloak-realm-ready.js +5 -2
  192. package/lib/utils/logger.js +1 -0
  193. package/lib/utils/paths.js +26 -5
  194. package/lib/utils/schema-loader.js +37 -0
  195. package/lib/utils/secrets-helpers.js +2 -2
  196. package/lib/utils/write-stream-and-wait.js +63 -0
  197. package/lib/validation/validate-external-file.js +5 -1
  198. package/lib/validation/validate.js +3 -2
  199. package/package.json +20 -6
  200. package/templates/agent-kit/adapters/claude/nested.CLAUDE.md +1 -0
  201. package/templates/agent-kit/adapters/claude/root.CLAUDE.md +5 -0
  202. package/templates/agent-kit/adapters/cursor/commands/cust-0-plan.md +5 -0
  203. package/templates/agent-kit/adapters/cursor/commands/cust-1-validate.md +5 -0
  204. package/templates/agent-kit/adapters/cursor/commands/cust-2-build.md +5 -0
  205. package/templates/agent-kit/adapters/cursor/commands/cust-3-push.md +5 -0
  206. package/templates/agent-kit/adapters/cursor/commands/cust-biz-1-validate.md +5 -0
  207. package/templates/agent-kit/adapters/cursor/commands/cust-biz-2-build.md +5 -0
  208. package/templates/agent-kit/adapters/cursor/commands/cust-biz-3-prove.md +5 -0
  209. package/templates/agent-kit/agent-kit.yaml +45 -0
  210. package/templates/agent-kit/instructions/AGENTKIT.md +104 -0
  211. package/templates/agent-kit/instructions/integration.AGENTS.md +25 -0
  212. package/templates/agent-kit/instructions/role-assistant.AGENTS.md +22 -0
  213. package/templates/agent-kit/instructions/root.AGENTS.md +37 -0
  214. package/templates/agent-kit/parity-inventory.yaml +188 -0
  215. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +59 -0
  216. package/templates/agent-kit/skills/aifabrix-connected-system/references/contract-checklist.md +40 -0
  217. package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +54 -0
  218. package/templates/agent-kit/skills/aifabrix-connected-system/references/production-safety.md +35 -0
  219. package/templates/agent-kit/skills/aifabrix-connected-system/scripts/reserved-system-key.js +19 -0
  220. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +52 -0
  221. package/templates/agent-kit/skills/aifabrix-plan/references/challenge-checklist.md +108 -0
  222. package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +34 -0
  223. package/templates/agent-kit/skills/aifabrix-plan/references/plan-template.md +182 -0
  224. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +51 -0
  225. package/templates/agent-kit/skills/aifabrix-prove/references/demo-template.md +65 -0
  226. package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +68 -0
  227. package/templates/agent-kit/skills/aifabrix-prove/references/learning-template.md +66 -0
  228. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +43 -0
  229. package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
  230. package/templates/agent-kit/skills/shared/hosts.md +65 -0
  231. package/templates/agent-kit/skills/shared/login.md +16 -0
  232. package/templates/agent-kit/workspace/.cursor/plans/README.md +22 -0
  233. package/templates/agent-kit/workspace/LICENSE.mit +21 -0
  234. package/templates/agent-kit/workspace/README.md +89 -0
  235. package/templates/applications/builder-api/Dockerfile +3 -1
  236. package/templates/applications/dataplane/application.yaml +2 -3
  237. package/templates/applications/dataplane/env.template +5 -5
  238. package/templates/applications/dataplane/rbac.yaml +28 -0
  239. package/templates/applications/keycloak/env.template +3 -3
  240. package/templates/applications/miso-controller/application.yaml +21 -2
  241. package/templates/applications/miso-controller/env.template +96 -25
  242. package/templates/applications/miso-controller/rbac.yaml +5 -0
  243. package/templates/channels/claude/TROUBLESHOOTING.md +3 -0
  244. package/templates/channels/claude/channel.json +1 -1
  245. package/templates/channels/claude/install.template.md.hbs +1 -0
  246. package/templates/channels/claude/integration/claude-system.json +1 -1
  247. package/templates/channels/slack/channel.json +11 -0
  248. package/templates/channels/slack/install.template.md.hbs +9 -0
  249. package/templates/channels/slack/integration/slack-system.json +11 -0
  250. package/templates/channels/slack/manifest.template.json.hbs +6 -3
  251. package/templates/channels/teams-bot/channel.json +1 -0
  252. package/templates/python/docker-compose.hbs +14 -0
  253. package/templates/typescript/docker-compose.hbs +14 -0
package/lib/app/show.js CHANGED
@@ -33,6 +33,8 @@ const {
33
33
  attachCertificationVerifyFromDataplane,
34
34
  sanitizeCertificationForJson
35
35
  } = require('./certification-show-enrich');
36
+ const { resolveManifestAuthMethod } = require('../utils/external-system-readiness-compact-display');
37
+ const { resolveAuthenticationSlots } = require('../utils/authentication-slot-show');
36
38
 
37
39
  /**
38
40
  * Attach `runReloadDefault` / `runProxyDefault` from ~/.aifabrix `applications.<appKey>`.
@@ -466,6 +468,13 @@ function pickExternalVersion(res, config, system) {
466
468
  return (res && res.version) ?? config.version ?? system.version ?? '—';
467
469
  }
468
470
 
471
+ function pickCredentialMethod(config, system) {
472
+ const source = config && (config.authentication || config.authentications) ? config : system;
473
+ const method = resolveManifestAuthMethod(source);
474
+ if (!method || method === 'unknown') return undefined;
475
+ return method;
476
+ }
477
+
469
478
  function resolveExternalSystemMeta(res, config, system, application, appKey) {
470
479
  return {
471
480
  displayName: pickExternalDisplayName(res, system, application, appKey),
@@ -501,13 +510,27 @@ function buildBaseExternalResult(configData, appKey, openapiFiles, openapiEndpoi
501
510
  permissions: application.permissions
502
511
  },
503
512
  openapiFiles,
504
- openapiEndpoints
513
+ openapiEndpoints,
514
+ credentialMethod: pickCredentialMethod(config, system),
515
+ authenticationSlots: resolveAuthenticationSlots(config, system)
505
516
  };
506
517
  }
507
518
 
519
+ function applyCredentialFieldsToResult(result, res) {
520
+ if (res.credentialId !== undefined && res.credentialId !== null) result.credentialId = res.credentialId;
521
+ if (res.authenticationStatus !== undefined && res.authenticationStatus !== null) {
522
+ result.authenticationStatus = res.authenticationStatus;
523
+ }
524
+ const resConfig = res.config && typeof res.config === 'object' ? res.config : {};
525
+ const fromConfig = pickCredentialMethod(resConfig, {});
526
+ if (fromConfig) result.credentialMethod = fromConfig;
527
+ const fromSlots = resolveAuthenticationSlots(resConfig, {});
528
+ if (fromSlots.length > 0) result.authenticationSlots = fromSlots;
529
+ }
530
+
508
531
  function applySystemResponseToResult(result, res) {
509
532
  result.dataplaneStatus = res.status;
510
- if (res.credentialId !== undefined && res.credentialId !== null) result.credentialId = res.credentialId;
533
+ applyCredentialFieldsToResult(result, res);
511
534
  if (res.showOpenApiDocs !== undefined) result.showOpenApiDocs = res.showOpenApiDocs;
512
535
  if (res.mcpServerUrl !== undefined && res.mcpServerUrl !== null) result.mcpServerUrl = res.mcpServerUrl;
513
536
  if (res.apiDocumentUrl !== undefined && res.apiDocumentUrl !== null) result.apiDocumentUrl = res.apiDocumentUrl;
@@ -350,6 +350,7 @@ async function resolveInstallRuntimeValues(params, packageContext, runtimeToolNa
350
350
  appDescription: description,
351
351
  icon: options.icon,
352
352
  commandPrefix: options.commandPrefix,
353
+ enableMcpServer: options.enableMcpServer,
353
354
  layerBToolNames: runtimeToolNames,
354
355
  packageContext,
355
356
  entraProvider,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Claude remaining workspace steps (customer-facing).
3
3
  *
4
- * @fileoverview Short Claude connector Name and Server URL steps — no protocol dump
4
+ * @fileoverview Short Claude connector Name, Server URL, and OAuth steps — no protocol dump
5
5
  */
6
6
 
7
7
  'use strict';
@@ -21,7 +21,7 @@ function buildClaudeApprovalGuide(ctx) {
21
21
  credentialPortalUrl: null,
22
22
  steps: [
23
23
  `Open ${CLAUDE_CONNECTORS_URL}`,
24
- `Add a custom connector with Name: ${name}; Server URL: ${serverUrl}.`
24
+ `Add a custom connector with Name: ${name}; Server URL: ${serverUrl}; Authentication: OAuth.`
25
25
  ]
26
26
  };
27
27
  }
@@ -16,6 +16,7 @@ const BOUNDARY_MATCHERS = [
16
16
  tests: [/unknown channel/i, /already configured/i, /needs a terminal/i, /--name is required/i, /needs --target/i, /unknown mcp client profile/i]
17
17
  },
18
18
  { boundary: 'experimental', tests: [/is experimental/i] },
19
+ { boundary: 'unavailable', tests: [/is coming soon/i, /is not available/i] },
19
20
  { boundary: 'preflight', tests: [/chatgpt preflight/i, /claude preflight/i, /mcp client preflight/i, /authentication required/i, /dataplanebaseurl is required/i] },
20
21
  { boundary: 'callback', tests: [/chatgpt callback/i, /claude callback/i, /mcp client callback/i] },
21
22
  { boundary: 'oauth', tests: [/oauth/i, /trustedissuer/i, /vault-reference/i] },
@@ -30,6 +30,7 @@ const { printMcpClientDryRunTty } = require('./mcp-client-channel-add');
30
30
  const { printClaudeDryRunTty } = require('./claude-channel-add');
31
31
  const { CLAUDE_REMAINING_STEPS } = require('./claude-runtime-contract');
32
32
  const { vendorFacingUrlsFromCtx } = require('./vendor-dataplane-url');
33
+ const { slackMcpRemainingSteps } = require('./slack-mcp-runtime');
33
34
  const {
34
35
  channelDisplayLabel,
35
36
  printValidating,
@@ -280,18 +281,23 @@ function slackRecoveryOrHandshake(ctx, custom) {
280
281
  * @param {Object|null} ctx
281
282
  * @returns {Object}
282
283
  */
283
- function slackRemainingSpec(ctx) {
284
+ function slackRemainingSpec(ctx, runtimeValues) {
284
285
  const custom = slackCustomSteps(ctx);
286
+ const mcpSteps = slackMcpRemainingSteps(runtimeValues);
287
+ let spec;
285
288
  if (ctx && ctx.slackConnected === true) {
286
- return slackConnectedRemaining(ctx, custom);
289
+ spec = slackConnectedRemaining(ctx, custom);
290
+ } else if (ctx && ctx.slackSlashCommand) {
291
+ spec = slackSlashRemaining(ctx, custom);
292
+ } else if (ctx && ctx.slackHandshakeFailed === true) {
293
+ spec = slackFailedRemaining(custom);
294
+ } else {
295
+ spec = slackRecoveryOrHandshake(ctx, custom);
287
296
  }
288
- if (ctx && ctx.slackSlashCommand) {
289
- return slackSlashRemaining(ctx, custom);
297
+ if (mcpSteps.length === 0) {
298
+ return spec;
290
299
  }
291
- if (ctx && ctx.slackHandshakeFailed === true) {
292
- return slackFailedRemaining(custom);
293
- }
294
- return slackRecoveryOrHandshake(ctx, custom);
300
+ return { ...spec, steps: [...(spec.steps || []), ...mcpSteps] };
295
301
  }
296
302
 
297
303
  /**
@@ -350,7 +356,7 @@ function teamsBotRemainingSpec(ctx, runtimeValues) {
350
356
  */
351
357
  function remainingSpec(channelTarget, ctx, runtimeValues) {
352
358
  if (channelTarget === 'slack') {
353
- return slackRemainingSpec(ctx);
359
+ return slackRemainingSpec(ctx, runtimeValues);
354
360
  }
355
361
  if (channelTarget === 'microsoft-copilot') {
356
362
  return copilotRemainingSpec(ctx, runtimeValues);
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Channel Definition catalog/install status (visible | hide | coming-soon).
3
+ *
4
+ * @fileoverview Omit or visible: listed and installable. hide: omitted and refused. coming-soon: listed read-only.
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const registry = require('./channel-definition-registry');
12
+
13
+ const CHANNEL_STATUSES = ['visible', 'hide', 'coming-soon'];
14
+ const COMING_SOON_REASON = 'This channel is coming soon.';
15
+ const HIDE_REASON = 'This channel is not available.';
16
+
17
+ /**
18
+ * @param {Object|null} definition
19
+ * @returns {'visible'|'hide'|'coming-soon'}
20
+ */
21
+ function normalizeChannelStatus(definition) {
22
+ const raw = definition && definition.channel && definition.channel.status;
23
+ if (raw === 'hide' || raw === 'coming-soon') {
24
+ return raw;
25
+ }
26
+ return 'visible';
27
+ }
28
+
29
+ /**
30
+ * Live status from the Channel Definition registry (spy-friendly).
31
+ * @param {string} key
32
+ * @returns {'visible'|'hide'|'coming-soon'}
33
+ */
34
+ function channelStatusOf(key) {
35
+ return normalizeChannelStatus(registry.getChannelDefinition(key));
36
+ }
37
+
38
+ /**
39
+ * @param {string} status
40
+ * @returns {boolean}
41
+ */
42
+ function isCatalogHiddenStatus(status) {
43
+ return status === 'hide';
44
+ }
45
+
46
+ /**
47
+ * @param {string} status
48
+ * @returns {boolean}
49
+ */
50
+ function isInstallableStatus(status) {
51
+ return status === 'visible';
52
+ }
53
+
54
+ /**
55
+ * @param {string} key
56
+ * @param {string} status
57
+ * @returns {Error}
58
+ */
59
+ function statusUnavailableError(key, status) {
60
+ const message =
61
+ status === 'coming-soon'
62
+ ? `Channel target "${key}" is coming soon.`
63
+ : `Channel target "${key}" is not available.`;
64
+ const err = new Error(message);
65
+ err.statusCode = 403;
66
+ return err;
67
+ }
68
+
69
+ /**
70
+ * Refuse new install for hide and coming-soon. Continue of an existing session skips.
71
+ * --force / allowExperimental do not override.
72
+ * @param {string} key
73
+ * @param {{ continueInstall?: boolean }} [options]
74
+ * @returns {void}
75
+ */
76
+ function assertChannelStatusInstallable(key, options = {}) {
77
+ if (options.continueInstall === true) {
78
+ return;
79
+ }
80
+ const status = channelStatusOf(key);
81
+ if (isInstallableStatus(status)) {
82
+ return;
83
+ }
84
+ throw statusUnavailableError(key, status);
85
+ }
86
+
87
+ /**
88
+ * Overlay coming-soon onto a catalog/detail projection (canInstall false).
89
+ * @param {string} status
90
+ * @param {Object} [projection]
91
+ * @returns {Object}
92
+ */
93
+ function applyChannelStatusProjection(status, projection = {}) {
94
+ if (status !== 'coming-soon') {
95
+ return { ...projection, status };
96
+ }
97
+ return {
98
+ ...projection,
99
+ status,
100
+ canInstall: false,
101
+ blockedReason: COMING_SOON_REASON
102
+ };
103
+ }
104
+
105
+ module.exports = {
106
+ CHANNEL_STATUSES,
107
+ COMING_SOON_REASON,
108
+ HIDE_REASON,
109
+ normalizeChannelStatus,
110
+ channelStatusOf,
111
+ isCatalogHiddenStatus,
112
+ isInstallableStatus,
113
+ assertChannelStatusInstallable,
114
+ applyChannelStatusProjection
115
+ };
@@ -99,7 +99,8 @@ function fillSlackManifestDescriptions(channelTarget, runtimeValues) {
99
99
  return {
100
100
  ...runtimeValues,
101
101
  appLongDescription,
102
- appLongDescriptionJson: JSON.stringify(appLongDescription)
102
+ appLongDescriptionJson: JSON.stringify(appLongDescription),
103
+ enableMcpServer: runtimeValues.enableMcpServer === true
103
104
  };
104
105
  }
105
106
 
@@ -135,7 +135,8 @@ function claudeCopyActions(runtimeValues) {
135
135
  const values = buildClaudeFormValues({ runtimeValues: runtimeValues || {} });
136
136
  return [
137
137
  copyValueAction('Name', values.name, 'copy-name'),
138
- copyValueAction('Server URL', values.serverUrl, 'copy-server-url')
138
+ copyValueAction('Server URL', values.serverUrl, 'copy-server-url'),
139
+ copyValueAction('Authentication', values.authentication, 'copy-authentication')
139
140
  ].filter(Boolean);
140
141
  }
141
142
 
@@ -195,7 +196,8 @@ function claudeEnvelopeParts(params) {
195
196
  useValues: runtimeOk
196
197
  ? {
197
198
  Name: values.name,
198
- 'Server URL': values.serverUrl
199
+ 'Server URL': values.serverUrl,
200
+ Authentication: values.authentication
199
201
  }
200
202
  : {}
201
203
  };
@@ -12,6 +12,7 @@
12
12
 
13
13
  const path = require('path');
14
14
  const { getChannelTarget } = require('./channel-targets');
15
+ const { assertChannelStatusInstallable } = require('./channel-definition-status');
15
16
  const { getIntegrationPath } = require('../utils/paths');
16
17
  const {
17
18
  copyChannelIntegrationTemplate,
@@ -29,6 +30,7 @@ const { generateDeployJson } = require('../generator/index');
29
30
  */
30
31
  async function scaffoldChannelIntegration(channelTarget, options = {}) {
31
32
  const target = getChannelTarget(channelTarget);
33
+ assertChannelStatusInstallable(channelTarget, options);
32
34
  if (target.experimental && !options.allowExperimental) {
33
35
  throw new Error(
34
36
  `Channel target "${channelTarget}" is experimental. Pass --allow-experimental to scaffold.`
@@ -36,6 +36,7 @@ const { applyCopilotOauthProfile, applyCopilotRuntimeDomain } = require('./chann
36
36
  const { chatgptDiscoveryBlockerLabel } = require('./chatgpt-setup-values');
37
37
  const { applyMcpClientRuntimeValues } = require('./mcp-client/runtime');
38
38
  const { applyClaudeRuntimeValues } = require('./claude-runtime');
39
+ const { applySlackMcpRuntimeValues } = require('./slack-mcp-runtime');
39
40
 
40
41
  const DEFAULT_SLACK_COMMAND_PREFIX = 'af';
41
42
 
@@ -347,6 +348,7 @@ function applySlackRuntimeValues(resolved, params) {
347
348
  Object.assign(resolved, resolveSlackOAuthManifestFields());
348
349
  delete resolved.oauthCallbackUrl;
349
350
  resolved.commandPrefix = normalizeSlackCommandPrefix(params.commandPrefix);
351
+ resolved.enableMcpServer = isTrueLike(params.enableMcpServer);
350
352
  resolved.packageVersion =
351
353
  typeof params.packageVersion === 'string' && params.packageVersion.trim()
352
354
  ? params.packageVersion.trim()
@@ -356,6 +358,17 @@ function applySlackRuntimeValues(resolved, params) {
356
358
  resolved.appLongDescriptionJson = JSON.stringify(appLongDescription);
357
359
  }
358
360
 
361
+ /**
362
+ * @param {unknown} value
363
+ * @returns {boolean}
364
+ */
365
+ function isTrueLike(value) {
366
+ if (value === true) {
367
+ return true;
368
+ }
369
+ return typeof value === 'string' && /^(true|1|yes|on)$/i.test(value.trim());
370
+ }
371
+
359
372
  /**
360
373
  * Slack slash alias prefix: letters then letters/digits, 1–16 chars.
361
374
  * @param {unknown} raw
@@ -438,6 +451,7 @@ function applyChannelSpecificRuntime(resolved, params) {
438
451
  if (params.channelTarget === 'slack') {
439
452
  applySlackRuntimeValues(resolved, params);
440
453
  applyDiscoveryPackageContext(resolved, params.packageContext);
454
+ applySlackMcpRuntimeValues(resolved, params);
441
455
  }
442
456
  if (params.channelTarget === 'microsoft-copilot') {
443
457
  applyMicrosoftCopilotRuntimeValues(resolved, params);
@@ -14,6 +14,12 @@ const {
14
14
  listChannelDefinitionKeys
15
15
  } = require('./channel-definition-registry');
16
16
  const { toChannelTargetProjection } = require('./channel-definition-project');
17
+ const {
18
+ assertChannelStatusInstallable,
19
+ channelStatusOf,
20
+ isCatalogHiddenStatus,
21
+ isInstallableStatus
22
+ } = require('./channel-definition-status');
17
23
 
18
24
  function buildChannelTargets() {
19
25
  const targets = {};
@@ -48,15 +54,21 @@ function isChannelTargetKey(channelTarget) {
48
54
  */
49
55
  function formatSupportedChannelTargetsHelp() {
50
56
  const targets = resolveChannelTargets();
51
- const keys = Object.keys(targets);
52
- const stable = keys.filter((key) => !targets[key].experimental);
53
- const experimental = keys.filter((key) => targets[key].experimental);
57
+ const installable = listInstallableChannelTargetKeys({ allowExperimental: true });
58
+ const stable = installable.filter((key) => !targets[key].experimental);
59
+ const experimental = installable.filter((key) => targets[key].experimental);
60
+ const comingSoon = listLiveChannelTargetKeys({ allowExperimental: true }).filter(
61
+ (key) => channelStatusOf(key) === 'coming-soon'
62
+ );
54
63
  const lines = ['Supported channels:', ` ${stable.join(', ')}`];
55
64
  if (experimental.length > 0) {
56
65
  lines.push(
57
66
  ` ${experimental.join(', ')} (experimental — scaffold with --allow-experimental)`
58
67
  );
59
68
  }
69
+ if (comingSoon.length > 0) {
70
+ lines.push(` ${comingSoon.join(', ')} (coming soon — not installable)`);
71
+ }
60
72
  return lines.join('\n');
61
73
  }
62
74
 
@@ -81,18 +93,30 @@ function getChannelTarget(channelTarget) {
81
93
  }
82
94
 
83
95
  /**
84
- * Live keys, plus experimental when `--allow-experimental` is set.
96
+ * Live keys (not hide), plus experimental when `--allow-experimental` is set.
85
97
  * @param {{ allowExperimental?: boolean }} [options]
86
98
  * @returns {string[]}
87
99
  */
88
100
  function listLiveChannelTargetKeys(options = {}) {
89
101
  const targets = resolveChannelTargets();
90
102
  return Object.keys(targets).filter((key) => {
103
+ if (isCatalogHiddenStatus(channelStatusOf(key))) {
104
+ return false;
105
+ }
91
106
  const target = targets[key];
92
107
  return !target.experimental || options.allowExperimental === true;
93
108
  });
94
109
  }
95
110
 
111
+ /**
112
+ * Keys that may start a new install (visible). Coming-soon is catalog-only.
113
+ * @param {{ allowExperimental?: boolean }} [options]
114
+ * @returns {string[]}
115
+ */
116
+ function listInstallableChannelTargetKeys(options = {}) {
117
+ return listLiveChannelTargetKeys(options).filter((key) => isInstallableStatus(channelStatusOf(key)));
118
+ }
119
+
96
120
  /**
97
121
  * Inquirer list choices for `aifabrix channel add` (labels from the registry).
98
122
  * @param {{ allowExperimental?: boolean }} [options]
@@ -100,7 +124,7 @@ function listLiveChannelTargetKeys(options = {}) {
100
124
  */
101
125
  function listWizardChannelChoices(options = {}) {
102
126
  const targets = resolveChannelTargets();
103
- return listLiveChannelTargetKeys(options)
127
+ return listInstallableChannelTargetKeys(options)
104
128
  .map((key) => targets[key])
105
129
  .sort((a, b) => (a.wizardOrder || 100) - (b.wizardOrder || 100))
106
130
  .map((target) => ({ name: target.displayLabel, value: target.key }));
@@ -114,6 +138,7 @@ function listWizardChannelChoices(options = {}) {
114
138
  */
115
139
  function assertChannelTargetInstallable(channelTarget, options = {}) {
116
140
  const target = getChannelTarget(channelTarget);
141
+ assertChannelStatusInstallable(channelTarget, options);
117
142
  if (target.experimental && options.allowExperimental !== true) {
118
143
  throw new Error(
119
144
  `Channel target "${channelTarget}" is experimental. Pass --allow-experimental to install.`
@@ -146,6 +171,7 @@ module.exports = {
146
171
  formatSupportedChannelTargetsHelp,
147
172
  formatUnknownChannelTargetError,
148
173
  listLiveChannelTargetKeys,
174
+ listInstallableChannelTargetKeys,
149
175
  listWizardChannelChoices,
150
176
  assertChannelTargetInstallable,
151
177
  getChannelDefinition,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Customer-facing Claude connector form values: Name and Server URL.
2
+ * Customer-facing Claude connector form values: Name, Server URL, OAuth.
3
3
  *
4
4
  * @fileoverview Claude channel form values — describe, don't configure
5
5
  */
@@ -78,6 +78,9 @@ function formatClaudeFormValueLines(values) {
78
78
  if (values.serverUrl) {
79
79
  lines.push(`Server URL: ${values.serverUrl}`);
80
80
  }
81
+ if (values.authentication) {
82
+ lines.push(`Authentication: ${values.authentication}`);
83
+ }
81
84
  return lines;
82
85
  }
83
86
 
@@ -21,6 +21,7 @@ const {
21
21
  maybeOnboardSlackUsers,
22
22
  unmatchedRemainingStep
23
23
  } = require('./slack-provisioning/onboard');
24
+ const { registerSlackMcpCallback, slackMcpProfileUrl } = require('./slack-mcp-callback');
24
25
 
25
26
  /**
26
27
  * @param {Error} error
@@ -223,36 +224,88 @@ async function recoverOrRefreshAuth(error, params, options, deps, ctx, projectRo
223
224
  * @param {Object} params
224
225
  * @returns {Promise<Object|null>}
225
226
  */
226
- async function maybeProvisionSlackChannel(params) {
227
- if (!params || params.channelTarget !== 'slack') {
227
+ async function maybeRegisterSlackMcpCallback(params) {
228
+ const runtime = params && params.runtimeValues;
229
+ const ctx = params && params.ctx;
230
+ if (!runtime || !runtime.enableMcpServer) {
228
231
  return null;
229
232
  }
230
- if (params.options && params.options.dryRun === true) {
233
+ if (!ctx || !ctx.controllerUrl || !ctx.authConfig) {
234
+ return {
235
+ ok: false,
236
+ fallback: true,
237
+ remaining: ['Open the OAuth2 profile and add the Slack MCP callback URL']
238
+ };
239
+ }
240
+ try {
241
+ const result = await registerSlackMcpCallback({ ctx, ...(params.slackMcpCallbackDeps || {}) });
242
+ if (result && result.fallback) {
243
+ const profileUrl = result.profileUrl || slackMcpProfileUrl(ctx);
244
+ return {
245
+ ok: false,
246
+ fallback: true,
247
+ remaining: [`Open ${profileUrl} and add the Slack MCP callback URL`]
248
+ };
249
+ }
250
+ return result;
251
+ } catch (error) {
252
+ return {
253
+ ok: false,
254
+ fallback: true,
255
+ remaining: [error && error.message ? error.message : 'Slack MCP callback could not be registered']
256
+ };
257
+ }
258
+ }
259
+
260
+ /**
261
+ * @param {Object} params
262
+ * @returns {Promise<Object|null>}
263
+ */
264
+ async function maybeProvisionSlackChannel(params) {
265
+ if (!params || params.channelTarget !== 'slack' || (params.options && params.options.dryRun === true)) {
231
266
  return null;
232
267
  }
233
268
  const ctx = params.ctx || {};
234
269
  const options = params.options || {};
235
270
  const deps = slackDepsFromOptions(options);
236
271
  const projectRoot = options.projectRoot || process.cwd();
272
+ const mcpCallback = await maybeRegisterSlackMcpCallback(params);
237
273
  if (options.quiet === true) {
238
274
  const portal = await preparePortalSlackAuth(options, deps);
239
275
  if (portal.waiting) {
240
276
  await publishSlackAfterSecrets({ connected: false }, options, deps);
241
- return portal.result;
277
+ return attachSlackMcpRemaining(portal.result, mcpCallback);
242
278
  }
243
279
  }
244
280
  try {
245
281
  if (options.quiet !== true) {
246
282
  await ensureSlackCliReady(options, deps);
247
283
  }
248
- return await provisionAndPublish(params, options, deps, ctx, projectRoot);
284
+ const result = await provisionAndPublish(params, options, deps, ctx, projectRoot);
285
+ return attachSlackMcpRemaining(result, mcpCallback);
249
286
  } catch (error) {
250
- return recoverOrRefreshAuth(error, params, options, deps, ctx, projectRoot);
287
+ const recovered = await recoverOrRefreshAuth(error, params, options, deps, ctx, projectRoot);
288
+ return attachSlackMcpRemaining(recovered, mcpCallback);
289
+ }
290
+ }
291
+
292
+ /**
293
+ * @param {Object|null} result
294
+ * @param {Object|null} mcpCallback
295
+ * @returns {Object|null}
296
+ */
297
+ function attachSlackMcpRemaining(result, mcpCallback) {
298
+ const extra = mcpCallback && Array.isArray(mcpCallback.remaining) ? mcpCallback.remaining : [];
299
+ if (extra.length === 0) {
300
+ return result;
251
301
  }
302
+ const base = result && typeof result === 'object' ? result : {};
303
+ return { ...base, remaining: [...(base.remaining || []), ...extra] };
252
304
  }
253
305
 
254
306
  module.exports = {
255
307
  maybeProvisionSlackChannel,
308
+ maybeRegisterSlackMcpCallback,
256
309
  applySlackOnboardToCtx,
257
310
  remainingFromError
258
311
  };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Allowlist Slack MCP OAuth callback on the existing customerOAuth client.
3
+ *
4
+ * @fileoverview Reuse ChatGPT Integration Client; never rotate the secret
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const {
10
+ registerChatGptCallbackUrls,
11
+ chatgptProfileUrl
12
+ } = require('./chatgpt-callback');
13
+ const {
14
+ CHATGPT_INTEGRATION_CLIENT_KEY,
15
+ CHATGPT_OAUTH2_PROFILE_ID,
16
+ CHATGPT_OAUTH2_PROFILE_PATH
17
+ } = require('./chatgpt-runtime-contract');
18
+ const { SLACK_MCP_CALLBACK_URI } = require('./slack-mcp-runtime');
19
+
20
+ const SLACK_MCP_CALLBACK_CONTRACT = {
21
+ integrationClientKey: CHATGPT_INTEGRATION_CLIENT_KEY,
22
+ oauth2ProfileId: CHATGPT_OAUTH2_PROFILE_ID,
23
+ oauth2ProfilePath: CHATGPT_OAUTH2_PROFILE_PATH,
24
+ vendorLabel: 'Slack MCP'
25
+ };
26
+
27
+ /**
28
+ * @param {Object} ctx
29
+ * @returns {string}
30
+ */
31
+ function slackMcpProfileUrl(ctx) {
32
+ return chatgptProfileUrl(ctx, SLACK_MCP_CALLBACK_CONTRACT);
33
+ }
34
+
35
+ /**
36
+ * @param {Object} params
37
+ * @returns {Promise<Object>}
38
+ */
39
+ async function registerSlackMcpCallback(params) {
40
+ return registerChatGptCallbackUrls({
41
+ ...params,
42
+ callbackUrls: [SLACK_MCP_CALLBACK_URI],
43
+ contract: SLACK_MCP_CALLBACK_CONTRACT
44
+ });
45
+ }
46
+
47
+ module.exports = {
48
+ SLACK_MCP_CALLBACK_CONTRACT,
49
+ slackMcpProfileUrl,
50
+ registerSlackMcpCallback
51
+ };