@aifabrix/builder 2.52.0 → 2.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/lib/api/datasources-extended.api.js +8 -8
  2. package/lib/api/keycloak.api.js +92 -0
  3. package/lib/api/token-providers.api.js +77 -0
  4. package/lib/api/types/keycloak.types.js +23 -0
  5. package/lib/api/types/token-providers.types.js +65 -0
  6. package/lib/app/deploy-config.js +3 -2
  7. package/lib/app/down.js +16 -1
  8. package/lib/channels/add-channel.js +134 -57
  9. package/lib/channels/approval-guides/chatgpt.js +1 -1
  10. package/lib/channels/approval-guides/index.js +3 -0
  11. package/lib/channels/approval-guides/microsoft-copilot.js +27 -14
  12. package/lib/channels/channel-add-ensure.js +128 -0
  13. package/lib/channels/channel-add-existing.js +72 -0
  14. package/lib/channels/channel-artifact-generator.js +11 -1
  15. package/lib/channels/channel-branding.js +94 -0
  16. package/lib/channels/channel-credential.js +8 -0
  17. package/lib/channels/channel-discovery.js +330 -0
  18. package/lib/channels/channel-external-system.js +1 -1
  19. package/lib/channels/channel-runtime-resolver.js +107 -14
  20. package/lib/channels/channel-status-display.js +36 -3
  21. package/lib/channels/microsoft-copilot-channel-add.js +138 -0
  22. package/lib/channels/microsoft-copilot-entra-sso-form.js +251 -0
  23. package/lib/channels/microsoft-copilot-entra-sso.js +285 -0
  24. package/lib/channels/microsoft-copilot-icons.js +74 -0
  25. package/lib/channels/microsoft-copilot-limits.js +103 -0
  26. package/lib/channels/microsoft-copilot-package.js +178 -52
  27. package/lib/channels/microsoft-copilot-validate.js +227 -0
  28. package/lib/cli/attach-default-help-examples.js +102 -0
  29. package/lib/cli/index.js +4 -0
  30. package/lib/cli/infra-guided.js +13 -6
  31. package/lib/cli/setup-credential-deployment.js +7 -5
  32. package/lib/cli/setup-infra.js +31 -4
  33. package/lib/cli/setup-utility-validate.js +1 -0
  34. package/lib/commands/channel-add-setup.js +28 -9
  35. package/lib/commands/channel.js +14 -10
  36. package/lib/commands/credential-push.js +37 -5
  37. package/lib/commands/integration-definition.js +158 -0
  38. package/lib/commands/package-score.js +72 -0
  39. package/lib/commands/repair-auth-apply.js +19 -5
  40. package/lib/commands/repair-datasource-sync-operations.js +4 -1
  41. package/lib/commands/role-assistant-test-output.js +200 -0
  42. package/lib/commands/role-assistant.js +163 -166
  43. package/lib/datasource/capability/capability-resolve.js +15 -5
  44. package/lib/datasource/capability/copy-operations.js +14 -4
  45. package/lib/deployment/deployer-poll-run.js +2 -2
  46. package/lib/deployment/deployer.js +1 -1
  47. package/lib/deployment/environment.js +2 -2
  48. package/lib/external-system/deploy.js +11 -21
  49. package/lib/infrastructure/index.js +19 -4
  50. package/lib/integration-definition/apply.js +476 -0
  51. package/lib/integration-definition/canonical-json.js +51 -0
  52. package/lib/integration-definition/emit-suite-bid.js +94 -0
  53. package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
  54. package/lib/integration-definition/enrich-openapi-operations.js +433 -0
  55. package/lib/integration-definition/from-discovery.js +339 -0
  56. package/lib/integration-definition/hash.js +37 -0
  57. package/lib/integration-definition/index.js +37 -0
  58. package/lib/integration-definition/resource-type-catalog.js +59 -0
  59. package/lib/integration-definition/system-kind-enum.js +40 -0
  60. package/lib/integration-definition/validate.js +148 -0
  61. package/lib/lab/package-parity-score.js +417 -0
  62. package/lib/programmatic/builder-api-request.js +5 -1
  63. package/lib/programmatic/builder-help-governance.js +3 -2
  64. package/lib/programmatic/capability-registry.js +20 -0
  65. package/lib/programmatic/help-content/channel-onboarding.md +35 -0
  66. package/lib/programmatic/help-content/cip-overview.md +27 -0
  67. package/lib/programmatic/help-content/connected-system-ui.md +70 -0
  68. package/lib/programmatic/help-content/dimensions-guide.md +23 -0
  69. package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
  70. package/lib/programmatic/help-content/overview.md +25 -0
  71. package/lib/programmatic/help-content/subscription-guide.md +27 -0
  72. package/lib/programmatic/help-content/workflow.md +50 -0
  73. package/lib/programmatic/openapi-component-schemas.js +7 -1
  74. package/lib/programmatic/openapi-descriptions.js +46 -0
  75. package/lib/programmatic/openapi-envelope-examples.js +280 -0
  76. package/lib/programmatic/openapi-operation-bindings.js +50 -0
  77. package/lib/programmatic/openapi-request-schemas.js +40 -0
  78. package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
  79. package/lib/programmatic/openapi-result-schemas.js +76 -99
  80. package/lib/programmatic/openapi-schema-descriptions-core.js +25 -4
  81. package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
  82. package/lib/programmatic/openapi-schema-descriptions-operations.js +43 -0
  83. package/lib/programmatic/openapi-schema-helpers.js +9 -9
  84. package/lib/programmatic/openapi-spec.js +11 -1
  85. package/lib/programmatic/orchestration-openapi-meta.js +10 -0
  86. package/lib/programmatic/persist-supplied-openapi.js +180 -0
  87. package/lib/programmatic/route-handler-map.js +35 -1
  88. package/lib/programmatic/run-channel-package.js +236 -0
  89. package/lib/programmatic/run-integration-definition.js +77 -0
  90. package/lib/role-assistant/evidence-sync.js +55 -7
  91. package/lib/role-assistant/knowledge-sync-logging.js +58 -0
  92. package/lib/role-assistant/knowledge-sync.js +88 -93
  93. package/lib/role-assistant/test-cases-bid.js +155 -0
  94. package/lib/role-assistant/test-cases-evaluate.js +9 -1
  95. package/lib/role-assistant/test-cases-honesty.js +24 -10
  96. package/lib/role-assistant/test-cases.js +28 -0
  97. package/lib/role-assistant/test-runner-attachments.js +118 -0
  98. package/lib/role-assistant/test-runner-bid-apply.js +201 -0
  99. package/lib/role-assistant/test-runner-bid-document.js +278 -0
  100. package/lib/role-assistant/test-runner-start-payload.js +96 -0
  101. package/lib/role-assistant/test-runner-workhub-answers.js +249 -20
  102. package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
  103. package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
  104. package/lib/role-assistant/test-runner-workhub.js +152 -107
  105. package/lib/role-assistant/test-runner.js +5 -63
  106. package/lib/role-assistant/test-suite.js +112 -0
  107. package/lib/schema/application-schema.json +56 -6
  108. package/lib/schema/external-datasource.schema.json +103 -17
  109. package/lib/schema/external-system.schema.json +54 -3
  110. package/lib/schema/integration-definition.schema.json +195 -0
  111. package/lib/utils/authentication-shape.js +6 -0
  112. package/lib/utils/compose-generator.js +10 -1
  113. package/lib/utils/compose-traefik-extra-routes.js +107 -0
  114. package/lib/utils/docker-build.js +2 -2
  115. package/lib/utils/help-builder.js +3 -1
  116. package/lib/utils/promote-dev-docker-image.js +102 -18
  117. package/lib/utils/transient-developer-id.js +28 -0
  118. package/package.json +14 -16
  119. package/templates/README.md +12 -1
  120. package/templates/applications/dataplane/application.yaml +10 -2
  121. package/templates/applications/dataplane/env.template +7 -6
  122. package/templates/applications/miso-controller/application.yaml +23 -8
  123. package/templates/applications/miso-controller/env.template +8 -2
  124. package/templates/applications/miso-controller/rbac.yaml +1 -0
  125. package/templates/channels/README.md +11 -1
  126. package/templates/channels/brand/color-192.png +0 -0
  127. package/templates/channels/brand/dark/128.png +0 -0
  128. package/templates/channels/brand/dark/192.png +0 -0
  129. package/templates/channels/brand/dark/256.png +0 -0
  130. package/templates/channels/brand/dark/32.png +0 -0
  131. package/templates/channels/brand/dark/512.png +0 -0
  132. package/templates/channels/brand/dark/64.png +0 -0
  133. package/templates/channels/brand/light/128.png +0 -0
  134. package/templates/channels/brand/light/192.png +0 -0
  135. package/templates/channels/brand/light/256.png +0 -0
  136. package/templates/channels/brand/light/32.png +0 -0
  137. package/templates/channels/brand/light/512.png +0 -0
  138. package/templates/channels/brand/light/64.png +0 -0
  139. package/templates/channels/brand/mono-white/128.png +0 -0
  140. package/templates/channels/brand/mono-white/192.png +0 -0
  141. package/templates/channels/brand/mono-white/256.png +0 -0
  142. package/templates/channels/brand/mono-white/32.png +0 -0
  143. package/templates/channels/brand/mono-white/512.png +0 -0
  144. package/templates/channels/brand/mono-white/64.png +0 -0
  145. package/templates/channels/brand/outline-32.png +0 -0
  146. package/templates/channels/chatgpt/install.template.md.hbs +6 -4
  147. package/templates/channels/chatgpt/integration/README.md +4 -5
  148. package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
  149. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +14 -16
  150. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
  151. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +30 -0
  152. package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
  153. package/templates/channels/microsoft-copilot/install.template.md.hbs +93 -22
  154. package/templates/channels/microsoft-copilot/integration/README.md +2 -3
  155. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
  156. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -19
  157. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +15 -0
  158. package/templates/channels/slack/integration/README.md +2 -4
  159. package/templates/channels/teams-bot/install.template.md.hbs +4 -0
  160. package/templates/channels/teams-bot/integration/README.md +3 -5
  161. package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
  162. package/templates/python/docker-compose.hbs +36 -0
  163. package/templates/typescript/docker-compose.hbs +36 -0
  164. package/.cursor/plans/Done/157.1-security-quality-violations-by-type.csv +0 -374
  165. package/.cursor/process/README.md +0 -9
  166. package/.cursor/rules/anchor-docs.mdc +0 -15
  167. package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
  168. package/.cursor/rules/cli-layout.mdc +0 -81
  169. package/.cursor/rules/cli-product-neutral.mdc +0 -43
  170. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
  171. package/.cursor/rules/docs-rules.mdc +0 -32
  172. package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
  173. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
  174. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
  175. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
  176. package/.cursor/rules/project-rules.mdc +0 -913
  177. package/.cursor/skills/README.md +0 -15
  178. package/.dockerignore +0 -52
  179. package/.eslintignore +0 -22
  180. package/.markdownlint.json +0 -14
  181. package/anchor-docs/README.md +0 -10
  182. package/anchor-docs/_TEMPLATE +0 -24
  183. package/babel.config.js +0 -6
  184. package/bin/builder-api-cleanup.js +0 -26
  185. package/bin/builder-api-nest.js +0 -10
  186. package/bin/builder-api-spike.js +0 -19
  187. package/enterprise-knowledge/README.md +0 -50
  188. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
  189. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
  190. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
  191. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
  192. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
  193. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
  194. package/integration/README.md +0 -81
  195. package/integration/github/README.md +0 -53
  196. package/integration/github/application.json +0 -21
  197. package/integration/github/deploy.js +0 -72
  198. package/integration/github/env.template +0 -11
  199. package/integration/github/github-datasource-issue-comments.json +0 -239
  200. package/integration/github/github-datasource-issues.json +0 -399
  201. package/integration/github/github-datasource-repository.json +0 -354
  202. package/integration/github/github-deploy.json +0 -1202
  203. package/integration/github/github-system.json +0 -82
  204. package/integration/hubspot-test/README.md +0 -159
  205. package/integration/hubspot-test/application.json +0 -54
  206. package/integration/hubspot-test/companies.json +0 -2048
  207. package/integration/hubspot-test/create-hubspot.js +0 -523
  208. package/integration/hubspot-test/env.template +0 -4
  209. package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
  210. package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
  211. package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
  212. package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
  213. package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
  214. package/integration/hubspot-test/hubspot-test-system.json +0 -74
  215. package/integration/hubspot-test/rbac.json +0 -166
  216. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
  217. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
  218. package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
  219. package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
  220. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
  221. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
  222. package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
  223. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
  224. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
  225. package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
  226. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
  227. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
  228. package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
  229. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
  230. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
  231. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
  232. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
  233. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
  234. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
  235. package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
  236. package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
  237. package/integration/hubspot-test/test-dataplane-down.js +0 -209
  238. package/integration/hubspot-test/test.js +0 -1588
  239. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
  240. package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
  241. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
  242. package/integration/roundtrip-test-local/README.md +0 -143
  243. package/integration/roundtrip-test-local/application.yaml +0 -13
  244. package/integration/roundtrip-test-local/env.template +0 -15
  245. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
  246. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
  247. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
  248. package/integration/roundtrip-test-local2/README.md +0 -143
  249. package/integration/roundtrip-test-local2/application.yaml +0 -13
  250. package/integration/roundtrip-test-local2/env.template +0 -15
  251. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
  252. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
  253. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
  254. package/integration/test/wizard.yaml +0 -8
  255. package/jest.config.coverage.js +0 -37
  256. package/jest.config.default.js +0 -11
  257. package/jest.config.integration.fixtures.js +0 -22
  258. package/jest.config.integration.js +0 -33
  259. package/jest.config.isolated.js +0 -11
  260. package/jest.config.manual.js +0 -30
  261. package/jest.global-live-fabrix-hooks.js +0 -36
  262. package/jest.isolated-projects.js +0 -260
  263. package/jest.projects.js +0 -76
  264. package/packages/builder-api/README.md +0 -120
  265. package/packages/builder-api/package.json +0 -30
  266. package/packages/builder-api/src/app.module.ts +0 -7
  267. package/packages/builder-api/src/auth/auth.module.ts +0 -5
  268. package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
  269. package/packages/builder-api/src/main.ts +0 -16
  270. package/packages/builder-api/tsconfig.json +0 -15
  271. package/scripts/check-builder-api-architecture-grep.js +0 -79
  272. package/scripts/check-datasource-test-run-schema-sync.js +0 -34
  273. package/scripts/ci-fix.sh +0 -19
  274. package/scripts/ci-simulate.sh +0 -19
  275. package/scripts/diagnose-cli.js +0 -150
  276. package/scripts/docker_image_content_gate.js +0 -47
  277. package/scripts/docker_image_content_gate.sh +0 -5
  278. package/scripts/export-builder-api-evidence.js +0 -262
  279. package/scripts/install-local.js +0 -490
  280. package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
  281. package/scripts/lib/builder-api-docker-staging-core.js +0 -183
  282. package/scripts/lib/docker-image-content-gate-core.js +0 -166
  283. package/scripts/lib/plan-actor.js +0 -109
  284. package/scripts/lib/plan-config.js +0 -20
  285. package/scripts/lib/plan-gates.js +0 -154
  286. package/scripts/lib/plan-meta.js +0 -104
  287. package/scripts/lib/plan-parse.js +0 -162
  288. package/scripts/lib/plan-prevalidate-gates.js +0 -337
  289. package/scripts/lib/plan-run-core.js +0 -125
  290. package/scripts/lib/plan-run-report.js +0 -119
  291. package/scripts/plan-approve.js +0 -24
  292. package/scripts/plan-archive.js +0 -49
  293. package/scripts/plan-run.js +0 -13
  294. package/scripts/plan-set-actor.js +0 -21
  295. package/scripts/plan-validate.js +0 -80
  296. package/scripts/pnpm/af.mjs +0 -110
  297. package/scripts/pnpm/check-quiet.mjs +0 -32
  298. package/scripts/pnpm/dev-install.mjs +0 -29
  299. package/scripts/pnpm/dev-reload.mjs +0 -18
  300. package/scripts/pnpm/help.mjs +0 -55
  301. package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
  302. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
  303. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
  304. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
  305. package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
  306. package/scripts/pnpm/lib/spinner.mjs +0 -42
  307. package/scripts/pnpm-global-remove.js +0 -48
  308. package/scripts/stage_builder_api_for_docker.js +0 -65
  309. package/scripts/sync-builder-api-template.js +0 -44
  310. package/scripts/test-dataplane-bootstrap.js +0 -331
@@ -1,189 +0,0 @@
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
- }
@@ -1,67 +0,0 @@
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
- }
@@ -1,32 +0,0 @@
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
- }
@@ -1,124 +0,0 @@
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 - Semver string.
14
- * @returns {number[]} Parsed numeric semver segments.
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 - Left semver.
25
- * @param {string} right - Right semver.
26
- * @returns {number} Compare result (1, 0, -1).
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 - Candidate executable path.
42
- * @returns {string|null} CLI version output or 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[]} Candidate aifabrix binary paths.
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} Resolved aifabrix executable path.
89
- */
90
- export function resolveAifabrixBin() {
91
- let bestBin = null;
92
- let bestVersion = null;
93
-
94
- for (const candidate of collectAifabrixCandidates()) {
95
- let resolved;
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
- }
@@ -1,183 +0,0 @@
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
- }
@@ -1,42 +0,0 @@
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
- }
@@ -1,48 +0,0 @@
1
- #!/usr/bin/env node
2
- /* eslint-disable no-console */
3
-
4
- /**
5
- * pnpm global remove with virtual-store repair retry (pnpm 9+ global layout).
6
- * @fileoverview Used by install-local.js uninstall path
7
- * @author AI Fabrix Team
8
- */
9
-
10
- const { execSync } = require('child_process');
11
-
12
- /**
13
- * @param {unknown} error - Thrown from execSync
14
- * @returns {boolean} True when `pnpm i -g` repair may fix the failure
15
- */
16
- function isPnpmUnexpectedVirtualStoreError(error) {
17
- const msg =
18
- error && typeof error === 'object' && 'message' in error ? String(error.message) : String(error);
19
- return msg.includes('ERR_PNPM_UNEXPECTED_VIRTUAL_STORE');
20
- }
21
-
22
- /**
23
- * @param {NodeJS.ProcessEnv} env - Environment
24
- * @returns {void} Nothing
25
- */
26
- function repairPnpmGlobalInstall(env) {
27
- execSync('pnpm i -g', { stdio: 'inherit', env });
28
- }
29
-
30
- /**
31
- * @param {NodeJS.ProcessEnv} env - pnpm env (e.g. pnpmEnv + CI)
32
- * @param {string} packageName - Scoped package name to remove globally
33
- * @returns {void} Nothing
34
- */
35
- function runPnpmGlobalRemove(env, packageName) {
36
- try {
37
- execSync(`pnpm remove -g ${packageName}`, { stdio: 'inherit', env });
38
- } catch (firstError) {
39
- if (!isPnpmUnexpectedVirtualStoreError(firstError)) throw firstError;
40
- console.log(
41
- '\n⚠️ pnpm global virtual store layout mismatch. Running `pnpm i -g` to repair, then retrying remove...\n'
42
- );
43
- repairPnpmGlobalInstall(env);
44
- execSync(`pnpm remove -g ${packageName}`, { stdio: 'inherit', env });
45
- }
46
- }
47
-
48
- module.exports = { runPnpmGlobalRemove };