@aifabrix/builder 2.52.0 → 2.53.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 (310) hide show
  1. package/lib/api/datasources-extended.api.js +8 -8
  2. package/lib/api/keycloak.api.js +92 -0
  3. package/lib/api/token-providers.api.js +77 -0
  4. package/lib/api/types/keycloak.types.js +23 -0
  5. package/lib/api/types/token-providers.types.js +65 -0
  6. package/lib/app/deploy-config.js +3 -2
  7. package/lib/app/down.js +16 -1
  8. package/lib/channels/add-channel.js +134 -57
  9. package/lib/channels/approval-guides/chatgpt.js +1 -1
  10. package/lib/channels/approval-guides/index.js +3 -0
  11. package/lib/channels/approval-guides/microsoft-copilot.js +27 -14
  12. package/lib/channels/channel-add-ensure.js +128 -0
  13. package/lib/channels/channel-add-existing.js +72 -0
  14. package/lib/channels/channel-artifact-generator.js +11 -1
  15. package/lib/channels/channel-branding.js +94 -0
  16. package/lib/channels/channel-credential.js +8 -0
  17. package/lib/channels/channel-discovery.js +330 -0
  18. package/lib/channels/channel-external-system.js +1 -1
  19. package/lib/channels/channel-runtime-resolver.js +107 -14
  20. package/lib/channels/channel-status-display.js +36 -3
  21. package/lib/channels/microsoft-copilot-channel-add.js +138 -0
  22. package/lib/channels/microsoft-copilot-entra-sso-form.js +251 -0
  23. package/lib/channels/microsoft-copilot-entra-sso.js +285 -0
  24. package/lib/channels/microsoft-copilot-icons.js +74 -0
  25. package/lib/channels/microsoft-copilot-limits.js +103 -0
  26. package/lib/channels/microsoft-copilot-package.js +178 -52
  27. package/lib/channels/microsoft-copilot-validate.js +227 -0
  28. package/lib/cli/attach-default-help-examples.js +102 -0
  29. package/lib/cli/index.js +4 -0
  30. package/lib/cli/infra-guided.js +13 -6
  31. package/lib/cli/setup-credential-deployment.js +7 -5
  32. package/lib/cli/setup-infra.js +31 -4
  33. package/lib/cli/setup-utility-validate.js +1 -0
  34. package/lib/commands/channel-add-setup.js +28 -9
  35. package/lib/commands/channel.js +14 -10
  36. package/lib/commands/credential-push.js +37 -5
  37. package/lib/commands/integration-definition.js +158 -0
  38. package/lib/commands/package-score.js +72 -0
  39. package/lib/commands/repair-auth-apply.js +19 -5
  40. package/lib/commands/repair-datasource-sync-operations.js +4 -1
  41. package/lib/commands/role-assistant-test-output.js +200 -0
  42. package/lib/commands/role-assistant.js +163 -166
  43. package/lib/datasource/capability/capability-resolve.js +15 -5
  44. package/lib/datasource/capability/copy-operations.js +14 -4
  45. package/lib/deployment/deployer-poll-run.js +2 -2
  46. package/lib/deployment/deployer.js +1 -1
  47. package/lib/deployment/environment.js +2 -2
  48. package/lib/external-system/deploy.js +11 -21
  49. package/lib/infrastructure/index.js +19 -4
  50. package/lib/integration-definition/apply.js +476 -0
  51. package/lib/integration-definition/canonical-json.js +51 -0
  52. package/lib/integration-definition/emit-suite-bid.js +94 -0
  53. package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
  54. package/lib/integration-definition/enrich-openapi-operations.js +433 -0
  55. package/lib/integration-definition/from-discovery.js +339 -0
  56. package/lib/integration-definition/hash.js +37 -0
  57. package/lib/integration-definition/index.js +37 -0
  58. package/lib/integration-definition/resource-type-catalog.js +59 -0
  59. package/lib/integration-definition/system-kind-enum.js +40 -0
  60. package/lib/integration-definition/validate.js +148 -0
  61. package/lib/lab/package-parity-score.js +417 -0
  62. package/lib/programmatic/builder-api-request.js +5 -1
  63. package/lib/programmatic/builder-help-governance.js +3 -2
  64. package/lib/programmatic/capability-registry.js +20 -0
  65. package/lib/programmatic/help-content/channel-onboarding.md +35 -0
  66. package/lib/programmatic/help-content/cip-overview.md +27 -0
  67. package/lib/programmatic/help-content/connected-system-ui.md +70 -0
  68. package/lib/programmatic/help-content/dimensions-guide.md +23 -0
  69. package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
  70. package/lib/programmatic/help-content/overview.md +25 -0
  71. package/lib/programmatic/help-content/subscription-guide.md +27 -0
  72. package/lib/programmatic/help-content/workflow.md +50 -0
  73. package/lib/programmatic/openapi-component-schemas.js +7 -1
  74. package/lib/programmatic/openapi-descriptions.js +46 -0
  75. package/lib/programmatic/openapi-envelope-examples.js +280 -0
  76. package/lib/programmatic/openapi-operation-bindings.js +50 -0
  77. package/lib/programmatic/openapi-request-schemas.js +40 -0
  78. package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
  79. package/lib/programmatic/openapi-result-schemas.js +76 -99
  80. package/lib/programmatic/openapi-schema-descriptions-core.js +25 -4
  81. package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
  82. package/lib/programmatic/openapi-schema-descriptions-operations.js +43 -0
  83. package/lib/programmatic/openapi-schema-helpers.js +9 -9
  84. package/lib/programmatic/openapi-spec.js +11 -1
  85. package/lib/programmatic/orchestration-openapi-meta.js +10 -0
  86. package/lib/programmatic/persist-supplied-openapi.js +180 -0
  87. package/lib/programmatic/route-handler-map.js +35 -1
  88. package/lib/programmatic/run-channel-package.js +236 -0
  89. package/lib/programmatic/run-integration-definition.js +77 -0
  90. package/lib/role-assistant/evidence-sync.js +55 -7
  91. package/lib/role-assistant/knowledge-sync-logging.js +58 -0
  92. package/lib/role-assistant/knowledge-sync.js +88 -93
  93. package/lib/role-assistant/test-cases-bid.js +155 -0
  94. package/lib/role-assistant/test-cases-evaluate.js +9 -1
  95. package/lib/role-assistant/test-cases-honesty.js +24 -10
  96. package/lib/role-assistant/test-cases.js +28 -0
  97. package/lib/role-assistant/test-runner-attachments.js +118 -0
  98. package/lib/role-assistant/test-runner-bid-apply.js +201 -0
  99. package/lib/role-assistant/test-runner-bid-document.js +278 -0
  100. package/lib/role-assistant/test-runner-start-payload.js +96 -0
  101. package/lib/role-assistant/test-runner-workhub-answers.js +249 -20
  102. package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
  103. package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
  104. package/lib/role-assistant/test-runner-workhub.js +152 -107
  105. package/lib/role-assistant/test-runner.js +5 -63
  106. package/lib/role-assistant/test-suite.js +112 -0
  107. package/lib/schema/application-schema.json +56 -6
  108. package/lib/schema/external-datasource.schema.json +103 -17
  109. package/lib/schema/external-system.schema.json +54 -3
  110. package/lib/schema/integration-definition.schema.json +195 -0
  111. package/lib/utils/authentication-shape.js +6 -0
  112. package/lib/utils/compose-generator.js +10 -1
  113. package/lib/utils/compose-traefik-extra-routes.js +107 -0
  114. package/lib/utils/docker-build.js +2 -2
  115. package/lib/utils/help-builder.js +3 -1
  116. package/lib/utils/promote-dev-docker-image.js +102 -18
  117. package/lib/utils/transient-developer-id.js +28 -0
  118. package/package.json +14 -16
  119. package/templates/README.md +12 -1
  120. package/templates/applications/dataplane/application.yaml +10 -2
  121. package/templates/applications/dataplane/env.template +7 -6
  122. package/templates/applications/miso-controller/application.yaml +23 -8
  123. package/templates/applications/miso-controller/env.template +8 -2
  124. package/templates/applications/miso-controller/rbac.yaml +1 -0
  125. package/templates/channels/README.md +11 -1
  126. package/templates/channels/brand/color-192.png +0 -0
  127. package/templates/channels/brand/dark/128.png +0 -0
  128. package/templates/channels/brand/dark/192.png +0 -0
  129. package/templates/channels/brand/dark/256.png +0 -0
  130. package/templates/channels/brand/dark/32.png +0 -0
  131. package/templates/channels/brand/dark/512.png +0 -0
  132. package/templates/channels/brand/dark/64.png +0 -0
  133. package/templates/channels/brand/light/128.png +0 -0
  134. package/templates/channels/brand/light/192.png +0 -0
  135. package/templates/channels/brand/light/256.png +0 -0
  136. package/templates/channels/brand/light/32.png +0 -0
  137. package/templates/channels/brand/light/512.png +0 -0
  138. package/templates/channels/brand/light/64.png +0 -0
  139. package/templates/channels/brand/mono-white/128.png +0 -0
  140. package/templates/channels/brand/mono-white/192.png +0 -0
  141. package/templates/channels/brand/mono-white/256.png +0 -0
  142. package/templates/channels/brand/mono-white/32.png +0 -0
  143. package/templates/channels/brand/mono-white/512.png +0 -0
  144. package/templates/channels/brand/mono-white/64.png +0 -0
  145. package/templates/channels/brand/outline-32.png +0 -0
  146. package/templates/channels/chatgpt/install.template.md.hbs +6 -4
  147. package/templates/channels/chatgpt/integration/README.md +4 -5
  148. package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
  149. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +14 -16
  150. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
  151. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +30 -0
  152. package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
  153. package/templates/channels/microsoft-copilot/install.template.md.hbs +93 -22
  154. package/templates/channels/microsoft-copilot/integration/README.md +2 -3
  155. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
  156. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -19
  157. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +15 -0
  158. package/templates/channels/slack/integration/README.md +2 -4
  159. package/templates/channels/teams-bot/install.template.md.hbs +4 -0
  160. package/templates/channels/teams-bot/integration/README.md +3 -5
  161. package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
  162. package/templates/python/docker-compose.hbs +36 -0
  163. package/templates/typescript/docker-compose.hbs +36 -0
  164. package/.cursor/plans/Done/157.1-security-quality-violations-by-type.csv +0 -374
  165. package/.cursor/process/README.md +0 -9
  166. package/.cursor/rules/anchor-docs.mdc +0 -15
  167. package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
  168. package/.cursor/rules/cli-layout.mdc +0 -81
  169. package/.cursor/rules/cli-product-neutral.mdc +0 -43
  170. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
  171. package/.cursor/rules/docs-rules.mdc +0 -32
  172. package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
  173. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
  174. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
  175. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
  176. package/.cursor/rules/project-rules.mdc +0 -913
  177. package/.cursor/skills/README.md +0 -15
  178. package/.dockerignore +0 -52
  179. package/.eslintignore +0 -22
  180. package/.markdownlint.json +0 -14
  181. package/anchor-docs/README.md +0 -10
  182. package/anchor-docs/_TEMPLATE +0 -24
  183. package/babel.config.js +0 -6
  184. package/bin/builder-api-cleanup.js +0 -26
  185. package/bin/builder-api-nest.js +0 -10
  186. package/bin/builder-api-spike.js +0 -19
  187. package/enterprise-knowledge/README.md +0 -50
  188. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
  189. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
  190. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
  191. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
  192. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
  193. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
  194. package/integration/README.md +0 -81
  195. package/integration/github/README.md +0 -53
  196. package/integration/github/application.json +0 -21
  197. package/integration/github/deploy.js +0 -72
  198. package/integration/github/env.template +0 -11
  199. package/integration/github/github-datasource-issue-comments.json +0 -239
  200. package/integration/github/github-datasource-issues.json +0 -399
  201. package/integration/github/github-datasource-repository.json +0 -354
  202. package/integration/github/github-deploy.json +0 -1202
  203. package/integration/github/github-system.json +0 -82
  204. package/integration/hubspot-test/README.md +0 -159
  205. package/integration/hubspot-test/application.json +0 -54
  206. package/integration/hubspot-test/companies.json +0 -2048
  207. package/integration/hubspot-test/create-hubspot.js +0 -523
  208. package/integration/hubspot-test/env.template +0 -4
  209. package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
  210. package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
  211. package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
  212. package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
  213. package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
  214. package/integration/hubspot-test/hubspot-test-system.json +0 -74
  215. package/integration/hubspot-test/rbac.json +0 -166
  216. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
  217. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
  218. package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
  219. package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
  220. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
  221. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
  222. package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
  223. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
  224. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
  225. package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
  226. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
  227. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
  228. package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
  229. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
  230. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
  231. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
  232. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
  233. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
  234. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
  235. package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
  236. package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
  237. package/integration/hubspot-test/test-dataplane-down.js +0 -209
  238. package/integration/hubspot-test/test.js +0 -1588
  239. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
  240. package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
  241. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
  242. package/integration/roundtrip-test-local/README.md +0 -143
  243. package/integration/roundtrip-test-local/application.yaml +0 -13
  244. package/integration/roundtrip-test-local/env.template +0 -15
  245. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
  246. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
  247. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
  248. package/integration/roundtrip-test-local2/README.md +0 -143
  249. package/integration/roundtrip-test-local2/application.yaml +0 -13
  250. package/integration/roundtrip-test-local2/env.template +0 -15
  251. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
  252. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
  253. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
  254. package/integration/test/wizard.yaml +0 -8
  255. package/jest.config.coverage.js +0 -37
  256. package/jest.config.default.js +0 -11
  257. package/jest.config.integration.fixtures.js +0 -22
  258. package/jest.config.integration.js +0 -33
  259. package/jest.config.isolated.js +0 -11
  260. package/jest.config.manual.js +0 -30
  261. package/jest.global-live-fabrix-hooks.js +0 -36
  262. package/jest.isolated-projects.js +0 -260
  263. package/jest.projects.js +0 -76
  264. package/packages/builder-api/README.md +0 -120
  265. package/packages/builder-api/package.json +0 -30
  266. package/packages/builder-api/src/app.module.ts +0 -7
  267. package/packages/builder-api/src/auth/auth.module.ts +0 -5
  268. package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
  269. package/packages/builder-api/src/main.ts +0 -16
  270. package/packages/builder-api/tsconfig.json +0 -15
  271. package/scripts/check-builder-api-architecture-grep.js +0 -79
  272. package/scripts/check-datasource-test-run-schema-sync.js +0 -34
  273. package/scripts/ci-fix.sh +0 -19
  274. package/scripts/ci-simulate.sh +0 -19
  275. package/scripts/diagnose-cli.js +0 -150
  276. package/scripts/docker_image_content_gate.js +0 -47
  277. package/scripts/docker_image_content_gate.sh +0 -5
  278. package/scripts/export-builder-api-evidence.js +0 -262
  279. package/scripts/install-local.js +0 -490
  280. package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
  281. package/scripts/lib/builder-api-docker-staging-core.js +0 -183
  282. package/scripts/lib/docker-image-content-gate-core.js +0 -166
  283. package/scripts/lib/plan-actor.js +0 -109
  284. package/scripts/lib/plan-config.js +0 -20
  285. package/scripts/lib/plan-gates.js +0 -154
  286. package/scripts/lib/plan-meta.js +0 -104
  287. package/scripts/lib/plan-parse.js +0 -162
  288. package/scripts/lib/plan-prevalidate-gates.js +0 -337
  289. package/scripts/lib/plan-run-core.js +0 -125
  290. package/scripts/lib/plan-run-report.js +0 -119
  291. package/scripts/plan-approve.js +0 -24
  292. package/scripts/plan-archive.js +0 -49
  293. package/scripts/plan-run.js +0 -13
  294. package/scripts/plan-set-actor.js +0 -21
  295. package/scripts/plan-validate.js +0 -80
  296. package/scripts/pnpm/af.mjs +0 -110
  297. package/scripts/pnpm/check-quiet.mjs +0 -32
  298. package/scripts/pnpm/dev-install.mjs +0 -29
  299. package/scripts/pnpm/dev-reload.mjs +0 -18
  300. package/scripts/pnpm/help.mjs +0 -55
  301. package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
  302. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
  303. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
  304. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
  305. package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
  306. package/scripts/pnpm/lib/spinner.mjs +0 -42
  307. package/scripts/pnpm-global-remove.js +0 -48
  308. package/scripts/stage_builder_api_for_docker.js +0 -65
  309. package/scripts/sync-builder-api-template.js +0 -44
  310. package/scripts/test-dataplane-bootstrap.js +0 -331
@@ -9,12 +9,19 @@
9
9
  'use strict';
10
10
 
11
11
  const crypto = require('crypto');
12
- const fs = require('fs');
12
+ const fs = require('../internal/fs-real-sync');
13
13
  const path = require('path');
14
14
  const AdmZip = require('adm-zip');
15
-
16
- const PLACEHOLDER_ICON_BASE64 =
17
- 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO2s9WQAAAAASUVORK5CYII=';
15
+ const { getMicrosoftCopilotIcons } = require('./microsoft-copilot-icons');
16
+ const { assertValidMicrosoftCopilotPackage } = require('./microsoft-copilot-validate');
17
+ const { applyMicrosoftCopilotDisplayLimits } = require('./microsoft-copilot-limits');
18
+ const {
19
+ assertCopilotPackageOauthPluginVaultReference
20
+ } = require('./microsoft-copilot-entra-sso');
21
+ const {
22
+ renderCopilotChannelTemplate,
23
+ applyWebApplicationInfoFields
24
+ } = require('./microsoft-copilot-entra-sso-form');
18
25
 
19
26
  /**
20
27
  * @param {string} outputPath
@@ -37,16 +44,20 @@ function buildCopilotOutputPaths(outputPath, runtimeValues) {
37
44
  zipFileName,
38
45
  zipPath: path.join(buildDir, zipFileName),
39
46
  validationPath: path.join(installDir, 'validation.json'),
40
- installPath: path.join(installDir, 'README.md')
47
+ installPath: path.join(rootDir, 'INSTALL.md'),
48
+ installReadmePath: path.join(installDir, 'README.md')
41
49
  };
42
50
  }
43
51
 
44
52
  /**
53
+ * @param {Object} [runtimeValues]
45
54
  * @returns {{ color: Buffer, outline: Buffer }}
46
55
  */
47
- function getPlaceholderIcons() {
48
- const icon = Buffer.from(PLACEHOLDER_ICON_BASE64, 'base64');
49
- return { color: icon, outline: icon };
56
+ function resolvePackageIcons(runtimeValues) {
57
+ return getMicrosoftCopilotIcons({
58
+ colorPath: runtimeValues?.iconColorPath,
59
+ outlinePath: runtimeValues?.iconOutlinePath
60
+ });
50
61
  }
51
62
 
52
63
  /**
@@ -65,9 +76,11 @@ function renderCopilotTemplates(runtimeValues, renderTemplateFile, templatesDir)
65
76
  'ai-plugin.json': renderTemplateFile(
66
77
  path.join(templatesDir, 'ai-plugin.template.json.hbs'),
67
78
  runtimeValues
68
- )
79
+ ),
80
+ 'fi-fi.json': renderTemplateFile(path.join(templatesDir, 'fi-fi.template.json.hbs'), runtimeValues)
69
81
  };
70
- const installText = renderTemplateFile(path.join(templatesDir, 'install.template.md.hbs'), runtimeValues);
82
+ // INSTALL prose + Entra SSO form table live in templates (partial entraSsoRegistration).
83
+ const installText = renderCopilotChannelTemplate('install.template.md.hbs', runtimeValues);
71
84
  return { sourceFiles, installText };
72
85
  }
73
86
 
@@ -91,6 +104,7 @@ function buildCopilotZipBuffer(sourceFiles, icons) {
91
104
  zip.addFile('manifest.json', Buffer.from(sourceFiles['manifest.json'], 'utf8'));
92
105
  zip.addFile('declarativeAgent.json', Buffer.from(sourceFiles['declarativeAgent.json'], 'utf8'));
93
106
  zip.addFile('ai-plugin.json', Buffer.from(sourceFiles['ai-plugin.json'], 'utf8'));
107
+ zip.addFile('fi-fi.json', Buffer.from(sourceFiles['fi-fi.json'], 'utf8'));
94
108
  zip.addFile('color.png', icons.color);
95
109
  zip.addFile('outline.png', icons.outline);
96
110
  return zip.toBuffer();
@@ -112,14 +126,18 @@ function buildCopilotValidation(runtimeValues, paths, sourceFileNames) {
112
126
  runtimeMcpUrl: runtimeValues.mcpUrl,
113
127
  runtimeTransport: runtimeValues.runtimeTransport,
114
128
  expectedLayerBToolNames: runtimeValues.layerBToolNames || [],
129
+ governedToolNames: runtimeValues.layerBToolNames || [],
130
+ installReady: runtimeValues.installReady === true,
131
+ blocker: runtimeValues.discoveryBlocker || null,
115
132
  boundaries: {
116
133
  onePackagePerEnvironment: true,
117
134
  topLevelVendorToolsExposed: false,
118
135
  roleAssistantResolution: 'dynamic-runtime'
119
136
  },
120
137
  requiresMicrosoftAdmin: [
121
- 'upload-package',
122
- 'tenant-approval',
138
+ 'developer-portal-import',
139
+ 'publish-to-org',
140
+ 'teams-admin-approval',
123
141
  'assignment-and-consent',
124
142
  'first-copilot-invoke'
125
143
  ]
@@ -142,6 +160,72 @@ function computeCopilotArtifactHash(parts) {
142
160
  return hash.digest('hex');
143
161
  }
144
162
 
163
+ /**
164
+ * @param {Object} runtimeValues
165
+ * @returns {Object}
166
+ */
167
+ function buildCopilotSummaryRuntime(runtimeValues) {
168
+ return {
169
+ runtimeSystemKey: runtimeValues.runtimeSystemKey,
170
+ remoteMcpUrl: runtimeValues.mcpUrl,
171
+ transport: runtimeValues.runtimeTransport,
172
+ assistantCatalogUrl: runtimeValues.assistantCatalogUrl,
173
+ roleAssistantResolution: 'dynamic-runtime',
174
+ layerBToolNames: runtimeValues.layerBToolNames || [],
175
+ governedToolNames: runtimeValues.layerBToolNames || []
176
+ };
177
+ }
178
+
179
+ /**
180
+ * @param {Object} runtimeValues
181
+ * @returns {Object}
182
+ */
183
+ function buildCopilotSummaryAuthentication(runtimeValues) {
184
+ const discovery = runtimeValues.discoveryAuthentication || null;
185
+ const serialized = discovery ? JSON.stringify(discovery) : '';
186
+ if (/authorizationServerMetadataUrl":"[^"]+"/i.test(serialized)) {
187
+ throw new Error('Keycloak authorizationServerMetadata must not appear in Copilot package summary');
188
+ }
189
+ return {
190
+ mode: runtimeValues.runtimeAuthMode,
191
+ pluginAuthType: 'OAuthPluginVault',
192
+ oauthPluginVaultReferenceId: runtimeValues.oauthPluginVaultReferenceId || null,
193
+ recommendedCapability: discovery?.recommendedCapability || null,
194
+ entraIssuer: runtimeValues.entraIssuer || discovery?.issuer || null,
195
+ entraEnterpriseAppId: runtimeValues.entraEnterpriseAppId || null,
196
+ entraTenantId: runtimeValues.entraTenantId || null,
197
+ entraSsoClientId: runtimeValues.entraSsoClientId || null,
198
+ scopes: runtimeValues.scopes || [],
199
+ discovery,
200
+ note:
201
+ 'Microsoft Entra SSO via OAuthPluginVault (Teams auth-config reference_id); ' +
202
+ 'miso-controller performs exchange — package carries public specs only; no Fabrix OAuth secrets'
203
+ };
204
+ }
205
+
206
+ /**
207
+ * @param {Object} runtimeValues
208
+ * @param {Object} paths
209
+ * @returns {Object}
210
+ */
211
+ function buildCopilotSummaryPackage(runtimeValues, paths) {
212
+ return {
213
+ appId: runtimeValues.packageAppId,
214
+ version: runtimeValues.packageVersion,
215
+ sourceFiles: [
216
+ 'manifest.json',
217
+ 'declarativeAgent.json',
218
+ 'ai-plugin.json',
219
+ 'fi-fi.json',
220
+ 'color.png',
221
+ 'outline.png'
222
+ ],
223
+ zipFileName: paths.zipFileName,
224
+ installGuide: 'INSTALL.md',
225
+ validationFile: path.relative(paths.rootDir, paths.validationPath)
226
+ };
227
+ }
228
+
145
229
  /**
146
230
  * @param {Object} runtimeValues
147
231
  * @param {Object} paths
@@ -156,27 +240,19 @@ function buildCopilotSummary(runtimeValues, paths, validation, artifactHash) {
156
240
  baseName: runtimeValues.baseName,
157
241
  description: runtimeValues.appDescription,
158
242
  environment: runtimeValues.environment,
159
- runtime: {
160
- runtimeSystemKey: runtimeValues.runtimeSystemKey,
161
- remoteMcpUrl: runtimeValues.mcpUrl,
162
- transport: runtimeValues.runtimeTransport,
163
- assistantCatalogUrl: runtimeValues.assistantCatalogUrl,
164
- roleAssistantResolution: 'dynamic-runtime',
165
- layerBToolNames: runtimeValues.layerBToolNames || []
166
- },
167
- authentication: {
168
- mode: runtimeValues.runtimeAuthMode,
169
- credentialKey: runtimeValues.credentialKey,
170
- credentialPortalUrl: runtimeValues.credentialPortalUrl,
171
- scopes: runtimeValues.scopes || []
172
- },
173
- package: {
174
- appId: runtimeValues.packageAppId,
175
- version: runtimeValues.packageVersion,
176
- sourceFiles: ['manifest.json', 'declarativeAgent.json', 'ai-plugin.json', 'color.png', 'outline.png'],
177
- zipFileName: paths.zipFileName,
178
- installGuide: path.relative(paths.rootDir, paths.installPath),
179
- validationFile: path.relative(paths.rootDir, paths.validationPath)
243
+ runtime: buildCopilotSummaryRuntime(runtimeValues),
244
+ authentication: buildCopilotSummaryAuthentication(runtimeValues),
245
+ package: buildCopilotSummaryPackage(runtimeValues, paths),
246
+ installReady: runtimeValues.installReady === true,
247
+ blocker: runtimeValues.discoveryBlocker || null,
248
+ packageReady: runtimeValues.packageReady !== false && runtimeValues.installReady === true,
249
+ packageBlocker: runtimeValues.packageBlocker || runtimeValues.discoveryBlocker || null,
250
+ microsoftPublicationPending: runtimeValues.microsoftPublicationPending !== false,
251
+ links: {
252
+ readme: paths.installPath,
253
+ zip: paths.zipPath,
254
+ filesRoot: paths.sourceDir,
255
+ validation: paths.validationPath
180
256
  },
181
257
  probeTiers: {
182
258
  builderValidated: true,
@@ -207,28 +283,26 @@ function writeCopilotArtifacts(params) {
207
283
  'utf8'
208
284
  );
209
285
  fs.writeFileSync(path.join(paths.sourceDir, 'ai-plugin.json'), sourceFiles['ai-plugin.json'], 'utf8');
286
+ fs.writeFileSync(path.join(paths.sourceDir, 'fi-fi.json'), sourceFiles['fi-fi.json'], 'utf8');
210
287
  fs.writeFileSync(path.join(paths.sourceDir, 'color.png'), icons.color);
211
288
  fs.writeFileSync(path.join(paths.sourceDir, 'outline.png'), icons.outline);
212
289
  fs.writeFileSync(paths.zipPath, zipBuffer);
213
290
  fs.writeFileSync(paths.installPath, installText, 'utf8');
291
+ if (paths.installReadmePath) {
292
+ fs.writeFileSync(paths.installReadmePath, installText, 'utf8');
293
+ }
214
294
  fs.writeFileSync(paths.validationPath, validationText, 'utf8');
215
295
  fs.writeFileSync(paths.summaryPath, summaryText, 'utf8');
216
296
  }
217
297
 
218
298
  /**
219
299
  * @param {Object} params
220
- * @param {Object} params.runtimeValues
221
- * @param {string} params.templatesDir
222
- * @param {string} params.outputPath
223
- * @param {boolean} [params.dryRun]
224
- * @param {(content: string) => void} params.assertNoSecretsInArtifact
225
- * @param {(templatePath: string, context: Object) => string} params.renderTemplateFile
226
- * @returns {{ outputPath: string, artifactHash: string, content: string, installPath: string }}
300
+ * @param {Object} runtimeValues
301
+ * @param {Object} paths
302
+ * @param {{ color: Buffer, outline: Buffer }} icons
303
+ * @returns {{ summary: Object, summaryText: string, zipBuffer: Buffer, sourceFiles: Object, installText: string, validationText: string }}
227
304
  */
228
- function generateMicrosoftCopilotPackage(params) {
229
- const runtimeValues = params.runtimeValues || {};
230
- const paths = buildCopilotOutputPaths(params.outputPath, runtimeValues);
231
- const icons = getPlaceholderIcons();
305
+ function buildCopilotPackagePayload(params, runtimeValues, paths, icons) {
232
306
  const { sourceFiles, installText } = renderCopilotTemplates(
233
307
  runtimeValues,
234
308
  params.renderTemplateFile,
@@ -236,6 +310,7 @@ function generateMicrosoftCopilotPackage(params) {
236
310
  );
237
311
  assertNoSecretsInSourceFiles(sourceFiles, params.assertNoSecretsInArtifact);
238
312
  params.assertNoSecretsInArtifact(installText);
313
+ assertValidMicrosoftCopilotPackage(sourceFiles, icons);
239
314
  const zipBuffer = buildCopilotZipBuffer(sourceFiles, icons);
240
315
  const validation = buildCopilotValidation(runtimeValues, paths, Object.keys(sourceFiles));
241
316
  const validationText = JSON.stringify(validation, null, 2);
@@ -243,6 +318,7 @@ function generateMicrosoftCopilotPackage(params) {
243
318
  sourceFiles['manifest.json'],
244
319
  sourceFiles['declarativeAgent.json'],
245
320
  sourceFiles['ai-plugin.json'],
321
+ sourceFiles['fi-fi.json'],
246
322
  installText,
247
323
  validationText,
248
324
  zipBuffer
@@ -250,22 +326,72 @@ function generateMicrosoftCopilotPackage(params) {
250
326
  const summary = buildCopilotSummary(runtimeValues, paths, validation, artifactHash);
251
327
  const summaryText = JSON.stringify(summary, null, 2);
252
328
  params.assertNoSecretsInArtifact(summaryText);
329
+ return { summary, summaryText, zipBuffer, sourceFiles, installText, validationText };
330
+ }
331
+
332
+ /**
333
+ * Read prior webApplicationInfo from an existing source manifest (preserve on regenerate).
334
+ * @param {string} sourceDir
335
+ * @returns {{ id: string, resource: string }|null}
336
+ */
337
+ function readPriorWebApplicationInfo(sourceDir) {
338
+ const manifestPath = path.join(sourceDir, 'manifest.json');
339
+ if (!fs.existsSync(manifestPath)) {
340
+ return null;
341
+ }
342
+ try {
343
+ const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
344
+ const info = parsed && parsed.webApplicationInfo;
345
+ if (
346
+ info &&
347
+ typeof info.id === 'string' &&
348
+ info.id.trim() &&
349
+ typeof info.resource === 'string' &&
350
+ info.resource.trim()
351
+ ) {
352
+ return { id: info.id.trim(), resource: info.resource.trim() };
353
+ }
354
+ } catch {
355
+ return null;
356
+ }
357
+ return null;
358
+ }
359
+
360
+ function generateMicrosoftCopilotPackage(params) {
361
+ const runtimeValues = applyMicrosoftCopilotDisplayLimits({ ...(params.runtimeValues || {}) });
362
+ assertCopilotPackageOauthPluginVaultReference(runtimeValues);
363
+ const paths = buildCopilotOutputPaths(params.outputPath, runtimeValues);
364
+ const prior = readPriorWebApplicationInfo(paths.sourceDir);
365
+ applyWebApplicationInfoFields(runtimeValues, {
366
+ webApplicationInfoId: runtimeValues.webApplicationInfoId,
367
+ webApplicationInfoResource: runtimeValues.webApplicationInfoResource,
368
+ priorWebApplicationInfo: prior
369
+ });
370
+ const icons = resolvePackageIcons(runtimeValues);
371
+ const payload = buildCopilotPackagePayload(params, runtimeValues, paths, icons);
253
372
  if (!params.dryRun) {
254
373
  writeCopilotArtifacts({
255
374
  paths,
256
- sourceFiles,
375
+ sourceFiles: payload.sourceFiles,
257
376
  icons,
258
- zipBuffer,
259
- installText,
260
- validationText,
261
- summaryText
377
+ zipBuffer: payload.zipBuffer,
378
+ installText: payload.installText,
379
+ validationText: payload.validationText,
380
+ summaryText: payload.summaryText
262
381
  });
263
382
  }
264
383
  return {
265
384
  outputPath: paths.summaryPath,
266
- artifactHash,
267
- content: summaryText,
268
- installPath: paths.installPath
385
+ artifactHash: payload.summary.artifact.hash,
386
+ content: payload.summaryText,
387
+ installPath: paths.installPath,
388
+ zipPath: paths.zipPath,
389
+ links: payload.summary.links,
390
+ installReady: payload.summary.installReady === true,
391
+ blocker: payload.summary.blocker || null,
392
+ packageReady: payload.summary.packageReady === true,
393
+ packageBlocker: payload.summary.packageBlocker || null,
394
+ microsoftPublicationPending: payload.summary.microsoftPublicationPending !== false
269
395
  };
270
396
  }
271
397
 
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Validate Microsoft Copilot package source files before ZIP.
3
+ *
4
+ * @fileoverview Schema-oriented checks for Teams + declarative agent + AI plugin manifests
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const {
12
+ TEAMS_NAME_SHORT_MAX,
13
+ TEAMS_NAME_FULL_MAX,
14
+ TEAMS_DESCRIPTION_SHORT_MAX,
15
+ TEAMS_DESCRIPTION_FULL_MAX,
16
+ PLUGIN_NAME_FOR_HUMAN_MAX,
17
+ PLUGIN_DESCRIPTION_FOR_HUMAN_MAX
18
+ } = require('./microsoft-copilot-limits');
19
+ const { readPngDimensions } = require('./microsoft-copilot-icons');
20
+
21
+ const ALLOWED_AUTH_TYPES = new Set(['None', 'OAuthPluginVault', 'ApiKeyPluginVault']);
22
+
23
+ /**
24
+ * @param {unknown} value
25
+ * @param {string} label
26
+ * @param {number} max
27
+ * @param {string[]} errors
28
+ */
29
+ function assertMaxLength(value, label, max, errors) {
30
+ if (typeof value !== 'string') {
31
+ errors.push(`${label} must be a string`);
32
+ return;
33
+ }
34
+ if (value.length > max) {
35
+ errors.push(`${label} exceeds ${max} characters (got ${value.length})`);
36
+ }
37
+ }
38
+
39
+ /**
40
+ * @param {Record<string, string>} sourceFiles
41
+ * @returns {{ manifest: Object|null, agent: Object|null, plugin: Object|null, errors: string[] }}
42
+ */
43
+ function parsePackageJsonFiles(sourceFiles) {
44
+ const errors = [];
45
+ const parsed = { manifest: null, agent: null, plugin: null };
46
+ try {
47
+ parsed.manifest = JSON.parse(sourceFiles['manifest.json'] || '');
48
+ } catch {
49
+ errors.push('manifest.json is not valid JSON');
50
+ }
51
+ try {
52
+ parsed.agent = JSON.parse(sourceFiles['declarativeAgent.json'] || '');
53
+ } catch {
54
+ errors.push('declarativeAgent.json is not valid JSON');
55
+ }
56
+ try {
57
+ parsed.plugin = JSON.parse(sourceFiles['ai-plugin.json'] || '');
58
+ } catch {
59
+ errors.push('ai-plugin.json is not valid JSON');
60
+ }
61
+ return { ...parsed, errors };
62
+ }
63
+
64
+ /**
65
+ * @param {Object|null} manifest
66
+ * @param {string[]} errors
67
+ */
68
+ function validateTeamsManifest(manifest, errors) {
69
+ if (!manifest) return;
70
+ assertMaxLength(manifest?.name?.short, 'manifest.name.short', TEAMS_NAME_SHORT_MAX, errors);
71
+ assertMaxLength(manifest?.name?.full, 'manifest.name.full', TEAMS_NAME_FULL_MAX, errors);
72
+ assertMaxLength(
73
+ manifest?.description?.short,
74
+ 'manifest.description.short',
75
+ TEAMS_DESCRIPTION_SHORT_MAX,
76
+ errors
77
+ );
78
+ assertMaxLength(
79
+ manifest?.description?.full,
80
+ 'manifest.description.full',
81
+ TEAMS_DESCRIPTION_FULL_MAX,
82
+ errors
83
+ );
84
+ if (!manifest.copilotAgents?.declarativeAgents?.length) {
85
+ errors.push('manifest.copilotAgents.declarativeAgents is required');
86
+ }
87
+ }
88
+
89
+ /**
90
+ * @param {Object|null} agent
91
+ * @param {string[]} errors
92
+ */
93
+ function validateDeclarativeAgent(agent, errors) {
94
+ if (!agent) return;
95
+ if (agent.version !== 'v1.4') {
96
+ errors.push('declarativeAgent.version must be "v1.4"');
97
+ }
98
+ if (!agent.id || !agent.name || !agent.description || !agent.instructions) {
99
+ errors.push('declarativeAgent requires id, name, description, and instructions');
100
+ }
101
+ }
102
+
103
+ /**
104
+ * @param {Object|null} plugin
105
+ * @param {string[]} errors
106
+ */
107
+ function validateAiPlugin(plugin, errors) {
108
+ if (!plugin) return;
109
+ if (plugin.schema_version !== 'v2.4') {
110
+ errors.push('ai-plugin.schema_version must be "v2.4"');
111
+ }
112
+ assertMaxLength(plugin.name_for_human, 'ai-plugin.name_for_human', PLUGIN_NAME_FOR_HUMAN_MAX, errors);
113
+ assertMaxLength(
114
+ plugin.description_for_human,
115
+ 'ai-plugin.description_for_human',
116
+ PLUGIN_DESCRIPTION_FOR_HUMAN_MAX,
117
+ errors
118
+ );
119
+ if (!plugin.namespace || !/^[A-Za-z0-9-]+$/.test(plugin.namespace)) {
120
+ errors.push('ai-plugin.namespace is required (alphanumeric and hyphen only)');
121
+ }
122
+ validateAiPluginRuntime(plugin, errors);
123
+ }
124
+
125
+ /**
126
+ * @param {Object} runtime
127
+ * @param {string[]} errors
128
+ */
129
+ function validateAiPluginAuth(runtime, errors) {
130
+ const authType = runtime.auth?.type;
131
+ if (!ALLOWED_AUTH_TYPES.has(authType)) {
132
+ errors.push(
133
+ `ai-plugin.runtimes[0].auth.type must be one of ${[...ALLOWED_AUTH_TYPES].join(', ')}`
134
+ );
135
+ }
136
+ if (authType === 'OAuthPluginVault') {
137
+ const ref = runtime.auth.reference_id;
138
+ if (typeof ref !== 'string' || !ref.trim()) {
139
+ errors.push(
140
+ 'OAuthPluginVault.reference_id is required — pass --oauth-plugin-vault-reference-id ' +
141
+ 'with the Teams Developer Portal Entra SSO auth-config id'
142
+ );
143
+ }
144
+ }
145
+ if (authType === 'None') {
146
+ errors.push(
147
+ 'ai-plugin.runtimes[0].auth.type None is not allowed; use OAuthPluginVault (Microsoft token / Entra)'
148
+ );
149
+ }
150
+ }
151
+
152
+ /**
153
+ * @param {Object} plugin
154
+ * @param {Object} runtime
155
+ * @param {string[]} errors
156
+ */
157
+ function validateAiPluginDiscovery(plugin, runtime, errors) {
158
+ const desc = runtime.spec?.mcp_tool_description;
159
+ if (desc && (desc.mode || desc.layerBToolNames)) {
160
+ errors.push(
161
+ 'ai-plugin mcp_tool_description must not use mode/layerBToolNames; omit for dynamic discovery or use tools/file'
162
+ );
163
+ }
164
+ if (!Array.isArray(plugin.functions) || plugin.functions.length !== 0) {
165
+ errors.push(
166
+ 'ai-plugin.functions must be [] for Microsoft dynamic MCP tool discovery ' +
167
+ '(see run_for_functions ["*"])'
168
+ );
169
+ }
170
+ const runFor = runtime.run_for_functions;
171
+ if (!Array.isArray(runFor) || runFor.length !== 1 || runFor[0] !== '*') {
172
+ errors.push(
173
+ 'ai-plugin.runtimes[0].run_for_functions must be ["*"] for dynamic MCP tool discovery'
174
+ );
175
+ }
176
+ }
177
+
178
+ /**
179
+ * @param {Object} plugin
180
+ * @param {string[]} errors
181
+ */
182
+ function validateAiPluginRuntime(plugin, errors) {
183
+ const runtime = Array.isArray(plugin.runtimes) ? plugin.runtimes[0] : null;
184
+ if (!runtime || runtime.type !== 'RemoteMCPServer') {
185
+ errors.push('ai-plugin.runtimes[0].type must be RemoteMCPServer');
186
+ return;
187
+ }
188
+ validateAiPluginAuth(runtime, errors);
189
+ validateAiPluginDiscovery(plugin, runtime, errors);
190
+ }
191
+
192
+ /**
193
+ * @param {{ color: Buffer, outline: Buffer }} icons
194
+ * @param {string[]} errors
195
+ */
196
+ function validatePackageIcons(icons, errors) {
197
+ const colorDims = readPngDimensions(icons.color);
198
+ const outlineDims = readPngDimensions(icons.outline);
199
+ if (!colorDims || colorDims.width !== 192 || colorDims.height !== 192) {
200
+ errors.push('color.png must be a 192x192 PNG');
201
+ }
202
+ if (!outlineDims || outlineDims.width !== 32 || outlineDims.height !== 32) {
203
+ errors.push('outline.png must be a 32x32 PNG');
204
+ }
205
+ }
206
+
207
+ /**
208
+ * @param {Record<string, string>} sourceFiles
209
+ * @param {{ color: Buffer, outline: Buffer }} icons
210
+ * @throws {Error}
211
+ */
212
+ function assertValidMicrosoftCopilotPackage(sourceFiles, icons) {
213
+ const parsed = parsePackageJsonFiles(sourceFiles);
214
+ const errors = [...parsed.errors];
215
+ validateTeamsManifest(parsed.manifest, errors);
216
+ validateDeclarativeAgent(parsed.agent, errors);
217
+ validateAiPlugin(parsed.plugin, errors);
218
+ validatePackageIcons(icons, errors);
219
+ if (errors.length) {
220
+ throw new Error(`Microsoft Copilot package validation failed:\n- ${errors.join('\n- ')}`);
221
+ }
222
+ }
223
+
224
+ module.exports = {
225
+ assertValidMicrosoftCopilotPackage,
226
+ ALLOWED_AUTH_TYPES
227
+ };
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Attach minimal product-neutral Examples: blocks to commands that lack them.
3
+ * Runs after setupCommands so intentional addHelpText Examples are preserved.
4
+ *
5
+ * @fileoverview Default CLI help Examples for check:cli-help gate
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const EXAMPLE_HEADER_RE = /Examples:/m;
11
+ const EXAMPLE_LINE_RE = /\$ aifabrix |\$ af /;
12
+
13
+ /**
14
+ * @param {import('commander').Command} cmd
15
+ * @returns {string}
16
+ */
17
+ function captureHelpOutput(cmd) {
18
+ if (!cmd || typeof cmd.outputHelp !== 'function') {
19
+ return '';
20
+ }
21
+ let buf = '';
22
+ cmd.outputHelp({
23
+ write: (chunk) => {
24
+ buf += String(chunk);
25
+ }
26
+ });
27
+ return buf;
28
+ }
29
+
30
+ /**
31
+ * @param {string} text
32
+ * @returns {boolean}
33
+ */
34
+ function hasValidExamples(text) {
35
+ return EXAMPLE_HEADER_RE.test(text) && EXAMPLE_LINE_RE.test(text);
36
+ }
37
+
38
+ /**
39
+ * @param {string} pathStr
40
+ * @returns {string}
41
+ */
42
+ function defaultExamplesBlock(pathStr) {
43
+ return `
44
+ Examples:
45
+ $ aifabrix ${pathStr}
46
+ $ aifabrix ${pathStr} -h
47
+ `;
48
+ }
49
+
50
+ /**
51
+ * @param {import('commander').Command} cmd
52
+ * @param {string[]} parts
53
+ * @param {Array<{ cmd: import('commander').Command, path: string }>} out
54
+ */
55
+ function collectCommands(cmd, parts, out) {
56
+ // Tests sometimes pass mock nodes without Commander methods — skip those.
57
+ if (!cmd || typeof cmd.name !== 'function') {
58
+ return;
59
+ }
60
+ const name = cmd.name();
61
+ if (name === 'help') {
62
+ return;
63
+ }
64
+ const next = name && name !== 'aifabrix' ? parts.concat(name) : parts;
65
+ const subs = Array.isArray(cmd.commands) ? cmd.commands : [];
66
+ if (next.length > 0) {
67
+ out.push({ cmd, path: next.join(' ') });
68
+ }
69
+ for (const child of subs) {
70
+ collectCommands(child, next, out);
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Ensure every leaf and parent has Examples with $ aifabrix / $ af.
76
+ * @param {import('commander').Command} program
77
+ * @returns {number} count of commands that received a default Examples block
78
+ */
79
+ function attachDefaultHelpExamples(program) {
80
+ const entries = [];
81
+ collectCommands(program, [], entries);
82
+ let attached = 0;
83
+ for (const { cmd, path: pathStr } of entries) {
84
+ if (typeof cmd.addHelpText !== 'function') {
85
+ continue;
86
+ }
87
+ const text = captureHelpOutput(cmd);
88
+ if (hasValidExamples(text)) {
89
+ continue;
90
+ }
91
+ cmd.addHelpText('after', defaultExamplesBlock(pathStr));
92
+ attached += 1;
93
+ }
94
+ return attached;
95
+ }
96
+
97
+ module.exports = {
98
+ attachDefaultHelpExamples,
99
+ hasValidExamples,
100
+ captureHelpOutput,
101
+ defaultExamplesBlock
102
+ };
package/lib/cli/index.js CHANGED
@@ -67,6 +67,8 @@ function setupCoreCliCommands(program) {
67
67
  setupChannelCommands(program);
68
68
  setupDatasourceCommands(program);
69
69
  setupManifestCommands(program);
70
+ const { setupIntegrationDefinitionCommands } = require('../commands/integration-definition');
71
+ setupIntegrationDefinitionCommands(program);
70
72
  }
71
73
 
72
74
  /**
@@ -98,6 +100,8 @@ function setupCommands(program) {
98
100
  setupCoreCliCommands(program);
99
101
  setupExtendedCliCommands(program);
100
102
  setupDevAndPlatformCommands(program);
103
+ const { attachDefaultHelpExamples } = require('./attach-default-help-examples');
104
+ attachDefaultHelpExamples(program);
101
105
  }
102
106
 
103
107
  module.exports = {