@aifabrix/builder 2.43.0 → 2.44.1

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 (371) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/.cursor/rules/cli-layout.mdc +75 -0
  3. package/.cursor/rules/project-rules.mdc +8 -0
  4. package/.npmrc.token +1 -0
  5. package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  6. package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  7. package/.nyc_output/processinfo/index.json +1 -0
  8. package/README.md +1 -1
  9. package/anchor-docs/README.md +10 -0
  10. package/anchor-docs/_TEMPLATE +24 -0
  11. package/bin/aifabrix.js +13 -4
  12. package/integration/hubspot-test/README.md +31 -0
  13. package/integration/hubspot-test/create-hubspot.js +5 -5
  14. package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
  15. package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
  16. package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
  17. package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
  18. package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
  19. package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
  20. package/integration/hubspot-test/test-dataplane-down.js +3 -3
  21. package/integration/hubspot-test/test.js +35 -43
  22. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  23. package/integration/roundtrip-test-local/README.md +144 -0
  24. package/integration/roundtrip-test-local/application.yaml +13 -0
  25. package/integration/roundtrip-test-local/env.template +15 -0
  26. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  27. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  28. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  29. package/integration/roundtrip-test-local2/README.md +144 -0
  30. package/integration/roundtrip-test-local2/application.yaml +13 -0
  31. package/integration/roundtrip-test-local2/env.template +15 -0
  32. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  33. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  34. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  35. package/integration/test/wizard.yaml +8 -0
  36. package/jest.config.default.js +10 -0
  37. package/jest.config.integration.fixtures.js +22 -0
  38. package/jest.config.integration.js +21 -18
  39. package/jest.config.isolated.js +10 -0
  40. package/jest.projects.js +301 -0
  41. package/lib/api/certificates.api.js +62 -0
  42. package/lib/api/datasources-core.api.js +3 -3
  43. package/lib/api/dev-mtls-request.js +110 -0
  44. package/lib/api/dev-server-https.js +145 -0
  45. package/lib/api/dev.api.js +133 -144
  46. package/lib/api/index.js +11 -3
  47. package/lib/api/pipeline.api.js +67 -20
  48. package/lib/api/types/certificates.types.js +48 -0
  49. package/lib/api/types/dev.types.js +4 -3
  50. package/lib/api/types/pipeline.types.js +8 -5
  51. package/lib/api/types/validation-run.types.js +56 -0
  52. package/lib/api/validation-run.api.js +111 -0
  53. package/lib/api/validation-runner.js +109 -0
  54. package/lib/app/certification-show-enrich.js +129 -0
  55. package/lib/app/certification-verify-rows.js +60 -0
  56. package/lib/app/config.js +1 -1
  57. package/lib/app/deploy-status-display.js +2 -2
  58. package/lib/app/deploy.js +7 -6
  59. package/lib/app/display.js +2 -1
  60. package/lib/app/dockerfile.js +3 -2
  61. package/lib/app/down.js +2 -1
  62. package/lib/app/helpers.js +6 -5
  63. package/lib/app/index.js +27 -8
  64. package/lib/app/list.js +7 -6
  65. package/lib/app/push.js +4 -3
  66. package/lib/app/register.js +16 -7
  67. package/lib/app/rotate-secret.js +14 -13
  68. package/lib/app/run-container-start.js +184 -0
  69. package/lib/app/run-docker-fallback.js +108 -0
  70. package/lib/app/run-env-compose.js +30 -42
  71. package/lib/app/run-helpers.js +49 -126
  72. package/lib/app/run-infra-requirements.js +30 -0
  73. package/lib/app/run-resolve-image.js +21 -0
  74. package/lib/app/run.js +74 -21
  75. package/lib/app/show-display.js +44 -1
  76. package/lib/app/show.js +93 -9
  77. package/lib/build/index.js +13 -10
  78. package/lib/certification/cli-cert-sync-skip.js +21 -0
  79. package/lib/certification/merge-certification-from-artifact.js +185 -0
  80. package/lib/certification/post-unified-cert-sync.js +33 -0
  81. package/lib/certification/sync-after-external-command.js +52 -0
  82. package/lib/certification/sync-system-certification.js +197 -0
  83. package/lib/cli/index.js +2 -0
  84. package/lib/cli/setup-app.help.js +67 -0
  85. package/lib/cli/setup-app.js +61 -121
  86. package/lib/cli/setup-app.test-commands.js +195 -0
  87. package/lib/cli/setup-auth.js +19 -5
  88. package/lib/cli/setup-credential-deployment.js +22 -8
  89. package/lib/cli/setup-dev-path-commands.js +124 -0
  90. package/lib/cli/setup-dev.js +170 -113
  91. package/lib/cli/setup-environment.js +7 -1
  92. package/lib/cli/setup-external-system.js +84 -23
  93. package/lib/cli/setup-infra.js +126 -47
  94. package/lib/cli/setup-parameters.js +32 -0
  95. package/lib/cli/setup-secrets.js +137 -18
  96. package/lib/cli/setup-service-user.js +1 -1
  97. package/lib/cli/setup-utility.js +54 -22
  98. package/lib/commands/app-down.js +5 -7
  99. package/lib/commands/app-install.js +14 -7
  100. package/lib/commands/app-logs.js +13 -10
  101. package/lib/commands/app-shell.js +4 -1
  102. package/lib/commands/app-test.js +25 -19
  103. package/lib/commands/app.js +32 -11
  104. package/lib/commands/auth-config.js +6 -6
  105. package/lib/commands/auth-status.js +4 -3
  106. package/lib/commands/credential-env.js +4 -3
  107. package/lib/commands/credential-list.js +5 -4
  108. package/lib/commands/credential-push.js +4 -3
  109. package/lib/commands/datasource-unified-test-cli.js +428 -0
  110. package/lib/commands/datasource-unified-test-cli.options.js +191 -0
  111. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +106 -0
  112. package/lib/commands/datasource-validation-cli.js +143 -0
  113. package/lib/commands/datasource.js +125 -95
  114. package/lib/commands/deployment-list.js +6 -5
  115. package/lib/commands/dev-cli-handlers.js +122 -18
  116. package/lib/commands/dev-down.js +4 -3
  117. package/lib/commands/dev-init.js +231 -116
  118. package/lib/commands/dev-show-display.js +473 -0
  119. package/lib/commands/login-credentials.js +3 -2
  120. package/lib/commands/login-device.js +4 -3
  121. package/lib/commands/login.js +5 -4
  122. package/lib/commands/logout.js +8 -7
  123. package/lib/commands/parameters-validate.js +54 -0
  124. package/lib/commands/repair-datasource.js +314 -68
  125. package/lib/commands/repair-env-template.js +2 -2
  126. package/lib/commands/repair.js +21 -3
  127. package/lib/commands/secrets-list.js +23 -12
  128. package/lib/commands/secrets-remove-all.js +220 -0
  129. package/lib/commands/secrets-remove.js +21 -12
  130. package/lib/commands/secrets-set.js +21 -12
  131. package/lib/commands/secrets-validate.js +4 -4
  132. package/lib/commands/secure.js +10 -9
  133. package/lib/commands/service-user.js +26 -25
  134. package/lib/commands/test-e2e-external.js +27 -1
  135. package/lib/commands/up-common.js +3 -2
  136. package/lib/commands/up-dataplane.js +29 -16
  137. package/lib/commands/up-miso.js +19 -29
  138. package/lib/commands/upload.js +149 -39
  139. package/lib/commands/wizard-core-helpers.js +1 -1
  140. package/lib/commands/wizard-dataplane.js +4 -3
  141. package/lib/commands/wizard-helpers.js +3 -3
  142. package/lib/commands/wizard.js +2 -2
  143. package/lib/core/admin-secrets.js +14 -5
  144. package/lib/core/audit-logger.js +12 -4
  145. package/lib/core/config-attach-extensions.js +46 -0
  146. package/lib/core/config-runtime-paths.js +29 -0
  147. package/lib/core/config.js +55 -56
  148. package/lib/core/diff.js +3 -2
  149. package/lib/core/ensure-encryption-key.js +1 -1
  150. package/lib/core/secrets-ensure-infra.js +77 -0
  151. package/lib/core/secrets-ensure.js +120 -64
  152. package/lib/core/secrets-env-write.js +35 -7
  153. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  154. package/lib/core/secrets.js +200 -37
  155. package/lib/core/templates-env.js +4 -3
  156. package/lib/datasource/abac-validator.js +1 -10
  157. package/lib/datasource/deploy.js +75 -53
  158. package/lib/datasource/field-reference-validator.js +9 -6
  159. package/lib/datasource/integration-context.js +63 -0
  160. package/lib/datasource/list.js +8 -7
  161. package/lib/datasource/log-viewer.js +189 -67
  162. package/lib/datasource/resolve-app.js +4 -4
  163. package/lib/datasource/test-e2e.js +113 -146
  164. package/lib/datasource/test-integration.js +114 -122
  165. package/lib/datasource/unified-validation-run-body.js +68 -0
  166. package/lib/datasource/unified-validation-run-post.js +23 -0
  167. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  168. package/lib/datasource/unified-validation-run.js +93 -0
  169. package/lib/datasource/validate.js +157 -13
  170. package/lib/deployment/deployer.js +4 -3
  171. package/lib/deployment/environment.js +7 -6
  172. package/lib/deployment/push.js +17 -8
  173. package/lib/external-system/delete.js +4 -3
  174. package/lib/external-system/deploy.js +166 -53
  175. package/lib/external-system/download-helpers.js +1 -1
  176. package/lib/external-system/download.js +7 -6
  177. package/lib/external-system/generator.js +92 -6
  178. package/lib/external-system/integration-test-dispatch.js +26 -0
  179. package/lib/external-system/test-execution.js +5 -1
  180. package/lib/external-system/test-helpers.js +0 -4
  181. package/lib/external-system/test-system-level-helpers.js +110 -0
  182. package/lib/external-system/test-system-level.js +83 -44
  183. package/lib/external-system/test.js +59 -8
  184. package/lib/generator/builders.js +23 -11
  185. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  186. package/lib/generator/external.js +16 -4
  187. package/lib/generator/helpers.js +58 -3
  188. package/lib/generator/index.js +4 -0
  189. package/lib/generator/split-readme.js +12 -7
  190. package/lib/generator/split-variables.js +2 -1
  191. package/lib/generator/split.js +1 -1
  192. package/lib/generator/wizard-readme.js +3 -3
  193. package/lib/generator/wizard.js +8 -8
  194. package/lib/infrastructure/compose.js +70 -7
  195. package/lib/infrastructure/helpers-docker-check.js +67 -0
  196. package/lib/infrastructure/helpers.js +203 -42
  197. package/lib/infrastructure/index.js +31 -18
  198. package/lib/infrastructure/services.js +21 -67
  199. package/lib/internal/fs-real-sync.js +104 -0
  200. package/lib/internal/node-fs.js +98 -0
  201. package/lib/parameters/database-secret-values.js +173 -0
  202. package/lib/parameters/infra-kv-discovery.js +121 -0
  203. package/lib/parameters/infra-parameter-catalog.js +458 -0
  204. package/lib/parameters/infra-parameter-validate.js +64 -0
  205. package/lib/schema/application-schema.json +37 -17
  206. package/lib/schema/datasource-test-run.schema.json +493 -0
  207. package/lib/schema/deployment-rules.yaml +102 -63
  208. package/lib/schema/external-datasource.schema.json +1200 -442
  209. package/lib/schema/external-system.schema.json +203 -5
  210. package/lib/schema/flag-map-validation-run.json +31 -0
  211. package/lib/schema/infra-parameter.schema.json +106 -0
  212. package/lib/schema/infra.parameter.yaml +421 -0
  213. package/lib/schema/type/credential-auth-templates.json +40 -0
  214. package/lib/schema/type/document-storage.json +226 -0
  215. package/lib/schema/type/message-service.json +123 -0
  216. package/lib/schema/type/vector-store.json +88 -0
  217. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  218. package/lib/utils/api-error-handler.js +2 -2
  219. package/lib/utils/api.js +77 -17
  220. package/lib/utils/app-register-api.js +3 -2
  221. package/lib/utils/app-register-auth.js +1 -1
  222. package/lib/utils/app-register-config.js +4 -4
  223. package/lib/utils/app-register-display.js +3 -2
  224. package/lib/utils/app-register-validator.js +3 -2
  225. package/lib/utils/app-run-containers.js +26 -22
  226. package/lib/utils/app-scoped-config.js +31 -0
  227. package/lib/utils/app-service-env-from-builder.js +164 -0
  228. package/lib/utils/build-copy.js +1 -1
  229. package/lib/utils/build-helpers.js +20 -20
  230. package/lib/utils/build-resolve-image.js +165 -0
  231. package/lib/utils/cli-layout-chalk.js +8 -0
  232. package/lib/utils/cli-test-layout-chalk.js +267 -0
  233. package/lib/utils/cli-utils.js +88 -11
  234. package/lib/utils/compose-db-passwords.js +138 -0
  235. package/lib/utils/compose-generate-docker-compose.js +216 -0
  236. package/lib/utils/compose-generator.js +197 -291
  237. package/lib/utils/compose-miso-env.js +18 -0
  238. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  239. package/lib/utils/config-paths.js +166 -7
  240. package/lib/utils/config-scoped-resources-preference.js +41 -0
  241. package/lib/utils/configuration-env-resolver.js +11 -8
  242. package/lib/utils/controller-deployment-outcome.js +68 -0
  243. package/lib/utils/credential-display.js +2 -2
  244. package/lib/utils/credential-secrets-env.js +5 -5
  245. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  246. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  247. package/lib/utils/datasource-test-run-certificate-tty.js +82 -0
  248. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  249. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  250. package/lib/utils/datasource-test-run-display.js +459 -0
  251. package/lib/utils/datasource-test-run-exit.js +83 -0
  252. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  253. package/lib/utils/datasource-test-run-report-version.js +51 -0
  254. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  255. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  256. package/lib/utils/datasource-validation-watch.js +266 -0
  257. package/lib/utils/declarative-url-ports.js +47 -0
  258. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  259. package/lib/utils/dev-ca-install.js +185 -23
  260. package/lib/utils/dev-cert-helper.js +266 -17
  261. package/lib/utils/dev-hosts-helper.js +307 -0
  262. package/lib/utils/dev-init-cert-hints.js +37 -0
  263. package/lib/utils/dev-init-health-messages.js +52 -0
  264. package/lib/utils/dev-init-resolve.js +86 -0
  265. package/lib/utils/dev-init-ssh-merge.js +65 -0
  266. package/lib/utils/dev-ssh-config-helper.js +196 -0
  267. package/lib/utils/dev-user-groups.js +93 -0
  268. package/lib/utils/docker-build.js +42 -17
  269. package/lib/utils/docker-exec.js +28 -0
  270. package/lib/utils/docker-manifest-public-port.js +116 -0
  271. package/lib/utils/docker-not-running-hint.js +52 -0
  272. package/lib/utils/docker.js +98 -11
  273. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  274. package/lib/utils/env-config-loader.js +10 -91
  275. package/lib/utils/env-copy.js +19 -10
  276. package/lib/utils/env-map.js +35 -8
  277. package/lib/utils/env-template.js +2 -2
  278. package/lib/utils/environment-scoped-resources.js +144 -0
  279. package/lib/utils/error-formatter.js +92 -13
  280. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  281. package/lib/utils/error-formatters/network-errors.js +2 -1
  282. package/lib/utils/error-formatters/permission-errors.js +2 -1
  283. package/lib/utils/error-formatters/validation-errors.js +2 -1
  284. package/lib/utils/external-readme.js +8 -1
  285. package/lib/utils/external-system-display.js +242 -136
  286. package/lib/utils/external-system-local-test-tty.js +389 -0
  287. package/lib/utils/external-system-readiness-core.js +377 -0
  288. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  289. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  290. package/lib/utils/external-system-readiness-display.js +186 -0
  291. package/lib/utils/external-system-system-test-tty-overview.js +120 -0
  292. package/lib/utils/external-system-system-test-tty.js +417 -0
  293. package/lib/utils/external-system-test-helpers.js +24 -6
  294. package/lib/utils/external-system-validators.js +30 -12
  295. package/lib/utils/health-check-url.js +119 -0
  296. package/lib/utils/health-check.js +59 -25
  297. package/lib/utils/help-builder.js +11 -8
  298. package/lib/utils/image-version.js +4 -8
  299. package/lib/utils/infra-containers.js +4 -7
  300. package/lib/utils/infra-env-defaults.js +162 -0
  301. package/lib/utils/infra-status-display.js +167 -0
  302. package/lib/utils/infra-status.js +16 -8
  303. package/lib/utils/local-secrets.js +3 -4
  304. package/lib/utils/paths.js +148 -47
  305. package/lib/utils/port-resolver.js +10 -23
  306. package/lib/utils/redis-env-scope.js +62 -0
  307. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  308. package/lib/utils/remote-builder-validation.js +99 -0
  309. package/lib/utils/remote-dev-auth.js +117 -21
  310. package/lib/utils/remote-docker-env.js +67 -15
  311. package/lib/utils/remote-secrets-loader.js +13 -4
  312. package/lib/utils/resolve-docker-image-ref.js +124 -0
  313. package/lib/utils/schema-loader.js +22 -9
  314. package/lib/utils/secrets-bash-kv.js +25 -0
  315. package/lib/utils/secrets-generator.js +169 -49
  316. package/lib/utils/secrets-helpers.js +70 -59
  317. package/lib/utils/secrets-kv-scope.js +60 -0
  318. package/lib/utils/secrets-utils.js +32 -38
  319. package/lib/utils/secrets-validation.js +3 -1
  320. package/lib/utils/secrets-yaml-preserve.js +109 -0
  321. package/lib/utils/ssh-key-helper.js +4 -2
  322. package/lib/utils/template-helpers.js +2 -2
  323. package/lib/utils/test-log-writer.js +3 -3
  324. package/lib/utils/token-manager.js +1 -2
  325. package/lib/utils/url-declarative-public-base.js +188 -0
  326. package/lib/utils/url-declarative-resolve-build.js +493 -0
  327. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  328. package/lib/utils/url-declarative-resolve.js +220 -0
  329. package/lib/utils/url-declarative-token-parse.js +74 -0
  330. package/lib/utils/url-declarative-url-flags.js +50 -0
  331. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  332. package/lib/utils/url-public-path-prefix.js +34 -0
  333. package/lib/utils/urls-local-registry.js +220 -0
  334. package/lib/utils/validation-report-tty-kit.js +77 -0
  335. package/lib/utils/validation-run-poll.js +112 -0
  336. package/lib/utils/validation-run-post-retry.js +85 -0
  337. package/lib/utils/validation-run-request.js +116 -0
  338. package/lib/utils/variable-transformer.js +21 -4
  339. package/lib/utils/yaml-preserve.js +33 -14
  340. package/lib/validation/datasource-warnings.js +56 -0
  341. package/lib/validation/env-template-auth.js +1 -1
  342. package/lib/validation/external-manifest-validator.js +27 -7
  343. package/lib/validation/validate-display.js +37 -31
  344. package/lib/validation/validate-external-cert-sync.js +23 -0
  345. package/lib/validation/validate.js +8 -14
  346. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  347. package/lib/validation/validator.js +22 -65
  348. package/lib/validation/wizard-config-validator.js +2 -1
  349. package/package.json +9 -4
  350. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  351. package/scripts/diagnose-cli.js +150 -0
  352. package/scripts/install-local.js +307 -55
  353. package/scripts/pnpm-global-remove.js +48 -0
  354. package/templates/README.md +15 -2
  355. package/templates/applications/dataplane/application.yaml +52 -2
  356. package/templates/applications/dataplane/env.template +79 -17
  357. package/templates/applications/dataplane/rbac.yaml +8 -0
  358. package/templates/applications/keycloak/application.yaml +9 -1
  359. package/templates/applications/keycloak/env.template +15 -6
  360. package/templates/applications/miso-controller/application.yaml +10 -2
  361. package/templates/applications/miso-controller/env.template +42 -12
  362. package/templates/applications/miso-controller/rbac.yaml +5 -0
  363. package/templates/external-system/README.md.hbs +20 -7
  364. package/templates/external-system/deploy.js.hbs +5 -5
  365. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  366. package/templates/infra/compose.yaml.hbs +33 -16
  367. package/templates/infra/servers.json.hbs +3 -1
  368. package/templates/python/docker-compose.hbs +16 -0
  369. package/templates/typescript/docker-compose.hbs +16 -0
  370. package/lib/api/external-test.api.js +0 -111
  371. package/lib/schema/env-config.yaml +0 -60
@@ -0,0 +1,459 @@
1
+ /**
2
+ * @fileoverview Minimal human TTY + --summary for DatasourceTestRun (plan §3.2 / §16.9 subset).
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+ const { sectionTitle, headerKeyValue, colorAggregateGlyph, successGlyph, failureGlyph } = require('./cli-test-layout-chalk');
9
+ const { appendCertificateTTY } = require('./datasource-test-run-certificate-tty');
10
+
11
+ const SEP = '────────────────────────────────';
12
+
13
+ /** @type {number} */
14
+ const DEFAULT_MAX_REF_CHARS = 200;
15
+
16
+ /**
17
+ * @param {'ok'|'warn'|'fail'|'skipped'} status
18
+ * @returns {string}
19
+ */
20
+ function statusGlyph(status) {
21
+ if (status === 'ok') return '✔';
22
+ if (status === 'warn') return '⚠';
23
+ if (status === 'fail') return '✖';
24
+ if (status === 'skipped') return '⏭';
25
+ return '?';
26
+ }
27
+
28
+ /**
29
+ * Map API status string to aggregate bucket for colors.
30
+ * @param {*} status
31
+ * @returns {'ok'|'warn'|'fail'|'skipped'|null} null = unknown / other
32
+ */
33
+ function envelopeStatusAggregate(status) {
34
+ const s = String(status || '').toLowerCase();
35
+ if (s === 'warn') return 'warn';
36
+ if (s === 'fail') return 'fail';
37
+ if (s === 'skipped' || s === 'skip') return 'skipped';
38
+ if (s === 'ok') return 'ok';
39
+ return null;
40
+ }
41
+
42
+ /**
43
+ * @param {*} status
44
+ * @param {string} rawWord - as returned by API (e.g. ok, warn)
45
+ * @returns {string}
46
+ */
47
+ function colorStatusWord(status, rawWord) {
48
+ const agg = envelopeStatusAggregate(status);
49
+ const w = String(rawWord);
50
+ if (!agg) return chalk.gray(w);
51
+ if (agg === 'ok') return chalk.green(w);
52
+ if (agg === 'warn') return chalk.yellow(w);
53
+ if (agg === 'fail') return chalk.red(w);
54
+ return chalk.gray(w);
55
+ }
56
+
57
+ /**
58
+ * Colored glyph for status (neutral when unknown).
59
+ * @param {*} status
60
+ * @returns {string}
61
+ */
62
+ function colorStatusGlyph(status) {
63
+ const agg = envelopeStatusAggregate(status);
64
+ const glyph = statusGlyph(status);
65
+ return agg ? colorAggregateGlyph(agg, glyph) : chalk.gray(glyph);
66
+ }
67
+
68
+ /**
69
+ * `Status: ✔ ok` with layout-aligned colors (preserves raw status text).
70
+ * @param {Object} envelope
71
+ * @returns {string}
72
+ */
73
+ function formatEnvelopeStatusLine(envelope) {
74
+ const raw = envelope.status !== undefined && envelope.status !== null ? String(envelope.status) : 'unknown';
75
+ const g = colorStatusGlyph(envelope.status);
76
+ return `${chalk.gray('Status:')} ${g} ${colorStatusWord(envelope.status, raw)}`;
77
+ }
78
+
79
+ /**
80
+ * @param {boolean} ok
81
+ * @param {string} body - step name + optional tail
82
+ * @returns {string}
83
+ */
84
+ function colorStepLine(ok, body) {
85
+ const sym = ok ? successGlyph() : failureGlyph();
86
+ return ` ${sym} ${chalk.white(body)}`;
87
+ }
88
+
89
+ /**
90
+ * Normalize CLI --capability value for matching envelope.capabilities[].key
91
+ * @param {*} focusCapabilityKey
92
+ * @returns {string} trimmed or ''
93
+ */
94
+ function normalizedFocusCapabilityKey(focusCapabilityKey) {
95
+ if (focusCapabilityKey === undefined || focusCapabilityKey === null) return '';
96
+ const s = String(focusCapabilityKey).trim();
97
+ return s;
98
+ }
99
+
100
+ /**
101
+ * @param {string[]} lines
102
+ * @param {Object|null|undefined} e2e
103
+ */
104
+ function pushCapabilityE2eLines(lines, e2e) {
105
+ if (!e2e || typeof e2e !== 'object') return;
106
+ if (e2e.status) {
107
+ const g = colorStatusGlyph(e2e.status);
108
+ lines.push(`${chalk.gray('E2E:')} ${g} ${colorStatusWord(e2e.status, e2e.status)}`);
109
+ }
110
+ const esteps = Array.isArray(e2e.steps) ? e2e.steps : [];
111
+ for (const st of esteps) {
112
+ const nm = st.name || st.step || 'step';
113
+ const ok = st.success !== false && !st.error;
114
+ const tail = st.error || st.message ? `: ${st.error || st.message}` : '';
115
+ lines.push(colorStepLine(ok, `${nm}${tail}`));
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Multi-line TTY block for a single capability row (plan §2.3 drill-down).
121
+ * @param {Object|null|undefined} envelope
122
+ * @param {string} focusKey - non-empty
123
+ * @returns {string}
124
+ */
125
+ function formatCapabilityFocusSection(envelope, focusKey) {
126
+ if (!focusKey) return '';
127
+ const lines = ['', chalk.gray(SEP), sectionTitle(`Capability scope: ${focusKey}`)];
128
+ const caps =
129
+ envelope && typeof envelope === 'object' && Array.isArray(envelope.capabilities)
130
+ ? envelope.capabilities
131
+ : [];
132
+ const cap = caps.find(c => c && String(c.key) === focusKey);
133
+ if (!cap) {
134
+ lines.push(chalk.yellow(`(No row with key "${focusKey}" in capabilities[])`));
135
+ return lines.join('\n');
136
+ }
137
+ lines.push(formatEnvelopeStatusLine(cap));
138
+ if (cap.permission) {
139
+ lines.push(headerKeyValue('Permission:', String(cap.permission)));
140
+ }
141
+ pushCapabilityE2eLines(lines, cap.e2e);
142
+ return lines.join('\n');
143
+ }
144
+
145
+ /**
146
+ * @param {Object} envelope
147
+ * @returns {string[]}
148
+ */
149
+ function buildTtyMetaLines(envelope) {
150
+ const lines = [];
151
+ lines.push(
152
+ headerKeyValue('Datasource:', `${envelope.datasourceKey} (${envelope.systemKey})`)
153
+ );
154
+ lines.push(headerKeyValue('Run:', String(envelope.runType)));
155
+ lines.push(formatEnvelopeStatusLine(envelope));
156
+ const rid = envelope.runId || envelope.testRunId;
157
+ if (rid) lines.push(`${chalk.gray('Run ID:')} ${chalk.cyan(String(rid))}`);
158
+ if (envelope.reportCompleteness && envelope.reportCompleteness !== 'full') {
159
+ lines.push(
160
+ `${chalk.gray('Report:')} ${chalk.yellow(String(envelope.reportCompleteness))}`
161
+ );
162
+ }
163
+ return lines;
164
+ }
165
+
166
+ /**
167
+ * @param {*} val
168
+ * @returns {string[]}
169
+ */
170
+ function normalizeRefArray(val) {
171
+ if (val === null || val === undefined) return [];
172
+ return Array.isArray(val) ? val : [val];
173
+ }
174
+
175
+ /**
176
+ * @param {string} str
177
+ * @param {number} maxChars
178
+ * @returns {string}
179
+ */
180
+ function truncateRefLine(str, maxChars) {
181
+ const s = String(str);
182
+ if (s.length <= maxChars) return s;
183
+ return `${s.slice(0, Math.max(0, maxChars - 24))}… [+${s.length - maxChars + 24} chars]`;
184
+ }
185
+
186
+ /**
187
+ * @param {string[]} lines
188
+ * @param {string} title
189
+ * @param {*} arr
190
+ * @param {number} maxRefChars
191
+ * @returns {boolean}
192
+ */
193
+ function appendStringRefBlock(lines, title, arr, maxRefChars) {
194
+ const entries = normalizeRefArray(arr).map(String);
195
+ if (!entries.length) return false;
196
+ lines.push(chalk.blue.bold(String(title)));
197
+ entries.forEach((text, i) => {
198
+ lines.push(` ${chalk.gray(`[${i + 1}]`)} ${chalk.white(truncateRefLine(text, maxRefChars))}`);
199
+ });
200
+ return true;
201
+ }
202
+
203
+ /**
204
+ * @param {string[]} lines
205
+ * @param {Object|null|undefined} dbg
206
+ * @param {number} maxRefChars
207
+ * @returns {boolean}
208
+ */
209
+ function appendDebugPayloadRefLines(lines, dbg, maxRefChars) {
210
+ const payloadRefs = dbg && typeof dbg === 'object' ? normalizeRefArray(dbg.payloadRefs) : [];
211
+ if (!payloadRefs.length) return false;
212
+ lines.push(chalk.blue.bold('debug.payloadRefs:'));
213
+ payloadRefs.forEach((pr, i) => {
214
+ const idx = chalk.gray(`[${i + 1}]`);
215
+ if (typeof pr === 'string') {
216
+ lines.push(` ${idx} ${chalk.white(truncateRefLine(pr, maxRefChars))}`);
217
+ return;
218
+ }
219
+ if (pr && typeof pr === 'object') {
220
+ const k = pr.key !== undefined && pr.key !== null ? String(pr.key) : 'payload';
221
+ const r = pr.ref !== undefined && pr.ref !== null ? String(pr.ref) : '';
222
+ const row = r ? `${k}: ${r}` : k;
223
+ lines.push(` ${idx} ${chalk.white(truncateRefLine(row, maxRefChars))}`);
224
+ return;
225
+ }
226
+ lines.push(` ${idx} ${chalk.gray('(ref)')}`);
227
+ });
228
+ return true;
229
+ }
230
+
231
+ /**
232
+ * @param {string[]} lines
233
+ * @param {Object} dbg
234
+ * @param {number} maxRefChars
235
+ * @returns {boolean}
236
+ */
237
+ function appendDebugMetaLines(lines, dbg, maxRefChars) {
238
+ let added = false;
239
+ function formatSecondsText(s) {
240
+ const txt = String(s);
241
+ // UI-only: reduce noisy float seconds to 3 decimals, e.g. "1.1713749s" -> "1.171s".
242
+ // Applies only to number tokens immediately followed by "s".
243
+ return txt.replace(/(\d+\.\d+)(?=s\b)/g, m => {
244
+ const n = Number(m);
245
+ if (!Number.isFinite(n)) return m;
246
+ return n.toFixed(3);
247
+ });
248
+ }
249
+ if (dbg.mode) {
250
+ lines.push(
251
+ `${chalk.blue.bold('debug.mode:')} ${chalk.white(String(dbg.mode))}`
252
+ );
253
+ added = true;
254
+ }
255
+ if (dbg.executionSummary) {
256
+ lines.push(
257
+ `${chalk.blue.bold('debug.executionSummary:')} ${chalk.white(
258
+ truncateRefLine(formatSecondsText(dbg.executionSummary), maxRefChars)
259
+ )}`
260
+ );
261
+ added = true;
262
+ }
263
+ return added;
264
+ }
265
+
266
+ /**
267
+ * Append audit + debug reference layout (OpenAPI AuditRefs, DebugTrace.payloadRefs).
268
+ * @param {string[]} lines
269
+ * @param {Object} envelope
270
+ * @param {{ maxRefChars?: number }} [opts]
271
+ * @returns {boolean} True if any reference line was added
272
+ */
273
+ function appendReferenceLayoutLines(lines, envelope, opts = {}) {
274
+ const maxRefChars = opts.maxRefChars ?? DEFAULT_MAX_REF_CHARS;
275
+ const audit = envelope && envelope.audit;
276
+ const dbg = envelope && envelope.debug;
277
+ const parts = [];
278
+
279
+ if (audit && typeof audit === 'object') {
280
+ parts.push(appendStringRefBlock(lines, 'audit.executionIds:', audit.executionIds, maxRefChars));
281
+ parts.push(appendStringRefBlock(lines, 'audit.traceRefs:', audit.traceRefs, maxRefChars));
282
+ parts.push(appendStringRefBlock(lines, 'audit.rbacTraceRefs:', audit.rbacTraceRefs, maxRefChars));
283
+ parts.push(appendStringRefBlock(lines, 'audit.abacTraceRefs:', audit.abacTraceRefs, maxRefChars));
284
+ }
285
+
286
+ parts.push(appendDebugPayloadRefLines(lines, dbg, maxRefChars));
287
+
288
+ if (dbg && typeof dbg === 'object') {
289
+ parts.push(appendStringRefBlock(lines, 'debug.executionIds:', dbg.executionIds, maxRefChars));
290
+ parts.push(appendDebugMetaLines(lines, dbg, maxRefChars));
291
+ }
292
+
293
+ return parts.some(Boolean);
294
+ }
295
+
296
+ /**
297
+ * @param {string[]} lines
298
+ * @param {Object} envelope
299
+ * @param {number} [maxIssues]
300
+ */
301
+ function appendValidationIssueLines(lines, envelope, maxIssues = 5) {
302
+ const issues = envelope && envelope.validation && Array.isArray(envelope.validation.issues) ? envelope.validation.issues : [];
303
+ if (!issues.length) return;
304
+ lines.push(sectionTitle('Validation issues:'));
305
+ const cap = Math.min(maxIssues, issues.length);
306
+ for (let i = 0; i < cap; i += 1) {
307
+ const iss = issues[i];
308
+ const code = iss && iss.code ? chalk.red(`[${iss.code}] `) : '';
309
+ const msg = iss && iss.message ? String(iss.message) : JSON.stringify(iss);
310
+ lines.push(` ${code}${chalk.yellow(msg)}`);
311
+ }
312
+ if (issues.length > cap) {
313
+ lines.push(chalk.gray(` … and ${issues.length - cap} more (see --json or debug full/raw)`));
314
+ }
315
+ }
316
+
317
+ /**
318
+ * @param {string[]} lines
319
+ * @param {Object} envelope
320
+ */
321
+ function formatIntegrationStepLine(st) {
322
+ const nm = (st && (st.name || st.step)) || 'step';
323
+ const ok = st && st.success !== false && !st.error;
324
+ const detail = st && (st.message || st.error) ? `: ${st.message || st.error}` : '';
325
+ return colorStepLine(ok, `${nm}${detail}`);
326
+ }
327
+
328
+ function appendIntegrationStepLines(lines, envelope) {
329
+ const integ = envelope && envelope.integration;
330
+ const steps = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
331
+ if (!steps.length) return;
332
+ lines.push(sectionTitle('Integration steps:'));
333
+ for (const st of steps) {
334
+ lines.push(formatIntegrationStepLine(st));
335
+ }
336
+ }
337
+
338
+ function pickExecutiveVerdictLine(envelope) {
339
+ const dev = envelope.developer;
340
+ const cert = envelope.certificate;
341
+ if (envelope.runType === 'e2e' && cert && typeof cert === 'object') {
342
+ const cs = cert.summary;
343
+ if (cs && String(cs).trim()) return String(cs).trim();
344
+ }
345
+ return (
346
+ (dev && dev.executiveSummary) ||
347
+ (cert && cert.summary) ||
348
+ (envelope.validation && envelope.validation.summary) ||
349
+ (envelope.integration && envelope.integration.summary) ||
350
+ `Run finished with status ${envelope.status}.`
351
+ );
352
+ }
353
+
354
+ /**
355
+ * Plan §3.9: explicit line when E2E has no capability rows (skipped when --capability drill-down is active).
356
+ * @param {string[]} lines
357
+ * @param {Object} envelope
358
+ * @param {{ focusCapabilityKey?: string }} [options]
359
+ */
360
+ function appendNoCapabilitiesReportedLine(lines, envelope, options = {}) {
361
+ if (envelope.runType !== 'e2e') return;
362
+ if (normalizedFocusCapabilityKey(options.focusCapabilityKey)) return;
363
+ const caps = envelope.capabilities;
364
+ if (Array.isArray(caps) && caps.length > 0) return;
365
+ lines.push(chalk.gray('No capabilities reported.'));
366
+ }
367
+
368
+ /**
369
+ * @param {string[]} parts
370
+ * @param {Object} envelope
371
+ * @param {string} focus - normalized or ''
372
+ */
373
+ function appendCapabilitySummaryPart(parts, envelope, focus) {
374
+ if (focus) {
375
+ const caps = Array.isArray(envelope.capabilities) ? envelope.capabilities : [];
376
+ const row = caps.find(c => c && String(c.key) === focus);
377
+ parts.push(
378
+ row ? `Cap ${focus}: ${statusGlyph(row.status)} ${row.status}` : `Cap ${focus}: (missing)`
379
+ );
380
+ return;
381
+ }
382
+ const capSummary = envelope.capabilitySummary;
383
+ if (capSummary && typeof capSummary === 'object') {
384
+ const passed = capSummary.passedCount;
385
+ const total = capSummary.totalCount;
386
+ if (typeof passed === 'number' && typeof total === 'number') {
387
+ parts.push(`Capabilities: ${passed}/${total}`);
388
+ }
389
+ }
390
+ }
391
+
392
+ /**
393
+ * @param {string[]} parts
394
+ * @param {Object} envelope
395
+ */
396
+ function appendCertificateSummaryPart(parts, envelope) {
397
+ const cert = envelope.certificate;
398
+ if (!cert || typeof cert !== 'object') return;
399
+ const level =
400
+ cert.level !== undefined && cert.level !== null ? String(cert.level) : '';
401
+ const cg = cert.status === 'passed' ? '✔' : cert.status === 'not_passed' ? '✖' : '⚠';
402
+ if (level) parts.push(`Certificate: ${level} ${cg}`);
403
+ }
404
+
405
+ /**
406
+ * One-line summary (plan §16.9 normative field order subset).
407
+ * @param {Object} envelope
408
+ * @param {{ focusCapabilityKey?: string }} [options]
409
+ * @returns {string}
410
+ */
411
+ function formatDatasourceTestRunSummary(envelope, options = {}) {
412
+ if (!envelope || typeof envelope !== 'object') return '';
413
+ const parts = [];
414
+ parts.push(String(envelope.datasourceKey || 'unknown'));
415
+ parts.push(`${statusGlyph(envelope.status)} ${(envelope.status || '').toUpperCase()}`);
416
+ const focus = normalizedFocusCapabilityKey(options.focusCapabilityKey);
417
+ appendCapabilitySummaryPart(parts, envelope, focus);
418
+ appendCertificateSummaryPart(parts, envelope);
419
+ return parts.join(' | ');
420
+ }
421
+
422
+ /**
423
+ * Default TTY block (header + verdict line + short summary + optional completeness).
424
+ * @param {Object} envelope
425
+ * @param {{ focusCapabilityKey?: string }} [options] - When set (e.g. --capability), append single-cap block (plan §2.3).
426
+ * @returns {string}
427
+ */
428
+ function formatDatasourceTestRunTTY(envelope, options = {}) {
429
+ if (!envelope || typeof envelope !== 'object') return '';
430
+ const lines = [...buildTtyMetaLines(envelope)];
431
+ appendNoCapabilitiesReportedLine(lines, envelope, options);
432
+ lines.push('');
433
+ lines.push(sectionTitle('Verdict:'));
434
+ lines.push(chalk.white(pickExecutiveVerdictLine(envelope)));
435
+ appendCertificateTTY(lines, envelope);
436
+ lines.push('');
437
+ lines.push(chalk.gray(SEP));
438
+ if (appendReferenceLayoutLines(lines, envelope, { maxRefChars: 160 })) {
439
+ lines.push('');
440
+ }
441
+ appendValidationIssueLines(lines, envelope);
442
+ appendIntegrationStepLines(lines, envelope);
443
+ const focus = normalizedFocusCapabilityKey(options.focusCapabilityKey);
444
+ if (focus) {
445
+ lines.push(formatCapabilityFocusSection(envelope, focus));
446
+ }
447
+ return lines.join('\n');
448
+ }
449
+
450
+ module.exports = {
451
+ formatDatasourceTestRunSummary,
452
+ formatDatasourceTestRunTTY,
453
+ formatCapabilityFocusSection,
454
+ normalizedFocusCapabilityKey,
455
+ statusGlyph,
456
+ SEP,
457
+ appendReferenceLayoutLines,
458
+ normalizeRefArray
459
+ };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @fileoverview Exit code matrix for DatasourceTestRun after successful HTTP (plan §3.1).
3
+ * HTTP/transport failures are exit 3 (handled by callers).
4
+ * @author AI Fabrix Team
5
+ * @version 2.0.0
6
+ */
7
+
8
+ /**
9
+ * Compute CLI exit code from parsed DatasourceTestRun envelope.
10
+ * Ordering: status / warnings-as-errors → require-cert (§3.1).
11
+ * @param {import('../api/types/validation-run.types').DatasourceTestRunLike|null|undefined} body
12
+ * @param {Object} [opts]
13
+ * @param {boolean} [opts.warningsAsErrors]
14
+ * @param {boolean} [opts.requireCert]
15
+ * @returns {number} 0 | 1 | 2 | 3 (3 = treat as parse/body unusable)
16
+ */
17
+ function computeExitCodeFromDatasourceTestRun(body, opts = {}) {
18
+ if (!body || typeof body !== 'object') {
19
+ return 3;
20
+ }
21
+ const status = body.status;
22
+ if (status === 'fail') {
23
+ return 1;
24
+ }
25
+ if (status === 'warn' && opts.warningsAsErrors === true) {
26
+ return 1;
27
+ }
28
+ if (status === 'ok' || status === 'skipped' || status === 'warn') {
29
+ if (opts.requireCert === true) {
30
+ const cert = body.certificate;
31
+ if (!cert) {
32
+ return 2;
33
+ }
34
+ if (cert.status === 'not_passed') {
35
+ return 2;
36
+ }
37
+ }
38
+ return 0;
39
+ }
40
+ return 3;
41
+ }
42
+
43
+ /**
44
+ * Exit code for poll timeout with last envelope (plan §3.4).
45
+ * @param {import('../api/types/validation-run.types').DatasourceTestRunLike|null} lastBody
46
+ * @returns {number} 1 if root fail, else 3
47
+ */
48
+ function exitCodeForPollTimeout(lastBody) {
49
+ if (lastBody && typeof lastBody === 'object' && lastBody.status === 'fail') {
50
+ return 1;
51
+ }
52
+ return 3;
53
+ }
54
+
55
+ const {
56
+ deriveSystemStatus,
57
+ systemCertStatus
58
+ } = require('./external-system-system-test-tty');
59
+
60
+ /**
61
+ * System-level exit code from per-datasource result rows (same matrix as §3.1 on synthetic rollup).
62
+ * @param {Array<{ skipped?: boolean, success?: boolean, datasourceTestRun?: Object|null }>} rows
63
+ * @param {Object} [opts]
64
+ * @param {boolean} [opts.warningsAsErrors]
65
+ * @param {boolean} [opts.requireCert]
66
+ * @returns {number}
67
+ */
68
+ function computeSystemExitCodeFromDatasourceRows(rows, opts = {}) {
69
+ const list = Array.isArray(rows) ? rows : [];
70
+ const status = deriveSystemStatus(list);
71
+ const certAgg = systemCertStatus(list);
72
+ const body = {
73
+ status,
74
+ certificate: certAgg ? { status: certAgg === 'passed' ? 'passed' : 'not_passed' } : undefined
75
+ };
76
+ return computeExitCodeFromDatasourceTestRun(body, opts);
77
+ }
78
+
79
+ module.exports = {
80
+ computeExitCodeFromDatasourceTestRun,
81
+ computeSystemExitCodeFromDatasourceRows,
82
+ exitCodeForPollTimeout
83
+ };
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @fileoverview Map DatasourceTestRun envelope → legacy CLI display shapes (integration + E2E).
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ /**
8
+ * @param {Object|null} envelope
9
+ * @returns {string|null}
10
+ */
11
+ function firstIssueMessage(envelope) {
12
+ const v = envelope && envelope.validation;
13
+ const issues = v && Array.isArray(v.issues) ? v.issues : [];
14
+ const first = issues.find(i => i && (i.message || i.hint));
15
+ if (first) return String(first.message || first.hint);
16
+ const integ = envelope && envelope.integration;
17
+ const steps = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
18
+ const bad = steps.find(s => s && s.success === false && (s.message || s.error));
19
+ if (bad) return String(bad.message || bad.error || 'Integration step failed');
20
+ return null;
21
+ }
22
+
23
+ /**
24
+ * Legacy integration result for displayIntegrationTestResults / verbose details.
25
+ * @param {Object|null} envelope
26
+ * @param {string} datasourceKey
27
+ * @returns {Object}
28
+ */
29
+ function integrationResultFromEnvelope(envelope, datasourceKey) {
30
+ if (!envelope || typeof envelope !== 'object') {
31
+ return {
32
+ key: datasourceKey,
33
+ systemKey: 'unknown',
34
+ success: false,
35
+ skipped: false,
36
+ validationResults: {},
37
+ fieldMappingResults: {},
38
+ endpointTestResults: {},
39
+ error: 'No report envelope',
40
+ envelope: null
41
+ };
42
+ }
43
+ const success = envelope.status !== 'fail';
44
+ const err = success ? undefined : firstIssueMessage(envelope) || `status: ${envelope.status}`;
45
+ return {
46
+ key: datasourceKey,
47
+ systemKey: envelope.systemKey || 'unknown',
48
+ success,
49
+ skipped: false,
50
+ error: err,
51
+ envelope
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Map integration.stepResults → E2E-style steps for displayE2EResults.
57
+ * @param {Object|null} envelope
58
+ * @returns {{ steps: Object[], success: boolean, status?: string, error?: string }}
59
+ */
60
+ function e2eShapeFromEnvelope(envelope) {
61
+ if (!envelope || typeof envelope !== 'object') {
62
+ return { steps: [], success: false, error: 'No report envelope' };
63
+ }
64
+ const integ = envelope.integration;
65
+ const raw = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
66
+ const steps = raw.map(s => ({
67
+ name: s.name || 'step',
68
+ step: s.name,
69
+ success: s.success !== false,
70
+ message: s.message,
71
+ error: s.success === false ? s.message || 'failed' : undefined
72
+ }));
73
+ const success = envelope.status !== 'fail';
74
+ let status;
75
+ if (envelope.status === 'fail') status = 'failed';
76
+ else if (envelope.reportCompleteness && envelope.reportCompleteness !== 'full') {
77
+ status = 'completed';
78
+ } else {
79
+ status = 'completed';
80
+ }
81
+ return {
82
+ steps,
83
+ success,
84
+ status,
85
+ error: success ? undefined : firstIssueMessage(envelope) || undefined
86
+ };
87
+ }
88
+
89
+ module.exports = {
90
+ integrationResultFromEnvelope,
91
+ e2eShapeFromEnvelope,
92
+ firstIssueMessage
93
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @fileoverview reportVersion compatibility warnings (plan §3.15).
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ /** CLI-supported major reportVersion (bump when breaking). */
8
+ const SUPPORTED_MAJOR = 1;
9
+
10
+ /**
11
+ * Parse leading major from semver-like string (e.g. 1.1.0 → 1).
12
+ * @param {string} v
13
+ * @returns {number|null}
14
+ */
15
+ function parseMajor(v) {
16
+ if (!v || typeof v !== 'string') return null;
17
+ const m = /^v?(\d+)/.exec(v.trim());
18
+ if (!m) return null;
19
+ return parseInt(m[1], 10);
20
+ }
21
+
22
+ /**
23
+ * stderr messages for reportVersion handling.
24
+ * @param {string|undefined} reportVersion - From envelope
25
+ * @returns {{ level: 'none'|'warn'|'info', message: string }|null}
26
+ */
27
+ function getReportVersionStderrMessage(reportVersion) {
28
+ const major = parseMajor(reportVersion || '');
29
+ if (major === null) {
30
+ return null;
31
+ }
32
+ if (major < SUPPORTED_MAJOR - 1) {
33
+ return {
34
+ level: 'warn',
35
+ message: `reportVersion unsupported (got ${reportVersion}, support ${SUPPORTED_MAJOR - 1}–${SUPPORTED_MAJOR} major)`
36
+ };
37
+ }
38
+ if (major > SUPPORTED_MAJOR) {
39
+ return {
40
+ level: 'info',
41
+ message: 'Newer reportVersion; some fields may be ignored'
42
+ };
43
+ }
44
+ return null;
45
+ }
46
+
47
+ module.exports = {
48
+ SUPPORTED_MAJOR,
49
+ parseMajor,
50
+ getReportVersionStderrMessage
51
+ };