@aifabrix/builder 2.53.1 → 2.55.0

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 (470) hide show
  1. package/README.md +8 -0
  2. package/bin/aifabrix.js +2 -2
  3. package/lib/agent-kit/apply-ops.js +82 -0
  4. package/lib/agent-kit/checksums.js +28 -0
  5. package/lib/agent-kit/classify.js +113 -0
  6. package/lib/agent-kit/claude-shim.js +61 -0
  7. package/lib/agent-kit/constants.js +55 -0
  8. package/lib/agent-kit/file-list.js +103 -0
  9. package/lib/agent-kit/host-approve.js +130 -0
  10. package/lib/agent-kit/hosting/github.js +63 -0
  11. package/lib/agent-kit/hosts.js +71 -0
  12. package/lib/agent-kit/init.js +319 -0
  13. package/lib/agent-kit/kit-root.js +17 -0
  14. package/lib/agent-kit/managed-section.js +79 -0
  15. package/lib/agent-kit/package-load.js +45 -0
  16. package/lib/agent-kit/plan-ops.js +69 -0
  17. package/lib/agent-kit/remote-prompts.js +239 -0
  18. package/lib/agent-kit/render-host-markdown.js +40 -0
  19. package/lib/agent-kit/repo-guard.js +47 -0
  20. package/lib/agent-kit/report.js +107 -0
  21. package/lib/agent-kit/run.js +82 -0
  22. package/lib/agent-kit/scm/git.js +122 -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/assistants.api.js +8 -5
  30. package/lib/api/channel-identity.api.js +41 -0
  31. package/lib/api/evidence-authoring.api.js +5 -1
  32. package/lib/api/evidence.api.js +2 -0
  33. package/lib/api/role-assistant-test-pack.api.js +86 -0
  34. package/lib/api/types/evidence.types.js +2 -0
  35. package/lib/api/work-search.api.js +163 -0
  36. package/lib/api/work.api.js +19 -12
  37. package/lib/app/list-external-systems.js +2 -1
  38. package/lib/app/show-display.js +33 -6
  39. package/lib/app/show.js +25 -2
  40. package/lib/channels/add-channel.js +164 -126
  41. package/lib/channels/approval-guides/chatgpt.js +14 -18
  42. package/lib/channels/approval-guides/claude.js +29 -0
  43. package/lib/channels/approval-guides/index.js +88 -22
  44. package/lib/channels/approval-guides/mcp-client.js +27 -0
  45. package/lib/channels/approval-guides/microsoft-copilot.js +52 -3
  46. package/lib/channels/approval-guides/slack.js +10 -10
  47. package/lib/channels/approval-guides/teams-bot.js +8 -12
  48. package/lib/channels/channel-add-continuations.js +91 -0
  49. package/lib/channels/channel-add-ensure.js +124 -27
  50. package/lib/channels/channel-add-existing.js +160 -28
  51. package/lib/channels/channel-add-failure.js +61 -0
  52. package/lib/channels/channel-add-remaining.js +492 -0
  53. package/lib/channels/channel-add-tty.js +190 -0
  54. package/lib/channels/channel-add-wizard-config.js +138 -0
  55. package/lib/channels/channel-add-wizard.js +250 -0
  56. package/lib/channels/channel-artifact-generator.js +27 -13
  57. package/lib/channels/channel-cardinality.js +83 -0
  58. package/lib/channels/channel-catalog-icon.js +45 -0
  59. package/lib/channels/channel-cli-instructions.js +75 -0
  60. package/lib/channels/channel-configuration-map.js +213 -0
  61. package/lib/channels/channel-credential.js +11 -14
  62. package/lib/channels/channel-definition-project.js +101 -0
  63. package/lib/channels/channel-definition-registry.js +154 -0
  64. package/lib/channels/channel-definition-status.js +115 -0
  65. package/lib/channels/channel-description.js +60 -2
  66. package/lib/channels/channel-discovery.js +16 -2
  67. package/lib/channels/channel-external-system.js +86 -9
  68. package/lib/channels/channel-install-envelope-actions.js +88 -0
  69. package/lib/channels/channel-install-envelope-microsoft.js +155 -0
  70. package/lib/channels/channel-install-envelope.js +358 -0
  71. package/lib/channels/channel-install-help-md.js +172 -0
  72. package/lib/channels/channel-install-http-payload.js +62 -0
  73. package/lib/channels/channel-install-inventory.js +115 -0
  74. package/lib/channels/channel-install-profiles.js +90 -0
  75. package/lib/channels/channel-instance-collision.js +118 -0
  76. package/lib/channels/channel-instance-key.js +100 -0
  77. package/lib/channels/channel-instance-materialize.js +240 -0
  78. package/lib/channels/channel-integration-generator.js +18 -9
  79. package/lib/channels/channel-integration-template.js +101 -22
  80. package/lib/channels/channel-inventory-fetch.js +79 -0
  81. package/lib/channels/channel-oauth-preflight.js +104 -0
  82. package/lib/channels/channel-package-version.js +76 -0
  83. package/lib/channels/channel-predefined-client.js +154 -0
  84. package/lib/channels/channel-probe.js +7 -2
  85. package/lib/channels/channel-runtime-resolver.js +194 -72
  86. package/lib/channels/channel-status-display.js +86 -16
  87. package/lib/channels/channel-targets.js +132 -92
  88. package/lib/channels/chatgpt-callback.js +318 -0
  89. package/lib/channels/chatgpt-channel-add.js +229 -0
  90. package/lib/channels/chatgpt-preflight.js +396 -0
  91. package/lib/channels/chatgpt-runtime-contract.js +17 -0
  92. package/lib/channels/chatgpt-setup-values.js +124 -0
  93. package/lib/channels/claude-callback.js +67 -0
  94. package/lib/channels/claude-channel-add.js +254 -0
  95. package/lib/channels/claude-runtime-contract.js +40 -0
  96. package/lib/channels/claude-runtime.js +58 -0
  97. package/lib/channels/claude-setup-values.js +92 -0
  98. package/lib/channels/mcp-client/config-merge.js +148 -0
  99. package/lib/channels/mcp-client/ensure-client.js +231 -0
  100. package/lib/channels/mcp-client/paths.js +53 -0
  101. package/lib/channels/mcp-client/profiles.js +122 -0
  102. package/lib/channels/mcp-client/redirect-uris.js +99 -0
  103. package/lib/channels/mcp-client/runtime.js +59 -0
  104. package/lib/channels/mcp-client-channel-add.js +186 -0
  105. package/lib/channels/microsoft-copilot-channel-add.js +117 -7
  106. package/lib/channels/microsoft-copilot-entra-identifier-uris.js +187 -0
  107. package/lib/channels/microsoft-copilot-entra-sso-form.js +106 -18
  108. package/lib/channels/microsoft-copilot-entra-sso.js +31 -2
  109. package/lib/channels/microsoft-copilot-package-prior.js +107 -0
  110. package/lib/channels/microsoft-copilot-package.js +29 -28
  111. package/lib/channels/microsoft-provisioning/a365.js +80 -0
  112. package/lib/channels/microsoft-provisioning/auth-config.js +240 -0
  113. package/lib/channels/microsoft-provisioning/auth.js +179 -0
  114. package/lib/channels/microsoft-provisioning/cli.js +71 -0
  115. package/lib/channels/microsoft-provisioning/constants.js +75 -0
  116. package/lib/channels/microsoft-provisioning/errors.js +117 -0
  117. package/lib/channels/microsoft-provisioning/index.js +55 -0
  118. package/lib/channels/microsoft-provisioning/install-atk.js +158 -0
  119. package/lib/channels/microsoft-provisioning/install-teams.js +115 -0
  120. package/lib/channels/microsoft-provisioning/login-portal-device.js +236 -0
  121. package/lib/channels/microsoft-provisioning/login-portal-parse.js +71 -0
  122. package/lib/channels/microsoft-provisioning/login-portal-teams.js +193 -0
  123. package/lib/channels/microsoft-provisioning/login-portal.js +230 -0
  124. package/lib/channels/microsoft-provisioning/persist.js +110 -0
  125. package/lib/channels/microsoft-provisioning/teams-bot-args.js +119 -0
  126. package/lib/channels/microsoft-provisioning/teams-bot-controller.js +123 -0
  127. package/lib/channels/microsoft-provisioning/teams-bot-parse.js +134 -0
  128. package/lib/channels/microsoft-provisioning/teams-bot-persist.js +113 -0
  129. package/lib/channels/microsoft-provisioning/teams-bot-provision.js +234 -0
  130. package/lib/channels/microsoft-provisioning/teams-bot-secrets.js +45 -0
  131. package/lib/channels/microsoft-provisioning/teams-cli.js +82 -0
  132. package/lib/channels/runtime-tool-catalog.js +5 -2
  133. package/lib/channels/slack-channel-add-portal.js +130 -0
  134. package/lib/channels/slack-channel-add-tty-auth.js +95 -0
  135. package/lib/channels/slack-channel-add.js +311 -0
  136. package/lib/channels/slack-mcp-callback.js +51 -0
  137. package/lib/channels/slack-mcp-runtime.js +156 -0
  138. package/lib/channels/slack-provisioning/apps.js +181 -0
  139. package/lib/channels/slack-provisioning/auth-store.js +110 -0
  140. package/lib/channels/slack-provisioning/auth-ticket.js +185 -0
  141. package/lib/channels/slack-provisioning/auth.js +115 -0
  142. package/lib/channels/slack-provisioning/callbacks.js +41 -0
  143. package/lib/channels/slack-provisioning/cli.js +226 -0
  144. package/lib/channels/slack-provisioning/constants.js +37 -0
  145. package/lib/channels/slack-provisioning/credentials.js +169 -0
  146. package/lib/channels/slack-provisioning/curl-shim.js +132 -0
  147. package/lib/channels/slack-provisioning/developer-install.js +118 -0
  148. package/lib/channels/slack-provisioning/env-file.js +120 -0
  149. package/lib/channels/slack-provisioning/errors.js +47 -0
  150. package/lib/channels/slack-provisioning/go-ca-bundle.js +137 -0
  151. package/lib/channels/slack-provisioning/index.js +250 -0
  152. package/lib/channels/slack-provisioning/install-cli.js +335 -0
  153. package/lib/channels/slack-provisioning/manifest.js +89 -0
  154. package/lib/channels/slack-provisioning/oauth-lock.js +33 -0
  155. package/lib/channels/slack-provisioning/offer-cli.js +113 -0
  156. package/lib/channels/slack-provisioning/onboard-members.js +122 -0
  157. package/lib/channels/slack-provisioning/onboard.js +89 -0
  158. package/lib/channels/slack-provisioning/persist.js +95 -0
  159. package/lib/channels/slack-provisioning/remaining-urls.js +158 -0
  160. package/lib/channels/slack-provisioning/with-curl-on-path.js +53 -0
  161. package/lib/channels/teams-bot-channel-add.js +94 -0
  162. package/lib/channels/vendor-dataplane-url.js +249 -0
  163. package/lib/cli/index.js +4 -0
  164. package/lib/cli/setup-certification-commands.js +2 -2
  165. package/lib/cli/setup-certification.help.js +5 -1
  166. package/lib/cli/setup-external-system-help.js +2 -0
  167. package/lib/cli/setup-external-system.js +1 -1
  168. package/lib/commands/agent-kit-help.js +79 -0
  169. package/lib/commands/agent-kit.js +346 -0
  170. package/lib/commands/channel-add-help.js +366 -0
  171. package/lib/commands/channel-add-setup.js +162 -80
  172. package/lib/commands/channel-configure.js +118 -0
  173. package/lib/commands/channel.js +10 -1
  174. package/lib/commands/datasource-capability-relate-cli.js +5 -4
  175. package/lib/commands/governance-upload-external.js +6 -3
  176. package/lib/commands/lifecycle-command-action.js +2 -5
  177. package/lib/commands/lifecycle-external.js +93 -21
  178. package/lib/commands/repair-auth-apply.js +1 -1
  179. package/lib/commands/repair-datasource-key-skip.js +39 -0
  180. package/lib/commands/repair-datasource-keys.js +24 -12
  181. package/lib/commands/repair-datasource-test-payload.js +4 -2
  182. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +23 -2
  183. package/lib/commands/repair-datasource.js +3 -0
  184. package/lib/commands/repair-external-run.js +59 -25
  185. package/lib/commands/repair-openapi-rest-runtime.js +127 -0
  186. package/lib/commands/repair-orchestration-tag-merge.js +339 -0
  187. package/lib/commands/repair-rbac-catalog-defaults.js +96 -0
  188. package/lib/commands/repair-rbac-platform-preset.js +26 -15
  189. package/lib/commands/repair-rbac-reader-roles.js +8 -21
  190. package/lib/commands/repair-rbac.js +26 -44
  191. package/lib/commands/repair-system-permissions.js +24 -22
  192. package/lib/commands/role-assistant-copy-output.js +61 -0
  193. package/lib/commands/role-assistant-copy.js +155 -0
  194. package/lib/commands/role-assistant-test-output.js +22 -9
  195. package/lib/commands/role-assistant-test-result-rows.js +42 -0
  196. package/lib/commands/role-assistant.js +150 -43
  197. package/lib/commands/search.js +143 -0
  198. package/lib/commands/test-e2e-external.js +148 -21
  199. package/lib/commands/test-trust-external.js +7 -5
  200. package/lib/commands/upload-credential-push-log.js +2 -1
  201. package/lib/commands/upload-publish-context.js +1 -1
  202. package/lib/commands/upload-role-assistant-shell.js +124 -0
  203. package/lib/commands/upload-sidecar-followups.js +10 -4
  204. package/lib/commands/upload.js +18 -3
  205. package/lib/commands/verify-operations-skip-e2e.js +131 -0
  206. package/lib/commands/verify-operations-step-plan.js +6 -33
  207. package/lib/commands/verify-operations-steps.js +3 -1
  208. package/lib/core/secrets-docker-env.js +4 -1
  209. package/lib/core/secrets-env-content.js +17 -3
  210. package/lib/datasource/capability/capability-manifest.js +0 -3
  211. package/lib/datasource/capability/copy-test-payload.js +3 -0
  212. package/lib/datasource/capability/relate-operations.js +28 -10
  213. package/lib/datasource/capability/run-capability-relate.js +48 -25
  214. package/lib/datasource/datasource-identifier.js +13 -5
  215. package/lib/deployment/deployer-poll-run.js +117 -35
  216. package/lib/external-system/deploy-dataplane-published.js +70 -0
  217. package/lib/external-system/deploy-helpers.js +26 -1
  218. package/lib/external-system/deploy.js +22 -8
  219. package/lib/external-system/download-helpers.js +29 -2
  220. package/lib/external-system/download-role-assistant.js +109 -4
  221. package/lib/external-system/download.js +46 -30
  222. package/lib/external-system/sync-deploy-manifest.js +3 -2
  223. package/lib/external-system/upload-identity.js +42 -0
  224. package/lib/generator/index.js +19 -15
  225. package/lib/generator/split.js +13 -2
  226. package/lib/generator/wizard-datasource-key.js +54 -0
  227. package/lib/generator/wizard.js +55 -54
  228. package/lib/integration-definition/apply-datasource-keys.js +75 -0
  229. package/lib/integration-definition/apply-relationships.js +195 -0
  230. package/lib/integration-definition/apply-static-enterprise.js +229 -0
  231. package/lib/integration-definition/apply-system-file.js +71 -0
  232. package/lib/integration-definition/apply-test-endpoint.js +89 -0
  233. package/lib/integration-definition/apply-viewpoint-defaults.js +157 -0
  234. package/lib/integration-definition/apply.js +78 -59
  235. package/lib/integration-definition/enrich-openapi-operations.js +36 -10
  236. package/lib/integration-definition/enrich-openapi-pick.js +87 -0
  237. package/lib/lifecycle/role-assistant-governance.js +181 -0
  238. package/lib/lifecycle/scenario-upload.js +181 -30
  239. package/lib/programmatic/builder-api-cors.js +143 -0
  240. package/lib/programmatic/builder-api-request.js +6 -0
  241. package/lib/programmatic/builder-api-route-dispatch.js +56 -42
  242. package/lib/programmatic/builder-api-server.js +8 -1
  243. package/lib/programmatic/capability-registry.js +55 -0
  244. package/lib/programmatic/channel-install-help-resolve.js +359 -0
  245. package/lib/programmatic/channel-install-session.js +218 -0
  246. package/lib/programmatic/help-content/channel-onboarding.md +2 -0
  247. package/lib/programmatic/help-content/cip-overview.md +3 -1
  248. package/lib/programmatic/http-raw-response.js +62 -0
  249. package/lib/programmatic/index.js +2 -0
  250. package/lib/programmatic/openapi-apply-result-schemas.js +8 -0
  251. package/lib/programmatic/openapi-channel-install-bindings.js +179 -0
  252. package/lib/programmatic/openapi-channel-install-schemas.js +289 -0
  253. package/lib/programmatic/openapi-component-schemas.js +19 -1
  254. package/lib/programmatic/openapi-description-enricher.js +3 -1
  255. package/lib/programmatic/openapi-descriptions.js +80 -3
  256. package/lib/programmatic/openapi-envelope-examples.js +124 -0
  257. package/lib/programmatic/openapi-operation-bindings.js +9 -1
  258. package/lib/programmatic/openapi-request-schemas.js +5 -0
  259. package/lib/programmatic/openapi-schema-descriptions-channel.js +319 -0
  260. package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
  261. package/lib/programmatic/openapi-spec.js +13 -8
  262. package/lib/programmatic/platform-rbac-catalog.js +36 -18
  263. package/lib/programmatic/request-timeout.js +3 -0
  264. package/lib/programmatic/route-handler-map.js +58 -1
  265. package/lib/programmatic/route-handlers-context.js +2 -1
  266. package/lib/programmatic/run-auth-permissions.js +54 -0
  267. package/lib/programmatic/run-channel-catalog.js +238 -0
  268. package/lib/programmatic/run-channel-install-artifacts.js +137 -0
  269. package/lib/programmatic/run-channel-install-copilot.js +353 -0
  270. package/lib/programmatic/run-channel-install-options.js +236 -0
  271. package/lib/programmatic/run-channel-install-teams-bot.js +204 -0
  272. package/lib/programmatic/run-channel-install.js +346 -0
  273. package/lib/programmatic/run-channel-package.js +87 -7
  274. package/lib/programmatic/run-download.js +41 -0
  275. package/lib/programmatic/workspace-context.js +2 -0
  276. package/lib/protection/auth-context.js +3 -1
  277. package/lib/protection/protection-display.js +3 -2
  278. package/lib/protection/report-exit.js +50 -0
  279. package/lib/protection/run-commands.js +2 -0
  280. package/lib/role-assistant/evidence-sync.js +4 -2
  281. package/lib/role-assistant/evidence-validation-issues.js +51 -0
  282. package/lib/role-assistant/knowledge-sync.js +10 -4
  283. package/lib/role-assistant/package-validate.js +175 -0
  284. package/lib/role-assistant/settings.js +49 -2
  285. package/lib/role-assistant/test-case-assertion-row.js +36 -0
  286. package/lib/role-assistant/test-case-copy-bind.js +77 -0
  287. package/lib/role-assistant/test-case-copy-expected.js +127 -0
  288. package/lib/role-assistant/test-case-copy-from-work.js +90 -0
  289. package/lib/role-assistant/test-case-copy-interactions.js +67 -0
  290. package/lib/role-assistant/test-case-copy.js +119 -0
  291. package/lib/role-assistant/test-case-expected-catalog.js +135 -0
  292. package/lib/role-assistant/test-case-validate.js +88 -0
  293. package/lib/role-assistant/test-cases-bid.js +117 -4
  294. package/lib/role-assistant/test-cases-evaluate.js +159 -24
  295. package/lib/role-assistant/test-cases-evidence.js +175 -0
  296. package/lib/role-assistant/test-cases-honesty.js +155 -6
  297. package/lib/role-assistant/test-cases-lifecycle.js +291 -0
  298. package/lib/role-assistant/test-cases-search-graph.js +122 -0
  299. package/lib/role-assistant/test-cases-search.js +247 -0
  300. package/lib/role-assistant/test-cases.js +71 -172
  301. package/lib/role-assistant/test-pack-map.js +180 -0
  302. package/lib/role-assistant/test-pack-sync.js +187 -0
  303. package/lib/role-assistant/test-runner-debug.js +54 -0
  304. package/lib/role-assistant/test-runner-respond-body.js +36 -0
  305. package/lib/role-assistant/test-runner-search.js +164 -0
  306. package/lib/role-assistant/test-runner-start-payload.js +63 -10
  307. package/lib/role-assistant/test-runner-workhub-answers.js +45 -16
  308. package/lib/role-assistant/test-runner-workhub-helpers.js +40 -2
  309. package/lib/role-assistant/test-runner-workhub-soft.js +9 -3
  310. package/lib/role-assistant/test-runner-workhub.js +74 -32
  311. package/lib/role-assistant/test-runner.js +66 -11
  312. package/lib/schema/external-datasource.schema.json +146 -21
  313. package/lib/schema/external-system.schema.json +177 -2
  314. package/lib/schema/mcp-client-profile.schema.json +103 -0
  315. package/lib/schema/role-assistant-test-case.schema.json +408 -0
  316. package/lib/search/dataplane-context.js +23 -0
  317. package/lib/search/search-args.js +211 -0
  318. package/lib/search/search-display.js +238 -0
  319. package/lib/search/search-errors.js +50 -0
  320. package/lib/search/search-prompts.js +119 -0
  321. package/lib/search/search-roles.js +85 -0
  322. package/lib/search/search-run.js +241 -0
  323. package/lib/search/search-skills.js +198 -0
  324. package/lib/utils/app-path-resolve.js +4 -0
  325. package/lib/utils/authentication-env-template.js +44 -6
  326. package/lib/utils/authentication-slot-show.js +153 -0
  327. package/lib/utils/credential-display.js +43 -1
  328. package/lib/utils/credential-secrets-env.js +6 -1
  329. package/lib/utils/env-copy.js +19 -7
  330. package/lib/utils/external-env-template.js +20 -2
  331. package/lib/utils/external-system-readiness-compact-blocks.js +5 -1
  332. package/lib/utils/external-system-readiness-compact-display.js +30 -1
  333. package/lib/utils/external-system-validators.js +2 -1
  334. package/lib/utils/help-builder.js +3 -1
  335. package/lib/utils/paths.js +18 -1
  336. package/lib/utils/platform-shell-package.js +69 -0
  337. package/lib/utils/port-resolver.js +50 -1
  338. package/lib/utils/rewrite-name-flag.js +20 -0
  339. package/lib/utils/role-assistant-paths.js +13 -10
  340. package/lib/utils/schema-loader.js +37 -0
  341. package/lib/utils/schema-resolver.js +11 -1
  342. package/lib/utils/secrets-helpers.js +12 -21
  343. package/lib/utils/token-manager.js +10 -5
  344. package/lib/validation/validate-external-file.js +5 -1
  345. package/lib/validation/validate.js +41 -0
  346. package/package.json +1 -1
  347. package/templates/README.md +1 -1
  348. package/templates/agent-kit/adapters/claude/nested.CLAUDE.md +1 -0
  349. package/templates/agent-kit/adapters/claude/root.CLAUDE.md +5 -0
  350. package/templates/agent-kit/adapters/cursor/commands/cust-0-plan.md +5 -0
  351. package/templates/agent-kit/adapters/cursor/commands/cust-1-validate.md +5 -0
  352. package/templates/agent-kit/adapters/cursor/commands/cust-2-build.md +5 -0
  353. package/templates/agent-kit/adapters/cursor/commands/cust-3-push.md +5 -0
  354. package/templates/agent-kit/adapters/cursor/commands/cust-biz-1-validate.md +5 -0
  355. package/templates/agent-kit/adapters/cursor/commands/cust-biz-2-build.md +5 -0
  356. package/templates/agent-kit/adapters/cursor/commands/cust-biz-3-prove.md +5 -0
  357. package/templates/agent-kit/agent-kit.yaml +45 -0
  358. package/templates/agent-kit/instructions/AGENTKIT.md +83 -0
  359. package/templates/agent-kit/instructions/integration.AGENTS.md +25 -0
  360. package/templates/agent-kit/instructions/role-assistant.AGENTS.md +22 -0
  361. package/templates/agent-kit/instructions/root.AGENTS.md +37 -0
  362. package/templates/agent-kit/parity-inventory.yaml +188 -0
  363. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +58 -0
  364. package/templates/agent-kit/skills/aifabrix-connected-system/references/contract-checklist.md +40 -0
  365. package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +54 -0
  366. package/templates/agent-kit/skills/aifabrix-connected-system/references/production-safety.md +35 -0
  367. package/templates/agent-kit/skills/aifabrix-connected-system/scripts/reserved-system-key.js +19 -0
  368. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +51 -0
  369. package/templates/agent-kit/skills/aifabrix-plan/references/challenge-checklist.md +108 -0
  370. package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +34 -0
  371. package/templates/agent-kit/skills/aifabrix-plan/references/plan-template.md +182 -0
  372. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +50 -0
  373. package/templates/agent-kit/skills/aifabrix-prove/references/demo-template.md +65 -0
  374. package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +68 -0
  375. package/templates/agent-kit/skills/aifabrix-prove/references/learning-template.md +66 -0
  376. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +42 -0
  377. package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
  378. package/templates/agent-kit/skills/shared/hosts.md +78 -0
  379. package/templates/agent-kit/workspace/.cursor/plans/README.md +22 -0
  380. package/templates/agent-kit/workspace/LICENSE.mit +21 -0
  381. package/templates/agent-kit/workspace/README.md +89 -0
  382. package/templates/applications/builder-api/Dockerfile +3 -1
  383. package/templates/applications/builder-api/env.template +7 -0
  384. package/templates/applications/dataplane/application.yaml +6 -5
  385. package/templates/applications/dataplane/env.template +2 -2
  386. package/templates/applications/dataplane/rbac.yaml +35 -2
  387. package/templates/applications/keycloak/Dockerfile +30 -4
  388. package/templates/applications/keycloak/application.yaml +2 -2
  389. package/templates/applications/keycloak/cimd-lenient-parse/AbstractClientIdMetadataDocumentExecutor.java +896 -0
  390. package/templates/applications/keycloak/cimd-lenient-parse/SOURCE.md +19 -0
  391. package/templates/applications/keycloak/env.template +3 -0
  392. package/templates/applications/miso-controller/application.yaml +1 -2
  393. package/templates/applications/miso-controller/env.template +10 -9
  394. package/templates/channels/README.md +5 -5
  395. package/templates/channels/chatgpt/TROUBLESHOOTING.md +51 -0
  396. package/templates/channels/chatgpt/channel.json +59 -0
  397. package/templates/channels/chatgpt/icon.svg +1 -0
  398. package/templates/channels/chatgpt/install.template.md.hbs +20 -95
  399. package/templates/channels/chatgpt/integration/README.md +1 -1
  400. package/templates/channels/chatgpt/integration/application.json +2 -2
  401. package/templates/channels/chatgpt/integration/chatgpt-system.json +49 -4
  402. package/templates/channels/chatgpt/integration/env.template +2 -4
  403. package/templates/channels/chatgpt/integration/rbac.json +13 -0
  404. package/templates/channels/claude/TROUBLESHOOTING.md +44 -0
  405. package/templates/channels/claude/channel.json +59 -0
  406. package/templates/channels/claude/icon.svg +1 -0
  407. package/templates/channels/claude/install.template.md.hbs +22 -0
  408. package/templates/channels/claude/integration/README.md +14 -0
  409. package/templates/channels/claude/integration/application.json +15 -0
  410. package/templates/channels/claude/integration/claude-system.json +59 -0
  411. package/templates/channels/claude/integration/env.template +2 -0
  412. package/templates/channels/claude/integration/rbac.json +13 -0
  413. package/templates/channels/claude/manifest.template.json.hbs +40 -0
  414. package/templates/channels/mcp-client/channel.json +72 -0
  415. package/templates/channels/mcp-client/icon.svg +1 -0
  416. package/templates/channels/mcp-client/install.template.md.hbs +24 -0
  417. package/templates/channels/mcp-client/integration/README.md +13 -0
  418. package/templates/channels/mcp-client/integration/application.json +15 -0
  419. package/templates/channels/mcp-client/integration/env.template +2 -0
  420. package/templates/channels/mcp-client/integration/mcp-client-system.json +72 -0
  421. package/templates/channels/mcp-client/integration/rbac.json +13 -0
  422. package/templates/channels/mcp-client/manifest.template.json.hbs +41 -0
  423. package/templates/channels/mcp-client/profiles/cursor.json +26 -0
  424. package/templates/channels/mcp-client/profiles/github-copilot.json +29 -0
  425. package/templates/channels/mcp-client/profiles/vscode.json +29 -0
  426. package/templates/channels/microsoft-copilot/channel.json +73 -0
  427. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +8 -4
  428. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +65 -5
  429. package/templates/channels/microsoft-copilot/icon.svg +1 -0
  430. package/templates/channels/microsoft-copilot/install.template.md.hbs +9 -9
  431. package/templates/channels/microsoft-copilot/integration/README.md +1 -1
  432. package/templates/channels/microsoft-copilot/integration/application.json +2 -2
  433. package/templates/channels/microsoft-copilot/integration/env.template +3 -6
  434. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +63 -4
  435. package/templates/channels/microsoft-copilot/integration/rbac.json +13 -0
  436. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +5 -5
  437. package/templates/channels/slack/channel.json +234 -0
  438. package/templates/channels/slack/icon.svg +1 -0
  439. package/templates/channels/slack/install.template.md.hbs +45 -28
  440. package/templates/channels/slack/integration/README.md +245 -22
  441. package/templates/channels/slack/integration/application.json +44 -7
  442. package/templates/channels/slack/integration/env.template +15 -6
  443. package/templates/channels/slack/integration/openapi/openapi.json +126 -0
  444. package/templates/channels/slack/integration/rbac.json +84 -0
  445. package/templates/channels/slack/integration/slack-datasource-commands.json +154 -0
  446. package/templates/channels/slack/integration/slack-datasource-conversations.json +28 -3
  447. package/templates/channels/slack/integration/slack-datasource-events.json +154 -0
  448. package/templates/channels/slack/integration/slack-datasource-interactive.json +154 -0
  449. package/templates/channels/slack/integration/slack-datasource-messages.json +40 -2
  450. package/templates/channels/slack/integration/slack-system.json +161 -72
  451. package/templates/channels/slack/manifest.template.json.hbs +10 -4
  452. package/templates/channels/teams-bot/channel.json +162 -0
  453. package/templates/channels/teams-bot/icon.svg +1 -0
  454. package/templates/channels/teams-bot/install.template.md.hbs +12 -13
  455. package/templates/channels/teams-bot/integration/README.md +5 -4
  456. package/templates/channels/teams-bot/integration/application.json +6 -4
  457. package/templates/channels/teams-bot/integration/env.template +5 -4
  458. package/templates/channels/teams-bot/integration/openapi/openapi.json +68 -0
  459. package/templates/channels/teams-bot/integration/rbac.json +21 -0
  460. package/templates/channels/teams-bot/integration/teams-bot-datasource-activities.json +154 -0
  461. package/templates/channels/teams-bot/integration/teams-bot-system.json +128 -23
  462. package/templates/channels/web-embed/channel.json +60 -0
  463. package/templates/channels/web-embed/install.template.md.hbs +1 -1
  464. package/templates/channels/web-embed/integration/README.md +2 -2
  465. package/templates/channels/web-embed/integration/application.json +2 -2
  466. package/templates/channels/web-embed/integration/env.template +1 -1
  467. package/templates/channels/web-embed/integration/rbac.json +13 -0
  468. package/templates/channels/web-embed/integration/web-embed-system.json +50 -4
  469. package/templates/python/docker-compose.hbs +14 -0
  470. package/templates/typescript/docker-compose.hbs +14 -0
@@ -1,92 +1,84 @@
1
1
  /**
2
- * Channel target registry for assistant communication channels (plan 152).
2
+ * Channel target registry projected from Channel Definitions.
3
3
  *
4
- * @fileoverview Channel install targets — templates, capabilities, approval semantics
4
+ * @fileoverview CHANNEL_TARGETS is a projection of templates/channels/<key>/channel.json
5
5
  * @author AI Fabrix Team
6
- * @version 1.0.0
6
+ * @version 1.2.0
7
7
  */
8
8
 
9
9
  'use strict';
10
10
 
11
11
  const {
12
- CHATGPT_RUNTIME_SYSTEM_KEY,
13
- COPILOT_RUNTIME_SYSTEM_KEY
14
- } = require('./chatgpt-runtime-contract');
12
+ getChannelDefinition,
13
+ getChannelDefinitionMap,
14
+ listChannelDefinitionKeys
15
+ } = require('./channel-definition-registry');
16
+ const { toChannelTargetProjection } = require('./channel-definition-project');
17
+ const {
18
+ assertChannelStatusInstallable,
19
+ channelStatusOf,
20
+ isCatalogHiddenStatus,
21
+ isInstallableStatus
22
+ } = require('./channel-definition-status');
15
23
 
16
- /** @typedef {'teams-bot'|'slack'|'microsoft-copilot'|'chatgpt'|'web-embed'} ChannelTargetKey */
24
+ function buildChannelTargets() {
25
+ const targets = {};
26
+ for (const [key, definition] of getChannelDefinitionMap().entries()) {
27
+ targets[key] = toChannelTargetProjection(definition);
28
+ }
29
+ return targets;
30
+ }
17
31
 
18
- const DEFAULT_CAPABILITIES = ['chat', 'notify', 'documentApproval'];
32
+ /** @type {Record<string, Object>|null} */
33
+ let cachedChannelTargets = null;
19
34
 
20
- const CHANNEL_TARGETS = {
21
- 'teams-bot': {
22
- key: 'teams-bot',
23
- channelType: 'teamsBot',
24
- templateDir: 'teams-bot',
25
- artifactFileName: 'channel-teams-bot.json',
26
- artifactFormat: 'json',
27
- credentialKey: 'teams-bot',
28
- routeSystemKey: 'teams',
29
- capabilities: DEFAULT_CAPABILITIES,
30
- approvalRequired: true,
31
- experimental: false
32
- },
33
- slack: {
34
- key: 'slack',
35
- channelType: 'slack',
36
- templateDir: 'slack',
37
- artifactFileName: 'channel-slack.json',
38
- artifactFormat: 'json',
39
- credentialKey: 'slack-app',
40
- routeSystemKey: 'slack',
41
- capabilities: DEFAULT_CAPABILITIES,
42
- approvalRequired: true,
43
- experimental: false
44
- },
45
- 'microsoft-copilot': {
46
- key: 'microsoft-copilot',
47
- channelType: 'microsoftCopilot',
48
- templateDir: 'microsoft-copilot',
49
- artifactFileName: 'channel-microsoft-copilot.json',
50
- artifactFormat: 'json',
51
- credentialKey: 'microsoft-copilot-channel',
52
- routeSystemKey: COPILOT_RUNTIME_SYSTEM_KEY,
53
- capabilities: [...DEFAULT_CAPABILITIES, 'enterpriseActions'],
54
- approvalRequired: true,
55
- experimental: false
56
- },
57
- chatgpt: {
58
- key: 'chatgpt',
59
- channelType: 'chatgpt',
60
- templateDir: 'chatgpt',
61
- artifactFileName: 'channel-chatgpt.json',
62
- artifactFormat: 'json',
63
- credentialKey: 'chatgpt-channel',
64
- routeSystemKey: CHATGPT_RUNTIME_SYSTEM_KEY,
65
- capabilities: ['chat', 'enterpriseActions'],
66
- approvalRequired: true,
67
- experimental: false
68
- },
69
- 'web-embed': {
70
- key: 'web-embed',
71
- channelType: 'webEmbed',
72
- templateDir: 'web-embed',
73
- artifactFileName: 'channel-web-embed.json',
74
- artifactFormat: 'json',
75
- credentialKey: 'web-embed-channel',
76
- capabilities: DEFAULT_CAPABILITIES,
77
- approvalRequired: false,
78
- experimental: true
35
+ function resolveChannelTargets() {
36
+ if (cachedChannelTargets && Object.keys(cachedChannelTargets).length > 0) {
37
+ return cachedChannelTargets;
79
38
  }
80
- };
81
-
82
- const CHANNEL_TARGET_KEYS = Object.keys(CHANNEL_TARGETS);
39
+ cachedChannelTargets = buildChannelTargets();
40
+ return cachedChannelTargets;
41
+ }
83
42
 
84
43
  /**
85
44
  * @param {string} channelTarget
86
45
  * @returns {boolean}
87
46
  */
88
47
  function isChannelTargetKey(channelTarget) {
89
- return typeof channelTarget === 'string' && CHANNEL_TARGET_KEYS.includes(channelTarget);
48
+ return typeof channelTarget === 'string' && channelTarget in resolveChannelTargets();
49
+ }
50
+
51
+ /**
52
+ * Human-readable supported channel list for CLI help and error hints.
53
+ * @returns {string}
54
+ */
55
+ function formatSupportedChannelTargetsHelp() {
56
+ const targets = resolveChannelTargets();
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
+ );
63
+ const lines = ['Supported channels:', ` ${stable.join(', ')}`];
64
+ if (experimental.length > 0) {
65
+ lines.push(
66
+ ` ${experimental.join(', ')} (experimental — scaffold with --allow-experimental)`
67
+ );
68
+ }
69
+ if (comingSoon.length > 0) {
70
+ lines.push(` ${comingSoon.join(', ')} (coming soon — not installable)`);
71
+ }
72
+ return lines.join('\n');
73
+ }
74
+
75
+ /**
76
+ * @param {string} channelTarget
77
+ * @returns {string}
78
+ */
79
+ function formatUnknownChannelTargetError(channelTarget) {
80
+ const live = listLiveChannelTargetKeys().join(', ');
81
+ return `Unknown channel: ${channelTarget}\nLive channels: ${live}`;
90
82
  }
91
83
 
92
84
  /**
@@ -95,11 +87,64 @@ function isChannelTargetKey(channelTarget) {
95
87
  */
96
88
  function getChannelTarget(channelTarget) {
97
89
  if (!isChannelTargetKey(channelTarget)) {
90
+ throw new Error(formatUnknownChannelTargetError(channelTarget));
91
+ }
92
+ return resolveChannelTargets()[channelTarget];
93
+ }
94
+
95
+ /**
96
+ * Live keys (not hide), plus experimental when `--allow-experimental` is set.
97
+ * @param {{ allowExperimental?: boolean }} [options]
98
+ * @returns {string[]}
99
+ */
100
+ function listLiveChannelTargetKeys(options = {}) {
101
+ const targets = resolveChannelTargets();
102
+ return Object.keys(targets).filter((key) => {
103
+ if (isCatalogHiddenStatus(channelStatusOf(key))) {
104
+ return false;
105
+ }
106
+ const target = targets[key];
107
+ return !target.experimental || options.allowExperimental === true;
108
+ });
109
+ }
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
+
120
+ /**
121
+ * Inquirer list choices for `aifabrix channel add` (labels from the registry).
122
+ * @param {{ allowExperimental?: boolean }} [options]
123
+ * @returns {{ name: string, value: string }[]}
124
+ */
125
+ function listWizardChannelChoices(options = {}) {
126
+ const targets = resolveChannelTargets();
127
+ return listInstallableChannelTargetKeys(options)
128
+ .map((key) => targets[key])
129
+ .sort((a, b) => (a.wizardOrder || 100) - (b.wizardOrder || 100))
130
+ .map((target) => ({ name: target.displayLabel, value: target.key }));
131
+ }
132
+
133
+ /**
134
+ * Reject experimental targets unless `--allow-experimental` is set.
135
+ * @param {string} channelTarget
136
+ * @param {{ allowExperimental?: boolean }} [options]
137
+ * @returns {typeof CHANNEL_TARGETS[string]}
138
+ */
139
+ function assertChannelTargetInstallable(channelTarget, options = {}) {
140
+ const target = getChannelTarget(channelTarget);
141
+ assertChannelStatusInstallable(channelTarget, options);
142
+ if (target.experimental && options.allowExperimental !== true) {
98
143
  throw new Error(
99
- `Unknown channel target "${channelTarget}". Expected one of: ${CHANNEL_TARGET_KEYS.join(', ')}`
144
+ `Channel target "${channelTarget}" is experimental. Pass --allow-experimental to install.`
100
145
  );
101
146
  }
102
- return CHANNEL_TARGETS[channelTarget];
147
+ return target;
103
148
  }
104
149
 
105
150
  /**
@@ -113,27 +158,22 @@ function getDefaultChannelDescription() {
113
158
  );
114
159
  }
115
160
 
116
- /**
117
- * Human-readable supported channel list for CLI help and error hints.
118
- * @returns {string}
119
- */
120
- function formatSupportedChannelTargetsHelp() {
121
- const stable = CHANNEL_TARGET_KEYS.filter((key) => !CHANNEL_TARGETS[key].experimental);
122
- const experimental = CHANNEL_TARGET_KEYS.filter((key) => CHANNEL_TARGETS[key].experimental);
123
- const lines = ['Supported channels:', ` ${stable.join(', ')}`];
124
- if (experimental.length > 0) {
125
- lines.push(
126
- ` ${experimental.join(', ')} (experimental — scaffold with --allow-experimental)`
127
- );
128
- }
129
- return lines.join('\n');
130
- }
131
-
132
161
  module.exports = {
133
- CHANNEL_TARGETS,
134
- CHANNEL_TARGET_KEYS,
162
+ get CHANNEL_TARGETS() {
163
+ return resolveChannelTargets();
164
+ },
165
+ get CHANNEL_TARGET_KEYS() {
166
+ return Object.keys(resolveChannelTargets());
167
+ },
135
168
  isChannelTargetKey,
136
169
  getChannelTarget,
137
170
  getDefaultChannelDescription,
138
- formatSupportedChannelTargetsHelp
171
+ formatSupportedChannelTargetsHelp,
172
+ formatUnknownChannelTargetError,
173
+ listLiveChannelTargetKeys,
174
+ listInstallableChannelTargetKeys,
175
+ listWizardChannelChoices,
176
+ assertChannelTargetInstallable,
177
+ getChannelDefinition,
178
+ listChannelDefinitionKeys
139
179
  };
@@ -0,0 +1,318 @@
1
+ /**
2
+ * Register ChatGPT callback URLs on the existing chatgpt Integration Client.
3
+ *
4
+ * Never rotates the client secret. Catalog sync is additive — extra URIs stay.
5
+ *
6
+ * @fileoverview HTTPS callback validation + idempotent redirect URI merge
7
+ * @author AI Fabrix Team
8
+ * @version 1.0.0
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ const {
14
+ listIntegrationClients,
15
+ getIntegrationClient,
16
+ updateIntegrationClientRedirectUris
17
+ } = require('../api/integration-clients.api');
18
+ const {
19
+ CHATGPT_INTEGRATION_CLIENT_KEY,
20
+ CHATGPT_OAUTH2_PROFILE_ID,
21
+ CHATGPT_OAUTH2_PROFILE_PATH
22
+ } = require('./chatgpt-runtime-contract');
23
+
24
+ const CHATGPT_CALLBACK_CONTRACT = {
25
+ integrationClientKey: CHATGPT_INTEGRATION_CLIENT_KEY,
26
+ oauth2ProfileId: CHATGPT_OAUTH2_PROFILE_ID,
27
+ oauth2ProfilePath: CHATGPT_OAUTH2_PROFILE_PATH,
28
+ vendorLabel: 'ChatGPT'
29
+ };
30
+
31
+ /**
32
+ * @param {Object|null|undefined} contract
33
+ * @returns {typeof CHATGPT_CALLBACK_CONTRACT}
34
+ */
35
+ function resolveCallbackContract(contract) {
36
+ return {
37
+ integrationClientKey: (contract && contract.integrationClientKey) || CHATGPT_CALLBACK_CONTRACT.integrationClientKey,
38
+ oauth2ProfileId: (contract && contract.oauth2ProfileId) || CHATGPT_CALLBACK_CONTRACT.oauth2ProfileId,
39
+ oauth2ProfilePath: (contract && contract.oauth2ProfilePath) || CHATGPT_CALLBACK_CONTRACT.oauth2ProfilePath,
40
+ vendorLabel: (contract && contract.vendorLabel) || CHATGPT_CALLBACK_CONTRACT.vendorLabel
41
+ };
42
+ }
43
+
44
+ /**
45
+ * @param {string} message
46
+ * @param {string} [boundary]
47
+ * @param {Object} [contract]
48
+ * @returns {Error}
49
+ */
50
+ function createChatGptCallbackError(message, boundary, contract) {
51
+ const resolved = resolveCallbackContract(contract);
52
+ const error = new Error(`${resolved.vendorLabel} callback: ${message}`);
53
+ error.boundary = boundary || 'callback';
54
+ return error;
55
+ }
56
+
57
+ /**
58
+ * @param {string|undefined} value
59
+ * @returns {string}
60
+ */
61
+ function assertHttpsRedirectUri(value, contract) {
62
+ const trimmed = typeof value === 'string' ? value.trim() : '';
63
+ if (!trimmed) {
64
+ throw createChatGptCallbackError('Callback URL is required.', 'callback', contract);
65
+ }
66
+ let parsed;
67
+ try {
68
+ parsed = new URL(trimmed);
69
+ } catch {
70
+ throw createChatGptCallbackError(`Callback URL is not a valid URL: ${trimmed}`, 'callback', contract);
71
+ }
72
+ if (parsed.protocol !== 'https:') {
73
+ throw createChatGptCallbackError(`Callback URL must be HTTPS: ${trimmed}`, 'callback', contract);
74
+ }
75
+ return trimmed;
76
+ }
77
+
78
+ /**
79
+ * @param {string[]|undefined} existing
80
+ * @param {string} nextUri
81
+ * @returns {{ uris: string[], added: boolean }}
82
+ */
83
+ function mergeRedirectUris(existing, nextUri) {
84
+ const list = Array.isArray(existing)
85
+ ? existing.filter((uri) => typeof uri === 'string' && uri.trim())
86
+ : [];
87
+ if (list.some((uri) => uri.trim() === nextUri)) {
88
+ return { uris: list, added: false };
89
+ }
90
+ return { uris: [...list, nextUri], added: true };
91
+ }
92
+
93
+ /**
94
+ * @param {string[]|undefined} existing
95
+ * @param {string[]} nextUris
96
+ * @returns {{ uris: string[], added: boolean }}
97
+ */
98
+ function mergeRedirectUriList(existing, nextUris) {
99
+ let uris = Array.isArray(existing) ? [...existing] : [];
100
+ let added = false;
101
+ for (const nextUri of nextUris) {
102
+ const merged = mergeRedirectUris(uris, nextUri);
103
+ uris = merged.uris;
104
+ added = added || merged.added;
105
+ }
106
+ return { uris, added };
107
+ }
108
+
109
+ /**
110
+ * @param {string[]|undefined} values
111
+ * @returns {string[]}
112
+ */
113
+ function normalizeCallbackUrls(values, contract) {
114
+ const unique = [];
115
+ for (const value of Array.isArray(values) ? values : []) {
116
+ const uri = assertHttpsRedirectUri(value, contract);
117
+ if (!unique.includes(uri)) {
118
+ unique.push(uri);
119
+ }
120
+ }
121
+ if (unique.length === 0) {
122
+ throw createChatGptCallbackError('Callback URL is required.', 'callback', contract);
123
+ }
124
+ return unique;
125
+ }
126
+
127
+ /**
128
+ * @param {Object} response
129
+ * @returns {Object|Array}
130
+ */
131
+ function unwrapApiBody(response) {
132
+ if (response && response.data && response.data.data !== undefined && response.data.data !== null) {
133
+ return response.data.data;
134
+ }
135
+ if (response && response.data !== undefined) {
136
+ return response.data;
137
+ }
138
+ return response || {};
139
+ }
140
+
141
+ /**
142
+ * @param {Object} response
143
+ * @returns {Array}
144
+ */
145
+ function unwrapIntegrationClientList(response) {
146
+ const body = unwrapApiBody(response);
147
+ if (Array.isArray(body)) {
148
+ return body;
149
+ }
150
+ if (Array.isArray(body.data)) {
151
+ return body.data;
152
+ }
153
+ if (Array.isArray(body.items)) {
154
+ return body.items;
155
+ }
156
+ return [];
157
+ }
158
+
159
+ /**
160
+ * @param {Object} response
161
+ * @returns {Object}
162
+ */
163
+ function unwrapIntegrationClientRecord(response) {
164
+ const body = unwrapApiBody(response);
165
+ return body.integrationClient || body;
166
+ }
167
+
168
+ /**
169
+ * @param {Object} ctx
170
+ * @param {Object} [contract]
171
+ * @returns {string}
172
+ */
173
+ function chatgptProfileUrl(ctx, contract) {
174
+ const resolved = resolveCallbackContract(contract);
175
+ const base = ctx && typeof ctx.controllerUrl === 'string' ? ctx.controllerUrl.replace(/\/$/, '') : '';
176
+ if (!base) {
177
+ return resolved.oauth2ProfilePath;
178
+ }
179
+ return `${base}${resolved.oauth2ProfilePath}`;
180
+ }
181
+
182
+ /**
183
+ * @param {Object} ctx
184
+ * @param {Object} [contract]
185
+ * @returns {string}
186
+ */
187
+ function formatMissingChatGptClientError(ctx, contract) {
188
+ const resolved = resolveCallbackContract(contract);
189
+ return [
190
+ `Integration client "${resolved.integrationClientKey}" was not found.`,
191
+ `Open the ${resolved.vendorLabel} OAuth2 profile (${resolved.oauth2ProfileId}): ${chatgptProfileUrl(ctx, resolved)}`,
192
+ `Enable the ${resolved.vendorLabel} profile, then retry callback registration.`
193
+ ].join(' ');
194
+ }
195
+
196
+ /**
197
+ * @param {Error|Object} errorOrResponse
198
+ * @returns {boolean}
199
+ */
200
+ function isForbiddenClientError(errorOrResponse) {
201
+ const status = errorOrResponse && errorOrResponse.status;
202
+ if (status === 403) {
203
+ return true;
204
+ }
205
+ const message = errorOrResponse && errorOrResponse.message
206
+ ? String(errorOrResponse.message)
207
+ : '';
208
+ return /\b403\b/.test(message) || /forbidden|not allowed|integration-client:update/i.test(message);
209
+ }
210
+
211
+ /**
212
+ * @param {Object} ctx
213
+ * @param {Object} [deps]
214
+ * @returns {Promise<Object>}
215
+ */
216
+ async function findChatGptIntegrationClient(ctx, deps = {}) {
217
+ const contract = resolveCallbackContract(deps.contract);
218
+ const listFn = deps.listIntegrationClients || listIntegrationClients;
219
+ const getFn = deps.getIntegrationClient || getIntegrationClient;
220
+ const response = await listFn(ctx.controllerUrl, ctx.authConfig, { pageSize: 100 });
221
+ if (response && response.success === false) {
222
+ throw createChatGptCallbackError(
223
+ response.formattedError || response.error || 'Failed to list integration clients.',
224
+ response.status === 403 ? 'permissions' : 'callback',
225
+ contract
226
+ );
227
+ }
228
+ const match = unwrapIntegrationClientList(response).find(
229
+ (row) => row && row.key === contract.integrationClientKey
230
+ );
231
+ if (!match || !match.id) {
232
+ throw createChatGptCallbackError(formatMissingChatGptClientError(ctx, contract), 'callback', contract);
233
+ }
234
+ const detail = await getFn(ctx.controllerUrl, ctx.authConfig, match.id);
235
+ const record = unwrapIntegrationClientRecord(detail);
236
+ return { ...match, ...record, id: match.id };
237
+ }
238
+
239
+ /**
240
+ * @param {Object} params
241
+ * @param {Object} client
242
+ * @param {string[]} uris
243
+ * @returns {Promise<Object|null>}
244
+ */
245
+ async function applyRedirectUriUpdate(params, client, uris) {
246
+ const contract = resolveCallbackContract(params.contract);
247
+ const updateFn = params.updateRedirectUris || updateIntegrationClientRedirectUris;
248
+ try {
249
+ const response = await updateFn(params.ctx.controllerUrl, params.ctx.authConfig, client.id, {
250
+ redirectUris: uris
251
+ });
252
+ if (response && response.success === false && response.status === 403) {
253
+ return { ok: false, fallback: true, profileUrl: chatgptProfileUrl(params.ctx, contract) };
254
+ }
255
+ if (response && response.success === false) {
256
+ throw createChatGptCallbackError(
257
+ response.formattedError || response.error || 'Failed to update redirect URIs.',
258
+ 'callback',
259
+ contract
260
+ );
261
+ }
262
+ } catch (error) {
263
+ if (isForbiddenClientError(error)) {
264
+ return { ok: false, fallback: true, profileUrl: chatgptProfileUrl(params.ctx, contract) };
265
+ }
266
+ throw error;
267
+ }
268
+ return null;
269
+ }
270
+
271
+ /**
272
+ * Idempotent HTTPS callback registration. Never rotates secrets.
273
+ * @param {Object} params
274
+ * @returns {Promise<{ ok: boolean, added?: boolean, fallback?: boolean, profileUrl?: string, redirectUris?: string[] }>}
275
+ */
276
+ async function registerChatGptCallbackUrls(params) {
277
+ const contract = resolveCallbackContract(params.contract);
278
+ const callbackUrls = normalizeCallbackUrls(params.callbackUrls, contract);
279
+ let client;
280
+ try {
281
+ client = await findChatGptIntegrationClient(params.ctx, { ...params, contract });
282
+ } catch (error) {
283
+ if (isForbiddenClientError(error)) {
284
+ return { ok: false, fallback: true, profileUrl: chatgptProfileUrl(params.ctx, contract) };
285
+ }
286
+ throw error;
287
+ }
288
+ const merged = mergeRedirectUriList(client.redirectUris, callbackUrls);
289
+ const forbidden = await applyRedirectUriUpdate(params, client, merged.uris);
290
+ if (forbidden) {
291
+ return forbidden;
292
+ }
293
+ return { ok: true, added: merged.added, redirectUris: merged.uris };
294
+ }
295
+
296
+ /**
297
+ * @param {Object} params
298
+ * @returns {Promise<Object>}
299
+ */
300
+ async function registerChatGptCallbackUrl(params) {
301
+ return registerChatGptCallbackUrls({
302
+ ...params,
303
+ callbackUrls: [params.callbackUrl]
304
+ });
305
+ }
306
+
307
+ module.exports = {
308
+ assertHttpsRedirectUri,
309
+ mergeRedirectUris,
310
+ unwrapIntegrationClientList,
311
+ findChatGptIntegrationClient,
312
+ formatMissingChatGptClientError,
313
+ registerChatGptCallbackUrl,
314
+ registerChatGptCallbackUrls,
315
+ chatgptProfileUrl,
316
+ resolveCallbackContract,
317
+ CHATGPT_CALLBACK_CONTRACT
318
+ };