@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,189 @@
1
+ import { spawn } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { resolveAifabrixBin } from './resolve-aifabrix-bin.mjs';
6
+ import { resolveAppUrl } from './resolve-app-url.mjs';
7
+ import { createSpinner } from './spinner.mjs';
8
+
9
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
10
+ const LOG_FILE = 'dev-reload.log';
11
+ const CAPTURE_PID_FILE = 'dev-reload-capture.pid';
12
+
13
+ /**
14
+ * @typedef {Object} DevReloadProfile
15
+ * @property {string} appKey
16
+ * @property {string} displayName
17
+ * @property {number} portBase
18
+ * @property {string} [webServerUrlEnvKey]
19
+ * @property {string} [healthPath]
20
+ * @property {boolean} [apiOnly]
21
+ * @property {string} [uiBuildCommand]
22
+ * @property {string} [uiOutputDir]
23
+ */
24
+
25
+ /**
26
+ * @param {DevReloadProfile} profile
27
+ * @returns {Promise<void>}
28
+ */
29
+ export async function runDevReload(profile) {
30
+ const logPath = prepareLogFile();
31
+ appendSessionBanner(profile.appKey, logPath);
32
+
33
+ const aifabrix = resolveAifabrixBin();
34
+ const spinner = createSpinner(`Starting ${profile.displayName} (live reload)…`);
35
+ spinner.start();
36
+
37
+ await runToLogFile(aifabrix, ['resolve', profile.appKey], logPath);
38
+ const runExit = await runToLogFile(aifabrix, ['run', profile.appKey, '--reload'], logPath);
39
+ if (runExit !== 0) {
40
+ spinner.stop();
41
+ printRunFailure(logPath);
42
+ process.exit(runExit);
43
+ }
44
+ spinner.stop();
45
+
46
+ startBackgroundLogCapture(profile.appKey, logPath);
47
+ printDevReloadSummary(profile, logPath);
48
+ }
49
+
50
+ /**
51
+ * @returns {string}
52
+ */
53
+ function prepareLogFile() {
54
+ const logDir = path.join(repoRoot, '.temp');
55
+ fs.mkdirSync(logDir, { recursive: true });
56
+ const logPath = path.join(logDir, LOG_FILE);
57
+ fs.writeFileSync(logPath, '');
58
+ return logPath;
59
+ }
60
+
61
+ /**
62
+ * @returns {string}
63
+ */
64
+ function capturePidPath() {
65
+ return path.join(repoRoot, '.temp', CAPTURE_PID_FILE);
66
+ }
67
+
68
+ function stopPreviousCapture() {
69
+ const pidPath = capturePidPath();
70
+ if (!fs.existsSync(pidPath)) {
71
+ return;
72
+ }
73
+ const pid = Number.parseInt(fs.readFileSync(pidPath, 'utf8').trim(), 10);
74
+ if (!pid) {
75
+ return;
76
+ }
77
+ try {
78
+ process.kill(pid, 'SIGTERM');
79
+ } catch {
80
+ // already stopped
81
+ }
82
+ }
83
+
84
+ /**
85
+ * @param {string} appKey
86
+ * @param {string} logPath
87
+ */
88
+ function startBackgroundLogCapture(appKey, logPath) {
89
+ stopPreviousCapture();
90
+
91
+ const captureScript = path.join(
92
+ path.dirname(fileURLToPath(import.meta.url)),
93
+ 'dev-reload-log-capture.mjs'
94
+ );
95
+ const child = spawn(process.execPath, [captureScript, appKey, logPath], {
96
+ cwd: repoRoot,
97
+ env: process.env,
98
+ detached: true,
99
+ stdio: 'ignore'
100
+ });
101
+ child.unref();
102
+ fs.writeFileSync(capturePidPath(), String(child.pid));
103
+ }
104
+
105
+ /**
106
+ * @param {DevReloadProfile} profile
107
+ * @param {string} logPath
108
+ */
109
+ function printDevReloadSummary(profile, logPath) {
110
+ const appUrl = resolveAppUrl(profile, { repoRoot }).replace(/\/+$/, '');
111
+ const absLog = path.resolve(logPath);
112
+ const healthUrl = profile.healthPath ? `${appUrl}${profile.healthPath}` : `${appUrl}/`;
113
+
114
+ console.log('');
115
+ console.log('═'.repeat(60));
116
+ console.log(` ${profile.displayName} — live reload (Docker)`);
117
+ console.log('═'.repeat(60));
118
+ console.log('');
119
+ console.log(` App URL: ${appUrl}/`);
120
+ if (profile.healthPath) {
121
+ console.log(` Health: ${healthUrl}`);
122
+ }
123
+ console.log(` Logs: ${absLog}`);
124
+ console.log('');
125
+ console.log(' Backend code on mounted paths reloads automatically.');
126
+ if (!profile.apiOnly && profile.uiBuildCommand && profile.uiOutputDir) {
127
+ console.log('');
128
+ console.log(' UI changes: run');
129
+ console.log(` ${profile.uiBuildCommand}`);
130
+ console.log(` → ${profile.uiOutputDir}`);
131
+ }
132
+ console.log('');
133
+ console.log(' Log capture runs in the background (this command exits).');
134
+ console.log('═'.repeat(60));
135
+ console.log('');
136
+ }
137
+
138
+ /**
139
+ * @param {string} logPath
140
+ */
141
+ function printRunFailure(logPath) {
142
+ console.error(`\n[dev-reload] Start failed. Logs: ${path.resolve(logPath)}\n`);
143
+ if (!fs.existsSync(logPath)) {
144
+ return;
145
+ }
146
+ const lines = fs.readFileSync(logPath, 'utf8').trim().split('\n').filter(Boolean);
147
+ const tail = lines.slice(-15).join('\n');
148
+ if (tail) {
149
+ console.error(tail);
150
+ console.error('');
151
+ }
152
+ }
153
+
154
+ /**
155
+ * @param {string} appKey
156
+ * @param {string} logPath
157
+ */
158
+ function appendSessionBanner(appKey, logPath) {
159
+ const banner =
160
+ `\n${'='.repeat(72)}\n` +
161
+ `[${new Date().toISOString()}] dev-reload session: ${appKey}\n` +
162
+ `${'='.repeat(72)}\n`;
163
+ fs.appendFileSync(logPath, banner);
164
+ }
165
+
166
+ /**
167
+ * @param {string} command
168
+ * @param {string[]} args
169
+ * @param {string} logPath
170
+ * @returns {Promise<number>}
171
+ */
172
+ function runToLogFile(command, args, logPath) {
173
+ return new Promise((resolve) => {
174
+ const proc = spawn(command, args, {
175
+ cwd: repoRoot,
176
+ env: process.env,
177
+ stdio: ['ignore', 'pipe', 'pipe']
178
+ });
179
+
180
+ const append = (chunk) => {
181
+ fs.appendFileSync(logPath, chunk);
182
+ };
183
+
184
+ proc.stdout.on('data', append);
185
+ proc.stderr.on('data', append);
186
+ proc.on('close', (code) => resolve(typeof code === 'number' ? code : 1));
187
+ proc.on('error', () => resolve(1));
188
+ });
189
+ }
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Background log capture for dev-reload (detached child).
4
+ * Usage: node dev-reload-log-capture.mjs <appKey> <logPath>
5
+ */
6
+ import { spawn } from 'node:child_process';
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import readline from 'node:readline';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { resolveAifabrixBin } from './resolve-aifabrix-bin.mjs';
12
+ import { resolveLogKeys } from './dev-reload-log-utils.mjs';
13
+
14
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
15
+ const appKey = process.argv[2];
16
+ const logPath = process.argv[3];
17
+
18
+ if (!appKey || !logPath) {
19
+ console.error('Usage: node dev-reload-log-capture.mjs <appKey> <logPath>');
20
+ process.exit(2);
21
+ }
22
+
23
+ const aifabrix = resolveAifabrixBin();
24
+ const logKeys = resolveLogKeys(repoRoot, appKey);
25
+
26
+ await Promise.all(
27
+ logKeys.map((key) => followAppLogsToFile(aifabrix, key, logPath, key === appKey))
28
+ );
29
+
30
+ /**
31
+ * @param {string} aifabrix
32
+ * @param {string} key
33
+ * @param {string} filePath
34
+ * @param {boolean} required
35
+ */
36
+ function followAppLogsToFile(aifabrix, key, filePath, required) {
37
+ return new Promise((resolve, reject) => {
38
+ const proc = spawn(aifabrix, ['logs', key, '-f', '--tail', '100'], {
39
+ cwd: repoRoot,
40
+ env: process.env,
41
+ stdio: ['ignore', 'pipe', 'pipe']
42
+ });
43
+
44
+ const prefix = `[${key}] `;
45
+ const onLine = (line) => {
46
+ fs.appendFileSync(filePath, `${new Date().toISOString()} ${prefix}${line}\n`);
47
+ };
48
+
49
+ readline.createInterface({ input: proc.stdout }).on('line', onLine);
50
+ readline.createInterface({ input: proc.stderr }).on('line', onLine);
51
+
52
+ proc.on('close', (code) => {
53
+ if (code !== 0 && required) {
54
+ reject(new Error(`Log capture ended for ${key} (exit ${code ?? 1})`));
55
+ return;
56
+ }
57
+ resolve();
58
+ });
59
+ proc.on('error', (err) => {
60
+ if (required) {
61
+ reject(err);
62
+ return;
63
+ }
64
+ resolve();
65
+ });
66
+ });
67
+ }
@@ -0,0 +1,32 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ /**
5
+ * @param {string} repoRoot
6
+ * @param {string} appKey
7
+ * @returns {string[]}
8
+ */
9
+ export function resolveLogKeys(repoRoot, appKey) {
10
+ return [appKey, ...readCompanionKeys(repoRoot, appKey)];
11
+ }
12
+
13
+ /**
14
+ * @param {string} repoRoot
15
+ * @param {string} appKey
16
+ * @returns {string[]}
17
+ */
18
+ function readCompanionKeys(repoRoot, appKey) {
19
+ const yamlPath = path.join(repoRoot, 'builder', appKey, 'application.yaml');
20
+ if (!fs.existsSync(yamlPath)) {
21
+ return [];
22
+ }
23
+ const text = fs.readFileSync(yamlPath, 'utf8');
24
+ if (!/^\s*worker:\s*true\s*$/m.test(text)) {
25
+ return [];
26
+ }
27
+ const companions = [`${appKey}-worker`];
28
+ if (/^\s*imageRunBeat:/m.test(text)) {
29
+ companions.push(`${appKey}-beat`);
30
+ }
31
+ return companions;
32
+ }
@@ -0,0 +1,124 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
8
+
9
+ /** application.yaml / platform apps need manifest-aware builder (not variables.yaml-only CLIs). */
10
+ const MIN_AIFABRIX_VERSION = '2.45.0';
11
+
12
+ /**
13
+ * @param {string} version
14
+ * @returns {number[]}
15
+ */
16
+ function parseSemver(version) {
17
+ return String(version)
18
+ .trim()
19
+ .split('.')
20
+ .map((part) => parseInt(part, 10) || 0);
21
+ }
22
+
23
+ /**
24
+ * @param {string} left
25
+ * @param {string} right
26
+ * @returns {number}
27
+ */
28
+ function compareSemver(left, right) {
29
+ const a = parseSemver(left);
30
+ const b = parseSemver(right);
31
+ for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
32
+ const av = a[i] || 0;
33
+ const bv = b[i] || 0;
34
+ if (av > bv) return 1;
35
+ if (av < bv) return -1;
36
+ }
37
+ return 0;
38
+ }
39
+
40
+ /**
41
+ * @param {string} bin
42
+ * @returns {string|null}
43
+ */
44
+ function readAifabrixVersion(bin) {
45
+ try {
46
+ return execFileSync(bin, ['--version'], { encoding: 'utf8' }).trim();
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * @returns {string[]}
54
+ */
55
+ function collectAifabrixCandidates() {
56
+ const candidates = [];
57
+ const seen = new Set();
58
+
59
+ const push = (candidate) => {
60
+ if (!candidate || seen.has(candidate)) {
61
+ return;
62
+ }
63
+ seen.add(candidate);
64
+ candidates.push(candidate);
65
+ };
66
+
67
+ push(path.join(repoRoot, 'bin', 'aifabrix.js'));
68
+
69
+ if (process.env.AIFABRIX_CLI) {
70
+ push(process.env.AIFABRIX_CLI);
71
+ }
72
+
73
+ const home = os.homedir();
74
+ push(path.join(home, '.npm-global', 'bin', 'aifabrix'));
75
+ push(path.join(home, '.local', 'bin', 'aifabrix'));
76
+
77
+ for (const dir of (process.env.PATH || '').split(path.delimiter)) {
78
+ if (!dir) continue;
79
+ push(path.join(dir, 'aifabrix'));
80
+ }
81
+
82
+ return candidates;
83
+ }
84
+
85
+ /**
86
+ * Prefer this repo's bin/aifabrix.js when developing the builder package locally.
87
+ *
88
+ * @returns {string}
89
+ */
90
+ export function resolveAifabrixBin() {
91
+ let bestBin = null;
92
+ let bestVersion = null;
93
+
94
+ for (const candidate of collectAifabrixCandidates()) {
95
+ let resolved = candidate;
96
+ try {
97
+ if (fs.existsSync(candidate)) {
98
+ resolved = fs.realpathSync(candidate);
99
+ } else {
100
+ continue;
101
+ }
102
+ } catch {
103
+ continue;
104
+ }
105
+
106
+ const version = readAifabrixVersion(resolved);
107
+ if (!version) {
108
+ continue;
109
+ }
110
+ if (!bestVersion || compareSemver(version, bestVersion) > 0) {
111
+ bestBin = resolved;
112
+ bestVersion = version;
113
+ }
114
+ }
115
+
116
+ if (!bestBin || !bestVersion || compareSemver(bestVersion, MIN_AIFABRIX_VERSION) < 0) {
117
+ throw new Error(
118
+ `@aifabrix/builder >= ${MIN_AIFABRIX_VERSION} is required (found ${bestVersion || 'none'}). ` +
119
+ 'Install: npm run install:local — or set AIFABRIX_CLI to a newer aifabrix binary.'
120
+ );
121
+ }
122
+
123
+ return bestBin;
124
+ }
@@ -0,0 +1,183 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+
6
+ /**
7
+ * @typedef {Object} AppUrlProfile
8
+ * @property {string} appKey
9
+ * @property {number} portBase
10
+ * @property {string} [webServerUrlEnvKey]
11
+ * @property {string} [healthPath]
12
+ */
13
+
14
+ /**
15
+ * @returns {string}
16
+ */
17
+ function readDeveloperIdRaw() {
18
+ const configPath = path.join(os.homedir(), '.aifabrix', 'config.yaml');
19
+ if (!fs.existsSync(configPath)) {
20
+ return '0';
21
+ }
22
+ const match = fs.readFileSync(configPath, 'utf8').match(/^developer-id:\s*['"]?(\d+)['"]?\s*$/m);
23
+ return match ? match[1] : '0';
24
+ }
25
+
26
+ /**
27
+ * @param {string} appKey
28
+ * @param {string} developerIdRaw
29
+ * @returns {string}
30
+ */
31
+ function buildContainerName(appKey, developerIdRaw) {
32
+ const idNum = Number.parseInt(developerIdRaw, 10) || 0;
33
+ if (idNum === 0) {
34
+ return `aifabrix-${appKey}`;
35
+ }
36
+ return `aifabrix-dev${developerIdRaw}-${appKey}`;
37
+ }
38
+
39
+ /**
40
+ * @param {string} filePath
41
+ * @returns {Record<string, string>}
42
+ */
43
+ function parseEnvFile(filePath) {
44
+ const values = {};
45
+ for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
46
+ const trimmed = line.trim();
47
+ if (!trimmed || trimmed.startsWith('#')) {
48
+ continue;
49
+ }
50
+ const eq = trimmed.indexOf('=');
51
+ if (eq === -1) {
52
+ continue;
53
+ }
54
+ const key = trimmed.slice(0, eq).trim();
55
+ let value = trimmed.slice(eq + 1).trim();
56
+ if (
57
+ (value.startsWith('"') && value.endsWith('"')) ||
58
+ (value.startsWith("'") && value.endsWith("'"))
59
+ ) {
60
+ value = value.slice(1, -1);
61
+ }
62
+ values[key] = value;
63
+ }
64
+ return values;
65
+ }
66
+
67
+ /**
68
+ * @param {string} raw
69
+ * @returns {string|null}
70
+ */
71
+ function normalizeHttpUrl(raw) {
72
+ const trimmed = raw?.trim();
73
+ if (!trimmed || trimmed.startsWith('kv://')) {
74
+ return null;
75
+ }
76
+ try {
77
+ const parsed = new URL(trimmed);
78
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
79
+ return null;
80
+ }
81
+ return parsed.toString().replace(/\/+$/, '');
82
+ } catch {
83
+ return null;
84
+ }
85
+ }
86
+
87
+ /**
88
+ * @param {string} repoRoot
89
+ * @param {string} appKey
90
+ * @param {string} envKey
91
+ * @returns {string|null}
92
+ */
93
+ function readBuilderEnvUrl(repoRoot, appKey, envKey) {
94
+ const envPath = path.join(repoRoot, 'builder', appKey, '.env');
95
+ if (!fs.existsSync(envPath)) {
96
+ return null;
97
+ }
98
+ return normalizeHttpUrl(parseEnvFile(envPath)[envKey]);
99
+ }
100
+
101
+ /**
102
+ * @param {string} containerName
103
+ * @param {string} envKey
104
+ * @returns {string|null}
105
+ */
106
+ function readContainerEnvUrl(containerName, envKey) {
107
+ const result = spawnSync('docker', ['exec', containerName, 'env'], {
108
+ encoding: 'utf8',
109
+ timeout: 8000
110
+ });
111
+ if (result.status !== 0) {
112
+ return null;
113
+ }
114
+ for (const line of result.stdout.split('\n')) {
115
+ if (!line.startsWith(`${envKey}=`)) {
116
+ continue;
117
+ }
118
+ return normalizeHttpUrl(line.slice(envKey.length + 1));
119
+ }
120
+ return null;
121
+ }
122
+
123
+ /**
124
+ * @param {string} containerName
125
+ * @returns {string|null}
126
+ */
127
+ function readDockerPublishedUrl(containerName) {
128
+ const result = spawnSync(
129
+ 'docker',
130
+ ['ps', '--filter', `name=^/${containerName}$`, '--format', '{{.Ports}}'],
131
+ { encoding: 'utf8', timeout: 8000 }
132
+ );
133
+ if (result.status !== 0) {
134
+ return null;
135
+ }
136
+ const portMatch = result.stdout.match(/:(\d+)->\d+\//);
137
+ if (!portMatch) {
138
+ return null;
139
+ }
140
+ return `http://localhost:${portMatch[1]}`;
141
+ }
142
+
143
+ /**
144
+ * @param {number} portBase
145
+ * @returns {number}
146
+ */
147
+ function resolveHostPort(portBase) {
148
+ const devId = Number.parseInt(readDeveloperIdRaw(), 10) || 0;
149
+ return devId === 0 ? portBase : portBase + devId * 100;
150
+ }
151
+
152
+ /**
153
+ * @param {AppUrlProfile} profile
154
+ * @param {{ repoRoot: string }} options
155
+ * @returns {string}
156
+ */
157
+ export function resolveAppUrl(profile, options) {
158
+ const { repoRoot } = options;
159
+ const envKey = profile.webServerUrlEnvKey;
160
+ const containerName = buildContainerName(profile.appKey, readDeveloperIdRaw());
161
+
162
+ if (envKey) {
163
+ const fromContainer = readContainerEnvUrl(containerName, envKey);
164
+ if (fromContainer) {
165
+ return `${fromContainer}/`;
166
+ }
167
+ }
168
+
169
+ const fromDockerPort = readDockerPublishedUrl(containerName);
170
+ if (fromDockerPort) {
171
+ return `${fromDockerPort}/`;
172
+ }
173
+
174
+ if (envKey) {
175
+ const fromBuilderEnv = readBuilderEnvUrl(repoRoot, profile.appKey, envKey);
176
+ if (fromBuilderEnv) {
177
+ return `${fromBuilderEnv}/`;
178
+ }
179
+ }
180
+
181
+ const port = resolveHostPort(profile.portBase);
182
+ return `http://localhost:${port}/`;
183
+ }
@@ -0,0 +1,42 @@
1
+ /** Minimal TTY spinner (no extra dependencies). */
2
+
3
+ const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
4
+
5
+ /**
6
+ * @param {string} label
7
+ * @returns {{ start: () => void, stop: (finalLine?: string) => void }}
8
+ */
9
+ export function createSpinner(label) {
10
+ let frameIndex = 0;
11
+ /** @type {NodeJS.Timeout | null} */
12
+ let timer = null;
13
+ const enabled = process.stdout.isTTY && process.env.CI !== 'true';
14
+
15
+ function clearLine() {
16
+ if (enabled) {
17
+ process.stdout.write('\r\x1b[K');
18
+ }
19
+ }
20
+
21
+ return {
22
+ start() {
23
+ if (!enabled) {
24
+ console.log(label);
25
+ return;
26
+ }
27
+ timer = setInterval(() => {
28
+ process.stdout.write(`\r${FRAMES[frameIndex++ % FRAMES.length]} ${label}`);
29
+ }, 80);
30
+ },
31
+ stop(finalLine) {
32
+ if (timer) {
33
+ clearInterval(timer);
34
+ timer = null;
35
+ }
36
+ clearLine();
37
+ if (finalLine) {
38
+ console.log(finalLine);
39
+ }
40
+ }
41
+ };
42
+ }
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Stage builder-api runtime files for Docker image build (plan 154.3).
4
+ *
5
+ * @fileoverview Host-side staging before `docker build`
6
+ * @author AI Fabrix Team
7
+ * @version 1.0.0
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const {
15
+ discoverRuntimeFiles,
16
+ findManifestViolations
17
+ } = require('./lib/builder-api-docker-staging-core');
18
+ const { stageFiles } = require('./lib/builder-api-docker-staging-copy');
19
+
20
+ const REPO_ROOT = path.resolve(__dirname, '..');
21
+
22
+ /**
23
+ * @param {string[]} argv
24
+ * @returns {number}
25
+ */
26
+ function main(argv) {
27
+ const args = argv.slice(2);
28
+ let destination = path.join(REPO_ROOT, 'docker-builder-api-staging');
29
+ let manifestPath = '';
30
+
31
+ for (let i = 0; i < args.length; i += 1) {
32
+ if (args[i] === '--destination' && args[i + 1]) {
33
+ destination = path.resolve(args[i + 1]);
34
+ i += 1;
35
+ } else if (args[i] === '--manifest' && args[i + 1]) {
36
+ manifestPath = path.resolve(args[i + 1]);
37
+ i += 1;
38
+ }
39
+ }
40
+
41
+ const manifest = discoverRuntimeFiles(REPO_ROOT);
42
+ const violations = findManifestViolations(manifest);
43
+ if (violations.length > 0) {
44
+ console.error('Staging manifest contains forbidden paths:');
45
+ for (const item of violations) {
46
+ console.error(` - ${item}`);
47
+ }
48
+ return 1;
49
+ }
50
+
51
+ const staged = stageFiles(REPO_ROOT, destination, manifest);
52
+ if (manifestPath) {
53
+ fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
54
+ fs.writeFileSync(manifestPath, `${JSON.stringify(staged, null, 2)}\n`, 'utf8');
55
+ }
56
+
57
+ console.log(`OK: staged ${staged.length} files → ${destination}`);
58
+ return 0;
59
+ }
60
+
61
+ if (require.main === module) {
62
+ process.exit(main(process.argv));
63
+ }
64
+
65
+ module.exports = { main };