@aifabrix/builder 2.49.1 → 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 (413) hide show
  1. package/.cursor/process/README.md +9 -0
  2. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +49 -0
  3. package/.cursor/rules/plan-rules/application-lifecycle.mdc +30 -0
  4. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +35 -0
  5. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +31 -0
  6. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +34 -0
  7. package/.cursor/skills/README.md +1 -0
  8. package/.dockerignore +52 -0
  9. package/.eslintignore +22 -0
  10. package/README.md +2 -0
  11. package/bin/builder-api-cleanup.js +26 -0
  12. package/bin/builder-api-nest.js +10 -0
  13. package/bin/builder-api-spike.js +19 -0
  14. package/enterprise-knowledge/README.md +50 -0
  15. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +22 -0
  16. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +15 -0
  17. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +69 -0
  18. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +52 -0
  19. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +29 -0
  20. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +2 -0
  21. package/integration/README.md +81 -0
  22. package/integration/github/README.md +53 -0
  23. package/integration/github/application.json +21 -0
  24. package/integration/github/deploy.js +72 -0
  25. package/integration/github/env.template +11 -0
  26. package/integration/github/github-datasource-issue-comments.json +239 -0
  27. package/integration/github/github-datasource-issues.json +399 -0
  28. package/integration/github/github-datasource-repository.json +354 -0
  29. package/integration/github/github-deploy.json +1202 -0
  30. package/integration/github/github-system.json +82 -0
  31. package/integration/hubspot-test/README.md +1 -1
  32. package/jest.isolated-projects.js +31 -1
  33. package/jest.projects.js +87 -1
  34. package/lib/api/dev-server-https.js +1 -1
  35. package/lib/api/dev.api.js +1 -0
  36. package/lib/api/enterprise-knowledge.api.js +63 -0
  37. package/lib/api/evidence.api.js +172 -0
  38. package/lib/api/external-systems.api.js +8 -2
  39. package/lib/api/host-ops.api.js +69 -0
  40. package/lib/api/resource-types.api.js +1 -0
  41. package/lib/api/types/enterprise-knowledge.types.js +46 -0
  42. package/lib/api/types/evidence.types.js +67 -0
  43. package/lib/api/types/resource-types.types.js +2 -0
  44. package/lib/app/controller-application-filter.js +36 -0
  45. package/lib/app/deploy.js +1 -1
  46. package/lib/app/list-external-systems.js +130 -0
  47. package/lib/app/list.js +20 -8
  48. package/lib/app/run.js +3 -1
  49. package/lib/app/show-display.js +8 -3
  50. package/lib/app/show-online.js +178 -0
  51. package/lib/app/show.js +37 -88
  52. package/lib/build/builder-api-docker-staging.js +47 -0
  53. package/lib/build/miso-controller-npm-sdk-guard.js +2 -2
  54. package/lib/build/standard-docker-build.js +2 -0
  55. package/lib/certification/post-unified-cert-sync.js +4 -31
  56. package/lib/certification/sync-after-external-command.js +0 -1
  57. package/lib/certification/sync-system-certification.js +0 -3
  58. package/lib/channels/add-channel.js +40 -34
  59. package/lib/channels/approval-guides/chatgpt.js +33 -0
  60. package/lib/channels/approval-guides/credential-portal.js +38 -0
  61. package/lib/channels/approval-guides/index.js +110 -0
  62. package/lib/channels/approval-guides/microsoft-copilot.js +34 -0
  63. package/lib/channels/approval-guides/slack.js +34 -0
  64. package/lib/channels/approval-guides/teams-bot.js +35 -0
  65. package/lib/channels/approval-guides/web-embed.js +32 -0
  66. package/lib/channels/channel-approval-guide.js +11 -0
  67. package/lib/channels/channel-artifact-generator.js +16 -4
  68. package/lib/channels/channel-audit.js +3 -0
  69. package/lib/channels/channel-auth-context.js +1 -1
  70. package/lib/channels/channel-description.js +59 -0
  71. package/lib/channels/channel-integration-generator.js +13 -230
  72. package/lib/channels/channel-integration-template.js +94 -0
  73. package/lib/channels/channel-runtime-resolver.js +43 -3
  74. package/lib/channels/channel-status-display.js +66 -26
  75. package/lib/channels/channel-targets.js +3 -3
  76. package/lib/cli/index.js +27 -3
  77. package/lib/cli/infra-guided.js +5 -1
  78. package/lib/cli/setup-app-external-create.js +111 -0
  79. package/lib/cli/setup-app.help.js +1 -1
  80. package/lib/cli/setup-app.js +38 -125
  81. package/lib/cli/setup-app.test-commands.js +26 -52
  82. package/lib/cli/setup-certification-commands.js +4 -4
  83. package/lib/cli/setup-certification.help.js +9 -9
  84. package/lib/cli/setup-dev-path-commands.js +24 -0
  85. package/lib/cli/setup-dev.js +115 -16
  86. package/lib/cli/setup-external-system-help.js +4 -6
  87. package/lib/cli/setup-external-system.js +58 -52
  88. package/lib/cli/setup-infra-up-builder-api-action.js +64 -0
  89. package/lib/cli/setup-infra-up-platform-action.js +3 -1
  90. package/lib/cli/setup-infra.js +15 -0
  91. package/lib/cli/setup-list.js +43 -0
  92. package/lib/cli/setup-utility-repair.js +26 -7
  93. package/lib/cli/setup-utility.js +5 -3
  94. package/lib/commands/app.js +15 -43
  95. package/lib/commands/channel-add-setup.js +110 -0
  96. package/lib/commands/channel.js +42 -8
  97. package/lib/commands/datasource-sync-display.js +96 -0
  98. package/lib/commands/datasource-sync-policy.js +210 -0
  99. package/lib/commands/datasource-test-trust-cli.js +6 -6
  100. package/lib/commands/datasource-unified-test-cli.js +2 -1
  101. package/lib/commands/datasource-unified-test-cli.options.js +33 -23
  102. package/lib/commands/deploy-gate-failure-details.js +163 -0
  103. package/lib/commands/deploy-gate-orchestrator.js +322 -0
  104. package/lib/commands/dev-cli-handlers.js +64 -61
  105. package/lib/commands/dev-host-ops-params.js +91 -0
  106. package/lib/commands/dev-host-ops-poll.js +111 -0
  107. package/lib/commands/dev-host-ops.js +252 -0
  108. package/lib/commands/dev-init.js +3 -1
  109. package/lib/commands/enterprise-knowledge.js +284 -0
  110. package/lib/commands/evidence-cli-leaves.js +250 -0
  111. package/lib/commands/evidence.js +51 -0
  112. package/lib/commands/governance-cli-shared.js +2 -2
  113. package/lib/commands/governance-command-action.js +2 -2
  114. package/lib/commands/governance-fixture-subjects.js +85 -0
  115. package/lib/commands/governance.js +1 -1
  116. package/lib/commands/lifecycle-command-action.js +2 -2
  117. package/lib/commands/lifecycle-external.js +3 -3
  118. package/lib/commands/manifest-cli-auth.js +29 -0
  119. package/lib/commands/manifest-cli-commands.js +170 -0
  120. package/lib/commands/manifest-cli-integration-path.js +63 -0
  121. package/lib/commands/manifest.js +21 -0
  122. package/lib/commands/protection-cli-leaves.js +3 -3
  123. package/lib/commands/repair-auth-apply.js +15 -1
  124. package/lib/commands/repair-authentications-454.js +169 -0
  125. package/lib/commands/repair-capability-openapi-warnings.js +126 -0
  126. package/lib/commands/repair-datasource-apply.js +135 -0
  127. package/lib/commands/repair-datasource-auto-rbac.js +62 -1
  128. package/lib/commands/repair-datasource-http-service-contract.js +239 -0
  129. package/lib/commands/repair-datasource-operation-security.js +180 -0
  130. package/lib/commands/repair-datasource-run.js +7 -2
  131. package/lib/commands/repair-datasource-sync-operations.js +177 -0
  132. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +133 -0
  133. package/lib/commands/repair-datasource.js +12 -68
  134. package/lib/commands/repair-env-template.js +11 -1
  135. package/lib/commands/repair-external-run.js +121 -31
  136. package/lib/commands/repair-internal.js +1 -1
  137. package/lib/commands/repair-openapi-export.js +156 -0
  138. package/lib/commands/repair-openapi-sync.js +19 -2
  139. package/lib/commands/repair-orchestration-datasource-split.js +259 -0
  140. package/lib/commands/repair-persist.js +22 -1
  141. package/lib/commands/repair-rbac-platform-preset.js +204 -0
  142. package/lib/commands/repair-rbac-reader-roles.js +191 -0
  143. package/lib/commands/repair-rbac.js +163 -86
  144. package/lib/commands/repair-steps.js +83 -18
  145. package/lib/commands/repair-system-permissions.js +1 -0
  146. package/lib/commands/repair.js +1 -1
  147. package/lib/commands/resource-type.js +65 -26
  148. package/lib/commands/run-post-publish-data-sync.js +68 -0
  149. package/lib/commands/setup-modes.js +1 -1
  150. package/lib/commands/test-e2e-external.js +21 -8
  151. package/lib/commands/test-governance-cli-options.js +2 -2
  152. package/lib/commands/test-trust-cli-options.js +2 -2
  153. package/lib/commands/up-builder-api-bootstrap.js +71 -0
  154. package/lib/commands/up-builder-api-provision.js +241 -0
  155. package/lib/commands/up-builder-api.js +88 -0
  156. package/lib/commands/up-common.js +25 -1
  157. package/lib/commands/upload-credential-push-log.js +117 -0
  158. package/lib/commands/upload-data-sync-finalize.js +60 -0
  159. package/lib/commands/upload-probe.js +66 -0
  160. package/lib/commands/upload-publish-context.js +4 -1
  161. package/lib/commands/upload-sidecar-followups.js +55 -27
  162. package/lib/commands/upload.js +116 -157
  163. package/lib/commands/verify-governance-combined-external.js +1 -1
  164. package/lib/commands/verify-governance-db.js +2 -2
  165. package/lib/commands/verify-operations-command-action.js +2 -2
  166. package/lib/commands/verify-operations-step-plan.js +2 -2
  167. package/lib/commands/verify-operations-steps.js +2 -2
  168. package/lib/commands/verify-trust-command-action.js +1 -1
  169. package/lib/commands/wizard-core.js +1 -1
  170. package/lib/commands/wizard-headless.js +2 -1
  171. package/lib/core/admin-secrets.js +2 -6
  172. package/lib/core/secrets-env-content.js +10 -4
  173. package/lib/core/secrets-env-write.js +2 -13
  174. package/lib/datasource/agent-trust-run.js +3 -3
  175. package/lib/datasource/deploy.js +3 -1
  176. package/lib/datasource/test-e2e.js +6 -1
  177. package/lib/datasource/unified-validation-run-body.js +4 -1
  178. package/lib/datasource/unified-validation-run.js +1 -1
  179. package/lib/deployment/deploy-poll-ui.js +73 -12
  180. package/lib/deployment/deployer-poll-run.js +113 -0
  181. package/lib/deployment/deployer.js +17 -87
  182. package/lib/evidence/dataplane-context.js +21 -0
  183. package/lib/evidence/evidence-display.js +78 -0
  184. package/lib/evidence/evidence-service.js +392 -0
  185. package/lib/external-system/deploy.js +290 -112
  186. package/lib/external-system/download.js +7 -3
  187. package/lib/external-system/test-execution.js +1 -1
  188. package/lib/external-system/test-system-level.js +8 -10
  189. package/lib/external-system/test.js +12 -6
  190. package/lib/generator/deploy-script.js +73 -0
  191. package/lib/generator/external.js +2 -1
  192. package/lib/generator/index.js +17 -2
  193. package/lib/generator/wizard.js +3 -36
  194. package/lib/internal/fs-real-sync.js +22 -1
  195. package/lib/internal/node-fs.js +2 -0
  196. package/lib/lifecycle/lifecycle-governance-options.js +1 -1
  197. package/lib/lifecycle/verify-step-progress.js +1 -1
  198. package/lib/programmatic/access-log.js +26 -0
  199. package/lib/programmatic/auth-config.js +44 -0
  200. package/lib/programmatic/bearer-auth.js +176 -0
  201. package/lib/programmatic/builder-api-request.js +175 -0
  202. package/lib/programmatic/builder-api-route-dispatch.js +82 -0
  203. package/lib/programmatic/builder-api-runtime-config.js +42 -0
  204. package/lib/programmatic/builder-api-server.js +230 -0
  205. package/lib/programmatic/builder-help-authentication-catalog.js +282 -0
  206. package/lib/programmatic/builder-help-connected-system-ui.js +266 -0
  207. package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +60 -0
  208. package/lib/programmatic/builder-help-envelope.js +36 -0
  209. package/lib/programmatic/builder-help-fixtures.js +200 -0
  210. package/lib/programmatic/builder-help-governance.js +172 -0
  211. package/lib/programmatic/builder-help-schema-catalog.js +92 -0
  212. package/lib/programmatic/builder-help.js +361 -0
  213. package/lib/programmatic/capability-registry.js +77 -0
  214. package/lib/programmatic/command-options.js +32 -0
  215. package/lib/programmatic/enterprise-mcp-client.js +98 -0
  216. package/lib/programmatic/http-problem-details.js +99 -0
  217. package/lib/programmatic/http-route-match.js +40 -0
  218. package/lib/programmatic/idempotency-cache.js +69 -0
  219. package/lib/programmatic/index.js +53 -0
  220. package/lib/programmatic/integration-path-scope.js +39 -0
  221. package/lib/programmatic/log-redaction.js +66 -0
  222. package/lib/programmatic/manifest-get-section.js +146 -0
  223. package/lib/programmatic/manifest-patch-section.js +252 -0
  224. package/lib/programmatic/manifest-repair.js +122 -0
  225. package/lib/programmatic/manifest-section-dependency-graph.js +160 -0
  226. package/lib/programmatic/manifest-section-io.js +225 -0
  227. package/lib/programmatic/manifest-section-quality.js +171 -0
  228. package/lib/programmatic/manifest-section-registry-data.js +269 -0
  229. package/lib/programmatic/manifest-section-registry.js +205 -0
  230. package/lib/programmatic/nest-http-bridge.js +34 -0
  231. package/lib/programmatic/openapi-component-schemas.js +68 -0
  232. package/lib/programmatic/openapi-description-enricher.js +117 -0
  233. package/lib/programmatic/openapi-descriptions.js +190 -0
  234. package/lib/programmatic/openapi-docs-serving.js +123 -0
  235. package/lib/programmatic/openapi-help-schemas.js +63 -0
  236. package/lib/programmatic/openapi-manifest-schemas.js +141 -0
  237. package/lib/programmatic/openapi-operation-bindings.js +274 -0
  238. package/lib/programmatic/openapi-request-schemas.js +155 -0
  239. package/lib/programmatic/openapi-result-schemas.js +476 -0
  240. package/lib/programmatic/openapi-schema-descriptions-certify.js +139 -0
  241. package/lib/programmatic/openapi-schema-descriptions-core.js +159 -0
  242. package/lib/programmatic/openapi-schema-descriptions-help.js +40 -0
  243. package/lib/programmatic/openapi-schema-descriptions-manifest.js +143 -0
  244. package/lib/programmatic/openapi-schema-descriptions-mcp.js +118 -0
  245. package/lib/programmatic/openapi-schema-descriptions-operations.js +281 -0
  246. package/lib/programmatic/openapi-schema-helpers.js +93 -0
  247. package/lib/programmatic/openapi-spec.js +203 -0
  248. package/lib/programmatic/orchestration-openapi-meta.js +159 -0
  249. package/lib/programmatic/platform-rbac-catalog.js +90 -0
  250. package/lib/programmatic/request-timeout.js +53 -0
  251. package/lib/programmatic/route-handler-map.js +143 -0
  252. package/lib/programmatic/route-handlers-context.js +29 -0
  253. package/lib/programmatic/route-handlers.js +33 -0
  254. package/lib/programmatic/run-certify.js +57 -0
  255. package/lib/programmatic/run-enterprise-mcp.js +32 -0
  256. package/lib/programmatic/run-lifecycle.js +29 -0
  257. package/lib/programmatic/run-repair.js +41 -0
  258. package/lib/programmatic/run-repository-emcp.js +54 -0
  259. package/lib/programmatic/run-template-workspace.js +61 -0
  260. package/lib/programmatic/run-test.js +49 -0
  261. package/lib/programmatic/run-upload.js +63 -0
  262. package/lib/programmatic/run-validate.js +53 -0
  263. package/lib/programmatic/run-wizard.js +40 -0
  264. package/lib/programmatic/system-key.js +48 -0
  265. package/lib/programmatic/wizard-config-normalize.js +118 -0
  266. package/lib/programmatic/workspace-cleanup.js +128 -0
  267. package/lib/programmatic/workspace-context.js +145 -0
  268. package/lib/programmatic/workspace-lock.js +75 -0
  269. package/lib/programmatic/workspace-meta.js +64 -0
  270. package/lib/programmatic/workspace-ops.js +149 -0
  271. package/lib/protection/run-commands-upload-sync.js +35 -0
  272. package/lib/protection/run-commands.js +2 -20
  273. package/lib/protection/upload-batch.js +11 -7
  274. package/lib/resolvers/resource-type-file.js +22 -0
  275. package/lib/schema/external-datasource.schema.json +161 -1
  276. package/lib/schema/external-system.schema.json +242 -4
  277. package/lib/schema/flag-map-validation-run.json +3 -0
  278. package/lib/schema/type/credential-field-registry.json +2 -2
  279. package/lib/schema/type/document-storage.json +9 -0
  280. package/lib/utils/agent-trust-run-display.js +1 -1
  281. package/lib/utils/app-path-resolve.js +168 -0
  282. package/lib/utils/authentication-env-template.js +222 -0
  283. package/lib/utils/cli-sync-options.js +7 -11
  284. package/lib/utils/cli-utils.js +4 -0
  285. package/lib/utils/cli-workspace-options.js +29 -0
  286. package/lib/utils/compose-generate-docker-compose.js +102 -0
  287. package/lib/utils/configuration-env-resolver.js +203 -27
  288. package/lib/utils/datasource-test-run-certificate-tty.js +28 -2
  289. package/lib/utils/datasource-test-run-certification-debug.js +130 -0
  290. package/lib/utils/datasource-test-run-debug-display.js +2 -0
  291. package/lib/utils/datasource-test-run-debug-slice.js +7 -0
  292. package/lib/utils/datasource-test-run-display.js +2 -1
  293. package/lib/utils/dev-init-ssh-merge.js +165 -23
  294. package/lib/utils/dev-pin-share-instructions.js +110 -0
  295. package/lib/utils/dev-ssh-config-helper.js +177 -33
  296. package/lib/utils/enterprise-knowledge-paths.js +142 -0
  297. package/lib/utils/env-copy.js +2 -1
  298. package/lib/utils/env-dotenv-format.js +103 -0
  299. package/lib/utils/external-env-template.js +4 -1
  300. package/lib/utils/external-system-display.js +5 -1
  301. package/lib/utils/external-system-readiness-compact-blocks.js +221 -0
  302. package/lib/utils/external-system-readiness-compact-display.js +324 -0
  303. package/lib/utils/external-system-readiness-core.js +16 -0
  304. package/lib/utils/external-system-readiness-deploy-display.js +29 -11
  305. package/lib/utils/external-system-readiness-display-internals.js +3 -1
  306. package/lib/utils/external-system-readiness-display.js +20 -30
  307. package/lib/utils/external-system-system-test-tty-certification.js +135 -0
  308. package/lib/utils/external-system-system-test-tty.js +5 -41
  309. package/lib/utils/help-builder.js +6 -1
  310. package/lib/utils/host-ops-job-labels.js +236 -0
  311. package/lib/utils/host-ops-job-result.js +61 -0
  312. package/lib/utils/host-ops-poll-ui.js +163 -0
  313. package/lib/utils/integration-path-resolve.js +112 -0
  314. package/lib/utils/paths-reload-source.js +148 -0
  315. package/lib/utils/paths-system-builder-keys.js +25 -0
  316. package/lib/utils/paths.js +151 -26
  317. package/lib/utils/runtime-configuration-values.js +64 -2
  318. package/lib/utils/secrets-helpers.js +5 -1
  319. package/lib/utils/ssh-known-hosts.js +130 -0
  320. package/lib/utils/test-target-cli-options.js +75 -0
  321. package/lib/utils/upload-sync-options.js +4 -0
  322. package/lib/utils/validation-run-request.js +11 -2
  323. package/lib/validation/external-manifest-validator.js +11 -1
  324. package/lib/validation/openapi-contract-surface-validator.js +426 -0
  325. package/lib/validation/openapi-contract-vendor-validation.js +238 -0
  326. package/lib/validation/validate-external-file.js +160 -0
  327. package/lib/validation/validate.js +6 -117
  328. package/package.json +46 -29
  329. package/packages/builder-api/README.md +120 -0
  330. package/packages/builder-api/package.json +30 -0
  331. package/packages/builder-api/src/app.module.ts +7 -0
  332. package/packages/builder-api/src/auth/auth.module.ts +5 -0
  333. package/packages/builder-api/src/external-system/external-system.module.ts +5 -0
  334. package/packages/builder-api/src/main.ts +16 -0
  335. package/packages/builder-api/tsconfig.json +15 -0
  336. package/scripts/check-builder-api-architecture-grep.js +79 -0
  337. package/scripts/docker_image_content_gate.js +47 -0
  338. package/scripts/docker_image_content_gate.sh +5 -0
  339. package/scripts/export-builder-api-evidence.js +262 -0
  340. package/scripts/lib/builder-api-docker-staging-copy.js +60 -0
  341. package/scripts/lib/builder-api-docker-staging-core.js +183 -0
  342. package/scripts/lib/docker-image-content-gate-core.js +166 -0
  343. package/scripts/lib/plan-actor.js +109 -0
  344. package/scripts/lib/plan-config.js +20 -0
  345. package/scripts/lib/plan-gates.js +154 -0
  346. package/scripts/lib/plan-meta.js +104 -0
  347. package/scripts/lib/plan-parse.js +162 -0
  348. package/scripts/lib/plan-prevalidate-gates.js +326 -0
  349. package/scripts/lib/plan-run-core.js +125 -0
  350. package/scripts/lib/plan-run-report.js +108 -0
  351. package/scripts/plan-approve.js +24 -0
  352. package/scripts/plan-archive.js +49 -0
  353. package/scripts/plan-run.js +13 -0
  354. package/scripts/plan-set-actor.js +21 -0
  355. package/scripts/plan-validate.js +80 -0
  356. package/scripts/pnpm/af.mjs +110 -0
  357. package/scripts/pnpm/check-quiet.mjs +32 -0
  358. package/scripts/pnpm/dev-install.mjs +29 -0
  359. package/scripts/pnpm/dev-reload.mjs +18 -0
  360. package/scripts/pnpm/help.mjs +55 -0
  361. package/scripts/pnpm/lib/dev-reload-core.mjs +189 -0
  362. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +67 -0
  363. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +32 -0
  364. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +124 -0
  365. package/scripts/pnpm/lib/resolve-app-url.mjs +183 -0
  366. package/scripts/pnpm/lib/spinner.mjs +42 -0
  367. package/scripts/stage_builder_api_for_docker.js +65 -0
  368. package/scripts/sync-builder-api-template.js +44 -0
  369. package/templates/README.md +3 -0
  370. package/templates/applications/builder-api/Dockerfile +38 -0
  371. package/templates/applications/builder-api/application.yaml +75 -0
  372. package/templates/applications/builder-api/env.template +48 -0
  373. package/templates/applications/dataplane/application.yaml +1 -1
  374. package/templates/applications/dataplane/env.template +10 -6
  375. package/templates/applications/dataplane/rbac.yaml +21 -1
  376. package/templates/applications/miso-controller/application.yaml +1 -1
  377. package/templates/applications/miso-controller/env.template +1 -3
  378. package/templates/channels/README.md +18 -0
  379. package/templates/channels/ai-fabrix-icon.jpg +0 -0
  380. package/templates/channels/chatgpt/install.template.md.hbs +21 -24
  381. package/templates/channels/chatgpt/integration/README.md +11 -0
  382. package/templates/channels/chatgpt/integration/application.json +15 -0
  383. package/templates/channels/chatgpt/integration/chatgpt-system.json +29 -0
  384. package/templates/channels/chatgpt/integration/env.template +4 -0
  385. package/templates/channels/microsoft-copilot/install.template.md.hbs +20 -25
  386. package/templates/channels/microsoft-copilot/integration/README.md +11 -0
  387. package/templates/channels/microsoft-copilot/integration/application.json +15 -0
  388. package/templates/channels/microsoft-copilot/integration/env.template +6 -0
  389. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +34 -0
  390. package/templates/channels/slack/install.template.md.hbs +48 -18
  391. package/templates/channels/slack/integration/README.md +38 -0
  392. package/templates/channels/slack/integration/application.json +18 -0
  393. package/templates/channels/slack/integration/env.template +29 -0
  394. package/templates/channels/slack/integration/slack-datasource-conversations.json +226 -0
  395. package/templates/channels/slack/integration/slack-datasource-messages.json +269 -0
  396. package/templates/channels/slack/integration/slack-system.json +86 -0
  397. package/templates/channels/slack/manifest.template.json.hbs +20 -10
  398. package/templates/channels/teams-bot/install.template.md.hbs +31 -17
  399. package/templates/channels/teams-bot/integration/README.md +18 -0
  400. package/templates/channels/teams-bot/integration/application.json +17 -0
  401. package/templates/channels/teams-bot/integration/env.template +5 -0
  402. package/templates/channels/teams-bot/integration/teams-bot-system.json +55 -0
  403. package/templates/channels/teams-bot/manifest.template.json.hbs +27 -0
  404. package/templates/channels/web-embed/install.template.md.hbs +16 -26
  405. package/templates/channels/web-embed/integration/README.md +11 -0
  406. package/templates/channels/web-embed/integration/application.json +15 -0
  407. package/templates/channels/web-embed/integration/env.template +4 -0
  408. package/templates/channels/web-embed/integration/web-embed-system.json +29 -0
  409. package/templates/openapi/redoc_page.html +86 -0
  410. package/templates/python/docker-compose.hbs +11 -0
  411. package/templates/python/requirements.txt +1 -1
  412. package/templates/typescript/docker-compose.hbs +11 -0
  413. package/lib/certification/cli-cert-sync-skip.js +0 -21
@@ -17,17 +17,17 @@ const { registerApplication } = require('../app/register');
17
17
  const { rotateSecret } = require('../app/rotate-secret');
18
18
  const { showApp } = require('../app/show');
19
19
  const { runAppDeploymentList } = require('./deployment-list');
20
- const { isChannelTargetKey } = require('../channels/channel-targets');
21
- const { addChannelCommand } = require('../channels/add-channel');
20
+ const { registerChannelAddCommand } = require('./channel-add-setup');
22
21
 
23
22
  const APP_HELP_AFTER = `
24
23
  Subcommands:
25
24
  register <appKey> Register app; get pipeline client id/secret
26
- list Applications in current environment
25
+ list Controller applications only (not connected systems)
27
26
  rotate-secret <key> New ClientSecret (shown once)
28
- show <key> From controller (like show --online)
27
+ show <key> Controller application details (pipeline apps only)
29
28
  deployment <key> Deployment history for app
30
- add-channel <target> Configure assistant channel install (after deploy)
29
+
30
+ Connected systems and channels: aifabrix list · aifabrix channel · aifabrix show <systemKey> --online
31
31
 
32
32
  Requires: aifabrix login
33
33
  `;
@@ -51,7 +51,7 @@ function setupAppRegisterCommand(app) {
51
51
 
52
52
  function setupAppListCommand(app) {
53
53
  app.command('list')
54
- .description('List apps in current environment')
54
+ .description('List controller applications (excludes connected systems)')
55
55
  .action(async(options) => {
56
56
  try {
57
57
  await listApplications(options);
@@ -91,7 +91,8 @@ function setupAppShowCommand(app) {
91
91
  online: true,
92
92
  json: !!options.json,
93
93
  permissions: !!options.permissions,
94
- verifyCert: options.verifyCert === true
94
+ verifyCert: options.verifyCert === true,
95
+ appsOnly: true
95
96
  });
96
97
  } catch (error) {
97
98
  logger.error(chalk.red(`Error: ${error.message}`));
@@ -121,41 +122,12 @@ function setupAppDeploymentCommand(app) {
121
122
  });
122
123
  }
123
124
 
124
- function setupAppAddChannelCommand(app) {
125
- app.command('add-channel <channelTarget>')
126
- .description(
127
- 'Configure assistant channel install (teams-bot, slack, …) after aifabrix deploy <target>'
128
- )
129
- .requiredOption('-n, --name <name>', 'Customer-visible channel name')
130
- .option('-d, --description <text>', 'Channel description (default generated)')
131
- .option('--icon <path>', 'Path to channel icon asset')
132
- .option('--template <name>', 'Template override (default from channel target)')
133
- .option('--dry-run', 'Generate artifacts only; do not patch external system or credentials')
134
- .option('--force', 'Regenerate artifacts and patch config (does not rotate secrets)')
135
- .option('--probe', 'After install, validate callbacks and assistant catalog')
136
- .action(async(channelTarget, options) => {
137
- try {
138
- if (!isChannelTargetKey(channelTarget)) {
139
- throw new Error(
140
- `Unknown channel target "${channelTarget}". Use teams-bot, slack, microsoft-copilot, or chatgpt.`
141
- );
142
- }
143
- await addChannelCommand(channelTarget, {
144
- name: options.name,
145
- description: options.description,
146
- icon: options.icon,
147
- template: options.template,
148
- dryRun: options.dryRun === true,
149
- force: options.force === true,
150
- probe: options.probe === true
151
- });
152
- } catch (error) {
153
- if (!error.message?.includes('Authentication required')) {
154
- logger.error(formatBlockingError('Channel install failed:'), error.message);
155
- }
156
- process.exit(1);
157
- }
158
- });
125
+ function setupAppDeprecatedAddChannelAlias(app) {
126
+ registerChannelAddCommand(app, {
127
+ commandName: 'add-channel <channelTarget>',
128
+ hidden: true,
129
+ deprecatedVia: 'aifabrix app add-channel'
130
+ });
159
131
  }
160
132
 
161
133
  /**
@@ -169,7 +141,7 @@ function setupAppCommands(program) {
169
141
  setupAppRotateSecretCommand(app);
170
142
  setupAppShowCommand(app);
171
143
  setupAppDeploymentCommand(app);
172
- setupAppAddChannelCommand(app);
144
+ setupAppDeprecatedAddChannelAlias(app);
173
145
  }
174
146
 
175
147
  module.exports = { setupAppCommands };
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Register `channel add` (and optional deprecated aliases).
3
+ *
4
+ * @fileoverview Shared Commander wiring for assistant channel install (plan 152)
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const chalk = require('chalk');
10
+ const logger = require('../utils/logger');
11
+ const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
12
+ const { isChannelTargetKey } = require('../channels/channel-targets');
13
+ const { addChannelCommand } = require('../channels/add-channel');
14
+
15
+ const CHANNEL_ADD_HELP_AFTER = `
16
+
17
+ Examples:
18
+ # After upload/deploy of the communication external system
19
+ $ aifabrix channel add slack --name "Elsa"
20
+ $ aifabrix channel add teams-bot --name "Elsa" --description "Enterprise AI assistant for employees"
21
+
22
+ # Slack slash-command prefix (registers /{prefix}-help in manifest)
23
+ $ aifabrix channel add slack --name "Elsa" --command-prefix af
24
+
25
+ # Generate artifacts only; no dataplane patch
26
+ $ aifabrix channel add slack --name "Elsa" --dry-run
27
+
28
+ # Regenerate artifacts and patch config (does not rotate secrets)
29
+ $ aifabrix channel add slack --name "Elsa" --force
30
+
31
+ # Validate callbacks and assistant catalog after install
32
+ $ aifabrix channel add slack --name "Elsa" --probe
33
+
34
+ Prerequisites: aifabrix upload <target> (or deploy) and aifabrix login
35
+ `;
36
+
37
+ /**
38
+ * @param {string} channelTarget
39
+ * @param {Object} options
40
+ * @param {{ deprecatedVia?: string }} [meta]
41
+ */
42
+ async function runChannelAddAction(channelTarget, options, meta = {}) {
43
+ if (meta.deprecatedVia) {
44
+ logger.warn(
45
+ chalk.yellow(
46
+ `Deprecated: use "aifabrix channel add ${channelTarget} ..." instead of "${meta.deprecatedVia}".`
47
+ )
48
+ );
49
+ }
50
+ if (!isChannelTargetKey(channelTarget)) {
51
+ throw new Error(
52
+ `Unknown channel target "${channelTarget}". Use teams-bot, slack, microsoft-copilot, or chatgpt.`
53
+ );
54
+ }
55
+ await addChannelCommand(channelTarget, {
56
+ name: options.name,
57
+ description: options.description,
58
+ icon: options.icon,
59
+ template: options.template,
60
+ commandPrefix: options.commandPrefix,
61
+ dryRun: options.dryRun === true,
62
+ force: options.force === true,
63
+ probe: options.probe === true
64
+ });
65
+ }
66
+
67
+ /**
68
+ * @param {import('commander').Command} parent
69
+ * @param {{ deprecatedVia?: string, commandName?: string, hidden?: boolean }} [meta]
70
+ * @returns {import('commander').Command}
71
+ */
72
+ function registerChannelAddCommand(parent, meta = {}) {
73
+ const description =
74
+ 'Configure channel install (manifest, credentials, admin guide) after upload/deploy';
75
+ const commandName = meta.commandName || 'add <channelTarget>';
76
+ const cmd = meta.hidden
77
+ ? parent.command(commandName, { hidden: true })
78
+ : parent.command(commandName);
79
+ cmd
80
+ .description(meta.deprecatedVia ? `(deprecated) ${description}` : description)
81
+ .requiredOption('-n, --name <name>', 'Customer-visible channel name (e.g. "Elsa")')
82
+ .option('-d, --description <text>', 'Channel description (default generated)')
83
+ .option('--icon <path>', 'Path to channel icon asset')
84
+ .option('--template <name>', 'Template override (default from channel target)')
85
+ .option('--dry-run', 'Generate artifacts only; do not patch external system or credentials')
86
+ .option('--force', 'Regenerate artifacts and patch config (does not rotate secrets)')
87
+ .option(
88
+ '--command-prefix <key>',
89
+ 'Slack slash alias prefix (default af) — registers /{prefix}-help etc. in manifest'
90
+ )
91
+ .option('--probe', 'After install, validate callbacks and assistant catalog')
92
+ .addHelpText('after', CHANNEL_ADD_HELP_AFTER)
93
+ .action(async(channelTarget, options) => {
94
+ try {
95
+ await runChannelAddAction(channelTarget, options, meta);
96
+ } catch (error) {
97
+ if (!error.message?.includes('Authentication required')) {
98
+ logger.error(formatBlockingError('Channel install failed:'), error.message);
99
+ }
100
+ process.exit(1);
101
+ }
102
+ });
103
+ return cmd;
104
+ }
105
+
106
+ module.exports = {
107
+ CHANNEL_ADD_HELP_AFTER,
108
+ registerChannelAddCommand,
109
+ runChannelAddAction
110
+ };
@@ -1,18 +1,43 @@
1
1
  /**
2
2
  * Channel CLI commands (plan 152).
3
3
  *
4
- * @fileoverview Scaffold communication external systems for channel deploy step 1
4
+ * @fileoverview Scaffold and install assistant communication channels (Slack, Teams, …)
5
5
  * @author AI Fabrix Team
6
- * @version 1.0.0
6
+ * @version 1.1.0
7
7
  */
8
8
 
9
9
  'use strict';
10
10
 
11
11
  const chalk = require('chalk');
12
12
  const logger = require('../utils/logger');
13
- const { formatSuccessLine, formatBlockingError, sectionTitle, metadata } = require('../utils/cli-test-layout-chalk');
13
+ const {
14
+ formatSuccessLine,
15
+ formatBlockingError,
16
+ sectionTitle,
17
+ metadata
18
+ } = require('../utils/cli-test-layout-chalk');
14
19
  const { CHANNEL_TARGET_KEYS, isChannelTargetKey } = require('../channels/channel-targets');
15
20
  const { scaffoldChannelIntegration } = require('../channels/channel-integration-generator');
21
+ const { registerChannelAddCommand } = require('./channel-add-setup');
22
+
23
+ const CHANNEL_HELP_AFTER = `
24
+ Subcommands:
25
+ scaffold <target> Create integration/<target>/ files locally (step 1)
26
+ add <target> Channel install guide + manifest/credential patch (step 3)
27
+
28
+ Targets:
29
+ teams-bot, slack, microsoft-copilot, chatgpt
30
+ web-embed (experimental — scaffold with --allow-experimental)
31
+
32
+ Typical flow (channels are connected systems, not controller apps):
33
+ aifabrix channel scaffold slack
34
+ aifabrix upload slack --force
35
+ aifabrix channel add slack --name "Elsa" --probe
36
+
37
+ Controller pipeline apps only: aifabrix app register · aifabrix app list
38
+
39
+ Requires: aifabrix login (for add)
40
+ `;
16
41
 
17
42
  /**
18
43
  * @param {import('commander').Command} program
@@ -20,11 +45,16 @@ const { scaffoldChannelIntegration } = require('../channels/channel-integration-
20
45
  function setupChannelCommands(program) {
21
46
  const channel = program
22
47
  .command('channel')
23
- .description('Assistant channel integration scaffolds (plan 152)');
48
+ .description(
49
+ 'Assistant channels (Slack, Teams, Copilot, ChatGPT) — scaffold integration and install'
50
+ )
51
+ .addHelpText('after', CHANNEL_HELP_AFTER);
24
52
 
25
53
  channel
26
54
  .command('scaffold <channelTarget>')
27
- .description('Generate integration/<target>/ communication external system for deploy step 1')
55
+ .description(
56
+ 'Generate integration/<target>/ communication external system (local files only)'
57
+ )
28
58
  .option('--force', 'Overwrite generated scaffold files when folder exists')
29
59
  .option('--allow-experimental', 'Allow web-embed scaffold')
30
60
  .action(async(channelTarget, options) => {
@@ -34,7 +64,7 @@ function setupChannelCommands(program) {
34
64
  `Unknown channel target "${channelTarget}". Expected: ${CHANNEL_TARGET_KEYS.join(', ')}`
35
65
  );
36
66
  }
37
- const result = scaffoldChannelIntegration(channelTarget, {
67
+ const result = await scaffoldChannelIntegration(channelTarget, {
38
68
  force: options.force === true,
39
69
  allowExperimental: options.allowExperimental === true
40
70
  });
@@ -46,13 +76,17 @@ function setupChannelCommands(program) {
46
76
  }
47
77
  logger.log('');
48
78
  logger.log(chalk.white('Next steps:'));
49
- logger.log(chalk.gray(` aifabrix deploy ${channelTarget}`));
50
- logger.log(chalk.gray(` aifabrix app add-channel ${channelTarget} --name "Your Assistant"`));
79
+ logger.log(chalk.gray(` aifabrix upload ${channelTarget} --force`));
80
+ logger.log(
81
+ chalk.gray(` aifabrix channel add ${channelTarget} --name "Your Assistant" --probe`)
82
+ );
51
83
  } catch (error) {
52
84
  logger.error(formatBlockingError(error.message || String(error)));
53
85
  process.exit(1);
54
86
  }
55
87
  });
88
+
89
+ registerChannelAddCommand(channel);
56
90
  }
57
91
 
58
92
  module.exports = { setupChannelCommands };
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @fileoverview TTY/JSON output for post-publish datasource data sync.
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const logger = require('../utils/logger');
10
+ const {
11
+ formatProgress,
12
+ formatSuccessLine,
13
+ formatWarningLine,
14
+ infoLine,
15
+ metadata
16
+ } = require('../utils/cli-test-layout-chalk');
17
+
18
+ const SKIP_REASON_LABELS = {
19
+ has_data: 'records already present',
20
+ no_connectivity: 'datasource not available on dataplane',
21
+ skipped: 'sync disabled'
22
+ };
23
+
24
+ /**
25
+ * @param {Object|null|undefined} result
26
+ * @param {Object} [options]
27
+ * @param {boolean} [options.syncExplicit]
28
+ * @returns {boolean}
29
+ */
30
+ function shouldEmitDatasourceSyncSummary(result, options = {}) {
31
+ if (!result || options.json === true) {
32
+ return false;
33
+ }
34
+ // Default upload/deploy: bootstrap may run, but output only when user passed --sync.
35
+ if (options.syncExplicit !== true) {
36
+ return false;
37
+ }
38
+ const executed = result.executed || [];
39
+ const skipped = result.skipped || [];
40
+ return executed.length > 0 || skipped.length > 0;
41
+ }
42
+
43
+ /**
44
+ * @param {Object} row
45
+ * @returns {string}
46
+ */
47
+ function formatSkippedSyncLine(row) {
48
+ const detail = SKIP_REASON_LABELS[row.reason] || row.reason;
49
+ if (row.reason === 'has_data') {
50
+ return metadata(` ${row.datasourceKey}: ${detail} (bootstrap not needed)`);
51
+ }
52
+ return formatWarningLine(` Skipped ${row.datasourceKey}: ${detail}`);
53
+ }
54
+
55
+ /**
56
+ * @param {Object} result
57
+ * @param {Object} [options]
58
+ * @param {boolean} [options.json]
59
+ * @param {boolean} [options.syncExplicit]
60
+ * @param {string} [options.label]
61
+ */
62
+ function logDatasourceSyncSummary(result, options = {}) {
63
+ if (!shouldEmitDatasourceSyncSummary(result, options)) {
64
+ return;
65
+ }
66
+ const label = options.label || 'Data sync';
67
+ logger.log('');
68
+ logger.log(infoLine(label));
69
+ for (const row of result.skipped || []) {
70
+ if (!options.syncExplicit && row.reason === 'has_data') {
71
+ continue;
72
+ }
73
+ logger.log(formatSkippedSyncLine(row));
74
+ }
75
+ for (const row of result.executed || []) {
76
+ if (row.syncJobId) {
77
+ logger.log(
78
+ formatSuccessLine(
79
+ ` Synced ${row.datasourceKey} (${row.reason}; syncJobId ${row.syncJobId})`
80
+ )
81
+ );
82
+ continue;
83
+ }
84
+ const warn = row.warning ? ` — ${row.warning}` : '';
85
+ logger.log(formatWarningLine(` Sync failed ${row.datasourceKey}${warn}`));
86
+ }
87
+ if ((result.executed || []).length === 0 && (result.skipped || []).length === 0) {
88
+ logger.log(formatProgress(' No datasource keys to evaluate.'));
89
+ }
90
+ }
91
+
92
+ module.exports = {
93
+ logDatasourceSyncSummary,
94
+ shouldEmitDatasourceSyncSummary,
95
+ SKIP_REASON_LABELS
96
+ };
@@ -0,0 +1,210 @@
1
+ /**
2
+ * @fileoverview Bootstrap vs explicit datasource data sync policy for upload/deploy.
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { getDatasource, getDatasourceStatus } = require('../api/datasources-core.api');
10
+ const { unwrapApiData } = require('../utils/external-system-readiness-core');
11
+ const { assertDatasourceExistsOnDataplane } = require('../protection/preflight-datasource-ready');
12
+ const { syncDatasourceAfterProtectionUpload } = require('../protection/sync-after-upload');
13
+
14
+ /**
15
+ * @param {Object|null|undefined} row
16
+ * @returns {number|null}
17
+ */
18
+ function readRecordCountFromRow(row) {
19
+ if (!row || typeof row !== 'object') {
20
+ return null;
21
+ }
22
+ const candidates = [
23
+ row.recordCount,
24
+ row.totalRecords,
25
+ row.activeRecords,
26
+ row.data?.recordCount,
27
+ row.data?.totalRecords,
28
+ row.data?.activeRecords,
29
+ row.stats?.recordCount,
30
+ row.stats?.totalRecords
31
+ ];
32
+ for (const value of candidates) {
33
+ if (typeof value === 'number' && Number.isFinite(value)) {
34
+ return value;
35
+ }
36
+ }
37
+ return null;
38
+ }
39
+
40
+ /**
41
+ * @param {string} dataplaneUrl
42
+ * @param {Object} authConfig
43
+ * @param {string} datasourceKey
44
+ * @param {Map<string, number|null>} [cache]
45
+ * @returns {Promise<number|null>}
46
+ */
47
+ async function resolveDatasourceRecordCount(dataplaneUrl, authConfig, datasourceKey, cache) {
48
+ const key = String(datasourceKey || '').trim();
49
+ if (!key) {
50
+ return null;
51
+ }
52
+ if (cache && cache.has(key)) {
53
+ return cache.get(key);
54
+ }
55
+
56
+ let count = null;
57
+ try {
58
+ const statusRes = await getDatasourceStatus(dataplaneUrl, key, authConfig);
59
+ count = readRecordCountFromRow(unwrapApiData(statusRes));
60
+ } catch {
61
+ count = null;
62
+ }
63
+
64
+ if (count === null) {
65
+ try {
66
+ const dsRes = await getDatasource(dataplaneUrl, key, authConfig);
67
+ count = readRecordCountFromRow(unwrapApiData(dsRes));
68
+ } catch {
69
+ count = null;
70
+ }
71
+ }
72
+
73
+ if (cache) {
74
+ cache.set(key, count);
75
+ }
76
+ return count;
77
+ }
78
+
79
+ /**
80
+ * Bootstrap preflight: datasource is deployed and readable on the dataplane.
81
+ * Does not call legacy POST /external/{key}/test (removed from dataplane OpenAPI).
82
+ *
83
+ * @param {string} dataplaneUrl
84
+ * @param {Object} authConfig
85
+ * @param {string} datasourceKey
86
+ * @returns {Promise<boolean>}
87
+ */
88
+ async function checkDatasourceConnectivity(dataplaneUrl, authConfig, datasourceKey) {
89
+ try {
90
+ await assertDatasourceExistsOnDataplane(dataplaneUrl, authConfig, datasourceKey);
91
+ return true;
92
+ } catch {
93
+ return false;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * @param {string} datasourceKey
99
+ * @param {Object} params
100
+ * @param {Map<string, number|null>} cache
101
+ * @returns {Promise<{ datasourceKey: string, bucket: string, reason: string }>}
102
+ */
103
+ async function evaluateBootstrapSyncCandidate(datasourceKey, params, cache) {
104
+ const count = await resolveDatasourceRecordCount(
105
+ params.dataplaneUrl,
106
+ params.authConfig,
107
+ datasourceKey,
108
+ cache
109
+ );
110
+ if (typeof count === 'number' && count > 0) {
111
+ return { datasourceKey, bucket: 'skipped', reason: 'has_data' };
112
+ }
113
+ const connected = await checkDatasourceConnectivity(
114
+ params.dataplaneUrl,
115
+ params.authConfig,
116
+ datasourceKey
117
+ );
118
+ if (!connected) {
119
+ return { datasourceKey, bucket: 'skipped', reason: 'no_connectivity' };
120
+ }
121
+ return { datasourceKey, bucket: 'run', reason: 'bootstrap' };
122
+ }
123
+
124
+ /**
125
+ * @param {Object} params
126
+ * @param {boolean} [params.syncExplicit]
127
+ * @param {boolean} [params.skipSync]
128
+ * @param {string[]} params.datasourceKeys
129
+ * @param {string} dataplaneUrl
130
+ * @param {Object} authConfig
131
+ * @returns {Promise<{ run: Object[], skipped: Object[] }>}
132
+ */
133
+ async function resolveSyncPlan(params) {
134
+ const keys = [
135
+ ...new Set((params.datasourceKeys || []).map((k) => String(k || '').trim()).filter(Boolean))
136
+ ];
137
+ const skipped = [];
138
+ const run = [];
139
+ const cache = new Map();
140
+
141
+ if (params.skipSync === true) {
142
+ keys.forEach((datasourceKey) => skipped.push({ datasourceKey, reason: 'skipped' }));
143
+ return { run, skipped };
144
+ }
145
+
146
+ if (params.syncExplicit === true) {
147
+ keys.forEach((datasourceKey) => run.push({ datasourceKey, reason: 'explicit' }));
148
+ return { run, skipped };
149
+ }
150
+
151
+ for (const datasourceKey of keys) {
152
+ const decision = await evaluateBootstrapSyncCandidate(datasourceKey, params, cache);
153
+ if (decision.bucket === 'skipped') {
154
+ skipped.push({ datasourceKey: decision.datasourceKey, reason: decision.reason });
155
+ continue;
156
+ }
157
+ run.push({ datasourceKey: decision.datasourceKey, reason: decision.reason });
158
+ }
159
+ return { run, skipped };
160
+ }
161
+
162
+ /**
163
+ * @param {{ run: Object[] }} plan
164
+ * @param {string} dataplaneUrl
165
+ * @param {Object} authConfig
166
+ * @returns {Promise<{ executed: Object[], skipped: Object[] }>}
167
+ */
168
+ async function executeSyncPlan(plan, dataplaneUrl, authConfig) {
169
+ const executed = [];
170
+ for (const item of plan.run) {
171
+ const syncResult = await syncDatasourceAfterProtectionUpload(
172
+ dataplaneUrl,
173
+ authConfig,
174
+ item.datasourceKey
175
+ );
176
+ executed.push({ ...item, ...syncResult });
177
+ }
178
+ return { executed, skipped: plan.skipped || [] };
179
+ }
180
+
181
+ /**
182
+ * @param {string} dataplaneUrl
183
+ * @param {Object} authConfig
184
+ * @param {string[]} datasourceKeys
185
+ * @returns {Promise<'never'|'auto'>}
186
+ */
187
+ async function resolveE2eSyncModeWhenPopulated(dataplaneUrl, authConfig, datasourceKeys) {
188
+ const keys = [
189
+ ...new Set((datasourceKeys || []).map((k) => String(k || '').trim()).filter(Boolean))
190
+ ];
191
+ if (keys.length === 0) {
192
+ return 'auto';
193
+ }
194
+ const cache = new Map();
195
+ for (const key of keys) {
196
+ const count = await resolveDatasourceRecordCount(dataplaneUrl, authConfig, key, cache);
197
+ if (count === null || count === 0) {
198
+ return 'auto';
199
+ }
200
+ }
201
+ return 'never';
202
+ }
203
+
204
+ module.exports = {
205
+ readRecordCountFromRow,
206
+ resolveDatasourceRecordCount,
207
+ resolveSyncPlan,
208
+ executeSyncPlan,
209
+ resolveE2eSyncModeWhenPopulated
210
+ };
@@ -13,7 +13,7 @@ const { writeTrustDebugLogAndPrint } = require('../datasource/agent-trust-debug-
13
13
  const { displayAgentTrustRunTTY } = require('../utils/agent-trust-run-display');
14
14
  const { computeExitCodeFromTrustRun } = require('../utils/agent-trust-run-exit');
15
15
  const { attachDatasourceTestCommonOptions } = require('./datasource-unified-test-cli.options');
16
- const { cliOptsSkipSync } = require('../utils/cli-sync-options');
16
+ const { cliOptsSkipPublish } = require('../utils/cli-sync-options');
17
17
 
18
18
  function datasourceVerifyTrustHelpAfter() {
19
19
  return `
@@ -25,7 +25,7 @@ Examples:
25
25
 
26
26
  Notes:
27
27
  - Semantic trust only (agent metadata validation). For live API proof use test-e2e.
28
- - Local files are published before run unless --no-sync.
28
+ - Local files are published before run unless --no-publish.
29
29
  - With --debug, JSON is saved under integration/<app>/logs/ (verify-trust-<key>-*.json). View with: aifabrix datasource log-trust <key>
30
30
  `;
31
31
  }
@@ -34,7 +34,7 @@ async function runDatasourceVerifyTrustOnce(datasourceKey, options) {
34
34
  const { trustRun, apiError } = await runDatasourceAgentTrust(datasourceKey, {
35
35
  app: options.app,
36
36
  environment: options.env,
37
- noSync: options.noSync === true,
37
+ noPublish: options.noPublish === true,
38
38
  force: options.force === true,
39
39
  revalidate: options.revalidate === true,
40
40
  summary: options.summary === true,
@@ -48,7 +48,7 @@ async function finalizeDatasourceVerifyTrust(datasourceKey, options, result) {
48
48
  json: options.json,
49
49
  verbose: options.verbose,
50
50
  environment: options.env,
51
- noSync: options.noSync === true,
51
+ noPublish: options.noPublish === true,
52
52
  strict: options.strict === true
53
53
  };
54
54
  if (options.json) {
@@ -70,7 +70,7 @@ async function finalizeDatasourceVerifyTrust(datasourceKey, options, result) {
70
70
 
71
71
  async function datasourceVerifyTrustAction(datasourceKey, options, cmd) {
72
72
  try {
73
- const merged = { ...options, noSync: cliOptsSkipSync(options, cmd) };
73
+ const merged = { ...options, noPublish: cliOptsSkipPublish(options, cmd) };
74
74
  const result = await runDatasourceVerifyTrustOnce(datasourceKey, merged);
75
75
  const { resolveAppKeyForDatasource } = require('../datasource/resolve-app');
76
76
  const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
@@ -97,7 +97,7 @@ function attachDatasourceTrustOptions(cmd) {
97
97
  timeoutDefault: '120000'
98
98
  });
99
99
  cmd
100
- .option('--no-sync', 'Skip publishing local integration files before validate')
100
+ .option('--no-publish', 'Skip publishing local integration files before validate')
101
101
  .option('--revalidate', 'Force new validation (ignore inputHash cache)')
102
102
  .option('--strict', 'Exit 1 unless trustDecision is trusted');
103
103
  }
@@ -47,7 +47,8 @@ async function writeDatasourceTestDebugLogIfRequested(appKey, datasourceKey, res
47
47
  const requestMeta = {
48
48
  datasourceKey,
49
49
  runType: 'test',
50
- includeDebug: includeDebugForRequest(options.debug)
50
+ includeDebug: includeDebugForRequest(options.debug),
51
+ explainCertification: includeDebugForRequest(options.debug)
51
52
  };
52
53
  const envelope = result && typeof result === 'object' ? result.envelope : null;
53
54
  const apiError = result && typeof result === 'object' ? result.apiError : null;