@aifabrix/builder 2.49.2 → 2.50.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 (409) hide show
  1. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +49 -0
  2. package/.cursor/rules/plan-rules/application-lifecycle.mdc +30 -0
  3. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +35 -0
  4. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +31 -0
  5. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +34 -0
  6. package/.cursor/skills/README.md +1 -0
  7. package/.dockerignore +52 -0
  8. package/.eslintignore +22 -0
  9. package/README.md +2 -0
  10. package/bin/builder-api-cleanup.js +26 -0
  11. package/bin/builder-api-nest.js +10 -0
  12. package/bin/builder-api-spike.js +19 -0
  13. package/enterprise-knowledge/README.md +50 -0
  14. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +22 -0
  15. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +15 -0
  16. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +69 -0
  17. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +52 -0
  18. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +29 -0
  19. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +2 -0
  20. package/integration/README.md +81 -0
  21. package/integration/github/README.md +53 -0
  22. package/integration/github/application.json +21 -0
  23. package/integration/github/deploy.js +72 -0
  24. package/integration/github/env.template +11 -0
  25. package/integration/github/github-datasource-issue-comments.json +239 -0
  26. package/integration/github/github-datasource-issues.json +399 -0
  27. package/integration/github/github-datasource-repository.json +354 -0
  28. package/integration/github/github-deploy.json +1202 -0
  29. package/integration/github/github-system.json +82 -0
  30. package/integration/hubspot-test/README.md +1 -1
  31. package/jest.isolated-projects.js +31 -1
  32. package/jest.projects.js +87 -1
  33. package/lib/api/dev-server-https.js +1 -1
  34. package/lib/api/enterprise-knowledge.api.js +63 -0
  35. package/lib/api/evidence.api.js +172 -0
  36. package/lib/api/external-systems.api.js +8 -2
  37. package/lib/api/resource-types.api.js +1 -0
  38. package/lib/api/types/enterprise-knowledge.types.js +46 -0
  39. package/lib/api/types/evidence.types.js +67 -0
  40. package/lib/api/types/resource-types.types.js +2 -0
  41. package/lib/app/controller-application-filter.js +36 -0
  42. package/lib/app/deploy.js +1 -1
  43. package/lib/app/list-external-systems.js +130 -0
  44. package/lib/app/list.js +20 -8
  45. package/lib/app/run.js +3 -1
  46. package/lib/app/show-display.js +8 -3
  47. package/lib/app/show-online.js +178 -0
  48. package/lib/app/show.js +37 -88
  49. package/lib/build/builder-api-docker-staging.js +47 -0
  50. package/lib/build/miso-controller-npm-sdk-guard.js +2 -2
  51. package/lib/build/standard-docker-build.js +2 -0
  52. package/lib/certification/post-unified-cert-sync.js +4 -31
  53. package/lib/certification/sync-after-external-command.js +0 -1
  54. package/lib/certification/sync-system-certification.js +0 -3
  55. package/lib/channels/add-channel.js +40 -34
  56. package/lib/channels/approval-guides/chatgpt.js +33 -0
  57. package/lib/channels/approval-guides/credential-portal.js +38 -0
  58. package/lib/channels/approval-guides/index.js +110 -0
  59. package/lib/channels/approval-guides/microsoft-copilot.js +34 -0
  60. package/lib/channels/approval-guides/slack.js +34 -0
  61. package/lib/channels/approval-guides/teams-bot.js +35 -0
  62. package/lib/channels/approval-guides/web-embed.js +32 -0
  63. package/lib/channels/channel-approval-guide.js +11 -0
  64. package/lib/channels/channel-artifact-generator.js +16 -4
  65. package/lib/channels/channel-audit.js +3 -0
  66. package/lib/channels/channel-auth-context.js +1 -1
  67. package/lib/channels/channel-description.js +59 -0
  68. package/lib/channels/channel-integration-generator.js +13 -230
  69. package/lib/channels/channel-integration-template.js +94 -0
  70. package/lib/channels/channel-runtime-resolver.js +43 -3
  71. package/lib/channels/channel-status-display.js +66 -26
  72. package/lib/channels/channel-targets.js +3 -3
  73. package/lib/cli/index.js +27 -3
  74. package/lib/cli/infra-guided.js +5 -1
  75. package/lib/cli/setup-app-external-create.js +111 -0
  76. package/lib/cli/setup-app.help.js +1 -1
  77. package/lib/cli/setup-app.js +38 -125
  78. package/lib/cli/setup-app.test-commands.js +26 -52
  79. package/lib/cli/setup-certification-commands.js +4 -4
  80. package/lib/cli/setup-certification.help.js +9 -9
  81. package/lib/cli/setup-dev.js +7 -2
  82. package/lib/cli/setup-external-system-help.js +4 -6
  83. package/lib/cli/setup-external-system.js +58 -52
  84. package/lib/cli/setup-infra-up-builder-api-action.js +64 -0
  85. package/lib/cli/setup-infra-up-platform-action.js +3 -1
  86. package/lib/cli/setup-infra.js +15 -0
  87. package/lib/cli/setup-list.js +43 -0
  88. package/lib/cli/setup-utility-repair.js +26 -7
  89. package/lib/cli/setup-utility.js +5 -3
  90. package/lib/commands/app.js +15 -43
  91. package/lib/commands/channel-add-setup.js +110 -0
  92. package/lib/commands/channel.js +42 -8
  93. package/lib/commands/datasource-sync-display.js +96 -0
  94. package/lib/commands/datasource-sync-policy.js +210 -0
  95. package/lib/commands/datasource-test-trust-cli.js +6 -6
  96. package/lib/commands/datasource-unified-test-cli.js +2 -1
  97. package/lib/commands/datasource-unified-test-cli.options.js +33 -23
  98. package/lib/commands/deploy-gate-failure-details.js +163 -0
  99. package/lib/commands/deploy-gate-orchestrator.js +322 -0
  100. package/lib/commands/dev-cli-handlers.js +1 -59
  101. package/lib/commands/dev-host-ops-params.js +91 -0
  102. package/lib/commands/dev-host-ops-poll.js +111 -0
  103. package/lib/commands/dev-host-ops.js +107 -94
  104. package/lib/commands/dev-init.js +3 -1
  105. package/lib/commands/enterprise-knowledge.js +284 -0
  106. package/lib/commands/evidence-cli-leaves.js +250 -0
  107. package/lib/commands/evidence.js +51 -0
  108. package/lib/commands/governance-cli-shared.js +2 -2
  109. package/lib/commands/governance-command-action.js +2 -2
  110. package/lib/commands/governance-fixture-subjects.js +85 -0
  111. package/lib/commands/governance.js +1 -1
  112. package/lib/commands/lifecycle-command-action.js +2 -2
  113. package/lib/commands/lifecycle-external.js +3 -3
  114. package/lib/commands/manifest-cli-auth.js +29 -0
  115. package/lib/commands/manifest-cli-commands.js +170 -0
  116. package/lib/commands/manifest-cli-integration-path.js +63 -0
  117. package/lib/commands/manifest.js +21 -0
  118. package/lib/commands/protection-cli-leaves.js +3 -3
  119. package/lib/commands/repair-auth-apply.js +15 -1
  120. package/lib/commands/repair-authentications-454.js +169 -0
  121. package/lib/commands/repair-capability-openapi-warnings.js +126 -0
  122. package/lib/commands/repair-datasource-apply.js +135 -0
  123. package/lib/commands/repair-datasource-auto-rbac.js +62 -1
  124. package/lib/commands/repair-datasource-http-service-contract.js +239 -0
  125. package/lib/commands/repair-datasource-operation-security.js +180 -0
  126. package/lib/commands/repair-datasource-run.js +7 -2
  127. package/lib/commands/repair-datasource-sync-operations.js +177 -0
  128. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +133 -0
  129. package/lib/commands/repair-datasource.js +12 -68
  130. package/lib/commands/repair-env-template.js +11 -1
  131. package/lib/commands/repair-external-run.js +121 -31
  132. package/lib/commands/repair-internal.js +1 -1
  133. package/lib/commands/repair-openapi-export.js +156 -0
  134. package/lib/commands/repair-openapi-sync.js +19 -2
  135. package/lib/commands/repair-orchestration-datasource-split.js +259 -0
  136. package/lib/commands/repair-persist.js +22 -1
  137. package/lib/commands/repair-rbac-platform-preset.js +204 -0
  138. package/lib/commands/repair-rbac-reader-roles.js +191 -0
  139. package/lib/commands/repair-rbac.js +163 -86
  140. package/lib/commands/repair-steps.js +83 -18
  141. package/lib/commands/repair-system-permissions.js +1 -0
  142. package/lib/commands/repair.js +1 -1
  143. package/lib/commands/resource-type.js +65 -26
  144. package/lib/commands/run-post-publish-data-sync.js +68 -0
  145. package/lib/commands/setup-modes.js +1 -1
  146. package/lib/commands/test-e2e-external.js +21 -8
  147. package/lib/commands/test-governance-cli-options.js +2 -2
  148. package/lib/commands/test-trust-cli-options.js +2 -2
  149. package/lib/commands/up-builder-api-bootstrap.js +71 -0
  150. package/lib/commands/up-builder-api-provision.js +241 -0
  151. package/lib/commands/up-builder-api.js +88 -0
  152. package/lib/commands/up-common.js +25 -1
  153. package/lib/commands/upload-credential-push-log.js +117 -0
  154. package/lib/commands/upload-data-sync-finalize.js +60 -0
  155. package/lib/commands/upload-probe.js +66 -0
  156. package/lib/commands/upload-publish-context.js +4 -1
  157. package/lib/commands/upload-sidecar-followups.js +55 -27
  158. package/lib/commands/upload.js +116 -157
  159. package/lib/commands/verify-governance-combined-external.js +1 -1
  160. package/lib/commands/verify-governance-db.js +2 -2
  161. package/lib/commands/verify-operations-command-action.js +2 -2
  162. package/lib/commands/verify-operations-step-plan.js +2 -2
  163. package/lib/commands/verify-operations-steps.js +2 -2
  164. package/lib/commands/verify-trust-command-action.js +1 -1
  165. package/lib/commands/wizard-core.js +1 -1
  166. package/lib/commands/wizard-headless.js +2 -1
  167. package/lib/core/admin-secrets.js +2 -6
  168. package/lib/core/secrets-env-content.js +10 -4
  169. package/lib/core/secrets-env-write.js +2 -13
  170. package/lib/datasource/agent-trust-run.js +3 -3
  171. package/lib/datasource/deploy.js +3 -1
  172. package/lib/datasource/test-e2e.js +6 -1
  173. package/lib/datasource/unified-validation-run-body.js +4 -1
  174. package/lib/datasource/unified-validation-run.js +1 -1
  175. package/lib/deployment/deploy-poll-ui.js +73 -12
  176. package/lib/deployment/deployer-poll-run.js +113 -0
  177. package/lib/deployment/deployer.js +17 -87
  178. package/lib/evidence/dataplane-context.js +21 -0
  179. package/lib/evidence/evidence-display.js +78 -0
  180. package/lib/evidence/evidence-service.js +392 -0
  181. package/lib/external-system/deploy.js +290 -112
  182. package/lib/external-system/download.js +7 -3
  183. package/lib/external-system/test-execution.js +1 -1
  184. package/lib/external-system/test-system-level.js +8 -10
  185. package/lib/external-system/test.js +12 -6
  186. package/lib/generator/deploy-script.js +73 -0
  187. package/lib/generator/external.js +2 -1
  188. package/lib/generator/index.js +17 -2
  189. package/lib/generator/wizard.js +3 -36
  190. package/lib/internal/fs-real-sync.js +22 -1
  191. package/lib/internal/node-fs.js +2 -0
  192. package/lib/lifecycle/lifecycle-governance-options.js +1 -1
  193. package/lib/lifecycle/verify-step-progress.js +1 -1
  194. package/lib/programmatic/access-log.js +26 -0
  195. package/lib/programmatic/auth-config.js +44 -0
  196. package/lib/programmatic/bearer-auth.js +176 -0
  197. package/lib/programmatic/builder-api-request.js +175 -0
  198. package/lib/programmatic/builder-api-route-dispatch.js +82 -0
  199. package/lib/programmatic/builder-api-runtime-config.js +42 -0
  200. package/lib/programmatic/builder-api-server.js +230 -0
  201. package/lib/programmatic/builder-help-authentication-catalog.js +282 -0
  202. package/lib/programmatic/builder-help-connected-system-ui.js +266 -0
  203. package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +60 -0
  204. package/lib/programmatic/builder-help-envelope.js +36 -0
  205. package/lib/programmatic/builder-help-fixtures.js +200 -0
  206. package/lib/programmatic/builder-help-governance.js +172 -0
  207. package/lib/programmatic/builder-help-schema-catalog.js +92 -0
  208. package/lib/programmatic/builder-help.js +361 -0
  209. package/lib/programmatic/capability-registry.js +77 -0
  210. package/lib/programmatic/command-options.js +32 -0
  211. package/lib/programmatic/enterprise-mcp-client.js +98 -0
  212. package/lib/programmatic/http-problem-details.js +99 -0
  213. package/lib/programmatic/http-route-match.js +40 -0
  214. package/lib/programmatic/idempotency-cache.js +69 -0
  215. package/lib/programmatic/index.js +53 -0
  216. package/lib/programmatic/integration-path-scope.js +39 -0
  217. package/lib/programmatic/log-redaction.js +66 -0
  218. package/lib/programmatic/manifest-get-section.js +146 -0
  219. package/lib/programmatic/manifest-patch-section.js +252 -0
  220. package/lib/programmatic/manifest-repair.js +122 -0
  221. package/lib/programmatic/manifest-section-dependency-graph.js +160 -0
  222. package/lib/programmatic/manifest-section-io.js +225 -0
  223. package/lib/programmatic/manifest-section-quality.js +171 -0
  224. package/lib/programmatic/manifest-section-registry-data.js +269 -0
  225. package/lib/programmatic/manifest-section-registry.js +205 -0
  226. package/lib/programmatic/nest-http-bridge.js +34 -0
  227. package/lib/programmatic/openapi-component-schemas.js +68 -0
  228. package/lib/programmatic/openapi-description-enricher.js +117 -0
  229. package/lib/programmatic/openapi-descriptions.js +190 -0
  230. package/lib/programmatic/openapi-docs-serving.js +123 -0
  231. package/lib/programmatic/openapi-help-schemas.js +63 -0
  232. package/lib/programmatic/openapi-manifest-schemas.js +141 -0
  233. package/lib/programmatic/openapi-operation-bindings.js +274 -0
  234. package/lib/programmatic/openapi-request-schemas.js +155 -0
  235. package/lib/programmatic/openapi-result-schemas.js +476 -0
  236. package/lib/programmatic/openapi-schema-descriptions-certify.js +139 -0
  237. package/lib/programmatic/openapi-schema-descriptions-core.js +159 -0
  238. package/lib/programmatic/openapi-schema-descriptions-help.js +40 -0
  239. package/lib/programmatic/openapi-schema-descriptions-manifest.js +143 -0
  240. package/lib/programmatic/openapi-schema-descriptions-mcp.js +118 -0
  241. package/lib/programmatic/openapi-schema-descriptions-operations.js +281 -0
  242. package/lib/programmatic/openapi-schema-helpers.js +93 -0
  243. package/lib/programmatic/openapi-spec.js +203 -0
  244. package/lib/programmatic/orchestration-openapi-meta.js +159 -0
  245. package/lib/programmatic/platform-rbac-catalog.js +90 -0
  246. package/lib/programmatic/request-timeout.js +53 -0
  247. package/lib/programmatic/route-handler-map.js +143 -0
  248. package/lib/programmatic/route-handlers-context.js +29 -0
  249. package/lib/programmatic/route-handlers.js +33 -0
  250. package/lib/programmatic/run-certify.js +57 -0
  251. package/lib/programmatic/run-enterprise-mcp.js +32 -0
  252. package/lib/programmatic/run-lifecycle.js +29 -0
  253. package/lib/programmatic/run-repair.js +41 -0
  254. package/lib/programmatic/run-repository-emcp.js +54 -0
  255. package/lib/programmatic/run-template-workspace.js +61 -0
  256. package/lib/programmatic/run-test.js +49 -0
  257. package/lib/programmatic/run-upload.js +63 -0
  258. package/lib/programmatic/run-validate.js +53 -0
  259. package/lib/programmatic/run-wizard.js +40 -0
  260. package/lib/programmatic/system-key.js +48 -0
  261. package/lib/programmatic/wizard-config-normalize.js +118 -0
  262. package/lib/programmatic/workspace-cleanup.js +128 -0
  263. package/lib/programmatic/workspace-context.js +145 -0
  264. package/lib/programmatic/workspace-lock.js +75 -0
  265. package/lib/programmatic/workspace-meta.js +64 -0
  266. package/lib/programmatic/workspace-ops.js +149 -0
  267. package/lib/protection/run-commands-upload-sync.js +35 -0
  268. package/lib/protection/run-commands.js +2 -20
  269. package/lib/protection/upload-batch.js +11 -7
  270. package/lib/resolvers/resource-type-file.js +22 -0
  271. package/lib/schema/external-datasource.schema.json +161 -1
  272. package/lib/schema/external-system.schema.json +244 -118
  273. package/lib/schema/flag-map-validation-run.json +3 -0
  274. package/lib/schema/type/credential-field-registry.json +2 -2
  275. package/lib/schema/type/document-storage.json +9 -0
  276. package/lib/utils/agent-trust-run-display.js +1 -1
  277. package/lib/utils/app-path-resolve.js +168 -0
  278. package/lib/utils/authentication-env-template.js +222 -0
  279. package/lib/utils/cli-sync-options.js +7 -11
  280. package/lib/utils/cli-utils.js +4 -0
  281. package/lib/utils/cli-workspace-options.js +29 -0
  282. package/lib/utils/compose-generate-docker-compose.js +102 -0
  283. package/lib/utils/configuration-env-resolver.js +203 -27
  284. package/lib/utils/datasource-test-run-certificate-tty.js +28 -2
  285. package/lib/utils/datasource-test-run-certification-debug.js +130 -0
  286. package/lib/utils/datasource-test-run-debug-display.js +2 -0
  287. package/lib/utils/datasource-test-run-debug-slice.js +7 -0
  288. package/lib/utils/datasource-test-run-display.js +2 -1
  289. package/lib/utils/dev-init-ssh-merge.js +165 -23
  290. package/lib/utils/dev-pin-share-instructions.js +110 -0
  291. package/lib/utils/dev-ssh-config-helper.js +177 -33
  292. package/lib/utils/enterprise-knowledge-paths.js +142 -0
  293. package/lib/utils/env-copy.js +2 -1
  294. package/lib/utils/env-dotenv-format.js +103 -0
  295. package/lib/utils/external-env-template.js +4 -1
  296. package/lib/utils/external-system-display.js +5 -1
  297. package/lib/utils/external-system-readiness-compact-blocks.js +221 -0
  298. package/lib/utils/external-system-readiness-compact-display.js +324 -0
  299. package/lib/utils/external-system-readiness-core.js +16 -0
  300. package/lib/utils/external-system-readiness-deploy-display.js +29 -11
  301. package/lib/utils/external-system-readiness-display-internals.js +3 -1
  302. package/lib/utils/external-system-readiness-display.js +20 -30
  303. package/lib/utils/external-system-system-test-tty-certification.js +135 -0
  304. package/lib/utils/external-system-system-test-tty.js +5 -41
  305. package/lib/utils/help-builder.js +6 -1
  306. package/lib/utils/host-ops-job-labels.js +236 -0
  307. package/lib/utils/host-ops-job-result.js +61 -0
  308. package/lib/utils/host-ops-poll-ui.js +163 -0
  309. package/lib/utils/integration-path-resolve.js +112 -0
  310. package/lib/utils/paths-reload-source.js +148 -0
  311. package/lib/utils/paths-system-builder-keys.js +25 -0
  312. package/lib/utils/paths.js +151 -26
  313. package/lib/utils/runtime-configuration-values.js +64 -2
  314. package/lib/utils/secrets-helpers.js +5 -1
  315. package/lib/utils/ssh-known-hosts.js +130 -0
  316. package/lib/utils/test-target-cli-options.js +75 -0
  317. package/lib/utils/upload-sync-options.js +4 -0
  318. package/lib/utils/validation-run-request.js +11 -2
  319. package/lib/validation/external-manifest-validator.js +11 -1
  320. package/lib/validation/openapi-contract-surface-validator.js +426 -0
  321. package/lib/validation/openapi-contract-vendor-validation.js +238 -0
  322. package/lib/validation/validate-external-file.js +160 -0
  323. package/lib/validation/validate.js +6 -117
  324. package/package.json +46 -29
  325. package/packages/builder-api/README.md +120 -0
  326. package/packages/builder-api/package.json +30 -0
  327. package/packages/builder-api/src/app.module.ts +7 -0
  328. package/packages/builder-api/src/auth/auth.module.ts +5 -0
  329. package/packages/builder-api/src/external-system/external-system.module.ts +5 -0
  330. package/packages/builder-api/src/main.ts +16 -0
  331. package/packages/builder-api/tsconfig.json +15 -0
  332. package/scripts/check-builder-api-architecture-grep.js +79 -0
  333. package/scripts/docker_image_content_gate.js +47 -0
  334. package/scripts/docker_image_content_gate.sh +5 -0
  335. package/scripts/export-builder-api-evidence.js +262 -0
  336. package/scripts/lib/builder-api-docker-staging-copy.js +60 -0
  337. package/scripts/lib/builder-api-docker-staging-core.js +183 -0
  338. package/scripts/lib/docker-image-content-gate-core.js +166 -0
  339. package/scripts/lib/plan-actor.js +109 -0
  340. package/scripts/lib/plan-config.js +20 -0
  341. package/scripts/lib/plan-gates.js +154 -0
  342. package/scripts/lib/plan-meta.js +104 -0
  343. package/scripts/lib/plan-parse.js +162 -0
  344. package/scripts/lib/plan-prevalidate-gates.js +326 -0
  345. package/scripts/lib/plan-run-core.js +125 -0
  346. package/scripts/lib/plan-run-report.js +108 -0
  347. package/scripts/plan-approve.js +24 -0
  348. package/scripts/plan-archive.js +49 -0
  349. package/scripts/plan-run.js +13 -0
  350. package/scripts/plan-set-actor.js +21 -0
  351. package/scripts/plan-validate.js +80 -0
  352. package/scripts/pnpm/af.mjs +110 -0
  353. package/scripts/pnpm/check-quiet.mjs +32 -0
  354. package/scripts/pnpm/dev-install.mjs +29 -0
  355. package/scripts/pnpm/dev-reload.mjs +18 -0
  356. package/scripts/pnpm/help.mjs +55 -0
  357. package/scripts/pnpm/lib/dev-reload-core.mjs +189 -0
  358. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +67 -0
  359. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +32 -0
  360. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +124 -0
  361. package/scripts/pnpm/lib/resolve-app-url.mjs +183 -0
  362. package/scripts/pnpm/lib/spinner.mjs +42 -0
  363. package/scripts/stage_builder_api_for_docker.js +65 -0
  364. package/scripts/sync-builder-api-template.js +44 -0
  365. package/templates/README.md +3 -0
  366. package/templates/applications/builder-api/Dockerfile +38 -0
  367. package/templates/applications/builder-api/application.yaml +75 -0
  368. package/templates/applications/builder-api/env.template +48 -0
  369. package/templates/applications/dataplane/application.yaml +1 -1
  370. package/templates/applications/dataplane/env.template +10 -6
  371. package/templates/applications/dataplane/rbac.yaml +21 -1
  372. package/templates/applications/miso-controller/application.yaml +1 -1
  373. package/templates/applications/miso-controller/env.template +1 -3
  374. package/templates/channels/README.md +18 -0
  375. package/templates/channels/ai-fabrix-icon.jpg +0 -0
  376. package/templates/channels/chatgpt/install.template.md.hbs +21 -24
  377. package/templates/channels/chatgpt/integration/README.md +11 -0
  378. package/templates/channels/chatgpt/integration/application.json +15 -0
  379. package/templates/channels/chatgpt/integration/chatgpt-system.json +29 -0
  380. package/templates/channels/chatgpt/integration/env.template +4 -0
  381. package/templates/channels/microsoft-copilot/install.template.md.hbs +20 -25
  382. package/templates/channels/microsoft-copilot/integration/README.md +11 -0
  383. package/templates/channels/microsoft-copilot/integration/application.json +15 -0
  384. package/templates/channels/microsoft-copilot/integration/env.template +6 -0
  385. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +34 -0
  386. package/templates/channels/slack/install.template.md.hbs +48 -18
  387. package/templates/channels/slack/integration/README.md +38 -0
  388. package/templates/channels/slack/integration/application.json +18 -0
  389. package/templates/channels/slack/integration/env.template +29 -0
  390. package/templates/channels/slack/integration/slack-datasource-conversations.json +226 -0
  391. package/templates/channels/slack/integration/slack-datasource-messages.json +269 -0
  392. package/templates/channels/slack/integration/slack-system.json +86 -0
  393. package/templates/channels/slack/manifest.template.json.hbs +20 -10
  394. package/templates/channels/teams-bot/install.template.md.hbs +31 -17
  395. package/templates/channels/teams-bot/integration/README.md +18 -0
  396. package/templates/channels/teams-bot/integration/application.json +17 -0
  397. package/templates/channels/teams-bot/integration/env.template +5 -0
  398. package/templates/channels/teams-bot/integration/teams-bot-system.json +55 -0
  399. package/templates/channels/teams-bot/manifest.template.json.hbs +27 -0
  400. package/templates/channels/web-embed/install.template.md.hbs +16 -26
  401. package/templates/channels/web-embed/integration/README.md +11 -0
  402. package/templates/channels/web-embed/integration/application.json +15 -0
  403. package/templates/channels/web-embed/integration/env.template +4 -0
  404. package/templates/channels/web-embed/integration/web-embed-system.json +29 -0
  405. package/templates/openapi/redoc_page.html +86 -0
  406. package/templates/python/docker-compose.hbs +11 -0
  407. package/templates/python/requirements.txt +1 -1
  408. package/templates/typescript/docker-compose.hbs +11 -0
  409. package/lib/certification/cli-cert-sync-skip.js +0 -21
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Migrate deprecated entityType none + vendor OpenAPI HTTP manifests to serviceContract (439.2).
3
+ *
4
+ * @fileoverview repair-datasource-http-service-contract
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const HTTP_CANONICAL_METADATA_SCHEMA = {
12
+ type: 'object',
13
+ properties: {
14
+ successPayload: {
15
+ type: 'object',
16
+ nullable: true,
17
+ description: 'Normalized success body from upstream HTTP response'
18
+ },
19
+ successMessage: {
20
+ type: 'string',
21
+ nullable: true,
22
+ description: 'Human-readable success message when present'
23
+ },
24
+ errorCode: {
25
+ type: 'string',
26
+ nullable: true,
27
+ description: 'Provider error code when the operation fails'
28
+ },
29
+ errorMessage: {
30
+ type: 'string',
31
+ nullable: true,
32
+ description: 'Human-readable provider error message'
33
+ }
34
+ }
35
+ };
36
+
37
+ const HTTP_CANONICAL_EXPOSED_SCHEMA = {
38
+ success: {
39
+ payload: 'metadata.successPayload',
40
+ message: 'metadata.successMessage'
41
+ },
42
+ error: {
43
+ code: 'metadata.errorCode',
44
+ message: 'metadata.errorMessage'
45
+ }
46
+ };
47
+
48
+ const HTTP_STUB_FIELD_MAPPINGS = {
49
+ successPayload: { expression: '{{raw.data}}' },
50
+ successMessage: { expression: '{{raw.message}}' },
51
+ errorCode: { expression: '{{raw.code}}' },
52
+ errorMessage: { expression: '{{raw.message}}' }
53
+ };
54
+
55
+ /**
56
+ * @param {Object} parsed
57
+ * @returns {boolean}
58
+ */
59
+ function hasVendorOpenapiBinding(parsed) {
60
+ const openapi = parsed?.openapi;
61
+ if (!openapi || typeof openapi !== 'object' || openapi.enabled === false) {
62
+ return false;
63
+ }
64
+ const operations = openapi.operations;
65
+ if (operations && typeof operations === 'object' && Object.keys(operations).length > 0) {
66
+ return true;
67
+ }
68
+ const documentKey =
69
+ typeof openapi.documentKey === 'string' ? openapi.documentKey.trim() : '';
70
+ return Boolean(documentKey) || openapi.enabled === true;
71
+ }
72
+
73
+ /**
74
+ * @param {Object} parsed
75
+ * @returns {boolean}
76
+ */
77
+ function isDeprecatedNoneOpenapiHttpManifest(parsed) {
78
+ if (parsed?.entityType !== 'none') {
79
+ return false;
80
+ }
81
+ if (parsed?.resourceType === 'llm') {
82
+ return false;
83
+ }
84
+ return hasVendorOpenapiBinding(parsed);
85
+ }
86
+
87
+ /**
88
+ * @param {*} value
89
+ * @returns {*}
90
+ */
91
+ function deepClone(value) {
92
+ return JSON.parse(JSON.stringify(value));
93
+ }
94
+
95
+ /**
96
+ * @param {Object} parsed
97
+ * @param {string[]} changes
98
+ * @returns {boolean}
99
+ */
100
+ function ensureHttpCipMapSteps(parsed, changes) {
101
+ const operations = parsed?.execution?.cip?.operations;
102
+ if (!operations || typeof operations !== 'object') {
103
+ return false;
104
+ }
105
+ let updated = false;
106
+ for (const [opKey, op] of Object.entries(operations)) {
107
+ if (!op || !Array.isArray(op.steps)) {
108
+ continue;
109
+ }
110
+ if (op.steps.some((step) => step && step.map)) {
111
+ continue;
112
+ }
113
+ const fetchIdx = op.steps.findIndex((step) => step && step.fetch);
114
+ if (fetchIdx < 0) {
115
+ continue;
116
+ }
117
+ op.steps.splice(fetchIdx + 1, 0, {
118
+ map: { useFieldMappings: true, inputPath: '$' }
119
+ });
120
+ if (!op.steps.some((step) => step && step.output)) {
121
+ op.steps.push({ output: { mode: 'records' } });
122
+ }
123
+ changes.push(`Inserted map+output steps for CIP operation "${opKey}"`);
124
+ updated = true;
125
+ }
126
+ return updated;
127
+ }
128
+
129
+ /**
130
+ * @param {Object} parsed
131
+ * @param {string[]} changes
132
+ */
133
+ function ensureHttpFieldMappings(parsed, changes) {
134
+ if (!parsed.fieldMappings) {
135
+ parsed.fieldMappings = {};
136
+ }
137
+ const attrs = parsed.fieldMappings.attributes;
138
+ if (!attrs || typeof attrs !== 'object' || Object.keys(attrs).length === 0) {
139
+ parsed.fieldMappings.attributes = deepClone(HTTP_STUB_FIELD_MAPPINGS);
140
+ changes.push(
141
+ 'Added stub fieldMappings.attributes — customize {{raw.*}} per operation'
142
+ );
143
+ }
144
+ }
145
+
146
+ /**
147
+ * @param {Object} parsed
148
+ * @param {string[]} changes
149
+ */
150
+ function ensureHttpExposedEnvelope(parsed, changes) {
151
+ if (!parsed.exposed) {
152
+ parsed.exposed = {};
153
+ }
154
+ if (!parsed.exposed.schema || typeof parsed.exposed.schema !== 'object') {
155
+ parsed.exposed.schema = deepClone(HTTP_CANONICAL_EXPOSED_SCHEMA);
156
+ changes.push('Set HTTP serviceContract exposed.schema envelope');
157
+ }
158
+ if (parsed.exposed.attributes !== undefined) {
159
+ delete parsed.exposed.attributes;
160
+ }
161
+ if (!parsed.exposed.profiles || typeof parsed.exposed.profiles !== 'object') {
162
+ parsed.exposed.profiles = { default: ['success', 'error'] };
163
+ changes.push('Set exposed.profiles default envelope');
164
+ }
165
+ }
166
+
167
+ /**
168
+ * @param {Object} parsed
169
+ * @param {string[]} changes
170
+ * @returns {boolean}
171
+ */
172
+ function applyHttpServiceContractStubs(parsed, changes) {
173
+ parsed.entityType = 'serviceContract';
174
+ changes.push('Migrated entityType none → serviceContract (HTTP/OpenAPI facade)');
175
+
176
+ parsed.metadataSchema = deepClone(HTTP_CANONICAL_METADATA_SCHEMA);
177
+ changes.push('Set HTTP serviceContract metadataSchema stub');
178
+
179
+ ensureHttpFieldMappings(parsed, changes);
180
+ ensureHttpExposedEnvelope(parsed, changes);
181
+ return true;
182
+ }
183
+
184
+ /**
185
+ * @param {Object} parsed
186
+ * @param {string[]} changes
187
+ * @returns {boolean}
188
+ */
189
+ function repairNoneOpenapiHttpToServiceContract(parsed, changes) {
190
+ if (!isDeprecatedNoneOpenapiHttpManifest(parsed)) {
191
+ return false;
192
+ }
193
+ let updated = applyHttpServiceContractStubs(parsed, changes);
194
+ updated = ensureHttpCipMapSteps(parsed, changes) || updated;
195
+ updated = normalizeCipOpenapiRefs(parsed, changes) || updated;
196
+ return updated;
197
+ }
198
+
199
+ /**
200
+ * Align fetch.openapiRef with execution.cip.operations keys (manifest SSOT).
201
+ *
202
+ * @param {Object} parsed
203
+ * @param {string[]} changes
204
+ * @returns {boolean}
205
+ */
206
+ function normalizeCipOpenapiRefs(parsed, changes) {
207
+ const operations = parsed?.execution?.cip?.operations;
208
+ if (!operations || typeof operations !== 'object') {
209
+ return false;
210
+ }
211
+ let updated = false;
212
+ for (const [opKey, op] of Object.entries(operations)) {
213
+ if (!op || !Array.isArray(op.steps)) {
214
+ continue;
215
+ }
216
+ for (const step of op.steps) {
217
+ const fetch = step?.fetch;
218
+ if (!fetch || fetch.source !== 'openapi') {
219
+ continue;
220
+ }
221
+ if (fetch.openapiRef !== opKey) {
222
+ fetch.openapiRef = opKey;
223
+ changes.push(
224
+ `Normalized fetch.openapiRef → "${opKey}" for CIP operation "${opKey}"`
225
+ );
226
+ updated = true;
227
+ }
228
+ }
229
+ }
230
+ return updated;
231
+ }
232
+
233
+ module.exports = {
234
+ HTTP_CANONICAL_METADATA_SCHEMA,
235
+ HTTP_CANONICAL_EXPOSED_SCHEMA,
236
+ isDeprecatedNoneOpenapiHttpManifest,
237
+ normalizeCipOpenapiRefs,
238
+ repairNoneOpenapiHttpToServiceContract
239
+ };
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Bind openapi.operations.*.security from rbac permissions for COM publish.
3
+ *
4
+ * @fileoverview repair-datasource-operation-security
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
14
+ const { backupIntegrationFile } = require('../utils/integration-file-backup');
15
+ const { trackRepairWrite } = require('./repair-changed-files');
16
+ const { resolveRbacPath } = require('../utils/app-config-resolver');
17
+
18
+ /**
19
+ * @param {Object} rbac
20
+ * @returns {Map<string, string[]>}
21
+ */
22
+ function permissionRoleIndex(rbac) {
23
+ const index = new Map();
24
+ const perms = rbac && Array.isArray(rbac.permissions) ? rbac.permissions : [];
25
+ for (const perm of perms) {
26
+ if (!perm || typeof perm !== 'object') continue;
27
+ const name = typeof perm.name === 'string' ? perm.name.trim() : '';
28
+ if (!name) continue;
29
+ const roles = Array.isArray(perm.roles)
30
+ ? perm.roles.filter((r) => typeof r === 'string' && r.trim())
31
+ : [];
32
+ if (roles.length) index.set(name, roles);
33
+ }
34
+ return index;
35
+ }
36
+
37
+ /**
38
+ * @param {Map<string, string[]>} permIndex
39
+ * @param {string} resourceType
40
+ * @param {string} opKey
41
+ * @returns {Object[]|null}
42
+ */
43
+ function expectedSecurityForOperation(permIndex, resourceType, opKey) {
44
+ const permName = `${resourceType}:${opKey}`;
45
+ const roles = permIndex.get(permName) || permIndex.get(permName.toLowerCase());
46
+ if (!roles || roles.length === 0) {
47
+ return null;
48
+ }
49
+ return roles.map((role) => ({ oauth2: [role] }));
50
+ }
51
+
52
+ /**
53
+ * @param {Object} opCfg
54
+ * @param {Object[]} expectedSecurity
55
+ * @returns {boolean}
56
+ */
57
+ function applyOperationSecurity(opCfg, expectedSecurity) {
58
+ if (JSON.stringify(opCfg.security) === JSON.stringify(expectedSecurity)) {
59
+ return false;
60
+ }
61
+ opCfg.security = expectedSecurity;
62
+ return true;
63
+ }
64
+
65
+ /**
66
+ * @param {Object} parsed
67
+ * @returns {{ ops: Object, resourceType: string }|null}
68
+ */
69
+ function openApiOpsForSecurityBind(parsed) {
70
+ const openapi = parsed && parsed.openapi;
71
+ if (!openapi || typeof openapi !== 'object' || openapi.autoRbac !== true) {
72
+ return null;
73
+ }
74
+ const ops = openapi.operations;
75
+ if (!ops || typeof ops !== 'object' || Array.isArray(ops)) {
76
+ return null;
77
+ }
78
+ const resourceType = (typeof parsed.resourceType === 'string' && parsed.resourceType.trim()) || 'document';
79
+ return { ops, resourceType };
80
+ }
81
+
82
+ /**
83
+ * @param {Object} parsed
84
+ * @param {Map<string, string[]>} permIndex
85
+ * @param {string[]} changes
86
+ * @param {string} fileName
87
+ * @returns {boolean}
88
+ */
89
+ function bindSecurityOnDatasource(parsed, permIndex, changes, fileName) {
90
+ const bindCtx = openApiOpsForSecurityBind(parsed);
91
+ if (!bindCtx) {
92
+ return false;
93
+ }
94
+ const { ops, resourceType } = bindCtx;
95
+ let updated = false;
96
+ for (const [opKey, opCfg] of Object.entries(ops)) {
97
+ if (!opCfg || typeof opCfg !== 'object') {
98
+ continue;
99
+ }
100
+ const expectedSecurity = expectedSecurityForOperation(permIndex, resourceType, opKey);
101
+ if (!expectedSecurity) {
102
+ continue;
103
+ }
104
+ updated = applyOperationSecurity(opCfg, expectedSecurity) || updated;
105
+ }
106
+ if (updated) {
107
+ changes.push(`${fileName}: Bound openapi.operations.*.security from rbac permissions`);
108
+ }
109
+ return updated;
110
+ }
111
+
112
+ /**
113
+ * @param {string} appPath
114
+ * @returns {Map<string, string[]>|null}
115
+ */
116
+ function loadRbacPermissionIndex(appPath) {
117
+ const rbacPath = resolveRbacPath(appPath);
118
+ if (!rbacPath || !fs.existsSync(rbacPath)) {
119
+ return null;
120
+ }
121
+ try {
122
+ return permissionRoleIndex(loadConfigFile(rbacPath));
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * @param {Object} opts
130
+ * @returns {boolean}
131
+ */
132
+ function bindSecurityOnDatasourceFile(opts) {
133
+ const { appPath, fileName, permIndex, dryRun, changes, backupCtx } = opts;
134
+ const filePath = path.join(appPath, fileName);
135
+ if (!fs.existsSync(filePath)) {
136
+ return false;
137
+ }
138
+ let parsed;
139
+ try {
140
+ parsed = loadConfigFile(filePath);
141
+ } catch {
142
+ return false;
143
+ }
144
+ const fileUpdated = bindSecurityOnDatasource(parsed, permIndex, changes, fileName);
145
+ if (!fileUpdated || dryRun) {
146
+ return fileUpdated;
147
+ }
148
+ backupIntegrationFile(filePath, backupCtx);
149
+ writeConfigFile(filePath, parsed);
150
+ trackRepairWrite(filePath, backupCtx);
151
+ return true;
152
+ }
153
+
154
+ /**
155
+ * @param {string} appPath
156
+ * @param {string[]} datasourceFiles
157
+ * @param {boolean} dryRun
158
+ * @param {string[]} changes
159
+ * @param {Object} backupCtx
160
+ * @returns {boolean}
161
+ */
162
+ function bindOpenApiOperationSecurityFromRbac(appPath, datasourceFiles, dryRun, changes, backupCtx) {
163
+ const permIndex = loadRbacPermissionIndex(appPath);
164
+ if (!permIndex || permIndex.size === 0) {
165
+ return false;
166
+ }
167
+
168
+ let anyUpdated = false;
169
+ for (const fileName of datasourceFiles || []) {
170
+ anyUpdated =
171
+ bindSecurityOnDatasourceFile({ appPath, fileName, permIndex, dryRun, changes, backupCtx }) ||
172
+ anyUpdated;
173
+ }
174
+ return anyUpdated;
175
+ }
176
+
177
+ module.exports = {
178
+ bindOpenApiOperationSecurityFromRbac,
179
+ permissionRoleIndex
180
+ };
@@ -23,11 +23,13 @@ const { repairDatasourceFile } = require('./repair-datasource');
23
23
  * @param {Object} options
24
24
  * @param {boolean} dryRun
25
25
  * @param {string[]} changes
26
+ * @param {Object} [context]
26
27
  * @returns {boolean}
27
28
  */
28
- function runDatasourceRepairs(appPath, datasourceFiles, options, dryRun, changes) {
29
+ function runDatasourceRepairs(appPath, datasourceFiles, options, dryRun, changes, context = {}) {
29
30
  if (!datasourceFiles || datasourceFiles.length === 0) return false;
30
31
  let updated = false;
32
+ const warnings = Array.isArray(context.warnings) ? context.warnings : [];
31
33
  for (const fileName of datasourceFiles) {
32
34
  const filePath = path.join(appPath, fileName);
33
35
  if (!fs.existsSync(filePath)) continue;
@@ -36,7 +38,10 @@ function runDatasourceRepairs(appPath, datasourceFiles, options, dryRun, changes
36
38
  const { updated: fileUpdated, changes: fileChanges } = repairDatasourceFile(parsed, {
37
39
  expose: options.expose,
38
40
  sync: options.sync,
39
- test: options.test
41
+ test: options.test,
42
+ operations: options.operations,
43
+ systemParsed: context.systemParsed,
44
+ warnings
40
45
  });
41
46
  if (fileUpdated) {
42
47
  updated = true;
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Sync capabilities[] → openapi.operations → execution.cip.operations (plan 154.7).
3
+ *
4
+ * @fileoverview repair-datasource-sync-operations
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { listCapabilityKeys } = require('../datasource/capability/capability-manifest');
12
+
13
+ const MANIFEST_KEY_PATTERN = /^[a-z][a-zA-Z0-9]*$/;
14
+
15
+ /**
16
+ * @param {string} key
17
+ * @returns {boolean}
18
+ */
19
+ function isManifestOperationKey(key) {
20
+ return typeof key === 'string' && MANIFEST_KEY_PATTERN.test(key.trim());
21
+ }
22
+
23
+ /**
24
+ * @param {unknown} capabilities
25
+ * @returns {string[]}
26
+ */
27
+ function capabilityKeysFromManifest(capabilities) {
28
+ return listCapabilityKeys(capabilities).filter(isManifestOperationKey);
29
+ }
30
+
31
+ /**
32
+ * @param {Object} parsed
33
+ * @param {string} key
34
+ * @returns {Object|undefined}
35
+ */
36
+ function openapiOperationEntry(parsed, key) {
37
+ const ops = parsed?.openapi?.operations;
38
+ if (!ops || typeof ops !== 'object') {
39
+ return undefined;
40
+ }
41
+ const entry = ops[key];
42
+ return entry && typeof entry === 'object' ? entry : undefined;
43
+ }
44
+
45
+ /**
46
+ * @param {Object} parsed
47
+ * @param {string} key
48
+ * @returns {Object|undefined}
49
+ */
50
+ function cipOperationEntry(parsed, key) {
51
+ const ops = parsed?.execution?.cip?.operations;
52
+ if (!ops || typeof ops !== 'object') {
53
+ return undefined;
54
+ }
55
+ const entry = ops[key];
56
+ return entry && typeof entry === 'object' ? entry : undefined;
57
+ }
58
+
59
+ /**
60
+ * @param {string} key
61
+ * @param {Object|undefined} openapiEntry
62
+ * @returns {Object}
63
+ */
64
+ function buildOpenapiOperationStub(key, openapiEntry) {
65
+ if (openapiEntry && typeof openapiEntry.operationId === 'string' && openapiEntry.operationId.trim()) {
66
+ return { operationId: openapiEntry.operationId.trim() };
67
+ }
68
+ return { operationId: key };
69
+ }
70
+
71
+ /**
72
+ * @param {string} key
73
+ * @param {Object|undefined} openapiEntry
74
+ * @returns {Object}
75
+ */
76
+ function buildCipOperationStub(key, openapiEntry) {
77
+ const description =
78
+ (openapiEntry && typeof openapiEntry.summary === 'string' && openapiEntry.summary.trim()) ||
79
+ `Execute ${key} via OpenAPI passthrough`;
80
+ return {
81
+ enabled: true,
82
+ description,
83
+ steps: [
84
+ {
85
+ fetch: {
86
+ source: 'openapi',
87
+ openapiRef: key,
88
+ query: {}
89
+ }
90
+ },
91
+ { output: { mode: 'records' } }
92
+ ]
93
+ };
94
+ }
95
+
96
+ /**
97
+ * @param {Object} parsed
98
+ * @returns {void}
99
+ */
100
+ function ensureSyncOperationScaffold(parsed) {
101
+ if (!parsed.openapi || typeof parsed.openapi !== 'object') {
102
+ parsed.openapi = {};
103
+ }
104
+ if (!parsed.openapi.operations || typeof parsed.openapi.operations !== 'object') {
105
+ parsed.openapi.operations = {};
106
+ }
107
+ if (!parsed.execution || typeof parsed.execution !== 'object') {
108
+ parsed.execution = { engine: 'cip' };
109
+ }
110
+ if (!parsed.execution.cip || typeof parsed.execution.cip !== 'object') {
111
+ parsed.execution.cip = { operations: {} };
112
+ }
113
+ if (!parsed.execution.cip.operations || typeof parsed.execution.cip.operations !== 'object') {
114
+ parsed.execution.cip.operations = {};
115
+ }
116
+ }
117
+
118
+ /**
119
+ * @param {Object} parsed
120
+ * @param {string} key
121
+ * @param {string[]} changes
122
+ * @returns {boolean}
123
+ */
124
+ function syncCapabilityOperationKey(parsed, key, changes) {
125
+ let updated = false;
126
+ const openapiEntry = openapiOperationEntry(parsed, key);
127
+ if (!openapiEntry) {
128
+ parsed.openapi.operations[key] = buildOpenapiOperationStub(key, openapiEntry);
129
+ changes.push(`Added openapi.operations.${key}`);
130
+ updated = true;
131
+ } else if (!openapiEntry.operationId) {
132
+ parsed.openapi.operations[key] = buildOpenapiOperationStub(key, openapiEntry);
133
+ changes.push(`Set openapi.operations.${key}.operationId`);
134
+ updated = true;
135
+ }
136
+
137
+ if (!cipOperationEntry(parsed, key)) {
138
+ parsed.execution.cip.operations[key] = buildCipOperationStub(key, parsed.openapi.operations[key]);
139
+ changes.push(`Added execution.cip.operations.${key}`);
140
+ updated = true;
141
+ }
142
+ return updated;
143
+ }
144
+
145
+ /**
146
+ * Ensure openapi.operations and execution.cip.operations mirror capabilities[] keys.
147
+ *
148
+ * @param {Object} parsed - Parsed datasource (mutated)
149
+ * @param {string[]} changes - Change log
150
+ * @returns {boolean}
151
+ */
152
+ function repairSyncOperationsFromCapabilities(parsed, changes) {
153
+ const keys = capabilityKeysFromManifest(parsed?.capabilities);
154
+ if (keys.length === 0) {
155
+ return false;
156
+ }
157
+
158
+ ensureSyncOperationScaffold(parsed);
159
+
160
+ let updated = false;
161
+ for (const key of keys) {
162
+ updated = syncCapabilityOperationKey(parsed, key, changes) || updated;
163
+ }
164
+
165
+ if (updated && parsed.openapi.enabled !== true) {
166
+ parsed.openapi.enabled = true;
167
+ changes.push('Set openapi.enabled=true (capabilities synced)');
168
+ }
169
+
170
+ return updated;
171
+ }
172
+
173
+ module.exports = {
174
+ repairSyncOperationsFromCapabilities,
175
+ capabilityKeysFromManifest,
176
+ isManifestOperationKey
177
+ };