@aifabrix/builder 2.45.0 → 2.46.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 (352) hide show
  1. package/.cursor/rules/cli-layout.mdc +2 -0
  2. package/.cursor/rules/cli-product-neutral.mdc +43 -0
  3. package/.cursor/rules/docs-rules.mdc +3 -1
  4. package/.cursor/rules/project-rules.mdc +1 -0
  5. package/README.md +43 -17
  6. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
  7. package/jest.config.default.js +2 -1
  8. package/jest.config.isolated.js +2 -1
  9. package/jest.global-live-fabrix-hooks.js +36 -0
  10. package/jest.isolated-projects.js +130 -0
  11. package/jest.projects.js +69 -121
  12. package/lib/api/agent-metadata-validation.api.js +93 -0
  13. package/lib/api/api-response-errors.js +124 -0
  14. package/lib/api/audit-api-helpers.js +68 -0
  15. package/lib/api/audit.api.js +119 -0
  16. package/lib/api/auth-cache.api.js +44 -0
  17. package/lib/api/certificates.api.js +4 -4
  18. package/lib/api/credential.api.js +2 -2
  19. package/lib/api/dataplane-health.api.js +137 -0
  20. package/lib/api/dataplane-sync.api.js +27 -0
  21. package/lib/api/datasources-core.api.js +21 -18
  22. package/lib/api/datasources-extended.api.js +22 -22
  23. package/lib/api/dimensions.api.js +3 -0
  24. package/lib/api/external-systems.api.js +13 -13
  25. package/lib/api/governance-scenario-pack.api.js +159 -0
  26. package/lib/api/governance-scenarios.api.js +39 -0
  27. package/lib/api/groups.api.js +79 -0
  28. package/lib/api/index.js +88 -5
  29. package/lib/api/lifecycle.api.js +77 -0
  30. package/lib/api/pipeline.api.js +7 -5
  31. package/lib/api/protection.api.js +157 -0
  32. package/lib/api/records-bulk.api.js +43 -0
  33. package/lib/api/records-search-parse.js +49 -0
  34. package/lib/api/records-search.api.js +29 -0
  35. package/lib/api/types/agent-metadata-validation.types.js +67 -0
  36. package/lib/api/types/audit.types.js +72 -0
  37. package/lib/api/types/dataplane-health.types.js +27 -0
  38. package/lib/api/types/dimensions.types.js +2 -0
  39. package/lib/api/types/governance-scenarios.types.js +39 -0
  40. package/lib/api/types/protection.types.js +69 -0
  41. package/lib/api/types/records-bulk.types.js +35 -0
  42. package/lib/api/types/records-search.types.js +28 -0
  43. package/lib/api/user-groups.api.js +50 -0
  44. package/lib/api/users.api.js +95 -0
  45. package/lib/api/validation-run.api.js +3 -3
  46. package/lib/api/validation-runner.js +5 -3
  47. package/lib/api/wizard-platform.api.js +3 -3
  48. package/lib/api/wizard.api.js +21 -21
  49. package/lib/app/deploy-config.js +4 -1
  50. package/lib/app/deploy.js +34 -19
  51. package/lib/app/down.js +20 -1
  52. package/lib/app/push.js +4 -5
  53. package/lib/app/register.js +7 -4
  54. package/lib/app/run-env-compose.js +84 -30
  55. package/lib/build/index.js +5 -0
  56. package/lib/certification/sync-system-certification.js +13 -6
  57. package/lib/cli/index.js +8 -2
  58. package/lib/cli/infra-guided-auth.js +109 -0
  59. package/lib/cli/infra-guided.js +91 -69
  60. package/lib/cli/setup-app.help.js +19 -2
  61. package/lib/cli/setup-app.js +58 -23
  62. package/lib/cli/setup-app.test-commands.js +28 -21
  63. package/lib/cli/setup-auth.js +55 -3
  64. package/lib/cli/setup-certification-commands.js +147 -0
  65. package/lib/cli/setup-certification.help.js +141 -0
  66. package/lib/cli/setup-environment.js +19 -2
  67. package/lib/cli/setup-external-system-help.js +62 -0
  68. package/lib/cli/setup-external-system.js +62 -6
  69. package/lib/cli/setup-infra.js +9 -1
  70. package/lib/cli/setup-platform.js +6 -1
  71. package/lib/cli/setup-secrets.js +33 -1
  72. package/lib/cli/setup-utility-help-after.js +65 -0
  73. package/lib/cli/setup-utility-repair.js +198 -0
  74. package/lib/cli/setup-utility-resolve.js +42 -6
  75. package/lib/cli/setup-utility-validate.js +197 -0
  76. package/lib/cli/setup-utility.js +41 -258
  77. package/lib/commands/auth-status-client-tokens.js +214 -0
  78. package/lib/commands/auth-status-dataplane-version.js +269 -0
  79. package/lib/commands/auth-status-display.js +94 -0
  80. package/lib/commands/auth-status.js +111 -53
  81. package/lib/commands/credential-push.js +10 -5
  82. package/lib/commands/datasource-load-export-cli.js +178 -0
  83. package/lib/commands/datasource-test-trust-cli.js +118 -0
  84. package/lib/commands/datasource-unified-test-cli.js +31 -20
  85. package/lib/commands/datasource-unified-test-cli.options.js +22 -3
  86. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
  87. package/lib/commands/datasource-verify-audit-cli.js +96 -0
  88. package/lib/commands/datasource.js +68 -1
  89. package/lib/commands/dev-show-display.js +8 -1
  90. package/lib/commands/dimension-value.js +43 -13
  91. package/lib/commands/dimension.js +38 -7
  92. package/lib/commands/governance-cli-shared.js +94 -0
  93. package/lib/commands/governance-command-action.js +132 -0
  94. package/lib/commands/governance-download-external.js +34 -0
  95. package/lib/commands/governance-generate-external.js +71 -0
  96. package/lib/commands/governance-upload-external.js +36 -0
  97. package/lib/commands/governance-verify-external.js +64 -0
  98. package/lib/commands/governance.js +144 -0
  99. package/lib/commands/identity-apply-sync.js +131 -0
  100. package/lib/commands/identity-group-cli.js +146 -0
  101. package/lib/commands/identity-membership-role-cache.js +175 -0
  102. package/lib/commands/identity-shared.js +94 -0
  103. package/lib/commands/identity-user-cli.js +158 -0
  104. package/lib/commands/identity.js +43 -0
  105. package/lib/commands/lifecycle-command-action.js +123 -0
  106. package/lib/commands/lifecycle-external.js +268 -0
  107. package/lib/commands/login.js +56 -17
  108. package/lib/commands/protection-cli-leaves.js +286 -0
  109. package/lib/commands/protection.js +50 -0
  110. package/lib/commands/repair-auth-apply.js +127 -0
  111. package/lib/commands/repair-changed-files.js +41 -0
  112. package/lib/commands/repair-datasource-keys.js +4 -1
  113. package/lib/commands/repair-datasource-run.js +59 -0
  114. package/lib/commands/repair-datasource-test-payload.js +259 -0
  115. package/lib/commands/repair-datasource.js +1 -51
  116. package/lib/commands/repair-env-template.js +64 -13
  117. package/lib/commands/repair-external-run.js +216 -0
  118. package/lib/commands/repair-openapi-sync.js +23 -0
  119. package/lib/commands/repair-persist.js +4 -0
  120. package/lib/commands/repair-rbac.js +52 -1
  121. package/lib/commands/repair-steps.js +145 -0
  122. package/lib/commands/repair.js +29 -286
  123. package/lib/commands/secrets-get.js +184 -0
  124. package/lib/commands/secrets-remove-all.js +3 -1
  125. package/lib/commands/setup-image-refresh.js +146 -0
  126. package/lib/commands/setup-modes.js +158 -162
  127. package/lib/commands/setup-platform-auth.js +76 -0
  128. package/lib/commands/setup-prompts-admin.js +244 -0
  129. package/lib/commands/setup-prompts-platform-mode.js +67 -0
  130. package/lib/commands/setup-prompts-validators.js +36 -0
  131. package/lib/commands/setup-prompts.js +24 -76
  132. package/lib/commands/setup-run-context.js +45 -0
  133. package/lib/commands/setup-spinners.js +39 -0
  134. package/lib/commands/setup.js +27 -5
  135. package/lib/commands/teardown.js +39 -0
  136. package/lib/commands/test-e2e-external.js +61 -14
  137. package/lib/commands/test-governance-cli-options.js +47 -0
  138. package/lib/commands/test-governance-external.js +67 -0
  139. package/lib/commands/test-trust-cli-options.js +32 -0
  140. package/lib/commands/test-trust-external.js +126 -0
  141. package/lib/commands/up-common.js +25 -13
  142. package/lib/commands/up-dataplane.js +50 -13
  143. package/lib/commands/upload-publish-context.js +75 -0
  144. package/lib/commands/upload-sidecar-followups.js +89 -0
  145. package/lib/commands/upload.js +108 -105
  146. package/lib/commands/verify-governance-combined-external.js +61 -0
  147. package/lib/commands/verify-governance-command-action.js +64 -0
  148. package/lib/commands/verify-governance-db.js +102 -0
  149. package/lib/commands/verify-governance-external.js +77 -0
  150. package/lib/commands/verify-governance-result-builders.js +71 -0
  151. package/lib/commands/verify-operations-command-action.js +68 -0
  152. package/lib/commands/verify-operations-external.js +268 -0
  153. package/lib/commands/verify-operations-persist.js +75 -0
  154. package/lib/commands/verify-operations-step-plan.js +68 -0
  155. package/lib/commands/verify-operations-steps.js +111 -0
  156. package/lib/commands/verify-trust-command-action.js +70 -0
  157. package/lib/commands/verify-trust-external.js +67 -0
  158. package/lib/commands/wizard-config-normalizer.js +43 -23
  159. package/lib/commands/wizard-core.js +5 -0
  160. package/lib/core/admin-password-generator.js +38 -0
  161. package/lib/core/admin-secrets-bundle.js +111 -0
  162. package/lib/core/admin-secrets-env-overlay.js +62 -0
  163. package/lib/core/admin-secrets.js +32 -4
  164. package/lib/core/config-attach-extensions.js +3 -0
  165. package/lib/core/config-device-dataplane.js +185 -0
  166. package/lib/core/config-platform-controller.js +44 -0
  167. package/lib/core/config-setup-installation-profile.js +42 -0
  168. package/lib/core/config-setup-platform-mode.js +46 -0
  169. package/lib/core/config.js +46 -36
  170. package/lib/core/secrets-admin-env.js +6 -2
  171. package/lib/core/secrets-ensure.js +4 -0
  172. package/lib/core/secrets-env-content.js +54 -48
  173. package/lib/core/secrets-env-write.js +10 -1
  174. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  175. package/lib/core/setup-installation-profile.js +43 -0
  176. package/lib/core/setup-platform-mode.js +55 -0
  177. package/lib/datasource/agent-trust-debug-log.js +45 -0
  178. package/lib/datasource/agent-trust-fetch.js +115 -0
  179. package/lib/datasource/agent-trust-map.js +101 -0
  180. package/lib/datasource/agent-trust-mock.js +44 -0
  181. package/lib/datasource/agent-trust-run.js +95 -0
  182. package/lib/datasource/agent-trust-timeout.js +25 -0
  183. package/lib/datasource/audit-evidence-display.js +80 -0
  184. package/lib/datasource/audit-evidence-extract-debug.js +115 -0
  185. package/lib/datasource/audit-evidence-extract.js +180 -0
  186. package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
  187. package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
  188. package/lib/datasource/audit-evidence-poll.js +109 -0
  189. package/lib/datasource/audit-evidence-run.js +177 -0
  190. package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
  191. package/lib/datasource/audit-evidence-verify-matrix.js +205 -0
  192. package/lib/datasource/audit-evidence-verify.js +108 -0
  193. package/lib/datasource/bulk-loader-run-batches.js +100 -0
  194. package/lib/datasource/bulk-loader-service-retry.js +52 -0
  195. package/lib/datasource/bulk-loader-service.js +127 -0
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -1
  197. package/lib/datasource/datasource-exporter-resolve.js +82 -0
  198. package/lib/datasource/datasource-exporter-service.js +144 -0
  199. package/lib/datasource/datasource-identifier.js +148 -0
  200. package/lib/datasource/datasource-load-export-context.js +95 -0
  201. package/lib/datasource/integration-context.js +6 -4
  202. package/lib/datasource/local-data-paths.js +145 -0
  203. package/lib/datasource/log-cleaner.js +241 -0
  204. package/lib/datasource/log-viewer.js +111 -6
  205. package/lib/datasource/record-file-parser.js +85 -0
  206. package/lib/datasource/record-mapper.js +129 -0
  207. package/lib/datasource/resolve-app.js +74 -55
  208. package/lib/datasource/test-e2e.js +29 -2
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run-resolve.js +45 -12
  211. package/lib/datasource/unified-validation-run.js +47 -18
  212. package/lib/datasource/validate.js +37 -20
  213. package/lib/deployment/environment-poll-status.js +138 -0
  214. package/lib/deployment/environment.js +42 -34
  215. package/lib/external-system/download.js +21 -20
  216. package/lib/external-system/generator.js +5 -1
  217. package/lib/external-system/integration-auth-context.js +45 -0
  218. package/lib/external-system/test-auth.js +12 -5
  219. package/lib/external-system/test-system-level.js +25 -4
  220. package/lib/external-system/test.js +9 -7
  221. package/lib/generator/external-controller-manifest.js +15 -0
  222. package/lib/governance/governance-cli-errors.js +96 -0
  223. package/lib/governance/governance-download-display.js +38 -0
  224. package/lib/governance/governance-pack-loader.js +70 -0
  225. package/lib/governance/governance-run-display.js +309 -0
  226. package/lib/identity/identity-apply-core.js +108 -0
  227. package/lib/identity/identity-apply-phases.js +244 -0
  228. package/lib/identity/identity-apply-service.js +77 -0
  229. package/lib/identity/identity-csv-parser.js +114 -0
  230. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  231. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  232. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  233. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  234. package/lib/infrastructure/helpers.js +23 -129
  235. package/lib/infrastructure/index.js +5 -6
  236. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  237. package/lib/internal/fs-real-sync.js +29 -1
  238. package/lib/lifecycle/certification-progress.js +231 -0
  239. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  240. package/lib/lifecycle/exit-codes.js +24 -0
  241. package/lib/lifecycle/json-envelope.js +25 -0
  242. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  243. package/lib/lifecycle/logger-quiet.js +29 -0
  244. package/lib/lifecycle/open-api-published.js +59 -0
  245. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  246. package/lib/lifecycle/product-model.js +196 -0
  247. package/lib/lifecycle/report-display.js +471 -0
  248. package/lib/lifecycle/scenario-upload.js +191 -0
  249. package/lib/lifecycle/verify-step-progress.js +87 -0
  250. package/lib/parameters/infra-kv-discovery.js +27 -2
  251. package/lib/protection/auth-context.js +51 -0
  252. package/lib/protection/convert-batch.js +90 -0
  253. package/lib/protection/load.js +41 -0
  254. package/lib/protection/paths.js +158 -0
  255. package/lib/protection/preflight-datasource-ready.js +46 -0
  256. package/lib/protection/protection-create-probe-lines.js +142 -0
  257. package/lib/protection/protection-create-probes.js +95 -0
  258. package/lib/protection/protection-create-scaffold.js +281 -0
  259. package/lib/protection/protection-display-helpers.js +445 -0
  260. package/lib/protection/protection-display.js +215 -0
  261. package/lib/protection/protection-preset-registry.js +97 -0
  262. package/lib/protection/report-exit.js +62 -0
  263. package/lib/protection/resolve.js +202 -0
  264. package/lib/protection/run-commands-validate.js +130 -0
  265. package/lib/protection/run-commands.js +216 -0
  266. package/lib/protection/run-protection-create-helpers.js +134 -0
  267. package/lib/protection/run-protection-create-probes-flow.js +43 -0
  268. package/lib/protection/run-protection-create.js +191 -0
  269. package/lib/protection/scope.js +22 -0
  270. package/lib/protection/sync-after-upload.js +64 -0
  271. package/lib/protection/upload-batch.js +127 -0
  272. package/lib/protection/validate-batch.js +113 -0
  273. package/lib/protection/validate-local.js +65 -0
  274. package/lib/resolvers/dimension-file.js +29 -4
  275. package/lib/schema/application-schema.json +1 -1
  276. package/lib/schema/datasource-test-run.schema.json +89 -6
  277. package/lib/schema/external-datasource.schema.json +2636 -2588
  278. package/lib/schema/external-system.schema.json +1089 -761
  279. package/lib/schema/flag-map-validation-run.json +2 -2
  280. package/lib/schema/infra.parameter.yaml +45 -0
  281. package/lib/schema/protection.schema.json +374 -0
  282. package/lib/schema/type/credential-field-registry.json +642 -0
  283. package/lib/schema/wizard-config.schema.json +1 -1
  284. package/lib/utils/agent-trust-run-display.js +231 -0
  285. package/lib/utils/agent-trust-run-exit.js +59 -0
  286. package/lib/utils/agent-trust-wait-ui.js +94 -0
  287. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  288. package/lib/utils/api.js +55 -31
  289. package/lib/utils/app-relative-path-env.js +112 -0
  290. package/lib/utils/cli-exit-codes.js +30 -0
  291. package/lib/utils/cli-secrets-error-format.js +83 -21
  292. package/lib/utils/cli-sync-options.js +33 -0
  293. package/lib/utils/cli-utils.js +16 -4
  294. package/lib/utils/compose-generate-docker-compose.js +4 -0
  295. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  296. package/lib/utils/config-secrets-path.js +46 -0
  297. package/lib/utils/controller-url.js +88 -1
  298. package/lib/utils/credential-push-ui.js +90 -0
  299. package/lib/utils/credential-secrets-env.js +137 -9
  300. package/lib/utils/dataplane-cli-version-gate.js +202 -0
  301. package/lib/utils/dataplane-cli-version-help.js +74 -0
  302. package/lib/utils/dataplane-resolver.js +129 -2
  303. package/lib/utils/datasource-export-display.js +137 -0
  304. package/lib/utils/datasource-load-display.js +174 -0
  305. package/lib/utils/datasource-load-export-ui.js +120 -0
  306. package/lib/utils/datasource-test-run-capability-scope.js +3 -3
  307. package/lib/utils/datasource-test-run-display.js +3 -3
  308. package/lib/utils/datasource-test-run-tty-log.js +5 -1
  309. package/lib/utils/declarative-url-ports.js +3 -3
  310. package/lib/utils/deployment-auth-mode.js +41 -0
  311. package/lib/utils/developer-volume-id.js +33 -0
  312. package/lib/utils/env-copy.js +14 -9
  313. package/lib/utils/env-kv-orphan-lines.js +43 -0
  314. package/lib/utils/error-formatters/network-errors.js +13 -4
  315. package/lib/utils/external-env-template.js +1 -0
  316. package/lib/utils/external-system-readiness-core.js +10 -0
  317. package/lib/utils/external-system-readiness-display.js +80 -23
  318. package/lib/utils/health-check.js +4 -1
  319. package/lib/utils/help-builder.js +35 -26
  320. package/lib/utils/keycloak-realm-ready.js +101 -0
  321. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  322. package/lib/utils/manifest-source-emit.js +24 -0
  323. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  324. package/lib/utils/platform-controller-url.js +156 -0
  325. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  326. package/lib/utils/postgres-wipe.js +9 -2
  327. package/lib/utils/resolve-env-mode.js +47 -0
  328. package/lib/utils/secrets-generator.js +31 -25
  329. package/lib/utils/secrets-missing-error.js +164 -0
  330. package/lib/utils/semver-compare.js +127 -0
  331. package/lib/utils/service-url-label.js +81 -0
  332. package/lib/utils/setup-quiet-output.js +25 -0
  333. package/lib/utils/template-helpers.js +15 -0
  334. package/lib/utils/token-manager-client-credentials.js +201 -0
  335. package/lib/utils/token-manager-messages.js +8 -0
  336. package/lib/utils/token-manager-refresh.js +12 -2
  337. package/lib/utils/token-manager.js +86 -105
  338. package/lib/utils/upload-pipeline-ui.js +98 -0
  339. package/lib/utils/upload-sync-options.js +42 -0
  340. package/lib/utils/url-declarative-public-base.js +21 -3
  341. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  342. package/lib/utils/validation-poll-ui.js +22 -7
  343. package/lib/utils/validation-run-stage.js +45 -0
  344. package/lib/validation/wizard-config-validator.js +58 -19
  345. package/package.json +1 -1
  346. package/templates/applications/dataplane/application.yaml +2 -1
  347. package/templates/applications/dataplane/env.template +36 -1
  348. package/templates/applications/dataplane/rbac.yaml +4 -0
  349. package/templates/applications/miso-controller/env.template +16 -0
  350. package/templates/external-system/README.md.hbs +116 -11
  351. package/templates/python/docker-compose.hbs +19 -18
  352. package/templates/typescript/docker-compose.hbs +18 -17
@@ -0,0 +1,137 @@
1
+ /**
2
+ * @fileoverview TTY display for `datasource export` (plan 144)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const fs = require('fs');
10
+ const logger = require('./logger');
11
+ const {
12
+ sectionTitle,
13
+ headerKeyValue,
14
+ metadata: metaGray,
15
+ formatSuccessLine,
16
+ formatWarningLine
17
+ } = require('./cli-test-layout-chalk');
18
+ const { emitManifestSourceMetadata } = require('./manifest-source-emit');
19
+ const { integrationManifestLabel } = require('../datasource/datasource-load-export-context');
20
+ const { formatElapsedMs } = require('./datasource-load-export-ui');
21
+
22
+ const SEP = '────────────────────────────────────────────────────────';
23
+
24
+ function logExportHeader(ctx, envLabel) {
25
+ logger.log(SEP);
26
+ logger.log(sectionTitle(`Export records — ${ctx.datasourceKey}`));
27
+ logger.log(headerKeyValue('Environment:', envLabel || '—'));
28
+ logger.log(headerKeyValue('System:', ctx.systemKey));
29
+ logger.log(SEP);
30
+ logger.log(metaGray(' Layer: governed records search (ABAC applied)'));
31
+ logger.log(metaGray(' Not used: direct database access'));
32
+ logger.log('');
33
+ }
34
+
35
+ function logExportVerboseStats(result) {
36
+ const excluded = result.meta?.excluded || {};
37
+ const abac = excluded.abac !== undefined && excluded.abac !== null ? excluded.abac : 0;
38
+ const filterEx =
39
+ excluded.filter !== undefined && excluded.filter !== null ? excluded.filter : 0;
40
+ logger.log(
41
+ metaGray(
42
+ ` Fetched: ${result.recordCount} records · excluded abac ${abac} · filter ${filterEx}`
43
+ )
44
+ );
45
+ const stat = fs.statSync(result.outputFile);
46
+ const mb = (stat.size / (1024 * 1024)).toFixed(2);
47
+ logger.log(
48
+ metaGray(` Wrote: ${result.recordCount} line(s) (${result.format}) · ${mb} MB`)
49
+ );
50
+ logger.log('');
51
+ }
52
+
53
+ /**
54
+ * @param {Object} result
55
+ */
56
+ function displayExportAbacZeroRowsWarning(result) {
57
+ const excludedAbac = Number(result.excludedAbac ?? result.meta?.excluded?.abac) || 0;
58
+ if (result.recordCount !== 0 || excludedAbac <= 0) {
59
+ return;
60
+ }
61
+ logger.log(
62
+ formatWarningLine(
63
+ `Governed search returned 0 rows; ABAC excluded ${excludedAbac} record(s) for your principal.`
64
+ )
65
+ );
66
+ logger.log(
67
+ metaGray(
68
+ ' The physical table may still hold data — export only includes rows your token may read.'
69
+ )
70
+ );
71
+ logger.log(
72
+ metaGray(
73
+ ' Fix: upload a protection manifest (aifabrix protection upload <datasourceKey>) with dimension grants for your user, then retry.'
74
+ )
75
+ );
76
+ logger.log('');
77
+ }
78
+
79
+ /**
80
+ * @param {Object} result
81
+ */
82
+ function displayExportLimitCapWarning(result) {
83
+ if (!result.hitLimitCap) {
84
+ return;
85
+ }
86
+ logger.log(
87
+ formatWarningLine(`Fetched ${result.recordCount} records (limit cap). More rows may exist.`)
88
+ );
89
+ logger.log(metaGray(' Re-run with --filter or wait for dataplane search pagination.'));
90
+ logger.log('');
91
+ }
92
+
93
+ /**
94
+ * @param {Object} result
95
+ */
96
+ function logExportDurationFooter(result) {
97
+ if (result.durationMs === undefined || result.durationMs === null) {
98
+ return;
99
+ }
100
+ logger.log(metaGray(` Completed in ${formatElapsedMs(result.durationMs)}`));
101
+ logger.log('');
102
+ }
103
+
104
+ /**
105
+ * @param {Object} result
106
+ * @param {Object} opts
107
+ */
108
+ function displayDatasourceExportTTY(result, opts = {}) {
109
+ const ctx = result.context || {};
110
+ logExportHeader(ctx, opts.environment);
111
+
112
+ const filterLabel = result.filters ? 'filters (set)' : 'filters (none)';
113
+ logger.log(
114
+ metaGray(` Search: intent ${result.intent} · limit ${result.limit} · ${filterLabel}`)
115
+ );
116
+ emitManifestSourceMetadata({
117
+ tier: 'int',
118
+ configPath: ctx.manifestPath,
119
+ labelPrefix: integrationManifestLabel(ctx.appKey)
120
+ });
121
+ logger.log(metaGray(` Output: ${result.outputFile}`));
122
+ logger.log('');
123
+
124
+ if (opts.verbose) {
125
+ logExportVerboseStats(result);
126
+ }
127
+
128
+ displayExportAbacZeroRowsWarning(result);
129
+ displayExportLimitCapWarning(result);
130
+ logger.log(formatSuccessLine('Export complete'));
131
+ logExportDurationFooter(result);
132
+ logger.log(SEP);
133
+ }
134
+
135
+ module.exports = {
136
+ displayDatasourceExportTTY
137
+ };
@@ -0,0 +1,174 @@
1
+ /**
2
+ * @fileoverview TTY display for `datasource load` (plan 144)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const chalk = require('chalk');
10
+ const logger = require('./logger');
11
+ const {
12
+ sectionTitle,
13
+ headerKeyValue,
14
+ metadata: metaGray,
15
+ formatSuccessLine,
16
+ formatBlockingError,
17
+ successGlyph,
18
+ failureGlyph
19
+ } = require('./cli-test-layout-chalk');
20
+ const { emitManifestSourceMetadata } = require('./manifest-source-emit');
21
+ const { integrationManifestLabel } = require('../datasource/datasource-load-export-context');
22
+ const { formatElapsedMs } = require('./datasource-load-export-ui');
23
+
24
+ const SEP = '────────────────────────────────────────────────────────';
25
+
26
+ function logLoadHeader(ctx, envLabel) {
27
+ logger.log(SEP);
28
+ logger.log(sectionTitle(`Load records — ${ctx.datasourceKey}`));
29
+ logger.log(headerKeyValue('Environment:', envLabel || '—'));
30
+ logger.log(headerKeyValue('System:', ctx.systemKey));
31
+ logger.log(SEP);
32
+ logger.log(metaGray(' Layer: dataplane bulk sync'));
33
+ emitManifestSourceMetadata({
34
+ tier: 'int',
35
+ configPath: ctx.manifestPath,
36
+ labelPrefix: integrationManifestLabel(ctx.appKey)
37
+ });
38
+ }
39
+
40
+ function displayLoadDryRun(result) {
41
+ logger.log(chalk.cyan(' Mode: dry-run (no upload)'));
42
+ logger.log('');
43
+ const mb = (result.estimatedPayloadBytes / (1024 * 1024)).toFixed(2);
44
+ const batchCount = Math.ceil(result.recordCount / result.batchSize) || 0;
45
+ logger.log(
46
+ metaGray(
47
+ ` Parsed: ${result.recordCount} records · format ${result.format} · est. payload ~${mb} MB`
48
+ )
49
+ );
50
+ logger.log(
51
+ metaGray(` Would upload: ${batchCount} batch(es) · syncType ${result.syncType}`)
52
+ );
53
+ logger.log('');
54
+ logger.log(formatSuccessLine('Dry-run passed'));
55
+ }
56
+
57
+ function displayLoadBatchesVerbose(batches) {
58
+ batches.forEach(batch => {
59
+ if (batch.error) {
60
+ logger.log(
61
+ ` Batch ${batch.index}/${batch.total} ${failureGlyph()} failed (${batch.error})`
62
+ );
63
+ return;
64
+ }
65
+ const failed = Array.isArray(batch.failed) ? batch.failed.length : 0;
66
+ if (failed > 0) {
67
+ logger.log(
68
+ ` Batch ${batch.index}/${batch.total} ${failureGlyph()} failed ${failed} of ${batch.recordCount || '?'}`
69
+ );
70
+ return;
71
+ }
72
+ logger.log(
73
+ ` Batch ${batch.index}/${batch.total} ${successGlyph()} inserted ${batch.insertedCount || 0} · updated ${batch.updatedCount || 0} · failed 0`
74
+ );
75
+ });
76
+ }
77
+
78
+ const MAX_FAILURE_LINES = 5;
79
+
80
+ /**
81
+ * @param {Object[]} batches
82
+ */
83
+ function displayLoadFailureSamples(batches) {
84
+ const samples = [];
85
+ (batches || []).forEach(batch => {
86
+ if (!Array.isArray(batch.failed)) return;
87
+ batch.failed.forEach(item => {
88
+ if (samples.length >= MAX_FAILURE_LINES) return;
89
+ const key = item.key ? String(item.key) : '—';
90
+ const message = item.message || batch.error || 'failed';
91
+ samples.push({ key, message });
92
+ });
93
+ });
94
+ if (samples.length === 0) return;
95
+ logger.log('');
96
+ logger.log(chalk.white(` Failures (first ${MAX_FAILURE_LINES})`));
97
+ samples.forEach(({ key, message }) => {
98
+ logger.log(` • ${key} — ${message}`);
99
+ });
100
+ }
101
+
102
+ function displayLoadVerdict(result) {
103
+ const failed = result.totals.failedCount || 0;
104
+ const ok = result.recordCount - failed;
105
+ if (failed > 0) {
106
+ if (result.batches && result.batches.length > 0) {
107
+ displayLoadFailureSamples(result.batches);
108
+ logger.log('');
109
+ }
110
+ logger.log(formatBlockingError(`${ok} ok · ${failed} failed`));
111
+ } else {
112
+ logger.log(
113
+ formatSuccessLine(
114
+ `${result.recordCount} processed · ${result.totals.insertedCount} inserted · ${result.totals.updatedCount} updated · 0 failed`
115
+ )
116
+ );
117
+ }
118
+ }
119
+
120
+ /**
121
+ * @param {Object} result
122
+ */
123
+ function logLoadDurationFooter(result) {
124
+ if (result.durationMs === undefined || result.durationMs === null) {
125
+ return;
126
+ }
127
+ logger.log(metaGray(` Completed in ${formatElapsedMs(result.durationMs)}`));
128
+ logger.log('');
129
+ }
130
+
131
+ /**
132
+ * @param {Object} result
133
+ * @param {Object} opts
134
+ */
135
+ function displayLoadUploadSummary(result, opts) {
136
+ const batchCount = Math.ceil(result.recordCount / result.batchSize) || 0;
137
+ logger.log(
138
+ metaGray(
139
+ ` Parsed: ${result.recordCount} records · format ${result.format} · est. ${batchCount} batch(es) @ ${result.batchSize}`
140
+ )
141
+ );
142
+ logger.log('');
143
+ if (opts.verbose) {
144
+ displayLoadBatchesVerbose(result.batches);
145
+ logger.log('');
146
+ }
147
+ displayLoadVerdict(result);
148
+ }
149
+
150
+ /**
151
+ * @param {Object} result
152
+ * @param {Object} opts
153
+ */
154
+ function displayDatasourceLoadTTY(result, opts = {}) {
155
+ const ctx = result.context || {};
156
+ logLoadHeader(ctx, opts.environment);
157
+ logger.log(metaGray(` Data file: ${result.file}`));
158
+ logger.log('');
159
+
160
+ if (result.dryRun) {
161
+ displayLoadDryRun(result);
162
+ logLoadDurationFooter(result);
163
+ logger.log(SEP);
164
+ return;
165
+ }
166
+
167
+ displayLoadUploadSummary(result, opts);
168
+ logLoadDurationFooter(result);
169
+ logger.log(SEP);
170
+ }
171
+
172
+ module.exports = {
173
+ displayDatasourceLoadTTY
174
+ };
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @fileoverview Spinner + elapsed time for datasource load/export (plan 144)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const chalk = require('chalk');
10
+ const logger = require('./logger');
11
+ const { formatProgress } = require('./cli-test-layout-chalk');
12
+
13
+ /**
14
+ * @param {number} ms
15
+ * @returns {string}
16
+ */
17
+ function formatElapsedMs(ms) {
18
+ const n = Math.max(0, Math.round(Number(ms) || 0));
19
+ if (n < 1000) {
20
+ return `${n} ms`;
21
+ }
22
+ if (n < 60000) {
23
+ const sec = n / 1000;
24
+ return sec >= 10 ? `${Math.round(sec)} s` : `${sec.toFixed(1)} s`;
25
+ }
26
+ const min = Math.floor(n / 60000);
27
+ const sec = Math.round((n % 60000) / 1000);
28
+ return sec > 0 ? `${min} m ${sec} s` : `${min} m`;
29
+ }
30
+
31
+ /**
32
+ * @param {Object} [options]
33
+ * @param {boolean} [options.json]
34
+ * @returns {boolean}
35
+ */
36
+ function shouldShowDatasourceLoadExportProgress(options = {}) {
37
+ return options.json !== true;
38
+ }
39
+
40
+ /**
41
+ * @param {Object} [options]
42
+ * @returns {boolean}
43
+ */
44
+ function shouldUseDatasourceLoadExportSpinner(options = {}) {
45
+ if (!shouldShowDatasourceLoadExportProgress(options)) {
46
+ return false;
47
+ }
48
+ return Boolean(process && process.stdout && process.stdout.isTTY);
49
+ }
50
+
51
+ /**
52
+ * @param {string} operation
53
+ * @param {string} datasourceKey
54
+ * @returns {string}
55
+ */
56
+ function buildDatasourceLoadExportSpinnerLabel(operation, datasourceKey) {
57
+ const key =
58
+ datasourceKey && String(datasourceKey).trim() ? String(datasourceKey).trim() : 'datasource';
59
+ if (operation === 'export') {
60
+ return `Exporting records for ${key}…`;
61
+ }
62
+ if (operation === 'load-dry-run') {
63
+ return `Parsing records for ${key}…`;
64
+ }
65
+ return `Loading records for ${key} into dataplane…`;
66
+ }
67
+
68
+ /**
69
+ * @param {string} operation
70
+ * @param {string} datasourceKey
71
+ * @returns {string}
72
+ */
73
+ function buildDatasourceLoadExportProgressText(operation, datasourceKey) {
74
+ return formatProgress(buildDatasourceLoadExportSpinnerLabel(operation, datasourceKey));
75
+ }
76
+
77
+ /**
78
+ * @async
79
+ * @param {Function} work
80
+ * @param {Object} [opts]
81
+ * @param {'load'|'load-dry-run'|'export'} [opts.operation]
82
+ * @param {string} [opts.datasourceKey]
83
+ * @param {boolean} [opts.json]
84
+ * @returns {Promise<*>}
85
+ */
86
+ async function runWithDatasourceLoadExportSpinner(work, opts = {}) {
87
+ if (!shouldShowDatasourceLoadExportProgress(opts)) {
88
+ return work();
89
+ }
90
+
91
+ const operation = opts.operation || 'load';
92
+ const datasourceKey = opts.datasourceKey || '';
93
+
94
+ if (!shouldUseDatasourceLoadExportSpinner(opts)) {
95
+ logger.log(buildDatasourceLoadExportProgressText(operation, datasourceKey));
96
+ return work();
97
+ }
98
+
99
+ const ora = require('ora');
100
+ const label = buildDatasourceLoadExportSpinnerLabel(operation, datasourceKey);
101
+ const spinner = ora({
102
+ text: chalk.white(label),
103
+ spinner: 'dots'
104
+ }).start();
105
+
106
+ try {
107
+ return await work();
108
+ } finally {
109
+ spinner.stop();
110
+ }
111
+ }
112
+
113
+ module.exports = {
114
+ formatElapsedMs,
115
+ shouldShowDatasourceLoadExportProgress,
116
+ shouldUseDatasourceLoadExportSpinner,
117
+ buildDatasourceLoadExportSpinnerLabel,
118
+ buildDatasourceLoadExportProgressText,
119
+ runWithDatasourceLoadExportSpinner
120
+ };
@@ -1,12 +1,12 @@
1
1
  /**
2
- * @fileoverview Single-capability CLI contract when --capability is set.
2
+ * @fileoverview Single-capability CLI contract when positional [capabilityKey] is set.
3
3
  * @author AI Fabrix Team
4
4
  * @version 2.0.0
5
5
  */
6
6
 
7
7
  /**
8
8
  * @param {Object|null|undefined} envelope - DatasourceTestRun-like
9
- * @param {string|undefined|null} requestedCapabilityKey - From CLI --capability
9
+ * @param {string|undefined|null} requestedCapabilityKey - From positional [capabilityKey]
10
10
  * @returns {{ violated: boolean, message?: string, count?: number }}
11
11
  */
12
12
  function analyzeCapabilityScope(envelope, requestedCapabilityKey) {
@@ -34,7 +34,7 @@ function analyzeCapabilityScope(envelope, requestedCapabilityKey) {
34
34
  return {
35
35
  violated: true,
36
36
  count: caps.length,
37
- message: `Capabilities scope: with --capability "${key}", expected a single row in capabilities[]; server returned ${caps.length} (${preview}${suffix}).`
37
+ message: `Capabilities scope: with capabilityKey "${key}", expected a single row in capabilities[]; server returned ${caps.length} (${preview}${suffix}).`
38
38
  };
39
39
  }
40
40
 
@@ -98,7 +98,7 @@ function colorStepLine(ok, body) {
98
98
  }
99
99
 
100
100
  /**
101
- * Normalize CLI --capability value for matching envelope.capabilities[].key
101
+ * Normalize positional [capabilityKey] for matching envelope.capabilities[].key
102
102
  * @param {*} focusCapabilityKey
103
103
  * @returns {string} trimmed or ''
104
104
  */
@@ -354,7 +354,7 @@ function pickExecutiveVerdictLine(envelope) {
354
354
  }
355
355
 
356
356
  /**
357
- * Plan §3.9: explicit line when E2E has no capability rows (skipped when --capability drill-down is active).
357
+ * Plan §3.9: explicit line when E2E has no capability rows (skipped when capability drill-down is active).
358
358
  * @param {string[]} lines
359
359
  * @param {Object} envelope
360
360
  * @param {{ focusCapabilityKey?: string }} [options]
@@ -428,7 +428,7 @@ function formatDatasourceTestRunSummary(envelope, options = {}) {
428
428
  * focusCapabilityKey?: string,
429
429
  * includeRefs?: boolean,
430
430
  * includeDebugExecutionSummary?: boolean
431
- * }} [options] - When focusCapabilityKey set (e.g. --capability), append single-cap block (plan §2.3).
431
+ * }} [options] - When focusCapabilityKey set (positional [capabilityKey]), append single-cap block (plan §2.3).
432
432
  * includeDebugExecutionSummary: show dataplane `debug.executionSummary` in header (TTY debug appendix uses CLI `--debug`).
433
433
  * @returns {string}
434
434
  */
@@ -49,7 +49,11 @@ function printDatasourceTestRunForTTY(envelope, options = {}) {
49
49
  includeDebugExecutionSummary: Boolean(mode)
50
50
  };
51
51
  if (options.json) {
52
- logger.log(JSON.stringify(envelope));
52
+ const payload =
53
+ options.auditEvidenceVerification && typeof options.auditEvidenceVerification === 'object'
54
+ ? { ...envelope, auditEvidenceVerification: options.auditEvidenceVerification }
55
+ : envelope;
56
+ logger.log(JSON.stringify(payload));
53
57
  return;
54
58
  }
55
59
  if (options.summary) {
@@ -21,7 +21,7 @@ function parseDeveloperIdNum(raw) {
21
21
  }
22
22
 
23
23
  /**
24
- * Docker published host port: port + devId*100 (dev 0 → base port).
24
+ * Host port for compose publish, localhost URLs, and health checks: port + devId×100 (dev 0 → base port).
25
25
  * @param {number} appPort - Manifest listen port
26
26
  * @param {number} developerIdNum
27
27
  * @returns {number}
@@ -31,13 +31,13 @@ function publishedHostPort(appPort, developerIdNum) {
31
31
  }
32
32
 
33
33
  /**
34
- * Local workstation host port: port + 10 + devId*100 (dev 0 → port+10).
34
+ * Same as {@link publishedHostPort} (legacy name kept for call sites).
35
35
  * @param {number} appPort
36
36
  * @param {number} developerIdNum
37
37
  * @returns {number}
38
38
  */
39
39
  function localHostPort(appPort, developerIdNum) {
40
- return appPort + 10 + developerIdNum * 100;
40
+ return publishedHostPort(appPort, developerIdNum);
41
41
  }
42
42
 
43
43
  module.exports = {
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Deployment auth mode for pipeline publish / external integration CLI.
3
+ * @fileoverview AIFABRIX_DEPLOYMENT_AUTH and options.deploymentAuth parsing
4
+ * @author AI Fabrix Team
5
+ * @version 1.0.0
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ /**
11
+ * @typedef {'auto'|'client-credentials'|'device'} DeploymentAuthMode
12
+ */
13
+
14
+ /**
15
+ * @param {Object} [options] - CLI or caller options
16
+ * @returns {DeploymentAuthMode}
17
+ */
18
+ function getDeploymentAuthMode(options = {}) {
19
+ const raw = options.deploymentAuth || process.env.AIFABRIX_DEPLOYMENT_AUTH || 'auto';
20
+ const mode = String(raw).trim().toLowerCase().replace(/_/g, '-');
21
+ if (mode === 'client-credentials' || mode === 'client') {
22
+ return 'client-credentials';
23
+ }
24
+ if (mode === 'device' || mode === 'device-token' || mode === 'bearer') {
25
+ return 'device';
26
+ }
27
+ return 'auto';
28
+ }
29
+
30
+ /**
31
+ * @param {DeploymentAuthMode} mode
32
+ * @returns {boolean}
33
+ */
34
+ function shouldUseDeviceTokenForDeployment(mode) {
35
+ return mode !== 'client-credentials';
36
+ }
37
+
38
+ module.exports = {
39
+ getDeploymentAuthMode,
40
+ shouldUseDeviceTokenForDeployment
41
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Developer ID suffix variants for Docker volume names (`dev6` vs `dev06`).
3
+ *
4
+ * @fileoverview Volume name suffix normalization for multi-dev Docker
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /**
12
+ * @param {string|number} developerId
13
+ * @returns {string[]}
14
+ */
15
+ function collectDeveloperVolumeIdSuffixes(developerId) {
16
+ const raw = String(developerId).trim();
17
+ const idNum = parseInt(raw, 10);
18
+ if (Number.isNaN(idNum) || idNum === 0) {
19
+ return ['0'];
20
+ }
21
+ const suffixes = new Set([String(idNum), raw]);
22
+ if (raw.length === 1) {
23
+ suffixes.add(raw.padStart(2, '0'));
24
+ }
25
+ if (String(idNum).length === 1) {
26
+ suffixes.add(String(idNum).padStart(2, '0'));
27
+ }
28
+ return [...suffixes];
29
+ }
30
+
31
+ module.exports = {
32
+ collectDeveloperVolumeIdSuffixes
33
+ };
@@ -272,14 +272,16 @@ async function patchEnvContentForLocal(envContent, variables) {
272
272
  * @param {string} outputPath - Resolved `build.envOutputPath`
273
273
  * @param {string} envOutputPathLabel - Label for log (e.g. raw `build.envOutputPath` value)
274
274
  */
275
- async function syncWrittenBuilderEnvToOutputPath(envPath, outputPath, envOutputPathLabel) {
275
+ async function syncWrittenBuilderEnvToOutputPath(envPath, outputPath, envOutputPathLabel, copyOptions = {}) {
276
276
  const { parseEnvContentToMap, mergeEnvMapIntoContent } = require('../core/secrets');
277
277
  const raw = fs.readFileSync(envPath, 'utf8');
278
278
  const synced = substituteMntDataForLocal(raw, outputPath);
279
279
  let toWrite = synced;
280
- if (fs.existsSync(outputPath)) {
280
+ if (!copyOptions.freshEnv && fs.existsSync(outputPath)) {
281
281
  const existingContent = fs.readFileSync(outputPath, 'utf8');
282
- toWrite = mergeEnvMapIntoContent(existingContent, parseEnvContentToMap(synced));
282
+ toWrite = mergeEnvMapIntoContent(existingContent, parseEnvContentToMap(synced), {
283
+ appendMissingFromNewMap: true
284
+ });
283
285
  }
284
286
  fs.writeFileSync(outputPath, toWrite, { mode: 0o600 });
285
287
  logger.log(formatSuccessLine(`Copied resolved .env to envOutputPath (${envOutputPathLabel})`));
@@ -300,10 +302,10 @@ async function writeLocalEnvToOutputPath(outputPath, appName, secretsPath, envOu
300
302
  let localEnvContent = await generateEnvContent(appName, secretsPath, 'local', false, genOpts);
301
303
  localEnvContent = substituteMntDataForLocal(localEnvContent, outputPath);
302
304
  let toWrite = localEnvContent;
303
- if (fs.existsSync(outputPath)) {
305
+ if (!extraOpts.freshEnv && fs.existsSync(outputPath)) {
304
306
  const existingContent = fs.readFileSync(outputPath, 'utf8');
305
307
  const localMap = parseEnvContentToMap(localEnvContent);
306
- toWrite = mergeEnvMapIntoContent(existingContent, localMap);
308
+ toWrite = mergeEnvMapIntoContent(existingContent, localMap, { appendMissingFromNewMap: true });
307
309
  }
308
310
  fs.writeFileSync(outputPath, toWrite, { mode: 0o600 });
309
311
  logger.log(formatSuccessLine(`Generated local .env at: ${envOutputPathLabel}`));
@@ -350,15 +352,16 @@ async function copyOrRegenerateEnvForNamedApp(opts) {
350
352
  secretsPath,
351
353
  label,
352
354
  preferLocal,
353
- appPathForLocal
355
+ appPathForLocal,
356
+ freshEnv
354
357
  } = opts;
355
- const localOpts = { appPath: appPathForLocal || undefined };
358
+ const localOpts = { appPath: appPathForLocal || undefined, freshEnv: freshEnv === true };
356
359
  if (preferLocal) {
357
360
  await writeLocalEnvToOutputPath(outputPath, appName, secretsPath, label, localOpts);
358
361
  return;
359
362
  }
360
363
  if (fs.existsSync(envPath)) {
361
- await syncWrittenBuilderEnvToOutputPath(envPath, outputPath, label);
364
+ await syncWrittenBuilderEnvToOutputPath(envPath, outputPath, label, { freshEnv: freshEnv === true });
362
365
  return;
363
366
  }
364
367
  await writeLocalEnvToOutputPath(outputPath, appName, secretsPath, label, localOpts);
@@ -386,6 +389,7 @@ async function processEnvVariables(envPath, variablesPath, appName, secretsPath,
386
389
  (variablesPath ? path.dirname(variablesPath) : null);
387
390
  const preferLocal =
388
391
  copyOptions && typeof copyOptions === 'object' && copyOptions.preferLocalEnvOutputPath === true;
392
+ const freshEnv = copyOptions && typeof copyOptions === 'object' && copyOptions.freshEnv === true;
389
393
  if (appName) {
390
394
  await copyOrRegenerateEnvForNamedApp({
391
395
  envPath,
@@ -394,7 +398,8 @@ async function processEnvVariables(envPath, variablesPath, appName, secretsPath,
394
398
  secretsPath,
395
399
  label,
396
400
  preferLocal,
397
- appPathForLocal
401
+ appPathForLocal,
402
+ freshEnv
398
403
  });
399
404
  } else {
400
405
  await writePatchedEnvToOutputPath(envPath, outputPath, variables, label);