@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,54 @@
1
+ /**
2
+ * Repository Enterprise MCP route handlers (154.1).
3
+ *
4
+ * @fileoverview Provider-neutral repository.* capabilities
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { runEnterpriseMcpCapability } = require('./run-enterprise-mcp');
12
+ const { invokeEnterpriseMcpCapability } = require('./enterprise-mcp-client');
13
+ const { runWithWorkspaceContext } = require('./workspace-context');
14
+
15
+ /**
16
+ * @param {import('./workspace-context').WorkspaceContext} ctx
17
+ * @param {Object} body
18
+ */
19
+ async function runRepositorySync(ctx, body = {}) {
20
+ return runEnterpriseMcpCapability(ctx, 'repository.sync', body);
21
+ }
22
+
23
+ /**
24
+ * @param {import('./workspace-context').WorkspaceContext} ctx
25
+ * @param {Object} body
26
+ */
27
+ async function runRepositoryCreateReview(ctx, body = {}) {
28
+ return runEnterpriseMcpCapability(ctx, 'repository.createReview', body);
29
+ }
30
+
31
+ /**
32
+ * @param {import('./workspace-context').WorkspaceContext} ctx
33
+ */
34
+ async function getRepositoryStatus(ctx) {
35
+ return runWithWorkspaceContext(ctx, async() => {
36
+ const result = await invokeEnterpriseMcpCapability(ctx, 'repository.status', {});
37
+ return { capabilityKey: 'repository.status', result };
38
+ });
39
+ }
40
+
41
+ /**
42
+ * @param {import('./workspace-context').WorkspaceContext} ctx
43
+ * @param {Object} body
44
+ */
45
+ async function runRepositoryDispatchPipeline(ctx, body = {}) {
46
+ return runEnterpriseMcpCapability(ctx, 'repository.dispatchPipeline', body);
47
+ }
48
+
49
+ module.exports = {
50
+ runRepositorySync,
51
+ runRepositoryCreateReview,
52
+ getRepositoryStatus,
53
+ runRepositoryDispatchPipeline
54
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Template and workspace Enterprise MCP route handlers (154.1).
3
+ *
4
+ * @fileoverview Provider-neutral template.* and workspace.* capabilities
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { runEnterpriseMcpCapability } = require('./run-enterprise-mcp');
12
+ const { getSystemManifest } = require('./workspace-ops');
13
+ const { invokeEnterpriseMcpCapability } = require('./enterprise-mcp-client');
14
+ const { runWithWorkspaceContext } = require('./workspace-context');
15
+
16
+ /**
17
+ * @param {import('./workspace-context').WorkspaceContext} ctx
18
+ * @param {Object} body
19
+ */
20
+ async function materializeTemplate(ctx, body = {}) {
21
+ return runEnterpriseMcpCapability(ctx, 'template.materializeWorkspace', body);
22
+ }
23
+
24
+ /**
25
+ * @param {import('./workspace-context').WorkspaceContext} ctx
26
+ */
27
+ async function getWorkspaceStatus(ctx) {
28
+ return runWithWorkspaceContext(ctx, async() => {
29
+ const local = getSystemManifest(ctx);
30
+ let remote = null;
31
+ try {
32
+ remote = await invokeEnterpriseMcpCapability(ctx, 'workspace.status', {});
33
+ } catch (err) {
34
+ remote = { unavailable: true, message: err.message };
35
+ }
36
+ return { local, remote };
37
+ });
38
+ }
39
+
40
+ /**
41
+ * @param {import('./workspace-context').WorkspaceContext} ctx
42
+ * @param {Object} body
43
+ */
44
+ async function runWorkspaceDiff(ctx, body = {}) {
45
+ return runEnterpriseMcpCapability(ctx, 'workspace.diff', body);
46
+ }
47
+
48
+ /**
49
+ * @param {import('./workspace-context').WorkspaceContext} ctx
50
+ * @param {Object} body
51
+ */
52
+ async function resetWorkspaceFromTemplate(ctx, body = {}) {
53
+ return runEnterpriseMcpCapability(ctx, 'workspace.resetFromTemplate', body);
54
+ }
55
+
56
+ module.exports = {
57
+ materializeTemplate,
58
+ getWorkspaceStatus,
59
+ runWorkspaceDiff,
60
+ resetWorkspaceFromTemplate
61
+ };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Programmatic test wrapper (unit | integration | e2e).
3
+ *
4
+ * @fileoverview POST /test
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { testExternalSystem, testExternalSystemIntegration } = require('../external-system/test');
12
+ const { runTestE2EForExternalSystem } = require('../commands/test-e2e-external');
13
+ const { runWithWorkspaceContext } = require('./workspace-context');
14
+ const { mergeProgrammaticOptions } = require('./command-options');
15
+ const { touchWorkspaceMeta } = require('./workspace-meta');
16
+
17
+ /**
18
+ * @param {string} runType
19
+ */
20
+ function assertRunType(runType) {
21
+ const allowed = new Set(['unit', 'integration', 'e2e']);
22
+ if (!allowed.has(runType)) {
23
+ throw new Error('runType must be unit, integration, or e2e');
24
+ }
25
+ }
26
+
27
+ /**
28
+ * @param {import('./workspace-context').WorkspaceContext} ctx
29
+ * @param {Object} [options]
30
+ */
31
+ async function runTest(ctx, options = {}) {
32
+ const runType = options.runType || 'integration';
33
+ assertRunType(runType);
34
+ const merged = mergeProgrammaticOptions(ctx, { ...options, noPublish: options.noPublish === true });
35
+ return runWithWorkspaceContext(ctx, async() => {
36
+ let result;
37
+ if (runType === 'unit') {
38
+ result = await testExternalSystem(ctx.systemKey, merged);
39
+ } else if (runType === 'integration') {
40
+ result = await testExternalSystemIntegration(ctx.systemKey, merged);
41
+ } else {
42
+ result = await runTestE2EForExternalSystem(ctx.systemKey, merged);
43
+ }
44
+ touchWorkspaceMeta(ctx, { lastOperation: `test:${runType}` });
45
+ return result;
46
+ });
47
+ }
48
+
49
+ module.exports = { runTest };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Programmatic upload wrapper — full upload.js chain with workspace + Bearer injection.
3
+ *
4
+ * @fileoverview runUpload for builder-api
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { uploadExternalSystem } = require('../commands/upload');
12
+ const { runWithWorkspaceContext } = require('./workspace-context');
13
+ const { mergeProgrammaticOptions } = require('./command-options');
14
+ const { touchWorkspaceMeta } = require('./workspace-meta');
15
+
16
+ /**
17
+ * @param {import('./workspace-context').WorkspaceContext} ctx
18
+ * @param {Object} [options]
19
+ * @param {boolean} [options.force]
20
+ * @param {boolean} [options.probe]
21
+ * @param {boolean} [options.dryRun]
22
+ * @param {boolean} [options.minimal]
23
+ * @param {boolean} [options.verbose]
24
+ * @returns {Promise<Object|void>}
25
+ */
26
+ async function runUpload(ctx, options = {}) {
27
+ const merged = mergeProgrammaticOptions(ctx, options);
28
+ return runWithWorkspaceContext(ctx, async() => {
29
+ const result = await uploadExternalSystem(ctx.systemKey, merged);
30
+ if (!options.dryRun) {
31
+ touchWorkspaceMeta(ctx, {
32
+ lastOperation: 'upload',
33
+ lastUploadId: result?.uploadId || null
34
+ });
35
+ }
36
+ return result;
37
+ });
38
+ }
39
+
40
+ /**
41
+ * Preview upload manifest without Dataplane mutation (no credential push).
42
+ *
43
+ * @param {import('./workspace-context').WorkspaceContext} ctx
44
+ * @param {Object} [options]
45
+ * @returns {Promise<{ manifest: Object, payload: Object }>}
46
+ */
47
+ async function runPreviewUpload(ctx, options = {}) {
48
+ const { buildValidatedUploadManifestPayload } = require('../commands/upload');
49
+ return runWithWorkspaceContext(ctx, async() => {
50
+ const built = await buildValidatedUploadManifestPayload(ctx.systemKey, {
51
+ force: options.force === true,
52
+ minimal: true,
53
+ quiet: true
54
+ });
55
+ touchWorkspaceMeta(ctx, { lastOperation: 'preview-upload' });
56
+ return built;
57
+ });
58
+ }
59
+
60
+ module.exports = {
61
+ runUpload,
62
+ runPreviewUpload
63
+ };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Programmatic validate wrapper.
3
+ *
4
+ * @fileoverview POST /validate → validateExternalSystemComplete
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('fs');
12
+ const { validateExternalSystemComplete } = require('../validation/validate');
13
+ const { validatePipelineConfig } = require('../api/pipeline.api');
14
+ const { buildValidatedUploadManifestPayload } = require('../commands/upload');
15
+ const { runWithWorkspaceContext } = require('./workspace-context');
16
+ const { mergeProgrammaticOptions } = require('./command-options');
17
+ const { touchWorkspaceMeta } = require('./workspace-meta');
18
+
19
+ /**
20
+ * @param {import('./workspace-context').WorkspaceContext} ctx
21
+ * @param {Object} [options]
22
+ */
23
+ async function runValidate(ctx, options = {}) {
24
+ const integrationPath = ctx.getIntegrationPath();
25
+ if (!fs.existsSync(integrationPath)) {
26
+ const err = new Error('System workspace not found');
27
+ err.statusCode = 404;
28
+ throw err;
29
+ }
30
+ const merged = mergeProgrammaticOptions(ctx, options);
31
+ return runWithWorkspaceContext(ctx, async() => {
32
+ const validationResult = await validateExternalSystemComplete(ctx.systemKey, { type: 'external' });
33
+ let pipelineValidation = null;
34
+ if (options.pipelineValidate === true && validationResult.valid) {
35
+ const { payload } = await buildValidatedUploadManifestPayload(ctx.systemKey, {
36
+ minimal: true,
37
+ quiet: true
38
+ });
39
+ const vr = await validatePipelineConfig(merged.dataplaneUrl, merged.authConfig, {
40
+ config: {
41
+ version: payload.version,
42
+ application: payload.application,
43
+ dataSources: payload.dataSources
44
+ }
45
+ });
46
+ pipelineValidation = vr?.data || vr;
47
+ }
48
+ touchWorkspaceMeta(ctx, { lastOperation: 'validate' });
49
+ return { validationResult, pipelineValidation };
50
+ });
51
+ }
52
+
53
+ module.exports = { runValidate };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Programmatic wizard wrapper.
3
+ *
4
+ * @fileoverview POST /wizard → executeWizardFromConfig
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { executeWizardFromConfig } = require('../commands/wizard-headless');
12
+ const {
13
+ runWithWorkspaceContext,
14
+ ensureIntegrationDirectory,
15
+ WORKSPACE_INTEGRATION_FORMAT
16
+ } = require('./workspace-context');
17
+ const { buildProgrammaticAuthContext } = require('./auth-config');
18
+ const { touchWorkspaceMeta } = require('./workspace-meta');
19
+ const { normalizeWizardConfig } = require('./wizard-config-normalize');
20
+
21
+ /**
22
+ * @param {import('./workspace-context').WorkspaceContext} ctx
23
+ * @param {Object} wizardConfig
24
+ * @param {Object} [options]
25
+ */
26
+ async function runWizard(ctx, wizardConfig, options = {}) {
27
+ const normalizedConfig = normalizeWizardConfig(wizardConfig, ctx.systemKey);
28
+ const auth = buildProgrammaticAuthContext(ctx);
29
+ return runWithWorkspaceContext(ctx, async() => {
30
+ ensureIntegrationDirectory(ctx);
31
+ await executeWizardFromConfig(normalizedConfig, auth.dataplaneUrl, auth.authConfig, {
32
+ debug: options.debug === true,
33
+ format: WORKSPACE_INTEGRATION_FORMAT
34
+ });
35
+ touchWorkspaceMeta(ctx, { lastOperation: 'wizard' });
36
+ return { systemKey: ctx.systemKey, status: 'completed' };
37
+ });
38
+ }
39
+
40
+ module.exports = { runWizard };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * System key validation for builder-api workspaces.
3
+ *
4
+ * @fileoverview Sanitize external system keys (same rules as upload.js)
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const SYSTEM_KEY_RE = /^[a-z0-9-_]+$/;
12
+
13
+ /**
14
+ * @param {string} systemKey
15
+ * @returns {string}
16
+ */
17
+ function assertValidSystemKey(systemKey) {
18
+ if (!systemKey || typeof systemKey !== 'string') {
19
+ throw new Error('System key is required and must be a string');
20
+ }
21
+ if (!SYSTEM_KEY_RE.test(systemKey)) {
22
+ throw new Error('System key must contain only lowercase letters, numbers, hyphens, and underscores');
23
+ }
24
+ return systemKey;
25
+ }
26
+
27
+ /**
28
+ * @param {string} userId
29
+ * @returns {string}
30
+ */
31
+ function assertValidUserId(userId) {
32
+ if (!userId || typeof userId !== 'string') {
33
+ throw new Error('userId is required and must be a string');
34
+ }
35
+ if (userId.includes('..') || userId.includes('/') || userId.includes('\\')) {
36
+ throw new Error('Invalid userId');
37
+ }
38
+ if (userId.length > 256) {
39
+ throw new Error('Invalid userId');
40
+ }
41
+ return userId;
42
+ }
43
+
44
+ module.exports = {
45
+ assertValidSystemKey,
46
+ assertValidUserId,
47
+ SYSTEM_KEY_RE
48
+ };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Normalize Builder API wizard JSON into wizard-headless shape.
3
+ *
4
+ * @fileoverview Maps OpenAPI camelCase source types; rewrites localhost OpenAPI URLs for dataplane fetch
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /** @type {Readonly<Record<string, string>>} */
12
+ const SOURCE_TYPE_MAP = Object.freeze({
13
+ openapiUrl: 'openapi-url',
14
+ openapiFile: 'openapi-file',
15
+ mcpServer: 'mcp-server',
16
+ knownPlatform: 'known-platform'
17
+ });
18
+
19
+ /**
20
+ * Rewrite localhost OpenAPI URLs so dataplane can fetch from the builder-api container.
21
+ *
22
+ * @param {string} url
23
+ * @returns {string}
24
+ */
25
+ function resolveOpenApiUrlForDataplaneFetch(url) {
26
+ if (!url || typeof url !== 'string') {
27
+ return url;
28
+ }
29
+ try {
30
+ const parsed = new URL(url);
31
+ if (parsed.hostname !== 'localhost' && parsed.hostname !== '127.0.0.1') {
32
+ return url;
33
+ }
34
+ const internalHost = process.env.BUILDER_API_INTERNAL_HOST || process.env.HOSTNAME;
35
+ const internalPort = process.env.PORT || '3005';
36
+ if (!internalHost) {
37
+ return url;
38
+ }
39
+ parsed.protocol = 'http:';
40
+ parsed.hostname = internalHost;
41
+ parsed.port = String(internalPort);
42
+ return parsed.toString();
43
+ } catch {
44
+ return url;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * @param {Object} [source]
50
+ * @returns {Object|undefined}
51
+ */
52
+ function normalizeWizardSource(source) {
53
+ if (!source || typeof source !== 'object') {
54
+ return source;
55
+ }
56
+ const type = SOURCE_TYPE_MAP[source.type] || source.type;
57
+ const out = { ...source, type };
58
+ if (type === 'openapi-url' && out.url) {
59
+ out.url = resolveOpenApiUrlForDataplaneFetch(out.url);
60
+ }
61
+ if (type === 'openapi-file' && out.path && !out.filePath) {
62
+ out.filePath = out.path;
63
+ }
64
+ return out;
65
+ }
66
+
67
+ /**
68
+ * @param {Object} [preferences]
69
+ * @returns {Object}
70
+ */
71
+ function normalizeWizardPreferences(preferences = {}) {
72
+ const prefs = { ...preferences };
73
+ if (prefs.rbac === true && prefs.enableRBAC === undefined) {
74
+ prefs.enableRBAC = true;
75
+ }
76
+ if (prefs.expose === true && prefs.enableOpenAPIGeneration === undefined) {
77
+ prefs.enableOpenAPIGeneration = true;
78
+ }
79
+ if (prefs.mcp === true && prefs.enableMCP === undefined) {
80
+ prefs.enableMCP = true;
81
+ }
82
+ if (!prefs.intent) {
83
+ prefs.intent = 'general integration';
84
+ }
85
+ if (!prefs.fieldOnboardingLevel) {
86
+ prefs.fieldOnboardingLevel = 'full';
87
+ }
88
+ if (prefs.enableOpenAPIGeneration === undefined) {
89
+ prefs.enableOpenAPIGeneration = true;
90
+ }
91
+ return prefs;
92
+ }
93
+
94
+ /**
95
+ * @param {Object} wizardConfig
96
+ * @param {string} systemKey
97
+ * @returns {Object}
98
+ */
99
+ function normalizeWizardConfig(wizardConfig, systemKey) {
100
+ if (!wizardConfig || typeof wizardConfig !== 'object') {
101
+ throw new Error('wizardConfig body is required');
102
+ }
103
+ return {
104
+ mode: 'create-system',
105
+ ...wizardConfig,
106
+ appName: systemKey,
107
+ source: normalizeWizardSource(wizardConfig.source),
108
+ preferences: normalizeWizardPreferences(wizardConfig.preferences)
109
+ };
110
+ }
111
+
112
+ module.exports = {
113
+ SOURCE_TYPE_MAP,
114
+ resolveOpenApiUrlForDataplaneFetch,
115
+ normalizeWizardSource,
116
+ normalizeWizardPreferences,
117
+ normalizeWizardConfig
118
+ };
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Expired workspace purge for builder-api (plan 154.0 §8).
3
+ *
4
+ * @fileoverview Draft TTL + inactive max age cleanup job
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('../internal/fs-real-sync');
12
+ const path = require('path');
13
+ const { resolveWorkspaceRoot } = require('./workspace-context');
14
+ const { META_FILENAME } = require('./workspace-meta');
15
+ const { writeAccessLog } = require('./access-log');
16
+
17
+ const MS_PER_DAY = 24 * 60 * 60 * 1000;
18
+
19
+ /**
20
+ * @param {string} isoDate
21
+ * @returns {number}
22
+ */
23
+ function daysSince(isoDate) {
24
+ return (Date.now() - new Date(isoDate).getTime()) / MS_PER_DAY;
25
+ }
26
+
27
+ /**
28
+ * @param {Object} meta
29
+ * @param {{ draftTtlDays?: number, inactiveMaxDays?: number }} options
30
+ * @returns {boolean}
31
+ */
32
+ function shouldPurgeWorkspace(meta, options) {
33
+ const modified = meta.lastModifiedAt || meta.createdAt;
34
+ if (!modified) {
35
+ return false;
36
+ }
37
+ const ageDays = daysSince(modified);
38
+ const inactiveMaxDays = Number(options.inactiveMaxDays ?? process.env.WORKSPACE_INACTIVE_MAX_DAYS ?? 180);
39
+ const draftTtlDays = Number(options.draftTtlDays ?? process.env.WORKSPACE_DRAFT_TTL_DAYS ?? 90);
40
+ if (ageDays > inactiveMaxDays) {
41
+ return true;
42
+ }
43
+ if (!meta.lastUploadId && ageDays > draftTtlDays) {
44
+ return true;
45
+ }
46
+ return false;
47
+ }
48
+
49
+ /**
50
+ * @param {string} metaPath
51
+ * @returns {Object|null}
52
+ */
53
+ function readMetaFile(metaPath) {
54
+ if (!fs.existsSync(metaPath)) {
55
+ return null;
56
+ }
57
+ return JSON.parse(fs.readFileSync(metaPath, 'utf8'));
58
+ }
59
+
60
+ /**
61
+ * @param {string} integrationRoot
62
+ * @param {string} userId
63
+ * @param {Object} options
64
+ * @param {boolean} dryRun
65
+ * @param {Object[]} purged
66
+ */
67
+ function collectExpiredSystemsUnderUser(integrationRoot, userId, options, dryRun, purged) {
68
+ for (const systemKey of fs.readdirSync(integrationRoot)) {
69
+ const systemPath = path.join(integrationRoot, systemKey);
70
+ if (!fs.statSync(systemPath).isDirectory()) {
71
+ continue;
72
+ }
73
+ const meta = readMetaFile(path.join(systemPath, META_FILENAME));
74
+ if (!meta || !shouldPurgeWorkspace(meta, options)) {
75
+ continue;
76
+ }
77
+ if (!dryRun) {
78
+ fs.rmSync(systemPath, { recursive: true, force: true });
79
+ }
80
+ purged.push({
81
+ userId,
82
+ systemKey,
83
+ lastModifiedAt: meta.lastModifiedAt,
84
+ lastUploadId: meta.lastUploadId ?? null
85
+ });
86
+ }
87
+ }
88
+
89
+ /**
90
+ * @param {Object} [options]
91
+ * @param {string} [options.workspaceRoot]
92
+ * @param {number} [options.draftTtlDays]
93
+ * @param {number} [options.inactiveMaxDays]
94
+ * @param {boolean} [options.dryRun]
95
+ * @returns {{ purged: Object[], count: number, dryRun: boolean }}
96
+ */
97
+ function purgeExpiredWorkspaces(options = {}) {
98
+ const workspaceRoot = resolveWorkspaceRoot(options.workspaceRoot);
99
+ const dryRun = options.dryRun === true;
100
+ const purged = [];
101
+
102
+ if (!fs.existsSync(workspaceRoot)) {
103
+ return { purged, count: 0, dryRun };
104
+ }
105
+
106
+ for (const userId of fs.readdirSync(workspaceRoot)) {
107
+ const integrationRoot = path.join(workspaceRoot, userId, 'integration');
108
+ if (!fs.existsSync(integrationRoot)) {
109
+ continue;
110
+ }
111
+ collectExpiredSystemsUnderUser(integrationRoot, userId, options, dryRun, purged);
112
+ }
113
+
114
+ writeAccessLog({
115
+ event: 'workspaceCleanup',
116
+ count: purged.length,
117
+ dryRun,
118
+ purgedSystemKeys: purged.map((row) => `${row.userId}/${row.systemKey}`)
119
+ });
120
+
121
+ return { purged, count: purged.length, dryRun };
122
+ }
123
+
124
+ module.exports = {
125
+ purgeExpiredWorkspaces,
126
+ shouldPurgeWorkspace,
127
+ daysSince
128
+ };