@gfdelarue/testkit 0.4.4 → 0.5.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 (817) hide show
  1. package/README.md +752 -462
  2. package/bin/testkit-windows-owner-arm64.exe +0 -0
  3. package/bin/testkit-windows-owner-x64.exe +0 -0
  4. package/dist/app/bugs/categories.js +1 -1
  5. package/dist/app/bugs/ci-report.js +2 -2
  6. package/dist/app/bugs/ci-summary.js +3 -3
  7. package/dist/app/bugs/draft.js +4 -4
  8. package/dist/app/bugs/facts.js +2 -2
  9. package/dist/app/bugs/file.js +1 -1
  10. package/dist/app/bugs/gate.js +1 -1
  11. package/dist/app/bugs/guide.js +3 -3
  12. package/dist/app/bugs/issue.js +4 -4
  13. package/dist/app/bugs/known-failures.js +1 -1
  14. package/dist/app/bugs/record.js +2 -2
  15. package/dist/app/bugs/run-reading.js +1 -1
  16. package/dist/app/bugs/supplied-reproduce.js +1 -0
  17. package/dist/app/campaigns/campaign.js +1 -1
  18. package/dist/app/cleanup/index.js +1 -1
  19. package/dist/app/db-schema/prepare.js +1 -1
  20. package/dist/app/destroy/index.js +1 -1
  21. package/dist/app/discover/index.js +2 -2
  22. package/dist/app/doctor/index.js +1 -1
  23. package/dist/app/environments/config-driven.js +1 -0
  24. package/dist/app/environments/environment-file.js +1 -0
  25. package/dist/app/environments/file-setup.js +1 -0
  26. package/dist/app/environments/routing.js +1 -0
  27. package/dist/app/environments/static-values.js +1 -0
  28. package/dist/app/environments/supplied-input.js +1 -0
  29. package/dist/app/environments/supplied.js +1 -0
  30. package/dist/app/environments/task-databases.js +2 -0
  31. package/dist/app/file-selection.js +1 -1
  32. package/dist/app/inspect/artifacts.js +1 -1
  33. package/dist/app/inspect/index.js +1 -1
  34. package/dist/app/lint/index.js +1 -1
  35. package/dist/app/lint/native.js +1 -1
  36. package/dist/app/lint/options.js +1 -1
  37. package/dist/app/lint/rules/data.js +1 -1
  38. package/dist/app/lint/rules/engine-imports.js +1 -1
  39. package/dist/app/lint/rules/syntax.js +1 -1
  40. package/dist/app/lint/rules/unit.js +1 -1
  41. package/dist/app/lint/shared.js +1 -1
  42. package/dist/app/package-inspection.js +1 -1
  43. package/dist/app/reports/files.js +1 -0
  44. package/dist/app/reports/prepare.js +2 -0
  45. package/dist/app/reports/publish.js +1 -0
  46. package/dist/app/run/caller-redaction.js +1 -0
  47. package/dist/app/run/engine-evidence-persistence.js +1 -1
  48. package/dist/app/run/engine-execution-failures.js +1 -1
  49. package/dist/app/run/engine-execution-reporting.js +1 -1
  50. package/dist/app/run/engine-execution.js +1 -1
  51. package/dist/app/run/engine-orchestration.js +1 -1
  52. package/dist/app/run/environment.js +1 -0
  53. package/dist/app/run/failure-details.js +1 -1
  54. package/dist/app/run/live-run.js +1 -1
  55. package/dist/app/run/orchestrator.js +1 -1
  56. package/dist/app/run/planning.js +1 -1
  57. package/dist/app/run/request.js +1 -1
  58. package/dist/app/run/results.js +1 -1
  59. package/dist/app/run/run-events.js +1 -1
  60. package/dist/app/run/run-finalization.js +1 -1
  61. package/dist/app/run/runtime-fixtures.js +1 -1
  62. package/dist/app/run/scheduler/estimates.js +1 -1
  63. package/dist/app/run/scheduler/identity.js +1 -1
  64. package/dist/app/run/scheduler/index.js +1 -1
  65. package/dist/app/run/scheduler/locks.js +1 -0
  66. package/dist/app/run/selection.js +1 -1
  67. package/dist/app/run/setup/runtime-node-setup-protocol.js +1 -1
  68. package/dist/app/run/setup/runtime-node-setup-worker.js +1 -1
  69. package/dist/app/run/setup/runtime-node-setup.js +2 -2
  70. package/dist/app/run/task-batches.js +1 -1
  71. package/dist/app/run/task-leases.js +1 -0
  72. package/dist/app/run/worker-loop.js +1 -1
  73. package/dist/app/status/runs.js +1 -1
  74. package/dist/app/tracker/index.js +1 -1
  75. package/dist/app/typecheck/index.js +4 -4
  76. package/dist/cli/command-catalog.js +1 -1
  77. package/dist/cli/command-flags.js +1 -1
  78. package/dist/cli/command-registry.js +1 -1
  79. package/dist/cli/commands/artifacts.js +2 -2
  80. package/dist/cli/commands/bug/file.js +2 -2
  81. package/dist/cli/commands/bug/record.js +2 -2
  82. package/dist/cli/commands/discover.js +1 -1
  83. package/dist/cli/commands/report/prepare.js +5 -0
  84. package/dist/cli/commands/report/publish.js +2 -0
  85. package/dist/cli/commands/run.js +2 -2
  86. package/dist/cli/commands/typecheck.js +1 -1
  87. package/dist/cli/commands/workspace.js +1 -1
  88. package/dist/cli/framework/errors.js +1 -1
  89. package/dist/cli/framework/execute.js +7 -6
  90. package/dist/cli/framework/parser.js +1 -1
  91. package/dist/cli/json-errors.js +1 -1
  92. package/dist/cli/operations/run/operation.js +2 -2
  93. package/dist/cli/renderers/bug/text.js +1 -1
  94. package/dist/cli/renderers/discover/report.js +1 -1
  95. package/dist/cli/renderers/doctor/text.js +1 -1
  96. package/dist/cli/renderers/run/events.js +2 -2
  97. package/dist/cli/renderers/run/formatting.js +1 -1
  98. package/dist/cli/renderers/run/status.js +1 -1
  99. package/dist/cli/renderers/run/text-reporter.js +24 -22
  100. package/dist/cli/terminal/colors.js +1 -1
  101. package/dist/cli/terminal/layout.js +2 -2
  102. package/dist/config/authoring/http-methods.js +1 -1
  103. package/dist/config/authoring/index.js +1 -1
  104. package/dist/config/authoring/preset-env.js +1 -1
  105. package/dist/config/loader/config-loader.js +1 -1
  106. package/dist/config/loader/database.js +1 -1
  107. package/dist/config/loader/decode-execution.js +1 -1
  108. package/dist/config/loader/dependencies.js +1 -1
  109. package/dist/config/loader/discover-tests.js +1 -1
  110. package/dist/config/loader/discovery-summary.js +1 -1
  111. package/dist/config/loader/discovery.js +2 -2
  112. package/dist/config/loader/env.js +1 -1
  113. package/dist/config/loader/execution-model.js +1 -1
  114. package/dist/config/loader/file-metadata.js +1 -1
  115. package/dist/config/loader/groups.js +1 -0
  116. package/dist/config/loader/index.js +1 -1
  117. package/dist/config/loader/load.js +1 -1
  118. package/dist/config/loader/managed-configs.js +1 -1
  119. package/dist/config/loader/owned-discovery.js +1 -0
  120. package/dist/config/loader/path-policy.js +1 -1
  121. package/dist/config/loader/runtime-isolation.js +1 -1
  122. package/dist/config/loader/runtime.js +1 -1
  123. package/dist/config/loader/skip-config.js +1 -1
  124. package/dist/config/loader/task-policy.js +1 -0
  125. package/dist/config/loader/test-selection.js +1 -1
  126. package/dist/config/loader/validation.js +1 -1
  127. package/dist/database/activity-gate.js +1 -1
  128. package/dist/database/admin.js +2 -2
  129. package/dist/database/bindings.js +1 -0
  130. package/dist/database/cleanup.js +1 -1
  131. package/dist/database/docker-metadata.js +3 -3
  132. package/dist/database/docker.js +3 -3
  133. package/dist/database/index.js +1 -1
  134. package/dist/database/lifecycle-cleanup.js +1 -1
  135. package/dist/database/local-postgres.js +1 -1
  136. package/dist/database/naming.js +1 -1
  137. package/dist/database/postgres/connection-check.js +1 -0
  138. package/dist/database/postgres/protocol.js +2 -0
  139. package/dist/database/schema-operations.js +1 -1
  140. package/dist/database/schema-source.js +3 -3
  141. package/dist/database/source-schema-env.js +1 -0
  142. package/dist/database/source-url.js +2 -2
  143. package/dist/database/state-files.js +1 -1
  144. package/dist/database/state.js +1 -1
  145. package/dist/database/steps.js +3 -3
  146. package/dist/domain/file-timeout.js +1 -1
  147. package/dist/domain/identifiers.js +1 -1
  148. package/dist/domain/operation-display.js +1 -1
  149. package/dist/domain/retired-test-types.js +1 -0
  150. package/dist/domain/runtime-isolation-contract.js +1 -1
  151. package/dist/domain/suite-selection.js +1 -1
  152. package/dist/domain/test-outcomes.js +1 -1
  153. package/dist/domain/test-types.js +1 -1
  154. package/dist/engines/adapters/evidence-files.js +1 -1
  155. package/dist/engines/adapters/evidence-identity.js +1 -1
  156. package/dist/engines/adapters/execution.js +1 -1
  157. package/dist/engines/adapters/json-bounds.js +2 -0
  158. package/dist/engines/adapters/native-report.js +1 -1
  159. package/dist/engines/api/execution-scope.js +1 -1
  160. package/dist/engines/api/execution.js +1 -1
  161. package/dist/engines/api/index.js +1 -1
  162. package/dist/engines/api/runtime-artifact.js +1 -1
  163. package/dist/engines/bundle-cache.js +1 -1
  164. package/dist/engines/catalog.js +1 -1
  165. package/dist/engines/contracts/environment-values.js +1 -0
  166. package/dist/engines/contracts/fixture-manifest.js +1 -1
  167. package/dist/engines/definitions.js +1 -1
  168. package/dist/engines/environment/handles.js +1 -0
  169. package/dist/engines/environment/index.js +1 -0
  170. package/dist/engines/factory.js +1 -1
  171. package/dist/engines/installations/node-vitest.js +1 -1
  172. package/dist/engines/installations/package-resolution.js +1 -1
  173. package/dist/engines/installations/playwright-resolution-child.js +1 -1
  174. package/dist/engines/installations/playwright.js +1 -1
  175. package/dist/engines/managed-module-resolution-policy-input.js +1 -1
  176. package/dist/engines/managed-module-resolution-policy.js +1 -1
  177. package/dist/engines/managed-module-resolution.js +2 -2
  178. package/dist/engines/manager.js +1 -1
  179. package/dist/engines/node-vitest/adapter/adapter.js +1 -1
  180. package/dist/engines/node-vitest/adapter/driver.js +2 -0
  181. package/dist/engines/node-vitest/adapter/evidence.js +2 -2
  182. package/dist/engines/node-vitest/adapter/failure-details.js +4 -2
  183. package/dist/engines/node-vitest/adapter/reporter.js +1 -1
  184. package/dist/engines/node-vitest/adapter/workspace.js +31 -192
  185. package/dist/engines/node-vitest/inventory/index.js +2 -0
  186. package/dist/engines/node-vitest/inventory/list-files.js +3 -0
  187. package/dist/engines/node-vitest/runtime/contract/index.js +1 -1
  188. package/dist/engines/node-vitest/runtime/data/http.js +1 -1
  189. package/dist/engines/node-vitest/runtime/data/index.js +1 -1
  190. package/dist/engines/node-vitest/runtime/data/report.js +5 -6
  191. package/dist/engines/node-vitest/runtime/data/scenario.js +2 -2
  192. package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
  193. package/dist/engines/node-vitest/selection.js +1 -0
  194. package/dist/engines/playwright/adapter/adapter.js +1 -1
  195. package/dist/engines/playwright/adapter/config.js +4 -4
  196. package/dist/engines/playwright/adapter/evidence-validation.js +1 -1
  197. package/dist/engines/playwright/adapter/evidence.js +1 -1
  198. package/dist/engines/playwright/adapter/reporter.js +1 -1
  199. package/dist/engines/playwright/runtime/config-file.js +1 -1
  200. package/dist/engines/playwright/runtime/config.js +1 -1
  201. package/dist/engines/playwright/runtime/runtime-input.js +43 -20
  202. package/dist/engines/runtime-input-file.js +1 -1
  203. package/dist/environment/lifecycle-artifacts.js +1 -1
  204. package/dist/environment/lifecycle-controller.js +1 -1
  205. package/dist/environment/lifecycle.js +1 -1
  206. package/dist/environment/ports.js +1 -0
  207. package/dist/environment/ready-environment.js +1 -1
  208. package/dist/environment/run-environment.js +1 -1
  209. package/dist/environment/run-stopping.js +1 -1
  210. package/dist/environment/runtime-contexts.js +1 -1
  211. package/dist/environment/runtime-manager.js +1 -1
  212. package/dist/environment/runtime-planning.js +1 -1
  213. package/dist/environment/runtime-preparation.js +1 -1
  214. package/dist/environment/services.js +3 -1
  215. package/dist/environment/state.js +1 -1
  216. package/dist/environment/template.js +1 -1
  217. package/dist/evidence/artifact-config.js +1 -1
  218. package/dist/evidence/artifact-validation.js +1 -1
  219. package/dist/evidence/artifacts.js +2 -2
  220. package/dist/evidence/bundles.js +1 -1
  221. package/dist/evidence/environment-record.js +1 -0
  222. package/dist/evidence/index.js +1 -1
  223. package/dist/evidence/logs.js +2 -2
  224. package/dist/evidence/operation-timings.js +1 -1
  225. package/dist/evidence/read-fields.js +1 -1
  226. package/dist/evidence/read-run.js +1 -1
  227. package/dist/evidence/reading.js +1 -1
  228. package/dist/evidence/redaction.js +4 -0
  229. package/dist/evidence/reporting.js +1 -1
  230. package/dist/evidence/run-model.js +1 -0
  231. package/dist/evidence/storage.js +2 -2
  232. package/dist/evidence/timing.js +1 -1
  233. package/dist/kernel/error-serialization.js +1 -1
  234. package/dist/kernel/redaction-targets.js +1 -0
  235. package/dist/kernel/redaction.js +4 -1
  236. package/dist/kernel/unknown-values.js +1 -1
  237. package/dist/process/environment.js +1 -1
  238. package/dist/process/execa-bundle.json +3 -3
  239. package/dist/process/files/json-file.js +1 -1
  240. package/dist/process/files/paths.js +1 -1
  241. package/dist/process/host/metadata.js +1 -1
  242. package/dist/process/host/platform.js +1 -1
  243. package/dist/process/host-process.js +1 -1
  244. package/dist/process/index.js +1 -1
  245. package/dist/process/lifecycle-fence.js +1 -1
  246. package/dist/process/locks.js +4 -4
  247. package/dist/process/port-listener.js +2 -0
  248. package/dist/process/process-group.js +1 -1
  249. package/dist/process/process-identity.js +1 -1
  250. package/dist/process/process.js +33 -33
  251. package/dist/process/readiness.js +1 -1
  252. package/dist/process/ready-deadline.js +1 -0
  253. package/dist/process/recovery.js +1 -1
  254. package/dist/process/runs/manifest.js +1 -1
  255. package/dist/process/runs/ownership.js +1 -1
  256. package/dist/process/runs/product-state.js +1 -1
  257. package/dist/process/runs/stop.js +1 -1
  258. package/dist/process/service-processes.js +1 -1
  259. package/dist/process/stoppable-settlement.js +1 -0
  260. package/dist/process/url-redaction.js +1 -0
  261. package/dist/process/windows-cli-owner.js +3 -3
  262. package/dist/process/windows-native.js +1 -1
  263. package/dist/repo/ci-environment.js +1 -1
  264. package/dist/repo/fingerprint-policy.js +1 -1
  265. package/dist/repo/managed-git.js +1 -1
  266. package/dist/repo/physical-tree.js +1 -1
  267. package/dist/repo/publish-directory.js +3 -0
  268. package/dist/repo/state.js +4 -4
  269. package/dist/steps/build-config.js +1 -1
  270. package/dist/steps/configured-step-testkit-modules.js +1 -1
  271. package/dist/steps/configured-steps.js +1 -1
  272. package/dist/steps/environment.js +1 -1
  273. package/dist/steps/index.js +1 -1
  274. package/dist/steps/run.js +2 -2
  275. package/dist/toolchains/archive.js +1 -1
  276. package/dist/toolchains/index.js +3 -3
  277. package/dist/toolchains/node-provisioning.js +2 -2
  278. package/dist/toolchains/semver.js +1 -1
  279. package/dist/toolchains/vitest/index.js +1 -1
  280. package/dist/tracker/redaction.js +1 -2
  281. package/dist/{config/runtime/build-assets.d.ts → types/config-build-assets.d.ts} +5 -3
  282. package/dist/{database/steps.d.ts → types/config-database-steps.d.ts} +7 -7
  283. package/dist/{config/runtime/next-runtime-tsconfig.d.ts → types/config-next-runtime-tsconfig.d.ts} +5 -3
  284. package/dist/types/config.d.ts +501 -0
  285. package/dist/types/drizzle.d.ts +13 -0
  286. package/dist/{config/runtime/env/index.d.ts → types/env.d.ts} +22 -20
  287. package/dist/types/environment.d.ts +40 -0
  288. package/dist/types/index.d.ts +21 -0
  289. package/dist/types/node-vitest-contract.d.ts +75 -0
  290. package/dist/types/node-vitest-data.d.ts +407 -0
  291. package/dist/types/playwright.d.ts +130 -0
  292. package/dist/types/tooling-vitest.d.ts +13 -0
  293. package/dist/types/workspace.d.ts +617 -0
  294. package/docs/bug-records.md +83 -81
  295. package/docs/engines.md +213 -0
  296. package/docs/test-types.md +35 -33
  297. package/package.json +22 -29
  298. package/testkit-config-schema.md +403 -171
  299. package/dist/app/bugs/areas.d.ts +0 -38
  300. package/dist/app/bugs/assessment.d.ts +0 -9
  301. package/dist/app/bugs/categories.d.ts +0 -41
  302. package/dist/app/bugs/ci-report.d.ts +0 -21
  303. package/dist/app/bugs/ci-summary.d.ts +0 -13
  304. package/dist/app/bugs/draft.d.ts +0 -70
  305. package/dist/app/bugs/facts.d.ts +0 -48
  306. package/dist/app/bugs/file.d.ts +0 -45
  307. package/dist/app/bugs/gate.d.ts +0 -22
  308. package/dist/app/bugs/guide.d.ts +0 -20
  309. package/dist/app/bugs/issue.d.ts +0 -18
  310. package/dist/app/bugs/known-failures.d.ts +0 -49
  311. package/dist/app/bugs/record.d.ts +0 -14
  312. package/dist/app/bugs/run-reading.d.ts +0 -51
  313. package/dist/app/bugs/store.d.ts +0 -34
  314. package/dist/app/campaigns/brief.d.ts +0 -7
  315. package/dist/app/campaigns/campaign.d.ts +0 -14
  316. package/dist/app/campaigns/index.d.ts +0 -38
  317. package/dist/app/campaigns/store.d.ts +0 -5
  318. package/dist/app/campaigns/summary.d.ts +0 -13
  319. package/dist/app/cleanup/index.d.ts +0 -52
  320. package/dist/app/db-schema/prepare.d.ts +0 -11
  321. package/dist/app/db-schema/refresh.d.ts +0 -17
  322. package/dist/app/db-schema/verify.d.ts +0 -11
  323. package/dist/app/destroy/index.d.ts +0 -16
  324. package/dist/app/discover/index.d.ts +0 -8
  325. package/dist/app/doctor/index.d.ts +0 -17
  326. package/dist/app/file-selection.d.ts +0 -1
  327. package/dist/app/inspect/artifacts.d.ts +0 -30
  328. package/dist/app/inspect/index.d.ts +0 -112
  329. package/dist/app/lint/index.d.ts +0 -28
  330. package/dist/app/lint/native.d.ts +0 -10
  331. package/dist/app/lint/options.d.ts +0 -67
  332. package/dist/app/lint/policy.d.ts +0 -21
  333. package/dist/app/lint/rules/data.d.ts +0 -3
  334. package/dist/app/lint/rules/engine-imports.d.ts +0 -3
  335. package/dist/app/lint/rules/syntax.d.ts +0 -4
  336. package/dist/app/lint/rules/unit.d.ts +0 -3
  337. package/dist/app/lint/shared.d.ts +0 -36
  338. package/dist/app/package-inspection.d.ts +0 -20
  339. package/dist/app/run/endpoint-readiness.d.ts +0 -43
  340. package/dist/app/run/endpoint-readiness.js +0 -1
  341. package/dist/app/run/engine-evidence-persistence.d.ts +0 -39
  342. package/dist/app/run/engine-execution-cleanup.d.ts +0 -8
  343. package/dist/app/run/engine-execution-cleanup.js +0 -1
  344. package/dist/app/run/engine-execution-failures.d.ts +0 -41
  345. package/dist/app/run/engine-execution-observer.d.ts +0 -21
  346. package/dist/app/run/engine-execution-reporting.d.ts +0 -17
  347. package/dist/app/run/engine-execution.d.ts +0 -63
  348. package/dist/app/run/engine-failure-stack.d.ts +0 -1
  349. package/dist/app/run/engine-orchestration.d.ts +0 -49
  350. package/dist/app/run/failure-details.d.ts +0 -37
  351. package/dist/app/run/live-run.d.ts +0 -27
  352. package/dist/app/run/operation-progress.d.ts +0 -13
  353. package/dist/app/run/orchestrator.d.ts +0 -68
  354. package/dist/app/run/planning-types.d.ts +0 -68
  355. package/dist/app/run/planning.d.ts +0 -15
  356. package/dist/app/run/playwright-configuration.d.ts +0 -2
  357. package/dist/app/run/playwright-configuration.js +0 -1
  358. package/dist/app/run/request.d.ts +0 -30
  359. package/dist/app/run/results.d.ts +0 -161
  360. package/dist/app/run/run-events.d.ts +0 -144
  361. package/dist/app/run/run-finalization.d.ts +0 -52
  362. package/dist/app/run/run-guards.d.ts +0 -3
  363. package/dist/app/run/runtime-failures.d.ts +0 -18
  364. package/dist/app/run/runtime-fixtures.d.ts +0 -2
  365. package/dist/app/run/runtime-task-types.d.ts +0 -20
  366. package/dist/app/run/scheduler/estimates.d.ts +0 -32
  367. package/dist/app/run/scheduler/identity.d.ts +0 -9
  368. package/dist/app/run/scheduler/index.d.ts +0 -124
  369. package/dist/app/run/scheduler/observations.d.ts +0 -20
  370. package/dist/app/run/selection.d.ts +0 -10
  371. package/dist/app/run/setup/runtime-node-setup-errors.d.ts +0 -13
  372. package/dist/app/run/setup/runtime-node-setup-protocol.d.ts +0 -85
  373. package/dist/app/run/setup/runtime-node-setup-worker.d.ts +0 -1
  374. package/dist/app/run/setup/runtime-node-setup.d.ts +0 -48
  375. package/dist/app/run/task-batches.d.ts +0 -23
  376. package/dist/app/run/worker-loop.d.ts +0 -57
  377. package/dist/app/setup/playwright.d.ts +0 -22
  378. package/dist/app/status/index.d.ts +0 -9
  379. package/dist/app/status/model.d.ts +0 -29
  380. package/dist/app/status/runs.d.ts +0 -99
  381. package/dist/app/stop/index.d.ts +0 -14
  382. package/dist/app/tracker/index.d.ts +0 -8
  383. package/dist/app/tracker/remote.d.ts +0 -13
  384. package/dist/app/tracker/token.d.ts +0 -7
  385. package/dist/app/typecheck/index.d.ts +0 -63
  386. package/dist/cli/command-catalog.d.ts +0 -137
  387. package/dist/cli/command-flags.d.ts +0 -19
  388. package/dist/cli/command-registry.d.ts +0 -3
  389. package/dist/cli/commands/artifacts.d.ts +0 -48
  390. package/dist/cli/commands/bug/file.d.ts +0 -16
  391. package/dist/cli/commands/bug/guide.d.ts +0 -5
  392. package/dist/cli/commands/bug/record.d.ts +0 -9
  393. package/dist/cli/commands/campaign/finish.d.ts +0 -10
  394. package/dist/cli/commands/campaign/start.d.ts +0 -7
  395. package/dist/cli/commands/campaign/status.d.ts +0 -13
  396. package/dist/cli/commands/ci/report.d.ts +0 -15
  397. package/dist/cli/commands/cleanup.d.ts +0 -13
  398. package/dist/cli/commands/db/schema/refresh.d.ts +0 -2
  399. package/dist/cli/commands/db/schema/verify.d.ts +0 -2
  400. package/dist/cli/commands/destroy.d.ts +0 -9
  401. package/dist/cli/commands/discover.d.ts +0 -2
  402. package/dist/cli/commands/doctor.d.ts +0 -2
  403. package/dist/cli/commands/guard/unsafe-entrypoint.d.ts +0 -2
  404. package/dist/cli/commands/lint.d.ts +0 -2
  405. package/dist/cli/commands/run/status.d.ts +0 -5
  406. package/dist/cli/commands/run/stop.d.ts +0 -7
  407. package/dist/cli/commands/run.d.ts +0 -9
  408. package/dist/cli/commands/setup/playwright.d.ts +0 -2
  409. package/dist/cli/commands/status.d.ts +0 -5
  410. package/dist/cli/commands/stop.d.ts +0 -12
  411. package/dist/cli/commands/typecheck.d.ts +0 -2
  412. package/dist/cli/commands/workspace.d.ts +0 -2
  413. package/dist/cli/entrypoint.d.ts +0 -1
  414. package/dist/cli/framework/command.d.ts +0 -21
  415. package/dist/cli/framework/definitions.d.ts +0 -100
  416. package/dist/cli/framework/errors.d.ts +0 -6
  417. package/dist/cli/framework/execute.d.ts +0 -14
  418. package/dist/cli/framework/help.d.ts +0 -11
  419. package/dist/cli/framework/index.d.ts +0 -3
  420. package/dist/cli/framework/parser.d.ts +0 -6
  421. package/dist/cli/index.d.ts +0 -4
  422. package/dist/cli/json-errors.d.ts +0 -3
  423. package/dist/cli/operations/db/schema/refresh/operation.d.ts +0 -7
  424. package/dist/cli/operations/db/schema/verify/operation.d.ts +0 -7
  425. package/dist/cli/operations/run/operation.d.ts +0 -24
  426. package/dist/cli/process-signal.d.ts +0 -1
  427. package/dist/cli/renderers/bug/text.d.ts +0 -8
  428. package/dist/cli/renderers/campaign/text.d.ts +0 -2
  429. package/dist/cli/renderers/ci/text.d.ts +0 -2
  430. package/dist/cli/renderers/cleanup/format.d.ts +0 -14
  431. package/dist/cli/renderers/db-schema/text.d.ts +0 -4
  432. package/dist/cli/renderers/destroy/text.d.ts +0 -4
  433. package/dist/cli/renderers/discover/report.d.ts +0 -7
  434. package/dist/cli/renderers/discover/text.d.ts +0 -3
  435. package/dist/cli/renderers/doctor/text.d.ts +0 -2
  436. package/dist/cli/renderers/lint/text.d.ts +0 -2
  437. package/dist/cli/renderers/run/events.d.ts +0 -8
  438. package/dist/cli/renderers/run/failure.d.ts +0 -8
  439. package/dist/cli/renderers/run/formatting.d.ts +0 -79
  440. package/dist/cli/renderers/run/status.d.ts +0 -6
  441. package/dist/cli/renderers/run/text-reporter.d.ts +0 -19
  442. package/dist/cli/renderers/status/text.d.ts +0 -2
  443. package/dist/cli/renderers/stop/text.d.ts +0 -7
  444. package/dist/cli/renderers/typecheck/text.d.ts +0 -2
  445. package/dist/cli/terminal/colors.d.ts +0 -10
  446. package/dist/cli/terminal/layout.d.ts +0 -11
  447. package/dist/cli/version-drift.d.ts +0 -25
  448. package/dist/config/authoring/build-config-contract.d.ts +0 -27
  449. package/dist/config/authoring/configured-step-contract.d.ts +0 -18
  450. package/dist/config/authoring/http-execution-contract.d.ts +0 -70
  451. package/dist/config/authoring/http-methods.d.ts +0 -18
  452. package/dist/config/authoring/index.d.ts +0 -381
  453. package/dist/config/authoring/preset-env.d.ts +0 -19
  454. package/dist/config/authoring/runtime.d.ts +0 -64
  455. package/dist/config/loader/bugs.d.ts +0 -15
  456. package/dist/config/loader/config-loader.d.ts +0 -9
  457. package/dist/config/loader/database-materialization.d.ts +0 -19
  458. package/dist/config/loader/database-roles.d.ts +0 -2
  459. package/dist/config/loader/database.d.ts +0 -55
  460. package/dist/config/loader/decode-discovery.d.ts +0 -5
  461. package/dist/config/loader/decode-execution.d.ts +0 -9
  462. package/dist/config/loader/dependencies.d.ts +0 -7
  463. package/dist/config/loader/discover-tests.d.ts +0 -111
  464. package/dist/config/loader/discovery-summary.d.ts +0 -29
  465. package/dist/config/loader/discovery.d.ts +0 -54
  466. package/dist/config/loader/env.d.ts +0 -4
  467. package/dist/config/loader/execution-model.d.ts +0 -16
  468. package/dist/config/loader/file-metadata.d.ts +0 -19
  469. package/dist/config/loader/index.d.ts +0 -10
  470. package/dist/config/loader/load.d.ts +0 -91
  471. package/dist/config/loader/managed-configs.d.ts +0 -23
  472. package/dist/config/loader/path-policy.d.ts +0 -9
  473. package/dist/config/loader/paths.d.ts +0 -5
  474. package/dist/config/loader/runtime-isolation.d.ts +0 -44
  475. package/dist/config/loader/runtime.d.ts +0 -25
  476. package/dist/config/loader/skip-config.d.ts +0 -44
  477. package/dist/config/loader/test-selection.d.ts +0 -15
  478. package/dist/config/loader/validation.d.ts +0 -16
  479. package/dist/config/loader/values.d.ts +0 -4
  480. package/dist/config/loader/values.js +0 -1
  481. package/dist/database/activity-gate.d.ts +0 -22
  482. package/dist/database/admin.d.ts +0 -31
  483. package/dist/database/cleanup.d.ts +0 -36
  484. package/dist/database/configured-steps.d.ts +0 -27
  485. package/dist/database/constants.d.ts +0 -11
  486. package/dist/database/docker-metadata.d.ts +0 -3
  487. package/dist/database/docker.d.ts +0 -65
  488. package/dist/database/drizzle/index.d.ts +0 -13
  489. package/dist/database/fingerprint.d.ts +0 -12
  490. package/dist/database/index.d.ts +0 -39
  491. package/dist/database/lifecycle-cleanup.d.ts +0 -7
  492. package/dist/database/local-postgres.d.ts +0 -71
  493. package/dist/database/naming.d.ts +0 -17
  494. package/dist/database/postgres/index.d.ts +0 -71
  495. package/dist/database/progress.d.ts +0 -6
  496. package/dist/database/roles.d.ts +0 -19
  497. package/dist/database/runtime-config.d.ts +0 -16
  498. package/dist/database/runtime-reservations.d.ts +0 -19
  499. package/dist/database/schema-operations.d.ts +0 -18
  500. package/dist/database/schema-source.d.ts +0 -96
  501. package/dist/database/source-refresh-lock.d.ts +0 -8
  502. package/dist/database/source-url.d.ts +0 -22
  503. package/dist/database/state-files.d.ts +0 -13
  504. package/dist/database/state.d.ts +0 -26
  505. package/dist/database/template-steps.d.ts +0 -39
  506. package/dist/domain/file-timeout.d.ts +0 -28
  507. package/dist/domain/identifiers.d.ts +0 -9
  508. package/dist/domain/operation-display.d.ts +0 -10
  509. package/dist/domain/operation-reason.d.ts +0 -5
  510. package/dist/domain/postgres-route.d.ts +0 -4
  511. package/dist/domain/runtime-identity.d.ts +0 -1
  512. package/dist/domain/runtime-isolation-contract.d.ts +0 -5
  513. package/dist/domain/service-name.d.ts +0 -2
  514. package/dist/domain/suite-selection.d.ts +0 -20
  515. package/dist/domain/test-outcomes.d.ts +0 -3
  516. package/dist/domain/test-types.d.ts +0 -16
  517. package/dist/engines/adapters/evidence-files.d.ts +0 -32
  518. package/dist/engines/adapters/evidence-identity.d.ts +0 -12
  519. package/dist/engines/adapters/execution.d.ts +0 -42
  520. package/dist/engines/adapters/native-report.d.ts +0 -25
  521. package/dist/engines/adapters/node-startup-cache.d.ts +0 -8
  522. package/dist/engines/adapters/workspace.d.ts +0 -4
  523. package/dist/engines/api/capabilities.d.ts +0 -31
  524. package/dist/engines/api/capabilities.js +0 -1
  525. package/dist/engines/api/evidence.d.ts +0 -38
  526. package/dist/engines/api/execution-observer.d.ts +0 -8
  527. package/dist/engines/api/execution-scope.d.ts +0 -17
  528. package/dist/engines/api/execution.d.ts +0 -101
  529. package/dist/engines/api/index.d.ts +0 -5
  530. package/dist/engines/api/k6-runtime-input.d.ts +0 -26
  531. package/dist/engines/api/k6-runtime-input.js +0 -1
  532. package/dist/engines/api/runtime-artifact.d.ts +0 -19
  533. package/dist/engines/bundle-cache.d.ts +0 -32
  534. package/dist/engines/catalog.d.ts +0 -27
  535. package/dist/engines/contracts/fixture-manifest.d.ts +0 -34
  536. package/dist/engines/contracts/json-bounds.d.ts +0 -36
  537. package/dist/engines/contracts/json-bounds.js +0 -2
  538. package/dist/engines/contracts/k6-repository-configuration.d.ts +0 -12
  539. package/dist/engines/contracts/k6-repository-configuration.js +0 -1
  540. package/dist/engines/contracts/test-context.d.ts +0 -15
  541. package/dist/engines/contracts/test-context.js +0 -1
  542. package/dist/engines/definitions.d.ts +0 -22
  543. package/dist/engines/factory.d.ts +0 -6
  544. package/dist/engines/generated-performance.d.ts +0 -1
  545. package/dist/engines/installation-catalog.d.ts +0 -27
  546. package/dist/engines/installation-catalog.js +0 -1
  547. package/dist/engines/installations/k6.d.ts +0 -98
  548. package/dist/engines/installations/k6.js +0 -1
  549. package/dist/engines/installations/node-vitest.d.ts +0 -33
  550. package/dist/engines/installations/package-requirements.d.ts +0 -28
  551. package/dist/engines/installations/package-resolution.d.ts +0 -51
  552. package/dist/engines/installations/playwright-resolution-child.d.ts +0 -1
  553. package/dist/engines/installations/playwright.d.ts +0 -75
  554. package/dist/engines/installations/types.d.ts +0 -10
  555. package/dist/engines/k6/adapter/bundle.d.ts +0 -25
  556. package/dist/engines/k6/adapter/bundle.js +0 -112
  557. package/dist/engines/k6/adapter/evidence.d.ts +0 -15
  558. package/dist/engines/k6/adapter/evidence.js +0 -4
  559. package/dist/engines/k6/adapter/executor.d.ts +0 -13
  560. package/dist/engines/k6/adapter/executor.js +0 -1
  561. package/dist/engines/k6/adapter/index.d.ts +0 -1
  562. package/dist/engines/k6/adapter/index.js +0 -1
  563. package/dist/engines/k6/adapter/input.d.ts +0 -21
  564. package/dist/engines/k6/adapter/input.js +0 -1
  565. package/dist/engines/k6/adapter/native-summary.d.ts +0 -11
  566. package/dist/engines/k6/adapter/native-summary.js +0 -1
  567. package/dist/engines/k6/adapter/repository-configuration.d.ts +0 -2
  568. package/dist/engines/k6/adapter/repository-configuration.js +0 -1
  569. package/dist/engines/k6/authoring-type-paths.d.ts +0 -3
  570. package/dist/engines/k6/authoring-type-paths.js +0 -1
  571. package/dist/engines/k6/runtime/ambient-types/bundle-manifest.json +0 -146
  572. package/dist/engines/k6/runtime/ambient-types/k6/LICENSE +0 -21
  573. package/dist/engines/k6/runtime/ambient-types/k6/browser/index.d.ts +0 -6332
  574. package/dist/engines/k6/runtime/ambient-types/k6/crypto/index.d.ts +0 -218
  575. package/dist/engines/k6/runtime/ambient-types/k6/data/index.d.ts +0 -16
  576. package/dist/engines/k6/runtime/ambient-types/k6/encoding/index.d.ts +0 -46
  577. package/dist/engines/k6/runtime/ambient-types/k6/execution/index.d.ts +0 -127
  578. package/dist/engines/k6/runtime/ambient-types/k6/experimental/csv/index.d.ts +0 -96
  579. package/dist/engines/k6/runtime/ambient-types/k6/experimental/fs/index.d.ts +0 -104
  580. package/dist/engines/k6/runtime/ambient-types/k6/experimental/redis/index.d.ts +0 -821
  581. package/dist/engines/k6/runtime/ambient-types/k6/experimental/streams/index.d.ts +0 -198
  582. package/dist/engines/k6/runtime/ambient-types/k6/global.d.ts +0 -83
  583. package/dist/engines/k6/runtime/ambient-types/k6/html/index.d.ts +0 -1325
  584. package/dist/engines/k6/runtime/ambient-types/k6/http/index.d.ts +0 -806
  585. package/dist/engines/k6/runtime/ambient-types/k6/index.d.ts +0 -126
  586. package/dist/engines/k6/runtime/ambient-types/k6/metrics/index.d.ts +0 -66
  587. package/dist/engines/k6/runtime/ambient-types/k6/net/grpc/index.d.ts +0 -247
  588. package/dist/engines/k6/runtime/ambient-types/k6/options/index.d.ts +0 -459
  589. package/dist/engines/k6/runtime/ambient-types/k6/package.json +0 -79
  590. package/dist/engines/k6/runtime/ambient-types/k6/secrets/index.d.ts +0 -36
  591. package/dist/engines/k6/runtime/ambient-types/k6/timers/index.d.ts +0 -47
  592. package/dist/engines/k6/runtime/ambient-types/k6/websockets/index.d.ts +0 -324
  593. package/dist/engines/k6/runtime/ambient-types/k6/ws/index.d.ts +0 -283
  594. package/dist/engines/k6/runtime/ambient-types/xk6-sql/LICENSE +0 -201
  595. package/dist/engines/k6/runtime/ambient-types/xk6-sql/index.d.ts +0 -397
  596. package/dist/engines/k6/runtime/ambient-types/xk6-sql/package.json +0 -15
  597. package/dist/engines/k6/runtime/artifacts.d.ts +0 -2
  598. package/dist/engines/k6/runtime/artifacts.js +0 -1
  599. package/dist/engines/k6/runtime/checks.d.ts +0 -17
  600. package/dist/engines/k6/runtime/checks.js +0 -1
  601. package/dist/engines/k6/runtime/dal-fixtures.d.ts +0 -24
  602. package/dist/engines/k6/runtime/dal-fixtures.js +0 -1
  603. package/dist/engines/k6/runtime/dal-suite.d.ts +0 -24
  604. package/dist/engines/k6/runtime/dal-suite.js +0 -1
  605. package/dist/engines/k6/runtime/dal.d.ts +0 -10
  606. package/dist/engines/k6/runtime/dal.js +0 -1
  607. package/dist/engines/k6/runtime/fixtures.d.ts +0 -3
  608. package/dist/engines/k6/runtime/fixtures.js +0 -1
  609. package/dist/engines/k6/runtime/http-assertions.d.ts +0 -19
  610. package/dist/engines/k6/runtime/http-assertions.js +0 -1
  611. package/dist/engines/k6/runtime/http-checks.d.ts +0 -19
  612. package/dist/engines/k6/runtime/http-checks.js +0 -1
  613. package/dist/engines/k6/runtime/http-suite-runtime.d.ts +0 -103
  614. package/dist/engines/k6/runtime/http-suite-runtime.js +0 -1
  615. package/dist/engines/k6/runtime/http.d.ts +0 -15
  616. package/dist/engines/k6/runtime/http.js +0 -1
  617. package/dist/engines/k6/runtime/index.d.ts +0 -11
  618. package/dist/engines/k6/runtime/index.js +0 -1
  619. package/dist/engines/k6/runtime/input.d.ts +0 -3
  620. package/dist/engines/k6/runtime/input.js +0 -1
  621. package/dist/engines/k6/runtime/k6-repository-configuration.d.ts +0 -9
  622. package/dist/engines/k6/runtime/k6-repository-configuration.js +0 -1
  623. package/dist/engines/k6/runtime/node-setup.d.ts +0 -13
  624. package/dist/engines/k6/runtime/node-setup.js +0 -1
  625. package/dist/engines/k6/runtime/runtime-globals.d.ts +0 -10
  626. package/dist/engines/k6/runtime/runtime.d.ts +0 -54
  627. package/dist/engines/k6/runtime/runtime.js +0 -1
  628. package/dist/engines/k6/runtime/shared/assertion-details.d.ts +0 -19
  629. package/dist/engines/k6/runtime/shared/assertion-details.js +0 -2
  630. package/dist/engines/k6/runtime/shared/db-normalization.d.ts +0 -19
  631. package/dist/engines/k6/runtime/shared/db-normalization.js +0 -1
  632. package/dist/engines/k6/runtime/shared/error-body.d.ts +0 -3
  633. package/dist/engines/k6/runtime/shared/error-body.js +0 -1
  634. package/dist/engines/k6/runtime/shared/file-data.d.ts +0 -1
  635. package/dist/engines/k6/runtime/shared/file-data.js +0 -1
  636. package/dist/engines/k6/runtime/shared/fixture-engine.d.ts +0 -8
  637. package/dist/engines/k6/runtime/shared/fixture-engine.js +0 -2
  638. package/dist/engines/k6/runtime/shared/http-check-plan.d.ts +0 -29
  639. package/dist/engines/k6/runtime/shared/http-check-plan.js +0 -1
  640. package/dist/engines/k6/runtime/shared/http-parsing.d.ts +0 -10
  641. package/dist/engines/k6/runtime/shared/http-parsing.js +0 -3
  642. package/dist/engines/k6/runtime/shared/ordering.d.ts +0 -2
  643. package/dist/engines/k6/runtime/shared/ordering.js +0 -1
  644. package/dist/engines/k6/runtime/shared/properties.d.ts +0 -1
  645. package/dist/engines/k6/runtime/shared/properties.js +0 -1
  646. package/dist/engines/k6/runtime/suite.d.ts +0 -4
  647. package/dist/engines/k6/runtime/suite.js +0 -1
  648. package/dist/engines/k6/runtime/types.d.ts +0 -244
  649. package/dist/engines/k6/runtime/types.js +0 -1
  650. package/dist/engines/k6/runtime/xk6-sql-driver-postgres.d.ts +0 -7
  651. package/dist/engines/k6/runtime/xk6-sql-driver-postgres.js +0 -1
  652. package/dist/engines/managed-module-resolution-policy-input.d.ts +0 -9
  653. package/dist/engines/managed-module-resolution-policy.d.ts +0 -25
  654. package/dist/engines/managed-module-resolution.d.ts +0 -13
  655. package/dist/engines/manager.d.ts +0 -25
  656. package/dist/engines/node-vitest/adapter/adapter.d.ts +0 -16
  657. package/dist/engines/node-vitest/adapter/consumer-typescript-paths.d.ts +0 -17
  658. package/dist/engines/node-vitest/adapter/consumer-typescript-paths.js +0 -3
  659. package/dist/engines/node-vitest/adapter/evidence.d.ts +0 -33
  660. package/dist/engines/node-vitest/adapter/failure-details.d.ts +0 -3
  661. package/dist/engines/node-vitest/adapter/index.d.ts +0 -1
  662. package/dist/engines/node-vitest/adapter/reporter.d.ts +0 -7
  663. package/dist/engines/node-vitest/adapter/resolution.d.ts +0 -12
  664. package/dist/engines/node-vitest/adapter/resolution.js +0 -1
  665. package/dist/engines/node-vitest/adapter/workspace.d.ts +0 -19
  666. package/dist/engines/node-vitest/runtime/contract/index.d.ts +0 -64
  667. package/dist/engines/node-vitest/runtime/data/http.d.ts +0 -4
  668. package/dist/engines/node-vitest/runtime/data/index.d.ts +0 -8
  669. package/dist/engines/node-vitest/runtime/data/primitives.d.ts +0 -1
  670. package/dist/engines/node-vitest/runtime/data/report.d.ts +0 -3
  671. package/dist/engines/node-vitest/runtime/data/runner.d.ts +0 -4
  672. package/dist/engines/node-vitest/runtime/data/scenario.d.ts +0 -12
  673. package/dist/engines/node-vitest/runtime/data/types.d.ts +0 -412
  674. package/dist/engines/node-vitest/runtime/runtime-input.d.ts +0 -64
  675. package/dist/engines/playwright/adapter/adapter.d.ts +0 -18
  676. package/dist/engines/playwright/adapter/attachments.d.ts +0 -26
  677. package/dist/engines/playwright/adapter/config.d.ts +0 -45
  678. package/dist/engines/playwright/adapter/evidence-validation.d.ts +0 -12
  679. package/dist/engines/playwright/adapter/evidence.d.ts +0 -32
  680. package/dist/engines/playwright/adapter/failure-details.d.ts +0 -2
  681. package/dist/engines/playwright/adapter/index.d.ts +0 -3
  682. package/dist/engines/playwright/adapter/reporter.d.ts +0 -12
  683. package/dist/engines/playwright/runtime/config-file.d.ts +0 -2
  684. package/dist/engines/playwright/runtime/config.d.ts +0 -24
  685. package/dist/engines/playwright/runtime/index.d.ts +0 -4
  686. package/dist/engines/playwright/runtime/runtime-input.d.ts +0 -36
  687. package/dist/engines/playwright/runtime/sandbox.d.ts +0 -84
  688. package/dist/engines/runtime-input-file.d.ts +0 -27
  689. package/dist/environment/lifecycle-artifacts.d.ts +0 -7
  690. package/dist/environment/lifecycle-controller.d.ts +0 -70
  691. package/dist/environment/lifecycle.d.ts +0 -29
  692. package/dist/environment/maintenance.d.ts +0 -68
  693. package/dist/environment/planning-types.d.ts +0 -35
  694. package/dist/environment/readiness.d.ts +0 -12
  695. package/dist/environment/readiness.js +0 -1
  696. package/dist/environment/ready-environment.d.ts +0 -19
  697. package/dist/environment/run-environment.d.ts +0 -38
  698. package/dist/environment/run-stopping.d.ts +0 -13
  699. package/dist/environment/runtime-contexts.d.ts +0 -33
  700. package/dist/environment/runtime-manager.d.ts +0 -95
  701. package/dist/environment/runtime-planning.d.ts +0 -16
  702. package/dist/environment/runtime-preparation.d.ts +0 -30
  703. package/dist/environment/runtime-service.d.ts +0 -18
  704. package/dist/environment/services.d.ts +0 -48
  705. package/dist/environment/state.d.ts +0 -18
  706. package/dist/environment/status-runtime.d.ts +0 -53
  707. package/dist/environment/template.d.ts +0 -180
  708. package/dist/evidence/artifact-config.d.ts +0 -14
  709. package/dist/evidence/artifact-validation.d.ts +0 -5
  710. package/dist/evidence/artifacts.d.ts +0 -75
  711. package/dist/evidence/bundles.d.ts +0 -27
  712. package/dist/evidence/ci-provenance.d.ts +0 -9
  713. package/dist/evidence/contracts.d.ts +0 -154
  714. package/dist/evidence/file-evidence.d.ts +0 -23
  715. package/dist/evidence/finalization.d.ts +0 -9
  716. package/dist/evidence/index.d.ts +0 -8
  717. package/dist/evidence/logs.d.ts +0 -31
  718. package/dist/evidence/operation-timings.d.ts +0 -60
  719. package/dist/evidence/read-bundle.d.ts +0 -4
  720. package/dist/evidence/read-fields.d.ts +0 -22
  721. package/dist/evidence/read-provenance.d.ts +0 -2
  722. package/dist/evidence/read-redaction.d.ts +0 -2
  723. package/dist/evidence/read-retention.d.ts +0 -2
  724. package/dist/evidence/read-run.d.ts +0 -2
  725. package/dist/evidence/reading.d.ts +0 -28
  726. package/dist/evidence/reporting-types.d.ts +0 -330
  727. package/dist/evidence/reporting.d.ts +0 -3
  728. package/dist/evidence/secure-file-copy.d.ts +0 -24
  729. package/dist/evidence/setup-progress.d.ts +0 -63
  730. package/dist/evidence/step-output.d.ts +0 -16
  731. package/dist/evidence/storage-inventory.d.ts +0 -27
  732. package/dist/evidence/storage.d.ts +0 -27
  733. package/dist/evidence/timing.d.ts +0 -23
  734. package/dist/file.d.ts +0 -11
  735. package/dist/index.d.ts +0 -4
  736. package/dist/kernel/error-serialization.d.ts +0 -38
  737. package/dist/kernel/redaction.d.ts +0 -2
  738. package/dist/kernel/unknown-values.d.ts +0 -6
  739. package/dist/kernel/work-metrics.d.ts +0 -6
  740. package/dist/process/capture-output.d.ts +0 -7
  741. package/dist/process/command-shell.d.ts +0 -1
  742. package/dist/process/environment-overlay.d.ts +0 -17
  743. package/dist/process/environment.d.ts +0 -33
  744. package/dist/process/files/contained-path.d.ts +0 -8
  745. package/dist/process/files/directory-status.d.ts +0 -14
  746. package/dist/process/files/dotenv.d.ts +0 -2
  747. package/dist/process/files/file-snapshot.d.ts +0 -34
  748. package/dist/process/files/json-file.d.ts +0 -12
  749. package/dist/process/files/paths.d.ts +0 -1
  750. package/dist/process/files/product-dir.d.ts +0 -1
  751. package/dist/process/files/temp-dir.d.ts +0 -11
  752. package/dist/process/host/metadata.d.ts +0 -6
  753. package/dist/process/host/platform.d.ts +0 -57
  754. package/dist/process/host-command.d.ts +0 -4
  755. package/dist/process/host-inspection-command.d.ts +0 -13
  756. package/dist/process/host-process.d.ts +0 -19
  757. package/dist/process/index.d.ts +0 -9
  758. package/dist/process/lifecycle-fence.d.ts +0 -11
  759. package/dist/process/locks.d.ts +0 -28
  760. package/dist/process/process-contracts.d.ts +0 -78
  761. package/dist/process/process-group.d.ts +0 -12
  762. package/dist/process/process-identity.d.ts +0 -27
  763. package/dist/process/process-limits.d.ts +0 -6
  764. package/dist/process/process.d.ts +0 -12
  765. package/dist/process/readiness.d.ts +0 -37
  766. package/dist/process/recovery.d.ts +0 -3
  767. package/dist/process/runs/inspection.d.ts +0 -5
  768. package/dist/process/runs/manifest.d.ts +0 -86
  769. package/dist/process/runs/ownership.d.ts +0 -11
  770. package/dist/process/runs/product-state.d.ts +0 -2
  771. package/dist/process/runs/schema.d.ts +0 -3
  772. package/dist/process/runs/stop.d.ts +0 -19
  773. package/dist/process/runtime-socket.d.ts +0 -4
  774. package/dist/process/service-processes.d.ts +0 -13
  775. package/dist/process/shutdown.d.ts +0 -10
  776. package/dist/process/windows-cli-owner.d.ts +0 -2
  777. package/dist/process/windows-native.d.ts +0 -6
  778. package/dist/process/windows-process-identity.d.ts +0 -4
  779. package/dist/repo/ci-environment.d.ts +0 -7
  780. package/dist/repo/fingerprint-policy.d.ts +0 -15
  781. package/dist/repo/git-path.d.ts +0 -2
  782. package/dist/repo/history.d.ts +0 -17
  783. package/dist/repo/managed-git.d.ts +0 -10
  784. package/dist/repo/metadata.d.ts +0 -3
  785. package/dist/repo/physical-tree.d.ts +0 -37
  786. package/dist/repo/remote.d.ts +0 -6
  787. package/dist/repo/state.d.ts +0 -26
  788. package/dist/repo/tree-listing.d.ts +0 -10
  789. package/dist/steps/build-config.d.ts +0 -35
  790. package/dist/steps/configured-step-testkit-modules.d.ts +0 -19
  791. package/dist/steps/configured-steps.d.ts +0 -51
  792. package/dist/steps/environment.d.ts +0 -84
  793. package/dist/steps/index.d.ts +0 -2
  794. package/dist/steps/module-runner.d.ts +0 -1
  795. package/dist/steps/run.d.ts +0 -36
  796. package/dist/toolchains/archive.d.ts +0 -53
  797. package/dist/toolchains/esbuild.d.ts +0 -9
  798. package/dist/toolchains/host-node-support.d.ts +0 -3
  799. package/dist/toolchains/index.d.ts +0 -114
  800. package/dist/toolchains/managed-node-releases.d.ts +0 -28
  801. package/dist/toolchains/node-cache.d.ts +0 -20
  802. package/dist/toolchains/node-integrity.d.ts +0 -18
  803. package/dist/toolchains/node-provisioning.d.ts +0 -29
  804. package/dist/toolchains/semver.d.ts +0 -13
  805. package/dist/toolchains/shared-operation.d.ts +0 -11
  806. package/dist/toolchains/timeouts.d.ts +0 -1
  807. package/dist/toolchains/vitest/index.d.ts +0 -13
  808. package/dist/tracker/gitea.d.ts +0 -14
  809. package/dist/tracker/github.d.ts +0 -14
  810. package/dist/tracker/http.d.ts +0 -33
  811. package/dist/tracker/index.d.ts +0 -4
  812. package/dist/tracker/redaction.d.ts +0 -4
  813. package/dist/tracker/requests.d.ts +0 -17
  814. package/dist/tracker/responses.d.ts +0 -24
  815. package/dist/tracker/types.d.ts +0 -51
  816. package/docs/engine-architecture.md +0 -654
  817. /package/dist/engines/{k6/runtime/runtime-globals.js → api/profiles.js} +0 -0
@@ -1 +1 @@
1
- import y from"fs";import x from"path";import{buildRuntimeIds as A}from"../domain/runtime-identity.js";import{formatError as R}from"../kernel/error-serialization.js";import{cleanupRuntimeInstanceContext as D,createRuntimeInstanceContext as K,ensureRuntimeInstanceReady as T}from"./runtime-contexts.js";import{timeOperation as $}from"../evidence/operation-timings.js";import{createReadyEnvironment as E}from"./ready-environment.js";export function createRuntimeManager({productDir:t,graphs:a,lifecycle:n,runtimeOptions:r={}}){const i=new Map(a.map(e=>[e.key,e])),c=new Map,s=new Map,u=W(a),f=new Map;let S=1;return{canAcquire(e){if(f.has(e.graphKey))return!1;const o=w(c,i,e);return j(s,v(e))?P(o,e,u)!==null:!1},async acquire(e,o={}){const l=w(c,i,e);if(n.isStopRequested())throw n.signal.reason||new Error("testkit run interrupted");const{leaseId:p,slot:g}=await G(r,o,"testkit.runtime.slot_claim",{summary:"claim runtime slot",scope:{graphKey:e.graphKey,taskId:e.id,serviceName:e.serviceName||null,targetName:e.targetName||null},metadata:{decision:"claim",lockCount:v(e).length.toString(),resourceCost:d(e).toString()}},()=>{const m=`lease-${e.id.toString()}-${S.toString()}`;if(S+=1,!B(s,v(e),m))throw new Error(`Task ${e.id.toString()} was claimed before its locks were available`);const h=q(l,e,u);if(!h)throw C(s,v(e),m),new Error(`Task ${e.id.toString()} was claimed before runtime capacity was available`);return{leaseId:m,slot:h}});try{const m=await F(g,t,e,n,r,o);n.signal.throwIfAborted();const h=x.join(m.runtimeDir,"leases",p);return y.mkdirSync(h,{recursive:!0}),{...E(m,{leaseId:p,leaseDir:h}),lockNames:v(e),resourceCost:d(e),slot:g,context:m}}catch(m){throw I(g,d(e)),C(s,v(e),p),U({leaseDir:x.join(g.context?.runtimeDir||t,"leases",p)}),g.context||N(g,u),await k(g,n,u),n.isStopRequested()||M(f,e.graphKey,R(m)),m}},async release(e,o={}){e?.slot&&(o.invalidate&&(e.slot.draining=!0),e.releaseState||(e.releaseState={locks:!1,runtimeSlot:!1,leaseDir:!1}),e.releaseState.locks||(C(s,e.lockNames,e.leaseId),e.releaseState.locks=!0),e.releaseState.runtimeSlot||(I(e.slot,e.resourceCost),e.releaseState.runtimeSlot=!0),e.releaseState.leaseDir||(U(e),e.releaseState.leaseDir=!0),e.released=!0,e.slot.draining&&e.slot.activeLeaseCount===0&&await k(e.slot,n,u))},async cleanupAll(){const e=[];for(const o of c.values())for(const l of o.slots){l.draining=!0;try{await k(l,n,u)}catch(p){e.push({slot:l,error:p})}}if(e.length>0)throw new AggregateError(e.map(o=>o.error),`Failed to clean up ${e.length.toString()} runtime ${e.length===1?"slot":"slots"}: ${e.map(o=>`${o.slot.runtimeId}: ${R(o.error)}`).join("; ")}`)},getStats(){return[...c.values()].map(e=>({graphKey:e.slots[0]?.graph.key||null,targetNames:[...e.slots.at(0)?.graph.targetNames??[]],maxConcurrentTasks:Number.isFinite(e.slots[0]?.graph.maxConcurrentTasks)?e.slots[0]?.graph.maxConcurrentTasks??null:null,runtimeCount:e.slots.length,runtimes:e.slots.map(o=>({runtimeId:o.runtimeId,peakLeaseCount:o.peakLeaseCount,peakResourceUnits:o.peakResourceUnits,resourceReservations:o.resourceReservations.map(l=>({...l}))})),resourceBudgets:[...u.values()].filter(o=>e.slots.some(l=>l.graph.resourceReservations.some(p=>p.key===o.key))).map(o=>({key:o.key,capacity:o.capacity,reserved:o.reserved,available:o.available,active:o.active,peakActive:o.peakActive}))})).sort((e,o)=>(e.graphKey||"").localeCompare(o.graphKey||""))},getGraphFailure(e){return f.get(e)??null},getGraph(e){return i.get(e)||null},markGraphFailed(e,o){M(f,e,o)}}}function w(t,a,n){const r=t.get(n.graphKey);if(r)return r;const i=a.get(n.graphKey);if(!i)throw new Error(`Unknown graph "${n.graphKey}"`);const s={slots:A(i.instanceCount).map(u=>({graph:i,runtimeId:u,context:null,activeLeaseCount:0,activeResourceUnits:0,resourceReservations:[],peakLeaseCount:0,peakResourceUnits:0,draining:!1}))};return t.set(n.graphKey,s),s}function q(t,a,n){const r=d(a),i=t.slots.filter(s=>!s.draining);if(i.length===0)return null;const c=[...i].filter(s=>L(s,r)&&b(s,n)).sort((s,u)=>s.activeResourceUnits-u.activeResourceUnits||s.activeLeaseCount-u.activeLeaseCount||s.runtimeId.localeCompare(u.runtimeId)).at(0);return c?(H(c,n),c.activeLeaseCount+=1,c.activeResourceUnits+=r,c.peakLeaseCount=Math.max(c.peakLeaseCount,c.activeLeaseCount),c.peakResourceUnits=Math.max(c.peakResourceUnits,c.activeResourceUnits),c):null}function I(t,a){t.activeLeaseCount=Math.max(0,t.activeLeaseCount-1),t.activeResourceUnits=Math.max(0,t.activeResourceUnits-a)}async function F(t,a,n,r,i,c={}){t.context||(t.context=K(t.runtimeId,t.graph,a),r.trackGraphContext(t.context));const s=i.operationTimingRegistry||null,u=s?.start({name:"testkit.runtime.ensure",kind:"runtime",summary:"ensure runtime instance ready",parentId:c.operationTimingParentId||null,scope:{graphKey:t.graph.key,runtimeId:t.runtimeId,serviceName:n.serviceName,targetName:n.targetName}})??null;try{await T(t.context,n.startApplicationServices,r,i),s?.finish(u,{status:"passed"})}catch(f){throw s?.finish(u,{status:"failed",error:R(f)}),f}return t.context}function G(t,a,n,r,i){return $(t.operationTimingRegistry||null,{name:n,kind:"runtime",summary:r.summary||null,parentId:a.operationTimingParentId||null,scope:r.scope||null,metadata:r.metadata||null},i)}async function k(t,a,n){!t.context||t.activeLeaseCount>0||(await D(t.context,a),N(t,n),t.context=null,t.draining=!1)}function B(t,a,n){const r=[...new Set(a)].sort();for(const i of r)if(t.has(i))return!1;for(const i of r)t.set(i,n);return!0}function j(t,a){return[...new Set(a)].every(n=>!t.has(n))}function P(t,a,n){const r=d(a);return t.slots.find(i=>!i.draining&&L(i,r)&&b(i,n))||null}function L(t,a){return t.activeResourceUnits+a<=t.graph.maxConcurrentTasks}function W(t){const a=new Map;for(const n of t)for(const r of n.resourceReservations){const i=a.get(r.key)||{key:r.key,capacity:r.capacity||0,reserved:r.reserved||0,available:r.available||Math.max(0,(r.capacity||0)-(r.reserved||0)),active:0,peakActive:0};i.capacity=Math.max(i.capacity,r.capacity||0),i.reserved=Math.max(i.reserved,r.reserved||0),i.available=Math.max(0,i.capacity-i.reserved),a.set(r.key,i)}return a}function b(t,a){return t.resourceReservations.length>0?!0:t.graph.resourceReservations.every(n=>{const r=a.get(n.key);return r?r.active+n.perRuntime<=r.available:!0})}function H(t,a){if(t.resourceReservations.length>0)return;const n=[];for(const r of t.graph.resourceReservations){const i=a.get(r.key);i&&(i.active+=r.perRuntime,i.peakActive=Math.max(i.peakActive,i.active),n.push({key:r.key,units:r.perRuntime,services:r.services}))}t.resourceReservations=n}function N(t,a){for(const n of t.resourceReservations){const r=a.get(n.key);r&&(r.active=Math.max(0,r.active-n.units))}t.resourceReservations=[]}function C(t,a,n){for(const r of[...new Set(a)].sort())t.get(r)===n&&t.delete(r)}function M(t,a,n){!a||t.has(a)||t.set(a,n)}function v(t){return t.locks||[]}function d(t){return t.resourceCost??1}function U(t){t?.leaseDir&&(t.engineWorkspaceDirectory&&y.rmSync(t.engineWorkspaceDirectory,{recursive:!0,force:!0}),y.rmSync(t.leaseDir,{recursive:!0,force:!0}))}
1
+ import{buildRuntimeIds as L}from"../domain/runtime-identity.js";import{formatError as h}from"../kernel/error-serialization.js";import{cleanupRuntimeInstanceContext as M,createRuntimeInstanceContext as S,ensureRuntimeInstanceReady as U}from"./runtime-contexts.js";import{timeOperation as N}from"../evidence/operation-timings.js";import{createReadyEnvironment as A}from"./ready-environment.js";import{buildRuntimeLabel as K}from"./template.js";export function createRuntimeManager({productDir:t,graphs:i,lifecycle:n,runtimeOptions:r={}}){const a=new Map(i.map(e=>[e.key,e])),u=new Map,o=G(i),c=new Map,d={...r,provisionedSharedDatabases:new Set};return{canAcquire(e){if(c.has(e.graphKey))return!1;const s=y(u,a,e);return F(s,e,o)!==null},async acquire(e,s={}){const p=y(u,a,e);if(n.isStopRequested())throw n.signal.reason||new Error("testkit run interrupted");const g=e.leaseId,m=await E(r,s,"testkit.runtime.slot_claim",{summary:"claim runtime slot",scope:{graphKey:e.graphKey,taskId:e.id,serviceName:e.serviceName||null,targetName:e.targetName||null},metadata:{decision:"claim",resourceCost:v(e).toString()}},()=>{const l=T(p,e,o);if(!l)throw new Error(`Task ${e.id.toString()} was claimed before runtime capacity was available`);return l});try{const l=K(m.graph.dirName,m.runtimeId);s.onRuntimeAssigned?.({runtimeId:m.runtimeId,services:m.graph.runtimeConfigs.map(({name:b})=>({serviceName:b,runtimeLabel:l}))});const R=await $(m,t,e,n,d,s);return n.signal.throwIfAborted(),{...A(R,g),resourceCost:v(e),slot:m,context:R}}catch(l){throw C(m,v(e)),m.context||w(m,o),await f(m,n,o),n.isStopRequested()||I(c,e.graphKey,h(l)),l}},async release(e,s={}){e?.slot&&(s.invalidate&&(e.slot.draining=!0),e.released||(C(e.slot,e.resourceCost),e.released=!0),e.slot.draining&&e.slot.activeLeaseCount===0&&await f(e.slot,n,o))},async cleanupAll(){const e=[];for(const s of u.values())for(const p of s.slots){p.draining=!0;try{await f(p,n,o)}catch(g){e.push({slot:p,error:g})}}if(e.length>0)throw new AggregateError(e.map(s=>s.error),`Failed to clean up ${e.length.toString()} runtime ${e.length===1?"slot":"slots"}: ${e.map(s=>`${s.slot.runtimeId}: ${h(s.error)}`).join("; ")}`)},getStats(){return[...u.values()].map(e=>({graphKey:e.slots[0]?.graph.key||null,targetNames:[...e.slots.at(0)?.graph.targetNames??[]],maxConcurrentTasks:Number.isFinite(e.slots[0]?.graph.maxConcurrentTasks)?e.slots[0]?.graph.maxConcurrentTasks??null:null,runtimeCount:e.slots.length,runtimes:e.slots.map(s=>({runtimeId:s.runtimeId,peakLeaseCount:s.peakLeaseCount,peakResourceUnits:s.peakResourceUnits,resourceReservations:s.resourceReservations.map(p=>({...p}))})),resourceBudgets:[...o.values()].filter(s=>e.slots.some(p=>p.graph.resourceReservations.some(g=>g.key===s.key))).map(s=>({key:s.key,capacity:s.capacity,reserved:s.reserved,available:s.available,active:s.active,peakActive:s.peakActive}))})).sort((e,s)=>(e.graphKey||"").localeCompare(s.graphKey||""))},getGraphFailure(e){return c.get(e)??null},getGraph(e){return a.get(e)||null},markGraphFailed(e,s){I(c,e,s)}}}function y(t,i,n){const r=t.get(n.graphKey);if(r)return r;const a=i.get(n.graphKey);if(!a)throw new Error(`Unknown graph "${n.graphKey}"`);const o={slots:L(a.instanceCount).map(c=>({graph:a,runtimeId:c,context:null,activeLeaseCount:0,activeResourceUnits:0,resourceReservations:[],peakLeaseCount:0,peakResourceUnits:0,draining:!1}))};return t.set(n.graphKey,o),o}function T(t,i,n){const r=v(i),a=t.slots.filter(o=>!o.draining);if(a.length===0)return null;const u=[...a].filter(o=>x(o,r)&&k(o,n)).sort((o,c)=>o.activeResourceUnits-c.activeResourceUnits||o.activeLeaseCount-c.activeLeaseCount||o.runtimeId.localeCompare(c.runtimeId)).at(0);return u?(q(u,n),u.activeLeaseCount+=1,u.activeResourceUnits+=r,u.peakLeaseCount=Math.max(u.peakLeaseCount,u.activeLeaseCount),u.peakResourceUnits=Math.max(u.peakResourceUnits,u.activeResourceUnits),u):null}function C(t,i){t.activeLeaseCount=Math.max(0,t.activeLeaseCount-1),t.activeResourceUnits=Math.max(0,t.activeResourceUnits-i)}async function $(t,i,n,r,a,u={}){t.context||(t.context=S(t.runtimeId,t.graph,i),r.trackGraphContext(t.context));const o=a.operationTimingRegistry||null,c=o?.start({name:"testkit.runtime.ensure",kind:"runtime",summary:"ensure runtime instance ready",parentId:u.operationTimingParentId||null,scope:{graphKey:t.graph.key,runtimeId:t.runtimeId,serviceName:n.serviceName,targetName:n.targetName}})??null;try{await U(t.context,r,a),o?.finish(c,{status:"passed"})}catch(d){throw o?.finish(c,{status:"failed",error:h(d)}),d}return t.context}function E(t,i,n,r,a){return N(t.operationTimingRegistry||null,{name:n,kind:"runtime",summary:r.summary||null,parentId:i.operationTimingParentId||null,scope:r.scope||null,metadata:r.metadata||null},a)}async function f(t,i,n){!t.context||t.activeLeaseCount>0||(await M(t.context,i),w(t,n),t.context=null,t.draining=!1)}function F(t,i,n){const r=v(i);return t.slots.find(a=>!a.draining&&x(a,r)&&k(a,n))||null}function x(t,i){return t.activeResourceUnits+i<=t.graph.maxConcurrentTasks}function G(t){const i=new Map;for(const n of t)for(const r of n.resourceReservations){const a=i.get(r.key)||{key:r.key,capacity:r.capacity||0,reserved:r.reserved||0,available:r.available||Math.max(0,(r.capacity||0)-(r.reserved||0)),active:0,peakActive:0};a.capacity=Math.max(a.capacity,r.capacity||0),a.reserved=Math.max(a.reserved,r.reserved||0),a.available=Math.max(0,a.capacity-a.reserved),i.set(r.key,a)}return i}function k(t,i){return t.resourceReservations.length>0?!0:t.graph.resourceReservations.every(n=>{const r=i.get(n.key);return r?r.active+n.perRuntime<=r.available:!0})}function q(t,i){if(t.resourceReservations.length>0)return;const n=[];for(const r of t.graph.resourceReservations){const a=i.get(r.key);a&&(a.active+=r.perRuntime,a.peakActive=Math.max(a.peakActive,a.active),n.push({key:r.key,units:r.perRuntime,services:r.services}))}t.resourceReservations=n}function w(t,i){for(const n of t.resourceReservations){const r=i.get(n.key);r&&(r.active=Math.max(0,r.active-n.units))}t.resourceReservations=[]}function I(t,i,n){!i||t.has(i)||t.set(i,n)}function v(t){return t.resourceCost??1}
@@ -1 +1 @@
1
- import{resolveRuntimeInstanceConfigs as p}from"./template.js";import{buildGraphResourceReservations as g}from"../database/runtime-reservations.js";import{resolveRuntimeConfigs as m}from"../config/loader/dependencies.js";export const runtimePlanning=Object.freeze({collectDesiredRuntimeGraphs,resolveRuntimeInstanceConfigs:p,buildRuntimeGraphs,resolveRuntimeConfigs:m,buildGraphDirName});export function buildRuntimeGraphs(r){const s=[],a=new Map;for(const e of r){const n=a.get(e.runtimeKey);if(n){n.targetNames.push(e.config.name),n.instanceCount=Math.max(n.instanceCount,e.config.testkit.runtime.instances),n.maxConcurrentTasks=Math.min(n.maxConcurrentTasks,u(e.runtimeConfigs));continue}const i={key:e.runtimeKey,runtimeNames:e.runtimeNames,runtimeConfigs:e.runtimeConfigs,targetNames:[e.config.name],dirName:buildGraphDirName(e.runtimeNames),instanceCount:e.config.testkit.runtime.instances,maxConcurrentTasks:u(e.runtimeConfigs),resourceReservations:g(e.runtimeConfigs)};s.push(i),a.set(e.runtimeKey,i)}const t=s.sort((e,n)=>e.dirName.localeCompare(n.dirName)),o=Math.max(1,...t.map(e=>e.instanceCount));return t.map((e,n)=>({...e,portNamespaceIndex:n,portNamespaceStride:o}))}export function buildGraphDirName(r){const s=r.map(f).join("__");return s.length>0?s:"graph"}function f(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"svc"}function u(r){return r.reduce((s,a)=>Math.min(s,a.testkit.runtime.maxConcurrentTasks),Number.POSITIVE_INFINITY)}export function collectDesiredRuntimeGraphs(r=[]){const s=new Map(r.map(t=>[t.name,t])),a=new Map;for(const t of r){const e=m(t,s).map(c=>c.name).sort(),n=e.join("|"),i=a.get(n);if(i){i.targetNames.push(t.name),i.targetNames.sort(),i.instanceCount=Math.max(i.instanceCount,t.testkit.runtime.instances);continue}a.set(n,{key:n,dirName:buildGraphDirName(e),runtimeNames:e,targetNames:[t.name],instanceCount:t.testkit.runtime.instances})}return[...a.values()].sort((t,o)=>t.dirName.localeCompare(o.dirName))}
1
+ import{resolveRuntimeInstanceConfigs as p}from"./template.js";import{buildGraphResourceReservations as f}from"../database/runtime-reservations.js";import{resolveRuntimeConfigs as m}from"../config/loader/dependencies.js";export const runtimePlanning=Object.freeze({collectDesiredRuntimeGraphs,resolveRuntimeInstanceConfigs:p,buildRuntimeGraphs,resolveRuntimeConfigs:m,buildGraphDirName});export function buildRuntimeGraphs(n){const t=[],s=new Map;for(const e of n){const r=s.get(e.runtimeKey);if(r){r.targetNames.push(e.config.name),r.instanceCount=Math.max(r.instanceCount,u(e.uses)),r.maxConcurrentTasks=Math.min(r.maxConcurrentTasks,c(e.runtimeConfigs));continue}const a={key:e.runtimeKey,runtimeNames:e.runtimeNames,runtimeConfigs:e.runtimeConfigs,targetNames:[e.config.name],dirName:buildGraphDirName(e.runtimeNames),instanceCount:u(e.uses),maxConcurrentTasks:c(e.runtimeConfigs),resourceReservations:f(e.runtimeConfigs)};t.push(a),s.set(e.runtimeKey,a)}return t.sort((e,r)=>e.dirName.localeCompare(r.dirName))}export function buildGraphDirName(n){const t=n.map(C).join("__");return t.length>0?t:"graph"}function C(n){return n.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"svc"}function u(n){return n.reduce((t,s)=>Math.max(t,s.testkit.runtime.instances),1)}function c(n){return n.reduce((t,s)=>Math.min(t,s.testkit.runtime.maxConcurrentTasks),Number.POSITIVE_INFINITY)}export function collectDesiredRuntimeGraphs(n=[]){const t=new Map(n.map(e=>[e.name,e])),s=new Map;for(const e of n){const a=m(e,t).map(g=>g.name).sort(),o=a.join("|"),i=s.get(o);if(i){i.targetNames.push(e.name),i.targetNames.sort(),i.instanceCount=Math.max(i.instanceCount,e.testkit.runtime.instances);continue}s.set(o,{key:o,dirName:buildGraphDirName(a),runtimeNames:a,targetNames:[e.name],instanceCount:e.testkit.runtime.instances})}return[...s.values()].sort((e,r)=>e.dirName.localeCompare(r.dirName))}
@@ -1 +1 @@
1
- import S from"crypto";import p from"fs";import k from"path";import{resolveServiceCwd as D}from"../config/loader/index.js";import{appendFileToHash as y}from"../repo/fingerprint-policy.js";import{announceResolvedToolchain as b,resolveConfiguredToolchain as v}from"../toolchains/index.js";import{readDatabaseUrl as m}from"../database/state.js";import{buildExecutionEnv as w,collectConfiguredInputs as x}from"../steps/index.js";import{runConfiguredSteps as R}from"../database/configured-steps.js";import"../evidence/setup-progress.js";const I="prepare-manifest.json";export async function prepareRuntimeServices(e,r={}){for(const t of e)await prepareRuntimeService(t,r)}export async function prepareRuntimeService(e,r={}){const t=e.testkit.runtime.prepare;if(!t||t.steps.length===0||!N(e))return;const n=e.testkit.prepareDir,s=await computeRuntimePrepareFingerprint(e,{signal:r.signal}),i=k.join(n,I);if(g(i)?.fingerprint===s){r.setupRegistry?.recordCached({config:e,stage:"runtime:prepare",kind:"runtime-prepare",summary:"runtime prepare cache hit"});return}p.rmSync(n,{recursive:!0,force:!0}),p.mkdirSync(n,{recursive:!0});const o={...w(e,{...e.testkit.local?.env||{},...r.extraEnv||{}},process.env)},d=m(e.stateDir);d&&(o.DATABASE_URL=d);const u=r.setupRegistry?.start({config:e,stage:"runtime:prepare",kind:"runtime-prepare",summary:"runtime prepare",recordLog:!1}),c=r.setupRegistry;try{await b(e,await v(e,{signal:r.signal}),r.reporter),await R({config:e,steps:t.steps,env:o,labelPrefix:"runtime:prepare",reporter:r.reporter,setupRegistry:c||null,parentOperation:u,signal:r.signal});const a=u?c?.finish(u,{status:"passed",summary:"runtime prepare"}):null;a&&r.reporter?.setupOperationFinished?.(a),A(i,{fingerprint:s,preparedAt:new Date().toISOString(),runtimeId:e.runtimeId||null,serviceName:e.name})}catch(a){const f=u?c?.finish(u,{status:"failed",summary:"runtime prepare",error:U(a,"message")||a}):null;throw f&&r.reporter?.setupOperationFinished?.(f),p.rmSync(n,{recursive:!0,force:!0}),a}}function N(e){return e.testkit.runtime.prepare!=null}export async function computeRuntimePrepareFingerprint(e,r={}){const t=await v(e,{signal:r.signal}),n=S.createHash("sha256");n.update(JSON.stringify({prepare:e.testkit.runtime.prepare,toolchain:t?{kind:"node",install:t.install,nodeVersion:t.nodeVersion,npmVersion:t.npmVersion,nodeSource:t.nodeSource,npmSource:t.npmSource,fingerprint:t.fingerprint}:null,serviceEnv:e.testkit.serviceEnv||{},local:e.testkit.local?{baseUrl:e.testkit.local.baseUrl,cwd:e.testkit.local.cwd,env:e.testkit.local.env||{},readyUrl:e.testkit.local.readyUrl,start:e.testkit.local.start}:null})),n.update(JSON.stringify(O(e)));const s=e.testkit.fingerprints||{exclude:[],include:[]};for(const i of e.testkit.envFiles||[])y(n,e.productDir,D(e.productDir,i),s);for(const i of x(e.productDir,e.testkit.runtime.prepare))y(n,e.productDir,i,s);return n.digest("hex")}function O(e){const r=[],t=m(e.stateDir);t&&r.push({service:e.name,url:t});const n=new Set;for(const i of Object.values(e.testkit.serviceEnv||{}))h(i,n,e.name);for(const i of Object.values(e.testkit.local?.env||{}))h(i,n,e.name);const s=e.testkit.templateContext?.stateDirByService;for(const i of[...n].sort()){const l=s?.get(i),o=l?m(l):null;r.push({service:i,url:o||null})}return r}function h(e,r,t){if(typeof e!="string")return;const n=/\{db(?:Url|Host|Port|Name|User|Password|Ssl)(?::([a-zA-Z0-9_-]+))?\}/g;let s=n.exec(e);for(;s;)r.add(s[1]||t),s=n.exec(e)}function g(e){if(!p.existsSync(e))return null;try{const r=JSON.parse(p.readFileSync(e,"utf8"));return F(r)?{fingerprint:r.fingerprint,...typeof r.preparedAt=="string"?{preparedAt:r.preparedAt}:{},...typeof r.runtimeId=="string"||typeof r.runtimeId=="number"||r.runtimeId===null?{runtimeId:r.runtimeId}:{},...typeof r.serviceName=="string"?{serviceName:r.serviceName}:{}}:null}catch{return null}}function A(e,r){p.writeFileSync(e,JSON.stringify(r,null,2))}function F(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function U(e,r){if(!((typeof e!="object"||e===null)&&typeof e!="function"))return Reflect.get(e,r)}
1
+ import y from"crypto";import p from"fs";import S from"path";import{resolveServiceCwd as k}from"../config/loader/index.js";import{appendFileToHash as f}from"../repo/fingerprint-policy.js";import{announceResolvedToolchain as w,resolveConfiguredToolchain as v}from"../toolchains/index.js";import{buildExecutionEnv as x,buildTemplateExecutionEnv as D,collectConfiguredInputs as R,serviceDatabaseBinding as l}from"../steps/index.js";import{runConfiguredSteps as b}from"../database/configured-steps.js";import"../evidence/setup-progress.js";import{isUnknownRecord as g,readDynamicProperty as I}from"../kernel/unknown-values.js";const N="prepare-manifest.json";export async function prepareRuntimeServices(e,r={}){for(const t of e)await prepareRuntimeService(t,r)}export async function prepareRuntimeService(e,r={}){const t=e.testkit.runtime.prepare;if(!t||t.steps.length===0||!F(e))return;const n=e.testkit.prepareDir,i=await computeRuntimePrepareFingerprint(e,{signal:r.signal}),s=S.join(n,N);if(E(s)?.fingerprint===i){r.setupRegistry?.recordCached({config:e,stage:"runtime:prepare",kind:"runtime-prepare",summary:"runtime prepare cache hit"});return}p.rmSync(n,{recursive:!0,force:!0}),p.mkdirSync(n,{recursive:!0});const c={...x(e,{...e.testkit.local?.env||{},...r.extraEnv||{}},process.env)},m=l(e)?.url;m&&(c.DATABASE_URL=m);const u=r.setupRegistry?.start({config:e,stage:"runtime:prepare",kind:"runtime-prepare",summary:"runtime prepare",recordLog:!1}),o=r.setupRegistry;try{await w(e,await v(e,{signal:r.signal}),r.reporter),await b({config:e,steps:t.steps,env:c,labelPrefix:"runtime:prepare",reporter:r.reporter,setupRegistry:o||null,parentOperation:u,signal:r.signal});const a=u?o?.finish(u,{status:"passed",summary:"runtime prepare"}):null;a&&r.reporter?.setupOperationFinished?.(a),A(s,{fingerprint:i,preparedAt:new Date().toISOString(),runtimeId:e.runtimeId||null,serviceName:e.name})}catch(a){const d=u?o?.finish(u,{status:"failed",summary:"runtime prepare",error:I(a,"message")||a}):null;throw d&&r.reporter?.setupOperationFinished?.(d),p.rmSync(n,{recursive:!0,force:!0}),a}}function F(e){return e.testkit.runtime.prepare!=null}export async function computeRuntimePrepareFingerprint(e,r={}){const t=await v(e,{signal:r.signal}),n=y.createHash("sha256");n.update(JSON.stringify({prepare:e.testkit.runtime.prepare,toolchain:t?{kind:"node",install:t.install,nodeVersion:t.nodeVersion,npmVersion:t.npmVersion,nodeSource:t.nodeSource,npmSource:t.npmSource,fingerprint:t.fingerprint}:null,env:D(e,{},{},{includeTestkitControls:!1}),envTemplates:{service:e.testkit.serviceEnv||{},local:e.testkit.local?.env||{}},cwd:e.testkit.local?e.testkit.local.cwd:null})),n.update(JSON.stringify(O(e)));const i=e.testkit.fingerprints||{exclude:[],include:[]};for(const s of e.testkit.envFiles||[])f(n,e.productDir,k(e.productDir,s),i);for(const s of R(e.productDir,e.testkit.runtime.prepare))f(n,e.productDir,s,i);return n.digest("hex")}function O(e){const r=[],t=l(e)?.url;t&&r.push({service:e.name,url:t});const n=new Set;for(const i of Object.values(e.testkit.serviceEnv||{}))h(i,n,e.name);for(const i of Object.values(e.testkit.local?.env||{}))h(i,n,e.name);for(const i of[...n].sort())r.push({service:i,url:l(e,i)?.url??null});return r}function h(e,r,t){if(typeof e!="string")return;const n=/\{db(?:Url|Host|Port|Name|User|Password|Ssl)(?::([a-zA-Z0-9_-]+))?\}/g;let i=n.exec(e);for(;i;)r.add(i[1]||t),i=n.exec(e)}function E(e){if(!p.existsSync(e))return null;try{const r=JSON.parse(p.readFileSync(e,"utf8"));return g(r)?{fingerprint:r.fingerprint,...typeof r.preparedAt=="string"?{preparedAt:r.preparedAt}:{},...typeof r.runtimeId=="string"||typeof r.runtimeId=="number"||r.runtimeId===null?{runtimeId:r.runtimeId}:{},...typeof r.serviceName=="string"?{serviceName:r.serviceName}:{}}:null}catch{return null}}function A(e,r){p.writeFileSync(e,JSON.stringify(r,null,2))}
@@ -1 +1,3 @@
1
- import{DEFAULT_READY_TIMEOUT_MS as x,waitForReady as M,serviceCompletionError as y}from"../process/readiness.js";import{resolveServiceCwd as A}from"../config/loader/index.js";import{startSupervisedProcess as f,ProcessExitedBeforeReadyError as k,DEFAULT_SHUTDOWN_TIMEOUT_MS as R}from"../process/index.js";import{announceResolvedToolchain as U,applyToolchainEnv as g,resolveConfiguredToolchain as D}from"../toolchains/index.js";import{buildExecutionEnv as O}from"../steps/index.js";import{numericPortFromUrl as P}from"./template.js";import{assertLocalServicePortsAvailable as _}from"./readiness.js";import{captureOutput as T}from"../process/index.js";import{prepareServiceStartInvocation as C}from"../process/service-processes.js";import{readDatabaseUrl as F}from"../database/state.js";export async function startLocalServices(e,r,t={}){const s=[];try{for(const a of e){if(!B(a))continue;const n=await startLocalService(a,r,t);s.push(n)}}catch(a){try{await stopLocalServices(s,r)}catch(n){throw new AggregateError([a,n],"Local service startup failed and its supervised cleanup also failed",{cause:n})}throw a}return s}export async function startLocalService(e,r,t={}){const s=A(e.productDir,e.testkit.local.cwd),a=await D(e,{signal:r.signal});await U(e,a,t.reporter);const n=g(O(e,{...e.testkit.local.env||{},...t.extraEnv||{}},process.env),a),l=e.testkit.local.port||P(e.testkit.local.baseUrl);l&&(n.PORT=String(l));const b=F(e.stateDir);b&&(n.DATABASE_URL=b),await _(e),t.reporter?.localServiceStarting?.(e,e.testkit.local.start);const v=C(e.testkit.local.start,n),d=t.logRegistry?.ensureServiceLogRecord(e),L=t.reporter?.outputMode==="debug"?o=>t.reporter?.writeDebugLine?.(o):null,i=f({args:v.args,windowsVerbatimArguments:v.windowsVerbatimArguments,cwd:s,displayLabel:`Testkit local service ${e.runtimeLabel}:${e.name}`,env:I(n),executable:v.executable,outputMode:"caller-drained",signal:r.signal,shutdownTimeoutMs:e.testkit.local.shutdownTimeoutMs??R,timeoutMs:null}),S=[T(i.stdout,{livePrefix:`[${e.runtimeLabel}:${e.name}]`,liveWriter:L,onLine(o){d&&t.logRegistry?.append(d,"stdout",o)}}),T(i.stderr,{livePrefix:`[${e.runtimeLabel}:${e.name}]`,liveWriter:L,onLine(o){d&&t.logRegistry?.append(d,"stderr",o)}})];let h,p=!1,w=!1;try{h=await i.ready,p=!0,r.registerService(e,i,h,s);const o=e.testkit.local.readyTimeoutMs||x;e.testkit.local.readyUrl!==!1&&e.testkit.local.readyUrl!=null&&await M({name:`${e.runtimeLabel}:${e.name}`,url:e.testkit.local.readyUrl,timeoutMs:o,process:i,signal:r.signal})}catch(o){const u=o instanceof k?y(`${e.runtimeLabel}:${e.name}`,o):o;w=!0;const c=[];try{c.push(...await $(i,S,!1))}catch(E){c.push(m(E))}if(p)try{r.unregisterService(i.pid)}catch(E){c.push(m(E))}throw c.length>0?new AggregateError([u,...c],`Local service ${e.runtimeLabel}:${e.name} startup and cleanup failed`,{cause:o}):u}return{completionMonitor:i.completion.then(o=>{if(w)return null;if(r.signal.aborted){if(p){p=!1;try{r.unregisterService(i.pid)}catch{}}return null}let u=y(`${e.runtimeLabel}:${e.name}`,o,"unexpectedly");if(p){p=!1;try{r.unregisterService(i.pid)}catch(c){u=new AggregateError([u,c],`Local service ${e.runtimeLabel}:${e.name} exited and its manifest entry could not be removed`)}}try{r.requestStop(u.message)}catch(c){u=new AggregateError([u,c],`Local service ${e.runtimeLabel}:${e.name} exited and the active run could not be interrupted`)}return u}),expectCompletion(){w=!0},name:e.name,outputDrains:S,ownership:h,supervisor:i}}export async function stopLocalServices(e,r){const t=[];for(const s of[...e].reverse()){s.expectCompletion();try{t.push(...await $(s.supervisor,s.outputDrains)),await s.completionMonitor}catch(a){t.push(m(a))}finally{try{r?.unregisterService(s.ownership.pid)}catch(a){t.push(m(a))}}}if(t.length>0)throw new AggregateError(t,"Could not stop all local services")}async function $(e,r,t=!0){const a=await e.stop().then(l=>({error:null,result:l}),l=>({error:m(l),result:null})),n=await Promise.allSettled(r);return[...a.result?j(a.result,t):[a.error],...n.flatMap(l=>l.status==="rejected"?[m(l.reason)]:[])]}function j(e,r=!0){return[...r?[e.error]:[],e.terminationError].filter(t=>t!==null)}function I(e){return Object.fromEntries(Object.entries(e).filter(r=>r[1]!==void 0))}function m(e){return e instanceof Error?e:new Error(String(e))}function B(e){return e.testkit.local!=null}
1
+ import{DEFAULT_READY_TIMEOUT_MS as I,ServiceExitedBeforeReadyError as x,ServiceReadinessTimeoutError as B,waitForReady as M,serviceCompletionError as A}from"../process/readiness.js";import{resolveServiceCwd as j}from"../config/loader/index.js";import{startSupervisedProcess as N,ProcessExitedBeforeReadyError as F,DEFAULT_SHUTDOWN_TIMEOUT_MS as q}from"../process/index.js";import{announceResolvedToolchain as V,applyToolchainEnv as H,resolveConfiguredToolchain as W}from"../toolchains/index.js";import{buildExecutionEnv as X,serviceDatabaseBinding as Y}from"../steps/index.js";import{SERVICE_START_ATTEMPTS as z}from"./ports.js";import{captureOutput as O}from"../process/index.js";import{prepareServiceStartInvocation as G}from"../process/service-processes.js";import{portListenerOwner as J}from"../process/port-listener.js";import{toError as S}from"../kernel/error-serialization.js";const K=20;class y extends Error{outcome;output;constructor(t,r,o){super(o.message,{cause:o}),this.outcome=t,this.output=r,this.name="LocalServiceExitedBeforeReadyError"}}export async function startLocalServices(e,t,r={}){const o=e.configs.filter(_).map(a=>a.name),n=[],m=new Map,u=new Map,v=new Map,$=(a,s)=>{const d=P(a);m.set(a.name,[...m.get(a.name)??[],{port:d,outcome:s}]);let h=v.get(a.name);!h&&r.environmentRecord&&(h=r.environmentRecord.service({runtimeLabel:a.runtimeLabel,serviceName:a.name}),v.set(a.name,h)),h?.recordAttempt({baseUrl:a.testkit.local.baseUrl??null,outcome:s,port:d,readyUrl:typeof a.testkit.local.readyUrl=="string"?a.testkit.local.readyUrl:null})},L=(a,s,d)=>{const h=m.get(a.name)?.at(-1);if(!d||!h){$(a,s);return}h.outcome=s,v.get(a.name)?.amendLastOutcome(s)};try{for(;n.length<o.length;){const a=o[n.length],s=te(e.configs,a);let d=!1;const h=async()=>{await e.releasePort(a),$(s,"starting"),d=!0};try{n.push(await startLocalService(s,t,r,h)),L(s,"ready",d)}catch(l){if(L(s,Z(l,t),d),t.signal.aborted)throw l;if(!(l instanceof y))throw U(s,m.get(a)??[],l,2);const b=[...u.get(a)??[],l];if(u.set(a,b),b.length>=z)throw ee(s,m.get(a)??[],b);try{const g=await e.reassignPort(a,new Set(n.map(w=>w.name))),f=n.findIndex(w=>g.includes(w.name));if(f>=0){const w=n.splice(f);for(const T of w)v.get(T.name)?.amendLastOutcome(`ready, then restarted after ${a} moved to a fresh port`);await stopLocalServices(w,t)}await e.prepare(new Set(o.slice(n.length)))}catch(g){throw Q(t)?g:U(s,m.get(a)??[],g,1)}}}}catch(a){try{await stopLocalServices(n,t)}catch(s){throw new AggregateError([a,s],"Local service startup failed and its supervised cleanup also failed",{cause:s})}throw a}return n}function Q(e){return e.signal.aborted}function Z(e,t){return t.signal.aborted?"cancelled":e instanceof y?e.outcome:e instanceof B?"readiness timed out":"failed to start"}function ee(e,t,r){const o=r.at(-1),n=[`Service "${e.runtimeLabel}:${e.name}" exited before becoming ready on all ${r.length.toString()} attempts, each on a fresh OS-assigned port:`,...k(t),...o&&o.output.length>0?[`Last output from attempt ${t.length.toString()}:`,...o.output.map(m=>` ${m}`)]:[]];return new Error(n.join(`
2
+ `),{cause:o})}function U(e,t,r,o){if(t.length<o)return r;const n=S(r);return new Error([`Service "${e.runtimeLabel}:${e.name}" did not start after ${t.length.toString()} attempts, each on a fresh OS-assigned port:`,...k(t),n.message].join(`
3
+ `),{cause:n})}function k(e){return e.map((t,r)=>` attempt ${(r+1).toString()} on port ${t.port.toString()}: ${t.outcome}`)}function te(e,t){const r=e.find(o=>o.name===t);if(!r||!_(r))throw new Error(`Runtime has no local service "${t}"`);return r}function P(e){const t=e.testkit.local.assignedPort;if(t===void 0)throw new Error(`Testkit assigned no port to service "${e.runtimeLabel}:${e.name}"`);return t}export async function startLocalService(e,t,r={},o=()=>Promise.resolve()){const n=j(e.productDir,e.testkit.local.cwd),m=await W(e,{signal:t.signal});await V(e,m,r.reporter);const u=H(X(e,{...e.testkit.local.env||{},...r.extraEnv||{}},process.env),m),v=P(e);u.PORT=String(v);const $=Y(e)?.url;$&&(u.DATABASE_URL=$),r.reporter?.localServiceStarting?.({serviceName:e.name,runtimeLabel:e.runtimeLabel||e.name,command:e.testkit.local.start,port:v});const L=G(e.testkit.local.start,u),a=r.logRegistry?.ensureServiceLogRecord(e),s=r.reporter?.outputMode==="debug"?i=>r.reporter?.writeDebugLine?.(i):null,d=[],h=i=>{d.push(i),d.length>K&&d.shift()};await o();const l=N({args:L.args,windowsVerbatimArguments:L.windowsVerbatimArguments,cwd:n,displayLabel:`Testkit local service ${e.runtimeLabel}:${e.name}`,env:ae(u),executable:L.executable,outputMode:"caller-drained",signal:t.signal,shutdownTimeoutMs:e.testkit.local.shutdownTimeoutMs??q,timeoutMs:null}),b=[O(l.stdout,{livePrefix:`[${e.runtimeLabel}:${e.name}]`,liveWriter:s,onLine(i){h(i),a&&r.logRegistry?.append(a,"stdout",i)}}),O(l.stderr,{livePrefix:`[${e.runtimeLabel}:${e.name}]`,liveWriter:s,onLine(i){h(i),a&&r.logRegistry?.append(a,"stderr",i)}})];let g,f=!1,w=!1;try{g=await l.ready,f=!0,t.registerService(e,l,g,n);const i=e.testkit.local.readyTimeoutMs||I,c=Date.now()+i,{baseUrl:p,readyUrl:E}=e.testkit.local,R={name:`${e.runtimeLabel}:${e.name}`,process:l,signal:t.signal};if(typeof E=="string"&&await M({...R,url:E,timeoutMs:i}),p!==void 0&&!(typeof E=="string"&&ne(E,p))&&await M({...R,url:p,requirement:"response",timeoutMs:Math.max(1,c-Date.now())}),await J(v,l.pid)==="foreign"){const C=`Readiness for "${e.runtimeLabel}:${e.name}" came from another process on port ${String(v)}`;throw new x(C,"another process held the port")}}catch(i){const c=i instanceof F?A(`${e.runtimeLabel}:${e.name}`,i):i;w=!0;const p=[];try{p.push(...await D(l,b,!1))}catch(E){p.push(S(E))}if(f)try{t.unregisterService(l.pid)}catch(E){p.push(S(E))}throw p.length>0?new AggregateError([c,...p],`Local service ${e.runtimeLabel}:${e.name} startup and cleanup failed`,{cause:i}):c instanceof x?new y(c.outcome,d,c):c}return{completionMonitor:l.completion.then(i=>{if(w)return null;if(t.signal.aborted){if(f){f=!1;try{t.unregisterService(l.pid)}catch{}}return null}let c=A(`${e.runtimeLabel}:${e.name}`,i,"unexpectedly");if(f){f=!1;try{t.unregisterService(l.pid)}catch(p){c=new AggregateError([c,p],`Local service ${e.runtimeLabel}:${e.name} exited and its manifest entry could not be removed`)}}try{t.requestStop(c.message)}catch(p){c=new AggregateError([c,p],`Local service ${e.runtimeLabel}:${e.name} exited and the active run could not be interrupted`)}return c}),expectCompletion(){w=!0},name:e.name,outputDrains:b,ownership:g,supervisor:l}}export async function stopLocalServices(e,t){const r=[];for(const o of[...e].reverse()){o.expectCompletion();try{r.push(...await D(o.supervisor,o.outputDrains)),await o.completionMonitor}catch(n){r.push(S(n))}finally{try{t?.unregisterService(o.ownership.pid)}catch(n){r.push(S(n))}}}if(r.length>0)throw new AggregateError(r,"Could not stop all local services")}async function D(e,t,r=!0){const n=await e.stop().then(u=>({error:null,result:u}),u=>({error:S(u),result:null})),m=await Promise.allSettled(t);return[...n.result?re(n.result,r):[n.error],...m.flatMap(u=>u.status==="rejected"?[S(u.reason)]:[])]}function re(e,t=!0){return[...t?[e.error]:[],e.terminationError].filter(r=>r!==null)}function ae(e){return Object.fromEntries(Object.entries(e).filter(t=>t[1]!==void 0))}function _(e){return e.testkit.local!=null}function ne(e,t){try{return new URL(e).origin===new URL(t).origin}catch{return!1}}
@@ -1 +1 @@
1
- import c from"fs";import u from"path";const y="graph.json";export function findRuntimeStateDirs(e,t){const n=[],a=r=>{if(!c.existsSync(r))return;const s=c.readdirSync(r,{withFileTypes:!0});t(r)&&n.push(r);for(const o of s)o.isDirectory()&&a(u.join(r,o.name))};return a(e),n.sort((r,s)=>s.length-r.length)}export function findGraphDirsForService(e,t){const n=u.join(e,".testkit","_graphs");if(!c.existsSync(n))return[];const a=[];for(const r of c.readdirSync(n,{withFileTypes:!0})){if(!r.isDirectory())continue;const s=u.join(n,r.name),o=readGraphMetadata(s);o&&(o.runtimeServices??[]).includes(t)&&a.push(s)}return a.sort()}export function writeGraphMetadata(e,t){c.mkdirSync(e,{recursive:!0});const n={key:t.key||null,dirName:t.dirName||null,instanceCount:Number.isFinite(t.instanceCount)?t.instanceCount:null,maxConcurrentTasks:Number.isFinite(t.maxConcurrentTasks)?t.maxConcurrentTasks:null,portNamespaceIndex:Number.isFinite(t.portNamespaceIndex)?t.portNamespaceIndex:null,portNamespaceStride:Number.isFinite(t.portNamespaceStride)?t.portNamespaceStride:null,runtimeNames:[...t.runtimeNames].sort(),runtimeServices:t.runtimeNames,targetServices:[...t.targetNames].sort()};c.writeFileSync(u.join(e,y),JSON.stringify(n,null,2))}export function readGraphMetadata(e){const t=u.join(e,y);if(!c.existsSync(t))return null;try{const n=JSON.parse(c.readFileSync(t,"utf8"));return x(n)}catch{return null}}export function normalizePathSeparators(e){return e.split(u.sep).join("/")}function x(e){if(!A(e))return null;const{dirName:t,instanceCount:n,key:a,maxConcurrentTasks:r,portNamespaceIndex:s,portNamespaceStride:o,runtimeNames:l,runtimeServices:p,targetServices:d,...S}=e,i={...S};return N(t)&&(i.dirName=t),m(n)&&(i.instanceCount=n),N(a)&&(i.key=a),m(r)&&(i.maxConcurrentTasks=r),m(s)&&(i.portNamespaceIndex=s),m(o)&&(i.portNamespaceStride=o),Array.isArray(l)&&(i.runtimeNames=l.filter(f)),Array.isArray(p)&&(i.runtimeServices=p.filter(f)),Array.isArray(d)&&(i.targetServices=d.filter(f)),i}function A(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function N(e){return e===null||typeof e=="string"}function m(e){return e===null||typeof e=="number"&&Number.isFinite(e)}function f(e){return typeof e=="string"}
1
+ import u from"fs";import c from"path";import{isNullableString as l,isUnknownRecord as N}from"../kernel/unknown-values.js";const y="graph.json";export function findRuntimeStateDirs(e,t){const n=[],s=r=>{if(!u.existsSync(r))return;const i=u.readdirSync(r,{withFileTypes:!0});t(r)&&n.push(r);for(const a of i)a.isDirectory()&&s(c.join(r,a.name))};return s(e),n.sort((r,i)=>i.length-r.length)}export function findGraphDirsForService(e,t){const n=c.join(e,".testkit","_graphs");if(!u.existsSync(n))return[];const s=[];for(const r of u.readdirSync(n,{withFileTypes:!0})){if(!r.isDirectory())continue;const i=c.join(n,r.name),a=readGraphMetadata(i);a&&(a.runtimeServices??[]).includes(t)&&s.push(i)}return s.sort()}export function writeGraphMetadata(e,t){u.mkdirSync(e,{recursive:!0});const n={key:t.key||null,dirName:t.dirName||null,instanceCount:Number.isFinite(t.instanceCount)?t.instanceCount:null,maxConcurrentTasks:Number.isFinite(t.maxConcurrentTasks)?t.maxConcurrentTasks:null,runtimeNames:[...t.runtimeNames].sort(),runtimeServices:t.runtimeNames,targetServices:[...t.targetNames].sort()};u.writeFileSync(c.join(e,y),JSON.stringify(n,null,2))}export function readGraphMetadata(e){const t=c.join(e,y);if(!u.existsSync(t))return null;try{const n=JSON.parse(u.readFileSync(t,"utf8"));return p(n)}catch{return null}}function p(e){if(!N(e))return null;const{dirName:t,instanceCount:n,key:s,maxConcurrentTasks:r,runtimeNames:i,runtimeServices:a,targetServices:f,...S}=e,o={...S};return l(t)&&(o.dirName=t),d(n)&&(o.instanceCount=n),l(s)&&(o.key=s),d(r)&&(o.maxConcurrentTasks=r),Array.isArray(i)&&(o.runtimeNames=i.filter(m)),Array.isArray(a)&&(o.runtimeServices=a.filter(m)),Array.isArray(f)&&(o.targetServices=f.filter(m)),o}function d(e){return e===null||typeof e=="number"&&Number.isFinite(e)}function m(e){return typeof e=="string"}
@@ -1 +1 @@
1
- import{finalizeRuntimeDatabaseConfig as R}from"../database/runtime-config.js";import w from"path";import{finalizeConfiguredInputs as N,finalizeConfiguredSteps as y}from"../steps/configured-steps.js";import"../config/loader/index.js";import{finalizeString as h,resolveTemplateString as E}from"../steps/index.js";import{readDatabaseInfo as M}from"../database/state.js";const O=100;export function resolveRuntimeInstanceConfigs(t,e,r,s={}){const o=B(s.graphDirName,e),c=buildPortMap(t,e,{index:s.portNamespaceIndex||0,stride:s.portNamespaceStride||1,portOffset:s.portOffset||0}),i=new Map,p=new Map,l=new Map,u=new Map,d=new Map,m=new Map,S=x(s.externalEndpoints),v=x(s.publicEndpoints),k=x(s.privateEndpoints),f=x(s.serviceContextEndpoints);for(const n of t)m.set(n.name,resolveServiceStateDir(r,n));for(const n of t)n.testkit.local&&(i.set(n.name,resolveRuntimeUrl(n.testkit.local.baseUrl,n.name,e,{runtimeId:e,runtimeLabel:o,runtimeDir:r,portMap:c,baseUrlByService:i,readyUrlByService:p,stateDirByService:m})),n.testkit.local.readyUrl!==!1&&n.testkit.local.readyUrl!=null&&p.set(n.name,resolveRuntimeUrl(n.testkit.local.readyUrl,n.name,e,{runtimeId:e,runtimeLabel:o,runtimeDir:r,portMap:c,baseUrlByService:i,readyUrlByService:p,stateDirByService:m})));for(const[n,a]of Object.entries(S))i.has(n)||i.set(n,a),p.has(n)||p.set(n,a);for(const[n,a]of Object.entries(v))l.set(n,a);for(const[n,a]of Object.entries(k))u.set(n,a);for(const[n,a]of Object.entries(f))d.set(n,a);for(const[n,a]of i.entries())l.has(n)||l.set(n,g(a,s.publicHost||null)),d.has(n)||d.set(n,a),u.has(n)||u.set(n,a);const b=[];for(const n of t){if(!n.testkit.local)continue;const a=i.get(n.name),U=p.get(n.name);a&&b.push([n.testkit.local.baseUrl,a]),U&&b.push([n.testkit.local.readyUrl,U])}return t.map(n=>resolveRuntimeConfig(n,e,o,r,c,i,p,l,u,d,s.publicHost||null,m,b))}function x(t){return Object.fromEntries(Object.entries(t??{}).map(([e,r])=>[e,(r??"").trim()]).filter(e=>e[1].length>0))}export function buildPortMap(t,e,r={}){const s=new Map,o=new Map,c=j(e,r)+Number(r.portOffset||0);for(const i of t){if(!i.testkit.local)continue;const p=i.testkit.local.port||numericPortFromUrl(i.testkit.local.baseUrl);if(!p)continue;const l=p+c;if(l>65535)throw new Error(`Runtime port resolution exceeded 65535 for service "${i.name}" (${String(l)}). Reduce runtime instances or choose lower local.port/baseUrl ports in testkit.config.ts.`);const u=o.get(l);if(u)throw new Error(`Runtime port collision: services "${u}" and "${i.name}" both resolve to ${String(l)}. Assign distinct local.port/baseUrl ports in testkit.config.ts.`);o.set(l,i.name),s.set(i.name,l)}return s}export function resolveRuntimeConfig(t,e,r,s,o,c,i,p,l,u,d,m,S){const v=resolveServiceStateDir(s,t),k=resolveServicePrepareDir(s,t),f={runtimeId:e,runtimeLabel:r,runtimeDir:s,productDir:t.productDir,serviceName:t.name,serviceCwd:t.testkit.local?.cwd||".",serviceStateDir:v,prepareDir:k,portMap:o,baseUrlByService:c,readyUrlByService:i,publicBaseUrlByService:p,privateBaseUrlByService:l,serviceContextUrlByService:u,publicHost:d,stateDirByService:m,urlMappings:S,leaseId:null,leaseDir:null,databaseBindingsReader:M},b=R(t.testkit.database,f),n={...t.testkit.runtime,prepare:P(t.testkit.runtime.prepare,f)},a=t.testkit.local?{...t.testkit.local,start:h(t.testkit.local.start,f),cwd:t.testkit.local.cwd!==void 0?h(t.testkit.local.cwd,f):t.testkit.local.cwd,port:o.get(t.name)||t.testkit.local.port,baseUrl:c.get(t.name),readyUrl:i.get(t.name),env:{...t.testkit.local.env||{}}}:void 0;return{...t,stateDir:v,runtimeId:e,runtimeLabel:r,testkit:{...t.testkit,database:b,prepareDir:k,templateContext:f,runtime:n,local:a}}}export function resolveServiceStateDir(t,e){return w.join(t,"services",e.name)}export function resolveServicePrepareDir(t,e){return w.join(resolveServiceStateDir(t,e),"prepared")}export function resolveRuntimeUrl(t,e,r,s){const o=E(t,{...s,runtimeId:r,serviceName:e}),c=s.portMap.get(e);return c?rewriteUrlPort(o,c):o}function g(t,e){if(!e)return t;try{const r=new URL(t);r.hostname=e;let s=r.toString();return!t.endsWith("/")&&r.pathname==="/"&&s.endsWith("/")&&(s=s.slice(0,-1)),s}catch{return t}}function P(t,e){return t?{inputs:N(t.inputs,r=>h(r,e)),steps:y(t.steps,r=>h(r,e))}:{inputs:[],steps:[]}}export function rewriteUrlPort(t,e){try{const r=new URL(t);if(!r.port)return t;const s=new URL(t);s.port=String(e);let o=s.toString();return!t.endsWith("/")&&r.pathname==="/"&&o.endsWith("/")&&(o=o.slice(0,-1)),o}catch{return t}}export function numericPortFromUrl(t){try{const e=new URL(t),r=Number(e.port);return Number.isInteger(r)&&r>0?r:null}catch{return null}}export function socketFromUrl(t){try{const e=new URL(t),r=Number(e.port);if(!Number.isInteger(r)||r<=0)return null;const s=normalizeSocketHost(e.hostname);return s?{host:s,port:r}:null}catch{return null}}export function normalizeSocketHost(t){return!t||t==="localhost"?"127.0.0.1":t==="[::1]"?"::1":t}function j(t,e={}){const r=String(t).match(/(\d+)$/),s=r?Number.parseInt(r[1],10)-1:0,o=Math.max(0,Number(e.index||0)),c=Math.max(1,Number(e.stride||1));return O*(o*c+s)}function B(t,e){return t?`${t}/${e}`:e}
1
+ import{finalizeRuntimeDatabaseConfig as w}from"../database/runtime-config.js";import h from"path";import{finalizeConfiguredInputs as E,finalizeConfiguredSteps as U}from"../steps/configured-steps.js";import"../config/loader/index.js";import{finalizeString as b,resolveTemplateString as y}from"../steps/index.js";export function resolveRuntimeInstanceConfigs(e,n,r,s={}){const c=buildRuntimeLabel(s.graphDirName,n),p=s.ports??new Map,a=new Map,l=new Map,u=new Map,d=new Map,f=new Map,x=k(s.externalEndpoints),m=k(s.publicEndpoints),v=k(s.privateEndpoints),o=k(s.serviceContextEndpoints);for(const t of e)t.testkit.local&&(t.testkit.local.baseUrl!==void 0&&a.set(t.name,resolveRuntimeUrl(t.testkit.local.baseUrl,t.name,n,{runtimeId:n,runtimeLabel:c,runtimeDir:r,portMap:p,baseUrlByService:a,readyUrlByService:l})),t.testkit.local.readyUrl!==!1&&t.testkit.local.readyUrl!=null&&l.set(t.name,resolveRuntimeUrl(t.testkit.local.readyUrl,t.name,n,{runtimeId:n,runtimeLabel:c,runtimeDir:r,portMap:p,baseUrlByService:a,readyUrlByService:l})));for(const[t,i]of Object.entries(x))a.has(t)||a.set(t,i),l.has(t)||l.set(t,i);for(const[t,i]of Object.entries(m))u.set(t,i);for(const[t,i]of Object.entries(v))d.set(t,i);for(const[t,i]of Object.entries(o))f.set(t,i);for(const[t,i]of a.entries())u.has(t)||u.set(t,C(i,s.publicHost||null)),f.has(t)||f.set(t,i),d.has(t)||d.set(t,i);return e.map(t=>resolveRuntimeConfig(t,n,c,r,p,a,l,u,d,f,s.publicHost||null,s.databaseBindings??new Map))}function k(e){return Object.fromEntries(Object.entries(e??{}).map(([n,r])=>[n,(r??"").trim()]).filter(n=>n[1].length>0))}export function resolveRuntimeConfig(e,n,r,s,c,p,a,l,u,d,f,x){const m=resolveServiceStateDir(s,e),v=resolveServicePrepareDir(s,e),o={runtimeId:n,runtimeLabel:r,runtimeDir:s,productDir:e.productDir,serviceName:e.name,serviceCwd:e.testkit.local?.cwd||".",serviceStateDir:m,prepareDir:v,portMap:c,baseUrlByService:p,readyUrlByService:a,publicBaseUrlByService:l,privateBaseUrlByService:u,serviceContextUrlByService:d,publicHost:f,leaseId:null,leaseDir:null,databaseBindingsByService:x},t=w(e.testkit.database,o),i={...e.testkit.runtime,prepare:j(e.testkit.runtime.prepare,o)},S=e.testkit.local?{...e.testkit.local,start:b(e.testkit.local.start,o),cwd:e.testkit.local.cwd!==void 0?b(e.testkit.local.cwd,o):e.testkit.local.cwd,assignedPort:c.get(e.name),baseUrl:p.get(e.name),readyUrl:a.get(e.name),env:{...e.testkit.local.env||{}}}:void 0;return{...e,stateDir:m,runtimeId:n,runtimeLabel:r,testkit:{...e.testkit,database:t,prepareDir:v,templateContext:o,runtime:i,local:S}}}export function resolveServiceStateDir(e,n){return h.join(e,"services",n.name)}export function resolveServicePrepareDir(e,n){return h.join(resolveServiceStateDir(e,n),"prepared")}export function resolveRuntimeUrl(e,n,r,s){return y(e,{...s,runtimeId:r,serviceName:n})}function C(e,n){if(!n)return e;try{const r=new URL(e);r.hostname=n;let s=r.toString();return!e.endsWith("/")&&r.pathname==="/"&&s.endsWith("/")&&(s=s.slice(0,-1)),s}catch{return e}}function j(e,n){return e?{inputs:E(e.inputs,r=>b(r,n)),steps:U(e.steps,r=>b(r,n))}:{inputs:[],steps:[]}}export function buildRuntimeLabel(e,n){return e?`${e}/${n}`:n}
@@ -1 +1 @@
1
- export function normalizeArtifactArchiveConfig(r){const n=e(r,"artifacts"),i=e(n?.retention,"artifacts.retention"),t=e(n?.publication,"artifacts.publication");return{retention:{maxRuns:o(i?.maxRuns,"artifacts.retention.maxRuns"),maxAgeDays:s(i?.maxAgeDays,"artifacts.retention.maxAgeDays"),preserveSuites:a(i?.preserveSuites,"artifacts.retention.preserveSuites")},publication:t?{directory:u(t.directory,"artifacts.publication.directory"),required:f(t.required,"artifacts.publication.required")}:null}}function o(r,n){if(r==null)return null;if(typeof r!="number"||!Number.isInteger(r)||r<=0)throw new Error(`${n} must be a positive integer`);return r}function s(r,n){if(r==null)return null;if(typeof r!="number"||!Number.isFinite(r)||r<=0)throw new Error(`${n} must be a positive number`);return r}function a(r,n){if(r==null)return[];if(!m(r))throw new Error(`${n} must be an array of non-empty strings`);const i=r.map(t=>{if(typeof t!="string"||t.trim().length===0)throw new Error(`${n} must be an array of non-empty strings`);return t.trim()});return[...new Set(i)].sort()}function u(r,n){if(typeof r!="string"||r.trim().length===0)throw new Error(`${n} is required`);return r.trim()}function f(r,n){if(r===void 0)return!1;if(typeof r!="boolean")throw new Error(`${n} must be a boolean`);return r}function e(r,n){if(r!=null){if(!c(r))throw new Error(`${n} must be an object`);return r}}function c(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function m(r){return Array.isArray(r)}
1
+ import{isUnknownArray as e,isUnknownRecord as o}from"../kernel/unknown-values.js";export function normalizeArtifactArchiveConfig(r){const n=normalizeOptionalRecord(r,"artifacts"),i=normalizeOptionalRecord(n?.retention,"artifacts.retention"),t=normalizeOptionalRecord(n?.publication,"artifacts.publication");return{retention:{maxRuns:s(i?.maxRuns,"artifacts.retention.maxRuns"),maxAgeDays:a(i?.maxAgeDays,"artifacts.retention.maxAgeDays"),preserveSuites:u(i?.preserveSuites,"artifacts.retention.preserveSuites")},publication:t?{directory:f(t.directory,"artifacts.publication.directory"),required:m(t.required,"artifacts.publication.required")}:null}}function s(r,n){if(r==null)return null;if(typeof r!="number"||!Number.isInteger(r)||r<=0)throw new Error(`${n} must be a positive integer`);return r}function a(r,n){if(r==null)return null;if(typeof r!="number"||!Number.isFinite(r)||r<=0)throw new Error(`${n} must be a positive number`);return r}function u(r,n){if(r==null)return[];if(!e(r))throw new Error(`${n} must be an array of non-empty strings`);const i=r.map(t=>{if(typeof t!="string"||t.trim().length===0)throw new Error(`${n} must be an array of non-empty strings`);return t.trim()});return[...new Set(i)].sort()}function f(r,n){if(typeof r!="string"||r.trim().length===0)throw new Error(`${n} is required`);return r.trim()}function m(r,n){if(r===void 0)return!1;if(typeof r!="boolean")throw new Error(`${n} must be a boolean`);return r}export function normalizeOptionalRecord(r,n){if(r!=null){if(!o(r))throw new Error(`${n} must be an object`);return r}}
@@ -1 +1 @@
1
- export{requireObjectRecord,isObjectRecord,requireStringArray as normalizeStringArray}from"./read-fields.js";export function isUnknownArray(r){return Array.isArray(r)}export function readOptionalProperty(r,n){return r?.[n]}export function normalizeOptionalNonEmptyString(r,n){if(r==null||r==="")return null;if(typeof r!="string")throw new Error(`${n} must be a string or null`);return r}
1
+ export{requireObjectRecord,requireStringArray as normalizeStringArray}from"./read-fields.js";export function readOptionalProperty(r,n){return r?.[n]}export function normalizeOptionalNonEmptyString(r,n){if(r==null||r==="")return null;if(typeof r!="string")throw new Error(`${n} must be a string or null`);return r}
@@ -1,2 +1,2 @@
1
- import{isPathWithin as F}from"../process/files/paths.js";import{readRunDocument as P}from"./read-run.js";import l from"node:fs";import o from"node:path";import"../engines/api/index.js";import"../domain/identifiers.js";import{normalizeArtifactArchiveConfig as _}from"./artifact-config.js";import{applyRunBundleRetention as C,publishRunBundle as M,sealRunBundle as B}from"./bundles.js";import{RETENTION_DECISION_SCHEMA_VERSION as $}from"./contracts.js";import{applyTimingUpdates as U,createEmptyTimings as I,normalizeTimings as J}from"./timing.js";import{isObjectRecord as q,isUnknownArray as V,normalizeOptionalNonEmptyString as E,normalizeStringArray as K,readOptionalProperty as x,requireObjectRecord as X}from"./artifact-validation.js";import{errorMessage as G,isPropertyContainer as W,readProperty as H,serializeJson as j,writeJsonFileAtomicWithRetry as k}from"../process/files/json-file.js";import{copyRegularFileSecurely as Q}from"./secure-file-copy.js";const N="timings.json",A="artifacts",Y="logs",Z="setup",R="live.json",tt=1e4,z=String;export function writeRunArtifact(t,e,r={},n={}){const i=e,s=o.join(t,".testkit","results");l.mkdirSync(s,{recursive:!0});const c=i.archive,a=r.archiveConfig??_(x(c,"request")||{}),u=r.declaredEnvironmentKeys??K(x(c,"declaredEnvironmentKeys")||[],"run artifact declaredEnvironmentKeys"),m=n.sealRunBundle??B,p=n.publishRunBundle??M,d=n.applyRunBundleRetention??C,y=n.writeLatestProjection??k,f=m(t,i,{env:r.env,archiveConfig:a,declaredEnvironmentKeys:u}),h=et(t,f.archive.runId,a.publication,p),S=rt(t,f.archive.runId,a.retention,d),v=i.finalizationFailure,L={...f,...v===void 0?{}:{finalizationFailure:v},run:h.status==="failed"&&h.required===!0||f.archive.cleanup?.status==="failed"||v!==void 0&&f.run.status!=="interrupted"?{...f.run,status:"failed"}:f.run,archive:{...f.archive,publication:h,retention:S}};return nt(s,L,y)}function et(t,e,r,n){try{return n(t,e,r)}catch(i){return{bytesUploaded:0,configured:r!==null,error:T(i),recordedAt:new Date().toISOString(),required:r?.required??!1,runId:e,schemaVersion:1,status:"failed",target:r===null?null:o.resolve(t,r.directory)}}}function rt(t,e,r,n){try{return n(t,e,r)}catch(i){return{currentRunId:e,decidedAt:new Date().toISOString(),error:T(i),garbageCollection:{failures:[],reclaimedBytes:0,removedObjects:0,status:"not_started"},policy:{maxAgeDays:r.maxAgeDays,maxRuns:r.maxRuns,preserveSuites:[...r.preserveSuites]},protectedRunIds:[e],removed:[],removalErrors:[],schemaVersion:$,status:"failed"}}}function nt(t,e,r){const n=o.join(t,"latest.json"),i={path:w(o.relative(o.dirname(t),n)),status:"complete"},s={...e,archive:{...e.archive,latest:i}};try{return r(n,s),s}catch(c){return{...s,archive:{...s.archive,latest:{...i,error:T(c),status:"failed"}}}}}function T(t){try{return G(t)}catch{return"Unknown post-seal archive operation failure"}}export function writeLiveRunArtifact(t,e){const r=e,n=o.join(t,".testkit","results");l.mkdirSync(n,{recursive:!0}),k(o.join(n,R),r)}export function finalizeLiveRunArtifact(t,e={}){const r=ot(e),n=o.join(t,".testkit","results",R),i=ft(n);if(i===null)return!1;const s=it(i,r);return s?(writeRunArtifact(t,s),!0):!1}function it(t,e){const r=P(t,"live run artifact"),n=r.run.id||null;if(e.runId&&n&&n!==e.runId)return null;const i=at(e.finishedAt),s=new Date(i).toISOString(),c=ut(r.run.startedAt),a=c===null?r.run.durationMs:Math.max(0,i-c);return{...r,generatedAt:s,run:{...r.run,id:n??e.runId,status:e.status,finishedAt:s,durationMs:a,interruptReason:e.reason},timings:st(r.timings,s,e.reason)}}function st(t,e,r){if(t==null)return t;const n=X(t,"live run artifact.timings"),i=n.operations;if(i==null)return n;if(!V(i))throw new Error("live run artifact.timings.operations must be an array");return{...n,operations:i.map(s=>!q(s)||s.status!=="running"?s:{...s,status:"cancelled",finishedAt:E(s.finishedAt,"live run operation.finishedAt")??e,message:E(s.message,"live run operation.message")??r})}}function ot(t){return{runId:t.runId??null,reason:t.reason??"run interrupted",status:t.status??"interrupted",finishedAt:t.finishedAt??Date.now()}}function at(t){if(t instanceof Date&&Number.isFinite(t.getTime()))return t.getTime();if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof t=="string"){const e=Date.parse(t);if(Number.isFinite(e))return e}return Date.now()}function ut(t){if(typeof t!="string")return null;const e=Date.parse(t);return Number.isFinite(e)?e:null}export function resetResultArtifacts(t){l.rmSync(o.join(t,".testkit","results",A),{recursive:!0,force:!0}),l.rmSync(o.join(t,".testkit","results",Y),{recursive:!0,force:!0}),l.rmSync(o.join(t,".testkit","results",Z),{recursive:!0,force:!0}),l.rmSync(o.join(t,".testkit","results",R),{force:!0})}export function persistTaskArtifacts(t,e,r){if(r.length===0)return[];const n=g(e.serviceName||"service"),i=D(t,n);return r.map((s,c)=>{const a=ct(s),u={schemaVersion:2,source:"testkit-runtime-artifact",service:e.serviceName,suite:{engineId:e.engineId,key:e.suiteKey,name:e.suiteName,profileId:e.profileId,testType:e.testType},file:e.file,taskId:e.id,index:c,name:a.name,kind:a.kind,summary:a.summary,contentType:a.contentType,emittedAt:a.emittedAt,data:a.data},m=`${j(u,"runtime artifact payload")}
2
- `,p=O(i,e.id,c,a.name,".json",y=>{l.writeFileSync(y,m,{flag:"wx"})}),d=o.join(".testkit","results",A,n,p);return{name:u.name,kind:u.kind,summary:u.summary,contentType:u.contentType,path:w(d)}})}export function persistTaskFileArtifacts(t,e,r,n={}){if(r.length===0)return[];const i=g(e.serviceName||"service"),s=D(t,i);return r.map((c,a)=>{const u=lt(c),m=o.resolve(u.path),p=pt(m,u.contentType),d=[],y=O(s,e.id,a,u.name,p,S=>{d.push(Q(m,S,{...n.maxBytes===void 0?{}:{maxBytes:n.maxBytes},...n.sourceRoot===void 0?{}:{sourceRoot:n.sourceRoot},...n.sizeLimitDescription===void 0?{}:{sizeLimitDescription:n.sizeLimitDescription}}))}),f=d.at(0);if(f===void 0)throw new Error("File artifact copy completed without a result");n.copyResults?.push(f);const h=o.join(".testkit","results",A,i,y);return{name:u.name,kind:u.kind,summary:u.summary,contentType:u.contentType??yt(m),path:w(h)}})}export function persistTaskOutputArtifacts(t,e,r){if(r.length===0)return[];const n=[];for(const i of r){const s=i.text;s.trim().length!==0&&n.push({name:i.name||"task-output",kind:i.kind||"runtime.output",summary:i.summary||dt(s),contentType:i.contentType||"text/plain",emittedAt:i.emittedAt||new Date().toISOString(),data:{stream:i.stream||null,text:s}})}return persistTaskArtifacts(t,e,n)}export function loadTimings(t){const e=o.join(t,".testkit",N);if(!l.existsSync(e))return I();try{const r=JSON.parse(l.readFileSync(e,"utf8"));return J(r)}catch{return I()}}export function saveTimings(t,e,r){if(r.length===0)return;const n=U(e,r),i=o.join(t,".testkit");l.mkdirSync(i,{recursive:!0}),l.writeFileSync(o.join(i,N),j(n,"timings"))}function ct(t){return{name:t.name,kind:t.kind||null,summary:t.summary||null,contentType:t.contentType||"application/json",emittedAt:t.emittedAt||null,data:t.data}}function lt(t){return{path:t.path,name:t.name||"artifact",kind:t.kind||null,summary:t.summary||null,contentType:t.contentType||null}}function mt(t,e,r,n,i=0){const s=i===0?"":`-${(i+1).toString().padStart(2,"0")}`;return`task-${g(t)}-${(e+1).toString().padStart(2,"0")}-${g(r)}${s}${n}`}function O(t,e,r,n,i,s){for(let c=0;c<tt;c+=1){const a=mt(e,r,n,i,c),u=o.join(t,a);try{return s(u),a}catch(m){if(b(m,"EEXIST"))continue;throw l.rmSync(u,{force:!0}),m}}throw new Error(`Could not allocate a unique artifact path for task ${z(e)} and artifact ${n}`)}function D(t,e){const r=o.resolve(t);if(!l.statSync(r).isDirectory())throw new Error("Artifact product directory must be a directory");const i=l.realpathSync(r);let s=r;for(const c of[".testkit","results",A,e]){s=o.join(s,c);try{l.mkdirSync(s)}catch(m){if(!b(m,"EEXIST"))throw m}const a=l.lstatSync(s);if(a.isSymbolicLink()||!a.isDirectory())throw new Error(`Artifact output directory ${JSON.stringify(s)} must be a real directory below productDir`);const u=l.realpathSync(s);if(!F(i,u))throw new Error(`Artifact output directory ${JSON.stringify(s)} escapes productDir`)}return s}function g(t){return z(t).trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"artifact"}function w(t){return t.split(o.sep).join("/")}function ft(t){try{return JSON.parse(l.readFileSync(t,"utf8"))}catch{return null}}function dt(t){const e=t.split(/\r?\n/u).map(r=>r.trim()).find(Boolean);return e?e.slice(0,120):"captured task output"}function pt(t,e){const r=o.extname(t);if(r)return r;const n=(e??"").split(";",1)[0].trim().toLowerCase();return n==="text/markdown"?".md":n==="text/plain"?".txt":n==="application/json"?".json":n==="application/zip"?".zip":n==="image/png"?".png":n==="image/jpeg"?".jpg":n==="text/html"?".html":n==="video/webm"?".webm":".artifact"}function yt(t){const e=o.extname(t).toLowerCase();return e===".md"||e===".markdown"?"text/markdown":e===".txt"||e===".log"?"text/plain":e===".json"?"application/json":"application/octet-stream"}function b(t,e){return W(t)&&H(t,"code")===e}
1
+ import{isPathWithin as _}from"../process/files/paths.js";import{isUnknownArray as C,isUnknownRecord as M}from"../kernel/unknown-values.js";import{readRunDocument as B}from"./read-run.js";import l from"node:fs";import o from"node:path";import"../engines/api/index.js";import"../domain/identifiers.js";import{normalizeArtifactArchiveConfig as $}from"./artifact-config.js";import{applyRunBundleRetention as K,publishRunBundle as U,sealRunBundle as V}from"./bundles.js";import{RETENTION_DECISION_SCHEMA_VERSION as q}from"./contracts.js";import{redactedRunValue as A,runRedaction as J}from"./redaction.js";import{applyTimingUpdates as X,createEmptyTimings as x,normalizeTimings as G}from"./timing.js";import{normalizeOptionalNonEmptyString as k,normalizeStringArray as W,readOptionalProperty as j,requireObjectRecord as H}from"./artifact-validation.js";import{errorMessage as Q,serializeJson as N,writeJsonFileAtomicWithRetry as z,readJsonFileOrNull as Y}from"../process/files/json-file.js";import{copyRegularFileSecurely as Z}from"./secure-file-copy.js";import{hasErrorCode as O}from"../kernel/error-serialization.js";import{posixPath as w}from"../process/files/paths.js";const D="timings.json",S="artifacts",tt="logs",et="setup",I="live.json",rt=1e4,b=String;export function writeRunArtifact(t,e,r={},n={}){const i=e,a=o.join(t,".testkit","results");l.mkdirSync(a,{recursive:!0});const u=i.archive,s=r.archiveConfig??$(j(u,"request")||{}),c=r.declaredEnvironmentKeys??W(j(u,"declaredEnvironmentKeys")||[],"run artifact declaredEnvironmentKeys"),m=n.sealRunBundle??V,p=n.publishRunBundle??U,d=n.applyRunBundleRetention??K,y=n.writeLatestProjection??z,f=m(t,i,{env:r.env,archiveConfig:s,declaredEnvironmentKeys:c,redactKeys:r.redactKeys,redactionTargets:r.redactionTargets}),h=nt(t,f.archive.runId,s.publication,p),v=it(t,f.archive.runId,s.retention,d),{targets:g}=J({env:r.env,redactKeys:r.redactKeys,redactionTargets:r.redactionTargets}),R=A(i.finalizationFailure,g),P={...f,...R===void 0?{}:{finalizationFailure:R},run:h.status==="failed"&&h.required===!0||f.archive.cleanup?.status==="failed"||R!==void 0&&f.run.status!=="interrupted"?{...f.run,status:"failed"}:f.run,archive:{...f.archive,publication:A(h,g),retention:A(v,g)}};return at(a,P,y,g)}function nt(t,e,r,n){try{return n(t,e,r)}catch(i){return{bytesUploaded:0,configured:r!==null,error:E(i),recordedAt:new Date().toISOString(),required:r?.required??!1,runId:e,schemaVersion:1,status:"failed",target:r===null?null:o.resolve(t,r.directory)}}}function it(t,e,r,n){try{return n(t,e,r)}catch(i){return{currentRunId:e,decidedAt:new Date().toISOString(),error:E(i),garbageCollection:{failures:[],reclaimedBytes:0,removedObjects:0,status:"not_started"},policy:{maxAgeDays:r.maxAgeDays,maxRuns:r.maxRuns,preserveSuites:[...r.preserveSuites]},protectedRunIds:[e],removed:[],removalErrors:[],schemaVersion:q,status:"failed"}}}function at(t,e,r,n){const i=o.join(t,"latest.json"),a={path:w(o.relative(o.dirname(t),i)),status:"complete"},u={...e,archive:{...e.archive,latest:a}};try{return r(i,u),u}catch(s){return{...u,archive:{...u.archive,latest:{...a,error:A(E(s),n),status:"failed"}}}}}function E(t){try{return Q(t)}catch{return"Unknown post-seal archive operation failure"}}export function writeLiveRunArtifact(t,e){const r=e,n=o.join(t,".testkit","results");l.mkdirSync(n,{recursive:!0}),z(o.join(n,I),r)}export function finalizeLiveRunArtifact(t,e={}){const r=ut(e),n=o.join(t,".testkit","results",I),i=Y(n);if(i===null)return!1;const a=st(i,r);return a?(writeRunArtifact(t,a,{redactKeys:e.redactKeys,redactionTargets:e.redactionTargets}),!0):!1}function st(t,e){const r=B(t,"live run artifact"),n=r.run.id||null;if(e.runId&&n&&n!==e.runId)return null;const i=ct(e.finishedAt),a=new Date(i).toISOString(),u=lt(r.run.startedAt),s=u===null?r.run.durationMs:Math.max(0,i-u);return{...r,generatedAt:a,run:{...r.run,id:n??e.runId,status:e.status,finishedAt:a,durationMs:s,interruptReason:e.reason},timings:ot(r.timings,a,e.reason)}}function ot(t,e,r){if(t==null)return t;const n=H(t,"live run artifact.timings"),i=n.operations;if(i==null)return n;if(!C(i))throw new Error("live run artifact.timings.operations must be an array");return{...n,operations:i.map(a=>!M(a)||a.status!=="running"?a:{...a,status:"cancelled",finishedAt:k(a.finishedAt,"live run operation.finishedAt")??e,message:k(a.message,"live run operation.message")??r})}}function ut(t){return{runId:t.runId??null,reason:t.reason??"run interrupted",status:t.status??"interrupted",finishedAt:t.finishedAt??Date.now()}}function ct(t){if(t instanceof Date&&Number.isFinite(t.getTime()))return t.getTime();if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof t=="string"){const e=Date.parse(t);if(Number.isFinite(e))return e}return Date.now()}function lt(t){if(typeof t!="string")return null;const e=Date.parse(t);return Number.isFinite(e)?e:null}export function resetResultArtifacts(t){l.rmSync(o.join(t,".testkit","results",S),{recursive:!0,force:!0}),l.rmSync(o.join(t,".testkit","results",tt),{recursive:!0,force:!0}),l.rmSync(o.join(t,".testkit","results",et),{recursive:!0,force:!0}),l.rmSync(o.join(t,".testkit","results",I),{force:!0})}export function persistTaskArtifacts(t,e,r){if(r.length===0)return[];const n=T(e.serviceName||"service"),i=F(t,n);return r.map((a,u)=>{const s=mt(a),c={schemaVersion:2,source:"testkit-runtime-artifact",service:e.serviceName,suite:{engineId:e.engineId,key:e.suiteKey,name:e.suiteName,profileId:e.profileId,testType:e.testType},file:e.file,taskId:e.id,index:u,name:s.name,kind:s.kind,summary:s.summary,contentType:s.contentType,emittedAt:s.emittedAt,data:s.data},m=`${N(c,"runtime artifact payload")}
2
+ `,p=L(i,e.id,u,s.name,".json",y=>{l.writeFileSync(y,m,{flag:"wx"})}),d=o.join(".testkit","results",S,n,p);return{name:c.name,kind:c.kind,summary:c.summary,contentType:c.contentType,path:w(d)}})}export function persistTaskFileArtifacts(t,e,r,n={}){if(r.length===0)return[];const i=T(e.serviceName||"service"),a=F(t,i);return r.map((u,s)=>{const c=ft(u),m=o.resolve(c.path),p=yt(m,c.contentType),d=[],y=L(a,e.id,s,c.name,p,v=>{d.push(Z(m,v,{...n.maxBytes===void 0?{}:{maxBytes:n.maxBytes},...n.sourceRoot===void 0?{}:{sourceRoot:n.sourceRoot},...n.sizeLimitDescription===void 0?{}:{sizeLimitDescription:n.sizeLimitDescription}}))}),f=d.at(0);if(f===void 0)throw new Error("File artifact copy completed without a result");n.copyResults?.push(f);const h=o.join(".testkit","results",S,i,y);return{name:c.name,kind:c.kind,summary:c.summary,contentType:c.contentType??ht(m),path:w(h)}})}export function persistTaskOutputArtifacts(t,e,r){if(r.length===0)return[];const n=[];for(const i of r){const a=i.text;a.trim().length!==0&&n.push({name:i.name||"task-output",kind:i.kind||"runtime.output",summary:i.summary||pt(a),contentType:i.contentType||"text/plain",emittedAt:i.emittedAt||new Date().toISOString(),data:{stream:i.stream||null,text:a}})}return persistTaskArtifacts(t,e,n)}export function loadTimings(t){const e=o.join(t,".testkit",D);if(!l.existsSync(e))return x();try{const r=JSON.parse(l.readFileSync(e,"utf8"));return G(r)}catch{return x()}}export function saveTimings(t,e,r){if(r.length===0)return;const n=X(e,r),i=o.join(t,".testkit");l.mkdirSync(i,{recursive:!0}),l.writeFileSync(o.join(i,D),N(n,"timings"))}function mt(t){return{name:t.name,kind:t.kind||null,summary:t.summary||null,contentType:t.contentType||"application/json",emittedAt:t.emittedAt||null,data:t.data}}function ft(t){return{path:t.path,name:t.name||"artifact",kind:t.kind||null,summary:t.summary||null,contentType:t.contentType||null}}function dt(t,e,r,n,i=0){const a=i===0?"":`-${(i+1).toString().padStart(2,"0")}`;return`task-${T(t)}-${(e+1).toString().padStart(2,"0")}-${T(r)}${a}${n}`}function L(t,e,r,n,i,a){for(let u=0;u<rt;u+=1){const s=dt(e,r,n,i,u),c=o.join(t,s);try{return a(c),s}catch(m){if(O(m,"EEXIST"))continue;throw l.rmSync(c,{force:!0}),m}}throw new Error(`Could not allocate a unique artifact path for task ${b(e)} and artifact ${n}`)}function F(t,e){const r=o.resolve(t);if(!l.statSync(r).isDirectory())throw new Error("Artifact product directory must be a directory");const i=l.realpathSync(r);let a=r;for(const u of[".testkit","results",S,e]){a=o.join(a,u);try{l.mkdirSync(a)}catch(m){if(!O(m,"EEXIST"))throw m}const s=l.lstatSync(a);if(s.isSymbolicLink()||!s.isDirectory())throw new Error(`Artifact output directory ${JSON.stringify(a)} must be a real directory below productDir`);const c=l.realpathSync(a);if(!_(i,c))throw new Error(`Artifact output directory ${JSON.stringify(a)} escapes productDir`)}return a}function T(t){return b(t).trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"artifact"}function pt(t){const e=t.split(/\r?\n/u).map(r=>r.trim()).find(Boolean);return e?e.slice(0,120):"captured task output"}function yt(t,e){const r=o.extname(t);if(r)return r;const n=(e??"").split(";",1)[0].trim().toLowerCase();return n==="text/markdown"?".md":n==="text/plain"?".txt":n==="application/json"?".json":n==="application/zip"?".zip":n==="image/png"?".png":n==="image/jpeg"?".jpg":n==="text/html"?".html":n==="video/webm"?".webm":".artifact"}function ht(t){const e=o.extname(t).toLowerCase();return e===".md"||e===".markdown"?"text/markdown":e===".txt"||e===".log"?"text/plain":e===".json"?"application/json":"application/octet-stream"}
@@ -1 +1 @@
1
- import{recordWork as H}from"../kernel/work-metrics.js";import{optionalString as A}from"../kernel/unknown-values.js";import{readRunProvenance as ue}from"./read-provenance.js";import{parseRunBundleArtifact as le,parseRunBundleManifest as J,readRunBundleArtifact as fe}from"./read-bundle.js";import{readRunDocument as de}from"./read-run.js";import me from"crypto";import c from"fs";import u from"path";import{redactSensitiveText as Y}from"../kernel/redaction.js";import{BUNDLE_SCHEMA_VERSION as G,OBJECTS_DIRNAME as Q,PROVENANCE_SCHEMA_VERSION as pe,RETENTION_DECISION_SCHEMA_VERSION as he,RUNS_DIRNAME as ge}from"./contracts.js";import{bundleRelativePath as x,errorMessage as k,hashFile as F,isObjectRecord as $,normalizePath as X,normalizeRunId as w,objectRecords as Z,optionalStringArray as z,optionalUnknownArray as ye,readJsonFile as P,requirePublicationPathOutsideResults as M,requireRunId as ve,runIncludesFile as Se,resolveManifestEntryPath as ee,resolveRunBundleDirectory as O,resolveRunsRoot as te,resultsRoot as U,sanitizeSegment as Re,sha256 as C,stableJson as q,treeBytes as ne,walkFiles as re,writeBufferAtomic as je,writeJson as N}from"./storage.js";import{resolveCiProvenance as be}from"./ci-provenance.js";const W=["artifacts","logs","setup"],Ie=/(?:PASSWORD|TOKEN|SECRET|PRIVATE_KEY|AUTH|COOKIE|SESSION|API_KEY)/iu,we=["package.json","package-lock.json","npm-shrinkwrap.json","pnpm-lock.yaml","yarn.lock","testkit.config.ts","testkit.config.mts","testkit.config.js","testkit.config.mjs"];export function sealRunBundle(e,n,t={},s={}){const r=n,o=ve(r),i=te(e,!0),a=u.dirname(i),f=u.join(i,o),m=s.cleanupActiveRunResults??ze,p=loadVerifiedRunBundleArtifactIfExists(e,o);if(p!==null)return{...p,archive:{...p.archive,cleanup:m(a)}};const d=u.join(i,`.${o}.${String(process.pid)}.${String(Date.now())}.${me.randomBytes(4).toString("hex")}.tmp`);c.mkdirSync(d,{recursive:!0});try{const R=Te(t.env??process.env),g=Ee({productDir:e,resultsDir:a,runId:o,tempDir:d,sensitiveValues:R}),h=Be(r,o,R),y=de(h.artifact,"run artifact");g.redaction.structuredReplacements=h.replacements,g.redaction.replacements+=h.replacements;const v=$e(e,y,o,{...t,redaction:g.redaction}),j={schemaVersion:G,runId:o,status:"complete",canonicalRunPath:x(o,"run.json"),manifestPath:x(o,"manifest.json"),provenancePath:x(o,"provenance.json"),integrity:"sha256",publication:{configured:!!t.archiveConfig?.publication,status:t.archiveConfig?.publication?"pending":"not_configured"},redaction:g.redaction};y.archive=j,N(u.join(d,"run.json"),y),N(u.join(d,"provenance.json"),v);const b=xe(d),D=C(Buffer.from(q(b))),E={schemaVersion:G,runId:o,createdAt:new Date().toISOString(),algorithm:"sha256",files:b,storage:{fileCount:b.length,logicalBytes:b.reduce((T,_)=>T+_.bytes,0),objectBytesWritten:g.objectBytesWritten,deduplicatedBytes:g.deduplicatedBytes},redaction:g.redaction,digest:D};return N(u.join(d,"manifest.json"),E),c.renameSync(d,f),{...y,archive:{...j,cleanup:m(a),manifestDigest:E.digest,storage:E.storage}}}catch(R){try{c.rmSync(d,{recursive:!0,force:!0})}catch{}try{Ce(e)}catch{}throw R}}export function loadVerifiedRunBundleArtifactIfExists(e,n){const t=w(n),s=O(e,t);if(!c.existsSync(s))return null;const r=verifyRunBundle(e,t);if(!r.ok)throw new Error(`Immutable run bundle ${t} already exists but failed integrity verification: ${r.errors.join("; ")}`);return loadRunBundleArtifact(e,t)}export function loadRunBundleArtifact(e,n){return se(e,n).artifact}function se(e,n){const t=w(n),s=fe(e,t),r=loadRunBundleManifest(e,t);return{manifest:r,artifact:{...s,archive:{...s.archive,manifestDigest:r.digest,storage:r.storage}}}}export function loadRunBundleManifest(e,n){const t=w(n),s=O(e,t),r=u.join(s,"manifest.json");if(!c.existsSync(r))throw new Error(`No immutable Testkit run manifest found for ${t}`);return J(P(r),r,t)}export function listRunBundles(e,n={}){return ie(e,n).map(({artifact:t,manifest:s,...r})=>r)}function ie(e,n={}){const t=te(e,!1);if(!c.existsSync(t))return[];const s=c.readdirSync(t,{withFileTypes:!0});return H("artifacts.runDirectoriesRead",1),H("artifacts.runEntriesVisited",s.length),s.filter(o=>o.isDirectory()&&!o.name.startsWith(".")).map(o=>{try{const{artifact:i,manifest:a}=se(e,o.name);return n.file&&!Se(i,n.file)?null:{artifact:i,manifest:a,runId:o.name,status:i.run.status,startedAt:i.run.startedAt,finishedAt:i.run.finishedAt??null,manifestDigest:i.archive.manifestDigest??null,canonicalRunPath:i.archive.canonicalRunPath}}catch{return null}}).filter(o=>o!==null).sort((o,i)=>(i.finishedAt??i.startedAt??"").localeCompare(o.finishedAt??o.startedAt??""))}export function verifyRunBundle(e,n){const t=w(n);try{return V(O(e,t),t)}catch(s){return{ok:!1,runId:t,errors:[k(s)],checkedFiles:0}}}export function publishRunBundle(e,n,t,s={}){const r=w(n),o=s.writePublicationReceipt??Pe;if(!t)return o(e,r,{status:"not_configured",required:!1,target:null,bytesUploaded:0});const i=u.resolve(e,t.directory);try{M(e,i)}catch(d){return o(e,r,{status:"failed",required:t.required,target:i,error:k(d),bytesUploaded:0})}const a=Re(u.basename(e)),f=u.join(i,a),m=u.join(f,r),p=u.join(f,`.${r}.${String(process.pid)}.${String(Date.now())}.tmp`);try{const d=O(e,r);if(c.mkdirSync(f,{recursive:!0}),M(e,f),c.existsSync(m)){const h=c.lstatSync(m);if(h.isSymbolicLink()||!h.isDirectory())throw new Error("Publication target must be a regular bundle directory");M(e,m);const y=V(d,r);if(!y.ok)throw new Error(`Source run bundle failed integrity verification: ${y.errors.join("; ")}`);const v=V(m,r);if(!v.ok)throw new Error(`Publication target failed integrity verification: ${v.errors.join("; ")}`);if(y.manifestDigest!==v.manifestDigest)throw new Error("Publication target already exists with a different manifest digest");return o(e,r,{status:"complete",required:t.required,target:m,manifestDigest:y.manifestDigest,reused:!0,bundleBytes:ne(d),bytesUploaded:0})}const R=ne(d);c.cpSync(d,p,{recursive:!0,preserveTimestamps:!0});const g=V(p,r);if(!g.ok)throw new Error(g.errors.join("; "));return c.renameSync(p,m),o(e,r,{status:"complete",required:t.required,target:m,manifestDigest:g.manifestDigest,reused:!1,bundleBytes:R,bytesUploaded:R})}catch(d){return c.rmSync(p,{recursive:!0,force:!0}),o(e,r,{status:"failed",required:t.required,target:m,error:k(d),bytesUploaded:0})}}export function applyRunBundleRetention(e,n,t={},s={}){const r=w(n),o=s.removeObject??ce,i=s.removeRunBundle??Ne,a=t.maxRuns??null,f=t.maxAgeDays??null,m=new Set(t.preserveSuites||[]),p=ie(e),d=new Set([r]);for(const l of p)Oe(l.artifact,m)&&d.add(l.runId);const R=new Set(a?p.slice(0,a).map(l=>l.runId):p.map(l=>l.runId)),g=f==null?null:Date.now()-f*24*60*60*1e3,h=[];for(const l of p){if(d.has(l.runId))continue;const S=g!=null&&Date.parse(l.finishedAt||l.startedAt||"")<g,I=!R.has(l.runId);if(!S&&!I)continue;const B=[];S&&B.push("max_age"),I&&B.push("max_runs"),h.push({path:u.join(U(e),ge,l.runId),reasons:B,runId:l.runId})}const y=new Map(p.map(l=>[l.runId,l.manifest.files.filter(S=>S.path.startsWith("files/")).map(S=>S.sha256)])),v=oe(e),j=[],b=[];for(const l of h){let S=null;try{i(l.path)}catch(B){S=L(B)}const I=!c.existsSync(l.path);!I&&S===null&&(S="Run bundle still exists after removal completed"),I&&j.push({reasons:l.reasons,runId:l.runId}),S!==null&&b.push({...l,error:S,removed:I})}const D=new Set(j.map(l=>l.runId)),E=new Set(p.filter(l=>!D.has(l.runId)).flatMap(l=>y.get(l.runId)??[])),T=ae(v,E,o),_=new Date().toISOString();return Ve({currentRunId:r,decidedAt:_,garbageCollection:T,policy:{maxRuns:a,maxAgeDays:f,preserveSuites:[...m].sort()},protectedRunIds:[...d].sort(),removed:j,removalErrors:b})}function Ee({resultsDir:e,tempDir:n,sensitiveValues:t}){let s=0,r=0,o=0,i=0,a=0;const f=u.join(e,Q,"sha256");c.mkdirSync(f,{recursive:!0});for(const m of W){const p=u.join(e,m);if(c.existsSync(p))for(const d of re(p)){const R=u.relative(p,d),g=c.readFileSync(d),h=De(g,d,t);h.scanned&&(o+=1),h.replacements>0&&(i+=1,a+=h.replacements);const y=C(h.buffer),v=u.join(f,y);c.existsSync(v)?r+=h.buffer.length:(je(v,h.buffer),c.chmodSync(v,292),s+=h.buffer.length);const j=u.join(n,"files",m,R);c.mkdirSync(u.dirname(j),{recursive:!0});try{c.linkSync(v,j)}catch{c.copyFileSync(v,j)}}}return{objectBytesWritten:s,deduplicatedBytes:r,redaction:{policyVersion:1,status:"applied",textualFilesScanned:o,filesRedacted:i,replacements:a,sensitiveEnvironmentKeys:t.map(m=>m.key).sort(),valuesStored:!1}}}function Be(e,n,t){const s=new Map(W.map(o=>[`.testkit/results/${o}/`,`${x(n,`files/${o}`)}/`])),r=K(e,s);return ke(Ae(r),t)}function Ae(e){if(!$(e))return e;const n={...e};if($(n.product)){const t={...n.product};delete t.directory,n.product=t}if($(n.git)){const t={...n.git};delete t.remoteUrl,delete t.repoRoot,delete t.worktreePath,n.git=t}return delete n.host,n}function K(e,n){if(Array.isArray(e))return e.map(s=>K(s,n));if($(e))return Object.fromEntries(Object.entries(e).map(([s,r])=>[s,K(r,n)]));if(typeof e!="string")return e;let t=e;for(const[s,r]of n)t.startsWith(s)&&(t=`${r}${t.slice(s.length)}`);return t}function ke(e,n){let t=0;function s(r){if(Array.isArray(r))return r.map(s);if($(r))return Object.fromEntries(Object.entries(r).map(([i,a])=>[i,s(a)]));if(typeof r!="string")return r;let o=Y(r);o!==r&&(t+=1);for(const i of n){if(!o.includes(i.value))continue;const a=o.split(i.value);t+=a.length-1,o=a.join("<redacted>")}return o}return{artifact:s(e),replacements:t}}function $e(e,n,t,s){const r=z(n.run.fileNames),o=[...new Set([...we,...r])].map(i=>Fe(e,i)).filter(i=>i!==null);return{schemaVersion:pe,runId:t,ci:be(s.env??process.env),source:{git:n.git??null,files:o},runtime:{controller:{testkitVersion:A(n.run.testkitVersion),node:process.versions.node,platform:process.platform,architecture:process.arch},runtimeStats:ye(n.run.runtimeStats)},scenario:{types:z(n.run.types),suiteSelectors:z(n.run.suiteSelectors),fileNames:r,serviceFilter:A(n.run.serviceFilter),planningDigest:C(Buffer.from(q(n.planning??null))),declaredEnvironmentKeys:[...new Set(s.declaredEnvironmentKeys??[])].sort()},redaction:s.redaction}}function xe(e){return re(e).map(n=>({path:X(u.relative(e,n)),bytes:c.statSync(n).size,sha256:F(n)})).sort((n,t)=>n.path.localeCompare(t.path))}function V(e,n){const t=u.join(e,"manifest.json"),s=J(P(t),t,n);le(P(u.join(e,"run.json")),u.join(e,"run.json"),n);const r=[];for(const i of s.files){let a;try{a=ee(e,i.path)}catch(m){r.push(k(m));continue}if(!c.existsSync(a)){r.push(`missing ${i.path}`);continue}const f=c.lstatSync(a);if(f.isSymbolicLink()){r.push(`symbolic link not allowed ${i.path}`);continue}if(!f.isFile()){r.push(`not a regular file ${i.path}`);continue}f.size!==i.bytes&&r.push(`size mismatch ${i.path}`),F(a)!==i.sha256&&r.push(`checksum mismatch ${i.path}`)}C(Buffer.from(q(s.files)))!==s.digest&&r.push("manifest digest mismatch"),s.storage.fileCount!==s.files.length&&r.push("manifest file count mismatch");for(const i of["run.json","provenance.json"])s.files.some(a=>a.path===i)||r.push(`manifest must include ${i}`);if(r.length===0){const i=ee(e,"provenance.json");ue(P(i),i,n)}return{runId:n,checkedFiles:s.files.length,storage:s.storage,ok:r.length===0,errors:r,manifestDigest:s.digest}}function Pe(e,n,t){const s={schemaVersion:1,runId:n,recordedAt:new Date().toISOString(),...t};return N(u.join(U(e),"publications",`${n}.json`),s),s}function Oe(e,n){return n.size===0?!1:Z(e.services).some(t=>Z(t.suites).some(s=>{const r=A(t.name)??"",o=A(s.name)??"",i=A(s.testType)??"";return[o,`${i}:${o}`,`${r}/${i}:${o}`].some(f=>n.has(f))}))}function Ce(e){const n=new Set;for(const t of listRunBundles(e)){const s=loadRunBundleManifest(e,t.runId);for(const r of s.files)r.path.startsWith("files/")&&n.add(r.sha256)}return ae(oe(e),n,ce)}function oe(e){const n=u.join(U(e),Q,"sha256");return c.existsSync(n)?c.readdirSync(n,{withFileTypes:!0}).filter(t=>t.isFile()).map(t=>{const s=u.join(n,t.name);return{bytes:c.statSync(s).size,digest:t.name,path:s}}):[]}function ae(e,n,t){const s=[];let r=0,o=0;for(const i of e){if(n.has(i.digest))continue;let a=null;try{t(i.path)}catch(m){a=L(m)}!c.existsSync(i.path)?(r+=1,o+=i.bytes):a===null&&(a="Object still exists after removal completed"),a!==null&&s.push({error:a,path:i.path})}return{failures:s,reclaimedBytes:o,removedObjects:r,status:s.length===0?"complete":"failed"}}function Ne(e){c.rmSync(e,{recursive:!0,force:!0})}function ce(e){c.rmSync(e,{force:!0})}function Ve({currentRunId:e,decidedAt:n,garbageCollection:t,policy:s,protectedRunIds:r,removed:o,removalErrors:i}){const a=[...i.map(f=>`remove ${f.runId}: ${f.error}`),...t.failures.map(f=>`garbage collect ${f.path}: ${f.error}`)];return{currentRunId:e,decidedAt:n,garbageCollection:t,policy:s,protectedRunIds:r,removed:o,removalErrors:i,schemaVersion:he,status:a.length===0?"complete":"failed",...a.length===0?{}:{error:a.join("; ")}}}function De(e,n,t){if(!_e(e,n)){for(const i of t)if(e.includes(Buffer.from(i.value)))throw new Error(`Refusing to archive binary file containing sensitive environment value: ${n}`);return{buffer:e,scanned:!1,replacements:0}}const s=e.toString("utf8");let r=Y(s),o=r===s?0:1;for(const i of t){if(!r.includes(i.value))continue;const a=r.split(i.value);o+=a.length-1,r=a.join("<redacted>")}return{buffer:Buffer.from(r),scanned:!0,replacements:o}}function Te(e){const n=[];for(const[t,s]of Object.entries(e))Ie.test(t)&&typeof s=="string"&&s.length>=8&&n.push({key:t,value:s});return n}function _e(e,n){if(e.includes(0))return!1;const t=u.extname(n).toLowerCase();return![".zip",".gz",".png",".jpg",".jpeg",".webm",".pdf"].includes(t)}function Fe(e,n){const t=u.resolve(e,n);return!t.startsWith(`${u.resolve(e)}${u.sep}`)||!c.existsSync(t)||!c.statSync(t).isFile()?null:{path:X(u.relative(e,t)),bytes:c.statSync(t).size,sha256:F(t)}}function ze(e){const n=[];for(const t of[...W.map(s=>u.join(e,s)),u.join(e,"live.json")])try{c.rmSync(t,{recursive:!0,force:!0})}catch(s){n.push(`${t}: ${L(s)}`)}return n.length===0?{status:"complete"}:{error:n.join("; "),status:"failed"}}function L(e){try{return k(e)}catch{return"Unknown post-seal archive operation failure"}}
1
+ import{recordWork as J}from"../kernel/work-metrics.js";import{isUnknownRecord as A,optionalString as H}from"../kernel/unknown-values.js";import{posixPath as K}from"../process/files/paths.js";import{readRunProvenance as oe}from"./read-provenance.js";import{parseRunBundleArtifact as ae,parseRunBundleManifest as Y,readRunBundleArtifact as ce}from"./read-bundle.js";import{readRunDocument as ue}from"./read-run.js";import{runModel as G}from"./run-model.js";import le from"crypto";import a from"fs";import u from"path";import{redactRunText as fe,redactRunValue as me,runRedaction as de}from"./redaction.js";import{BUNDLE_SCHEMA_VERSION as Q,OBJECTS_DIRNAME as X,PROVENANCE_SCHEMA_VERSION as pe,RETENTION_DECISION_SCHEMA_VERSION as he,RUNS_DIRNAME as ye}from"./contracts.js";import{bundleRelativePath as $,hashFile as z,normalizeRunId as I,optionalStringArray as D,optionalUnknownArray as ge,readJsonFile as x,requirePublicationPathOutsideResults as _,requireRunId as ve,runIncludesFile as Se,resolveManifestEntryPath as Z,resolveRunBundleDirectory as P,resolveRunsRoot as N,resultsRoot as T,sanitizeSegment as Re,sha256 as O,stableJson as M,treeBytes as ee,walkFiles as te,writeBufferAtomic as je,writeJson as C}from"./storage.js";import{resolveCiProvenance as be}from"./ci-provenance.js";import{errorMessage as B}from"../kernel/error-serialization.js";const U=["artifacts","logs","setup"],we=["package.json","package-lock.json","npm-shrinkwrap.json","pnpm-lock.yaml","yarn.lock","testkit.config.ts","testkit.config.mts","testkit.config.js","testkit.config.mjs"];export function sealRunBundle(e,n,t={},r={}){const s=n,o=ve(s),i=N(e,!0),c=u.dirname(i),f=u.join(i,o),l=r.cleanupActiveRunResults??_e,p=loadVerifiedRunBundleArtifactIfExists(e,o);if(p!==null)return{...p,archive:{...p.archive,cleanup:l(c)}};const m=u.join(i,`.${o}.${String(process.pid)}.${String(Date.now())}.${le.randomBytes(4).toString("hex")}.tmp`);a.mkdirSync(m,{recursive:!0});try{const S=de(t),y=Ie({productDir:e,resultsDir:c,runId:o,tempDir:m,redaction:S}),h=Be(s,o,S.targets),v=ue(h.artifact,"run artifact");y.redaction.structuredReplacements=h.replacements,y.redaction.replacements+=h.replacements;const g=ke(e,v,o,{...t,redaction:y.redaction}),j={schemaVersion:Q,runId:o,status:"complete",canonicalRunPath:$(o,"run.json"),manifestPath:$(o,"manifest.json"),provenancePath:$(o,"provenance.json"),integrity:"sha256",publication:{configured:!!t.archiveConfig?.publication,status:t.archiveConfig?.publication?"pending":"not_configured"},redaction:y.redaction};v.archive=j,C(u.join(m,"run.json"),v),C(u.join(m,"provenance.json"),g);const b=Ae(m),V=O(Buffer.from(M(b))),E={schemaVersion:Q,runId:o,createdAt:new Date().toISOString(),algorithm:"sha256",files:b,storage:{fileCount:b.length,logicalBytes:b.reduce((d,R)=>d+R.bytes,0),objectBytesWritten:y.objectBytesWritten,deduplicatedBytes:y.deduplicatedBytes},redaction:y.redaction,digest:V};return C(u.join(m,"manifest.json"),E),a.renameSync(m,f),{...v,archive:{...j,cleanup:l(c),manifestDigest:E.digest,storage:E.storage}}}catch(S){try{a.rmSync(m,{recursive:!0,force:!0})}catch{}try{Pe(e)}catch{}throw S}}export function loadVerifiedRunBundleArtifactIfExists(e,n){const t=I(n),r=P(e,t);if(!a.existsSync(r))return null;const s=verifyRunBundle(e,t);if(!s.ok)throw new Error(`Immutable run bundle ${t} already exists but failed integrity verification: ${s.errors.join("; ")}`);return loadRunBundleArtifact(e,t)}export function loadRunBundleArtifact(e,n){return ne(e,n).artifact}function ne(e,n){const t=I(n),r=ce(e,t),s=loadRunBundleManifest(e,t);return{manifest:s,artifact:{...r,archive:{...r.archive,manifestDigest:s.digest,storage:s.storage}}}}export function loadRunBundleManifest(e,n){const t=I(n),r=P(e,t),s=u.join(r,"manifest.json");if(!a.existsSync(s))throw new Error(`No immutable Testkit run manifest found for ${t}`);return Y(x(s),s,t)}export function listRunBundles(e,n={}){return q(e,n).map(({artifact:t,manifest:r,...s})=>s)}function q(e,n={}){const t=N(e,!1);if(!a.existsSync(t))return[];const r=a.readdirSync(t,{withFileTypes:!0});return J("artifacts.runDirectoriesRead",1),J("artifacts.runEntriesVisited",r.length),r.filter(o=>o.isDirectory()&&!o.name.startsWith(".")).map(o=>{try{const{artifact:i,manifest:c}=ne(e,o.name);return n.file&&!Se(G(i),n.file)?null:{artifact:i,manifest:c,runId:o.name,status:i.run.status,startedAt:i.run.startedAt,finishedAt:i.run.finishedAt??null,manifestDigest:i.archive.manifestDigest??null,canonicalRunPath:i.archive.canonicalRunPath}}catch{return null}}).filter(o=>o!==null).sort((o,i)=>(i.finishedAt??i.startedAt??"").localeCompare(o.finishedAt??o.startedAt??""))}export function verifyRunBundle(e,n){const t=I(n);try{return F(P(e,t),t)}catch(r){return{ok:!1,runId:t,errors:[B(r)],checkedFiles:0}}}export function publishRunBundle(e,n,t,r={}){const s=I(n),o=r.writePublicationReceipt??$e;if(!t)return o(e,s,{status:"not_configured",required:!1,target:null,bytesUploaded:0});const i=u.resolve(e,t.directory);try{_(e,i)}catch(m){return o(e,s,{status:"failed",required:t.required,target:i,error:B(m),bytesUploaded:0})}const c=Re(u.basename(e)),f=u.join(i,c),l=u.join(f,s),p=u.join(f,`.${s}.${String(process.pid)}.${String(Date.now())}.tmp`);try{const m=P(e,s);if(a.mkdirSync(f,{recursive:!0}),_(e,f),a.existsSync(l)){const h=a.lstatSync(l);if(h.isSymbolicLink()||!h.isDirectory())throw new Error("Publication target must be a regular bundle directory");_(e,l);const v=F(m,s);if(!v.ok)throw new Error(`Source run bundle failed integrity verification: ${v.errors.join("; ")}`);const g=F(l,s);if(!g.ok)throw new Error(`Publication target failed integrity verification: ${g.errors.join("; ")}`);if(v.manifestDigest!==g.manifestDigest)throw new Error("Publication target already exists with a different manifest digest");return o(e,s,{status:"complete",required:t.required,target:l,manifestDigest:v.manifestDigest,reused:!0,bundleBytes:ee(m),bytesUploaded:0})}const S=ee(m);a.cpSync(m,p,{recursive:!0,preserveTimestamps:!0});const y=F(p,s);if(!y.ok)throw new Error(y.errors.join("; "));return a.renameSync(p,l),o(e,s,{status:"complete",required:t.required,target:l,manifestDigest:y.manifestDigest,reused:!1,bundleBytes:S,bytesUploaded:S})}catch(m){return a.rmSync(p,{recursive:!0,force:!0}),o(e,s,{status:"failed",required:t.required,target:l,error:B(m),bytesUploaded:0})}}export function applyRunBundleRetention(e,n,t={},r={}){const s=I(n),o=r.removeObject??ie,i=r.removeRunBundle??Ce,c=t.maxRuns??null,f=t.maxAgeDays??null,l=new Set(t.preserveSuites||[]),p=q(e),m=new Set([s]);for(const d of p)xe(G(d.artifact),l)&&m.add(d.runId);const S=new Set(c?p.slice(0,c).map(d=>d.runId):p.map(d=>d.runId)),y=f==null?null:Date.now()-f*24*60*60*1e3,h=[];for(const d of p){if(m.has(d.runId))continue;const R=y!=null&&Date.parse(d.finishedAt||d.startedAt||"")<y,w=!S.has(d.runId);if(!R&&!w)continue;const k=[];R&&k.push("max_age"),w&&k.push("max_runs"),h.push({path:u.join(T(e),ye,d.runId),reasons:k,runId:d.runId})}const v=se(e),g=[],j=[];for(const d of h){let R=null;try{i(d.path)}catch(k){R=L(k)}const w=!a.existsSync(d.path);!w&&R===null&&(R="Run bundle still exists after removal completed"),w&&g.push({reasons:d.reasons,runId:d.runId}),R!==null&&j.push({...d,error:R,removed:w})}const b=new Set(g.map(d=>d.runId)),V=re(e,v,o,p.filter(d=>!b.has(d.runId))),E=new Date().toISOString();return Fe({currentRunId:s,decidedAt:E,garbageCollection:V,policy:{maxRuns:c,maxAgeDays:f,preserveSuites:[...l].sort()},protectedRunIds:[...m].sort(),removed:g,removalErrors:j})}function Ie({resultsDir:e,tempDir:n,redaction:t}){let r=0,s=0,o=0,i=0,c=0;const f=u.join(e,X,"sha256");a.mkdirSync(f,{recursive:!0});for(const l of U){const p=u.join(e,l);if(a.existsSync(p))for(const m of te(p)){const S=u.relative(p,m),y=a.readFileSync(m),h=Ve(y,m,t.targets);h.scanned&&(o+=1),h.replacements>0&&(i+=1,c+=h.replacements);const v=O(h.buffer),g=u.join(f,v);a.existsSync(g)?s+=h.buffer.length:(je(g,h.buffer),a.chmodSync(g,292),r+=h.buffer.length);const j=u.join(n,"files",l,S);a.mkdirSync(u.dirname(j),{recursive:!0});try{a.linkSync(g,j)}catch{a.copyFileSync(g,j)}}}return{objectBytesWritten:r,deduplicatedBytes:s,redaction:{policyVersion:1,status:t.status,textualFilesScanned:o,filesRedacted:i,replacements:c,sensitiveEnvironmentKeys:t.keys,valuesStored:!1}}}function Be(e,n,t){const r=new Map(U.map(i=>[`.testkit/results/${i}/`,`${$(n,`files/${i}`)}/`])),s=W(e,r),o=me(Ee(s),t);return{artifact:o.value,replacements:o.replacements}}function Ee(e){if(!A(e))return e;const n={...e};if(A(n.product)){const t={...n.product};delete t.directory,n.product=t}if(A(n.git)){const t={...n.git};delete t.remoteUrl,delete t.repoRoot,delete t.worktreePath,n.git=t}return delete n.host,n}function W(e,n){if(Array.isArray(e))return e.map(r=>W(r,n));if(A(e))return Object.fromEntries(Object.entries(e).map(([r,s])=>[r,W(s,n)]));if(typeof e!="string")return e;let t=e;for(const[r,s]of n)t.startsWith(r)&&(t=`${s}${t.slice(r.length)}`);return t}function ke(e,n,t,r){const s=D(n.run.fileNames),o=[...new Set([...we,...s])].map(i=>De(e,i)).filter(i=>i!==null);return{schemaVersion:pe,runId:t,ci:be(r.env??process.env),source:{git:n.git??null,files:o},runtime:{controller:{testkitVersion:H(n.run.testkitVersion),node:process.versions.node,platform:process.platform,architecture:process.arch},runtimeStats:n.schemaVersion===19?ge(n.run.runtimeStats):[...n.environment?.capacity?.runtimeStats??[]]},scenario:{types:D(n.run.types),suiteSelectors:D(n.run.suiteSelectors),fileNames:s,serviceFilter:H(n.schemaVersion===19?n.run.serviceFilter:n.run.groupFilter),planningDigest:O(Buffer.from(M(n.planning??null))),declaredEnvironmentKeys:[...new Set(r.declaredEnvironmentKeys??[])].sort()},redaction:r.redaction}}function Ae(e){return te(e).map(n=>({path:K(u.relative(e,n)),bytes:a.statSync(n).size,sha256:z(n)})).sort((n,t)=>n.path.localeCompare(t.path))}function F(e,n){const t=u.join(e,"manifest.json"),r=Y(x(t),t,n);ae(x(u.join(e,"run.json")),u.join(e,"run.json"),n);const s=[];for(const i of r.files){let c;try{c=Z(e,i.path)}catch(l){s.push(B(l));continue}if(!a.existsSync(c)){s.push(`missing ${i.path}`);continue}const f=a.lstatSync(c);if(f.isSymbolicLink()){s.push(`symbolic link not allowed ${i.path}`);continue}if(!f.isFile()){s.push(`not a regular file ${i.path}`);continue}f.size!==i.bytes&&s.push(`size mismatch ${i.path}`),z(c)!==i.sha256&&s.push(`checksum mismatch ${i.path}`)}O(Buffer.from(M(r.files)))!==r.digest&&s.push("manifest digest mismatch"),r.storage.fileCount!==r.files.length&&s.push("manifest file count mismatch");for(const i of["run.json","provenance.json"])r.files.some(c=>c.path===i)||s.push(`manifest must include ${i}`);if(s.length===0){const i=Z(e,"provenance.json");oe(x(i),i,n)}return{runId:n,checkedFiles:r.files.length,storage:r.storage,ok:s.length===0,errors:s,manifestDigest:r.digest}}function $e(e,n,t){const r={schemaVersion:1,runId:n,recordedAt:new Date().toISOString(),...t};return C(u.join(T(e),"publications",`${n}.json`),r),r}function xe(e,n){return n.size===0?!1:e.groups.some(t=>t.suites.some(r=>{const s=r.testType??"";return[r.name,`${s}:${r.name}`,`${t.name}/${s}:${r.name}`].some(i=>n.has(i))}))}function Pe(e){return re(e,se(e),ie,q(e))}function re(e,n,t,r){const s=N(e,!1),o=new Map(r.map(l=>[l.runId,l.manifest])),i=new Set,c=[],f=a.existsSync(s)?a.readdirSync(s,{withFileTypes:!0}):[];for(const l of f)if(!(!l.isDirectory()||l.name.startsWith(".")))try{for(const p of(o.get(l.name)??loadRunBundleManifest(e,l.name)).files)p.path.startsWith("files/")&&i.add(p.sha256)}catch(p){c.push({error:`No stored object was removed: ${B(p)}`,path:u.join(s,l.name)})}return c.length>0?{failures:c,reclaimedBytes:0,removedObjects:0,status:"not_started"}:Oe(n,i,t)}function se(e){const n=u.join(T(e),X,"sha256");return a.existsSync(n)?a.readdirSync(n,{withFileTypes:!0}).filter(t=>t.isFile()).map(t=>{const r=u.join(n,t.name);return{bytes:a.statSync(r).size,digest:t.name,path:r}}):[]}function Oe(e,n,t){const r=[];let s=0,o=0;for(const i of e){if(n.has(i.digest))continue;let c=null;try{t(i.path)}catch(l){c=L(l)}!a.existsSync(i.path)?(s+=1,o+=i.bytes):c===null&&(c="Object still exists after removal completed"),c!==null&&r.push({error:c,path:i.path})}return{failures:r,reclaimedBytes:o,removedObjects:s,status:r.length===0?"complete":"failed"}}function Ce(e){a.rmSync(e,{recursive:!0,force:!0})}function ie(e){a.rmSync(e,{force:!0})}function Fe({currentRunId:e,decidedAt:n,garbageCollection:t,policy:r,protectedRunIds:s,removed:o,removalErrors:i}){const c=[...i.map(f=>`remove ${f.runId}: ${f.error}`),...t.failures.map(f=>`garbage collect ${f.path}: ${f.error}`)];return{currentRunId:e,decidedAt:n,garbageCollection:t,policy:r,protectedRunIds:s,removed:o,removalErrors:i,schemaVersion:he,status:c.length===0?"complete":"failed",...c.length===0?{}:{error:c.join("; ")}}}function Ve(e,n,t){if(!ze(e,n)){for(const s of t)if(e.includes(Buffer.from(s)))throw new Error(`Refusing to archive binary file containing sensitive environment value: ${n}`);return{buffer:e,scanned:!1,replacements:0}}const r=fe(e.toString("utf8"),t);return r.replacements===0?{buffer:e,scanned:!0,replacements:0}:{buffer:Buffer.from(r.text),scanned:!0,replacements:r.replacements}}function ze(e,n){if(e.includes(0))return!1;const t=u.extname(n).toLowerCase();return![".zip",".gz",".png",".jpg",".jpeg",".webm",".pdf"].includes(t)}function De(e,n){const t=u.resolve(e,n);return!t.startsWith(`${u.resolve(e)}${u.sep}`)||!a.existsSync(t)||!a.statSync(t).isFile()?null:{path:K(u.relative(e,t)),bytes:a.statSync(t).size,sha256:z(t)}}function _e(e){const n=[];for(const t of[...U.map(r=>u.join(e,r)),u.join(e,"live.json")])try{a.rmSync(t,{recursive:!0,force:!0})}catch(r){n.push(`${t}: ${L(r)}`)}return n.length===0?{status:"complete"}:{error:n.join("; "),status:"failed"}}function L(e){try{return B(e)}catch{return"Unknown post-seal archive operation failure"}}
@@ -0,0 +1 @@
1
+ import{formatError as v}from"../kernel/error-serialization.js";import{jsonRedactionTargets as E,orderRedactionTargets as B,sensitiveKeyMatcher as I}from"../kernel/redaction-targets.js";import{redactUrlSecrets as C}from"../process/url-redaction.js";import{redactedRunValue as K}from"./redaction.js";export function publishEnvironmentRecord(a){return{...a,acquisitions:a.acquisitions.map(o=>({...o,settledAt:O(o.settledAt),setups:o.setups.map(p=>({...p,settledAt:O(p.settledAt),startedAt:new Date(p.startedAt).toISOString()})),startedAt:new Date(o.startedAt).toISOString()})),dbBackend:a.groups.some(o=>o.dbBackend==="local")?"local":null}}function O(a){return a===null?null:new Date(a).toISOString()}export function createRunEnvironmentRecord(a={}){const o=[],p=[],h=[],R=new Set,b=I(a.redactKeys);let y=[],m={instanceCount:0,resourceBudgets:[],runtimeStats:[]},k=null;const g=a.now??Date.now,f=()=>{a.onPublishedChange?.()},w=(e,t)=>({releaseFailed(r){e.releaseErrors.push(v(r)),e.failingReleases.add(t),e.releaseReported=!0},released(){e.failingReleases.delete(t),e.releaseReported=!0}});return{redactKeys:a.redactKeys??[],service({runtimeLabel:e,serviceName:t}){let r=null;return{recordAttempt({baseUrl:u,outcome:s,port:n,readyUrl:l}){const c={baseUrl:u===null?null:C(u),readyUrl:l===null?null:C(l)};r===null&&(r={serviceName:t,runtimeLabel:e,...c,port:n,attempts:[]},o.push(r)),Object.assign(r,c,{port:n}),r.attempts.push({port:n,outcome:s}),f()},amendLastOutcome(u){const s=r?.attempts.at(-1);s&&(s.outcome=u,f())}}},acquisition({graphKey:e,leaseId:t,source:r,tasks:u}){const s={source:r,graphKey:e,leaseId:t,runtimeId:null,services:[],status:"pending",startedAt:g(),settledAt:null,error:null,releaseErrors:[],failingReleases:new Set,releaseReported:!1,setups:[],tasks:u.map(l=>({...l})),values:null};p.push(s);const n=({runtimeId:l,services:c})=>{s.runtimeId=l,s.services=c.map(i=>({...i}))};return{...w(s,"source"),assigned:n,acquired(l){n(l),s.status="acquired",s.settledAt=g()},cancelled(l){s.status="cancelled",s.error=v(l),s.settledAt??=g()},failed(l){s.status="failed",s.error=v(l),s.settledAt??=g()},rendered(l){s.values=l,f()},setup({module:l,task:c}){const i={error:null,module:l,releaseErrors:[],releaseReported:!1,settledAt:null,startedAt:g(),status:"pending",task:{...c}};s.setups.push(i);const S=(d,A)=>{i.status=d,i.error=A===null?null:v(A),i.settledAt??=g()};return{prepared(d){S("prepared",null);for(const A of E("setupData",d,b))R.add(A);s.values!==null&&(s.values={...s.values,setupData:d}),f()},failed(d){S("failed",d)},cancelled(d){S("cancelled",d)},releaseFailed(d){i.releaseErrors.push(v(d)),i.releaseReported=!0},released(){i.releaseReported=!0}}}}},releaseFor(e){const t=p.find(r=>r.leaseId===e);return t===void 0?null:w(t,"lease")},recordCapacity({instanceCount:e,resourceBudgets:t}){m={...m,instanceCount:e,resourceBudgets:[...t]},f()},recordRuntimeStats(e){m={...m,runtimeStats:[...e]},f()},recordGroups(e){y=e.map(t=>({...t}))},recordMissingValues(e,t){for(const{kind:r,valueName:u}of t)h.push({kind:r,task:{...e},valueName:u})},recordCleanup(e){k=e==null?{status:"released"}:{status:"failed",errors:[v(e)],recovered:!1}},addRedactionTarget(e){e.length>0&&R.add(e)},redactionTargets(){return[...R]},snapshot(){const e={acquisitions:p.map(({failingReleases:t,releaseErrors:r,releaseReported:u,...s})=>({...s,services:s.services.map(n=>({...n})),setups:s.setups.map(({releaseErrors:n,releaseReported:l,...c})=>({...c,task:{...c.task},release:n.length>0?{status:"failed",errors:[...n],recovered:!1}:l?{status:"released"}:null})),tasks:s.tasks.map(n=>({...n})),values:s.values,release:r.length>0?{status:"failed",errors:[...r],recovered:t.size===0}:u?{status:"released"}:null})),capacity:{instanceCount:m.instanceCount,resourceBudgets:[...m.resourceBudgets],runtimeStats:[...m.runtimeStats]},cleanup:L(k),groups:y.map(t=>({...t})),logs:{services:a.logRegistry?.listServiceLogs()??[],setup:a.logRegistry?.listSetupLogs()??[]},missingValues:h.map(t=>({...t,task:{...t.task}})),services:o.map(t=>({...t,attempts:t.attempts.map(r=>({...r}))})).sort((t,r)=>t.runtimeLabel.localeCompare(r.runtimeLabel)||t.serviceName.localeCompare(r.serviceName)),setupOperations:a.setupRegistry?.listOperations()??[]};return K(e,B(R))}}}function L(a){return a===null||a.status==="released"?a:{status:"failed",errors:[...a.errors],recovered:a.recovered}}
@@ -1 +1 @@
1
- export{normalizeArtifactArchiveConfig}from"./artifact-config.js";export{finalizeLiveRunArtifact,loadTimings,persistTaskArtifacts,persistTaskFileArtifacts,persistTaskOutputArtifacts,resetResultArtifacts,saveTimings,writeLiveRunArtifact,writeRunArtifact}from"./artifacts.js";export{applyRunBundleRetention,listRunBundles,loadRunBundleArtifact,loadRunBundleManifest,loadVerifiedRunBundleArtifactIfExists,publishRunBundle,sealRunBundle,verifyRunBundle}from"./bundles.js";export{collectArtifactEntries,loadCurrentRunArtifact,loadLatestRunArtifact,loadRunArtifact}from"./reading.js";export{DEFAULT_REPORTED_ARCHIVE_CONFIG}from"./reporting-types.js";export{copyRegularFileSecurely,MAX_PERSISTED_FILE_ARTIFACT_BYTES}from"./secure-file-copy.js";export{collectTestkitStorageInventory}from"./storage-inventory.js";export{}from"./timing.js";
1
+ export{normalizeArtifactArchiveConfig}from"./artifact-config.js";export{finalizeLiveRunArtifact,loadTimings,persistTaskArtifacts,persistTaskFileArtifacts,persistTaskOutputArtifacts,resetResultArtifacts,saveTimings,writeLiveRunArtifact,writeRunArtifact}from"./artifacts.js";export{applyRunBundleRetention,listRunBundles,loadRunBundleArtifact,loadRunBundleManifest,loadVerifiedRunBundleArtifactIfExists,publishRunBundle,sealRunBundle,verifyRunBundle}from"./bundles.js";export{collectArtifactEntries,loadCurrentRunArtifact,loadLatestRunArtifact,loadRun,loadRunArtifact}from"./reading.js";export{DEFAULT_REPORTED_ARCHIVE_CONFIG}from"./reporting-types.js";export{runModel}from"./run-model.js";export{copyRegularFileSecurely,MAX_PERSISTED_FILE_ARTIFACT_BYTES}from"./secure-file-copy.js";export{collectTestkitStorageInventory}from"./storage-inventory.js";export{}from"./timing.js";
@@ -1,2 +1,2 @@
1
- import p from"fs";import i from"path";const S="logs",N="setup";export function createRunLogRegistry(r){const m=new Map,s=new Map,n=new Set;function L(e){const t=i.join(r,e.path);p.mkdirSync(i.dirname(t),{recursive:!0});const a=p.createWriteStream(t,{fd:p.openSync(t,"a"),flags:"a"});return n.add(a),{...e,write(o){a.write(o)}}}return{ensureServiceLogRecord(e){const t=`${e.runtimeLabel||e.name}:${e.name}`,a=m.get(t);if(a)return a;const o=`${l(e.runtimeLabel||e.name)}__${l(e.name)}.log`,c=i.join(".testkit","results",S,o),u=L({serviceName:e.name,runtimeLabel:e.runtimeLabel||e.name,path:b(c)});return m.set(t,u),u},ensureSetupLogRecord(e,t){const a=`${e.runtimeLabel||e.name}:${e.name}:${t}`,o=s.get(a);if(o)return o;const c=`${l(e.runtimeLabel||e.name)}__${l(e.name)}__${l(t)}.log`,u=i.join(".testkit","results",N,c),v=L({serviceName:e.name,runtimeLabel:e.runtimeLabel||e.name,stage:t,path:b(u)});return s.set(a,v),v},append(e,t,a){!e||typeof a!="string"||e.write(`${new Date().toISOString()} [${t}] ${a}
2
- `)},listServiceLogs(){return[...m.values()].map(e=>({serviceName:e.serviceName,runtimeLabel:e.runtimeLabel,path:e.path})).sort((e,t)=>e.serviceName.localeCompare(t.serviceName)||e.runtimeLabel.localeCompare(t.runtimeLabel))},listSetupLogs(){return[...s.values()].map(e=>({serviceName:e.serviceName,runtimeLabel:e.runtimeLabel,stage:e.stage,path:e.path})).sort((e,t)=>e.serviceName.localeCompare(t.serviceName)||e.runtimeLabel.localeCompare(t.runtimeLabel)||e.stage.localeCompare(t.stage))},async closeAll(){await Promise.all([...n].map(e=>$(e)))}}}function l(r){return r.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"log"}function b(r){return r.split(i.sep).join("/")}function $(r){return!r||r.destroyed||r.closed?Promise.resolve():new Promise(m=>{let s=!1;const n=()=>{s||(s=!0,r.off("close",n),r.off("error",n),m())};r.once("close",n),r.once("error",n),r.end()})}
1
+ import p from"fs";import u from"path";import{posixPath as b}from"../process/files/paths.js";const S="logs",N="setup";export function createRunLogRegistry(r){const m=new Map,s=new Map,n=new Set;function L(e){const t=u.join(r,e.path);p.mkdirSync(u.dirname(t),{recursive:!0});const a=p.createWriteStream(t,{fd:p.openSync(t,"a"),flags:"a"});return n.add(a),{...e,write(o){a.write(o)}}}return{ensureServiceLogRecord(e){const t=`${e.runtimeLabel||e.name}:${e.name}`,a=m.get(t);if(a)return a;const o=`${i(e.runtimeLabel||e.name)}__${i(e.name)}.log`,c=u.join(".testkit","results",S,o),l=L({serviceName:e.name,runtimeLabel:e.runtimeLabel||e.name,path:b(c)});return m.set(t,l),l},ensureSetupLogRecord(e,t){const a=`${e.runtimeLabel||e.name}:${e.name}:${t}`,o=s.get(a);if(o)return o;const c=`${i(e.runtimeLabel||e.name)}__${i(e.name)}__${i(t)}.log`,l=u.join(".testkit","results",N,c),v=L({serviceName:e.name,runtimeLabel:e.runtimeLabel||e.name,stage:t,path:b(l)});return s.set(a,v),v},append(e,t,a){!e||typeof a!="string"||e.write(`${new Date().toISOString()} [${t}] ${a}
2
+ `)},listServiceLogs(){return[...m.values()].map(e=>({serviceName:e.serviceName,runtimeLabel:e.runtimeLabel,path:e.path})).sort((e,t)=>e.serviceName.localeCompare(t.serviceName)||e.runtimeLabel.localeCompare(t.runtimeLabel))},listSetupLogs(){return[...s.values()].map(e=>({serviceName:e.serviceName,runtimeLabel:e.runtimeLabel,stage:e.stage,path:e.path})).sort((e,t)=>e.serviceName.localeCompare(t.serviceName)||e.runtimeLabel.localeCompare(t.runtimeLabel)||e.stage.localeCompare(t.stage))},async closeAll(){await Promise.all([...n].map(e=>$(e)))}}}function i(r){return r.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"log"}function $(r){return!r||r.destroyed||r.closed?Promise.resolve():new Promise(m=>{let s=!1;const n=()=>{s||(s=!0,r.off("close",n),r.off("error",n),m())};r.once("close",n),r.once("error",n),r.end()})}
@@ -1 +1 @@
1
- import{performance as y}from"node:perf_hooks";import{attachErrorOperation as R}from"../kernel/error-serialization.js";import{formatOperationSummary as b}from"../domain/operation-display.js";const g=String;export function createOperationTimingRegistry({onChange:t=null}={}){const r=[],i=new Map;let f=1;function d(e=[]){if(!t)return;const a=[],u=new Set;for(const s of e)!s||u.has(s.id)||(u.add(s.id),a.push(p(s)));t(a,I())}function l({name:e,kind:a="operation",source:u="testkit",summary:s=null,scope:o=null,parentId:n=null,metadata:m=null}){const c={id:`operation-${g(f++)}`,source:u,name:k(e),kind:a,summary:s,scope:h(o),parentId:n,status:"running",startedAt:new Date().toISOString(),updatedAt:null,finishedAt:null,durationMs:null,error:null,message:null,logRefs:[],metadata:h(m),_startedMonotonicMs:y.now()};return r.push(c),i.set(c.id,c),d([c,...A(c)]),c}function w(e,{summary:a,message:u,metadata:s=null,logRefs:o=null}={}){const n=typeof e=="string"?i.get(e):e;return n?(n.updatedAt=new Date().toISOString(),a!==void 0&&(n.summary=a),u!==void 0&&(n.message=u),s!==null&&(n.metadata={...n.metadata,...h(s)}),o!==null&&(n.logRefs=M(o)),d([n,...A(n)]),p(n)):null}function O(e,{status:a="passed",summary:u,error:s=null,metadata:o=null}={}){const n=typeof e=="string"?i.get(e):e;return n?(n.finishedAt=new Date().toISOString(),n.updatedAt=n.finishedAt,n.durationMs=Math.max(0,Math.round(y.now()-n._startedMonotonicMs)),n.status=a,u!==void 0&&(n.summary=u),s!==null&&(n.error=g(s)),o!==null&&(n.metadata={...n.metadata,...h(o)}),d([n,...A(n)]),p(n)):null}function $(e={}){const a=x(e,f++),u=i.get(a.id);return u?(Object.assign(u,a),d([u,...A(u)]),p(u)):(r.push(a),i.set(a.id,a),d([a,...A(a)]),p(a))}function I(){return r.map(e=>p(e))}return{start:l,update:w,finish:O,record:$,listOperations:I,countOperations(){return r.length}};function A(e){if(!e.parentId)return[];const a=[],u=new Date().toISOString();let s=i.get(e.parentId);const o=new Set([e.id]);for(;s&&s.status==="running"&&!o.has(s.id);){o.add(s.id),s.updatedAt=u;const n=e.status||"unknown",m=n==="running"?"activeChild":"lastChild";s.message=z(e),s.metadata={...s.metadata,[`${m}OperationId`]:e.id,[`${m}OperationName`]:e.name,[`${m}OperationKind`]:e.kind,[`${m}OperationStatus`]:n,[`${m}OperationSummary`]:e.summary||""},a.push(s),s=s.parentId?i.get(s.parentId):void 0}return a}}export async function timeOperation(t,r,i){if(!t)return i();const f=t.start(r);try{const d=await i(f);return t.finish(f,{status:"passed"}),d}catch(d){const l=t.finish(f,{status:"failed",error:N(d)});throw R(d,l),d}}function x(t,r){const i=S(t.startedAt)||new Date().toISOString(),f=t.status||"passed",d=f==="running"?null:S(t.finishedAt)||i,l=t.durationMs,w=Number(l),O=l!=null&&Number.isFinite(w)?Math.max(0,Math.round(w)):d?Math.max(0,Date.parse(d)-Date.parse(i)):null;return{id:t.id||`operation-${g(r)}`,source:t.source||"testkit",name:k(t.name),kind:t.kind||"operation",summary:t.summary||null,scope:h(t.scope),parentId:t.parentId||null,status:f,startedAt:i,updatedAt:S(t.updatedAt)||null,finishedAt:d,durationMs:O,error:t.error||null,message:t.message||null,logRefs:M(t.logRefs),metadata:h(t.metadata),_startedMonotonicMs:y.now()-(O||0)}}function p(t){return{id:t.id,source:t.source,name:t.name,kind:t.kind,summary:t.summary,scope:t.scope,parentId:t.parentId,status:t.status,startedAt:t.startedAt,updatedAt:t.updatedAt,finishedAt:t.finishedAt,durationMs:t.durationMs,error:t.error,message:t.message,logRefs:M(t.logRefs),metadata:t.metadata}}function k(t){const r=g(t||"").trim();if(!r)throw new Error("operation timing name is required");return r}function h(t){return D(t)?{...t}:{}}function M(t){return Array.isArray(t)?t.map(r=>D(r)?{...r}:r):[]}function z(t){const r=b(t),i=typeof r=="string"?r:"";return i?`${t.name} ${t.status||"unknown"} - ${i}`:`${t.name} ${t.status||"unknown"}`}function S(t){const r=Date.parse(t||"");return Number.isFinite(r)?new Date(r).toISOString():null}function D(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function N(t){return(typeof t!="object"||t===null)&&typeof t!="function"?g(t):Reflect.get(t,"message")||g(t)}
1
+ import{performance as M}from"node:perf_hooks";import{attachErrorOperation as R}from"../kernel/error-serialization.js";import{formatOperationSummary as x}from"../domain/operation-display.js";import{isUnknownRecord as k}from"../kernel/unknown-values.js";const g=String;export function createOperationTimingRegistry({onChange:t=null}={}){const r=[],i=new Map;let m=1;function d(e=[]){if(!t)return;const a=[],u=new Set;for(const s of e)!s||u.has(s.id)||(u.add(s.id),a.push(p(s)));t(a,I())}function f({name:e,kind:a="operation",source:u="testkit",summary:s=null,scope:o=null,parentId:n=null,metadata:l=null}){const c={id:`operation-${g(m++)}`,source:u,name:D(e),kind:a,summary:s,scope:h(o),parentId:n,status:"running",startedAt:new Date().toISOString(),updatedAt:null,finishedAt:null,durationMs:null,error:null,message:null,logRefs:[],metadata:h(l),_startedMonotonicMs:M.now()};return r.push(c),i.set(c.id,c),d([c,...w(c)]),c}function A(e,{summary:a,message:u,metadata:s=null,logRefs:o=null}={}){const n=typeof e=="string"?i.get(e):e;return n?(n.updatedAt=new Date().toISOString(),a!==void 0&&(n.summary=a),u!==void 0&&(n.message=u),s!==null&&(n.metadata={...n.metadata,...h(s)}),o!==null&&(n.logRefs=S(o)),d([n,...w(n)]),p(n)):null}function O(e,{status:a="passed",summary:u,error:s=null,metadata:o=null}={}){const n=typeof e=="string"?i.get(e):e;return n?(n.finishedAt=new Date().toISOString(),n.updatedAt=n.finishedAt,n.durationMs=Math.max(0,Math.round(M.now()-n._startedMonotonicMs)),n.status=a,u!==void 0&&(n.summary=u),s!==null&&(n.error=g(s)),o!==null&&(n.metadata={...n.metadata,...h(o)}),d([n,...w(n)]),p(n)):null}function $(e={}){const a=b(e,m++),u=i.get(a.id);return u?(Object.assign(u,a),d([u,...w(u)]),p(u)):(r.push(a),i.set(a.id,a),d([a,...w(a)]),p(a))}function I(){return r.map(e=>p(e))}return{start:f,update:A,finish:O,record:$,listOperations:I,countOperations(){return r.length}};function w(e){if(!e.parentId)return[];const a=[],u=new Date().toISOString();let s=i.get(e.parentId);const o=new Set([e.id]);for(;s&&s.status==="running"&&!o.has(s.id);){o.add(s.id),s.updatedAt=u;const n=e.status||"unknown",l=n==="running"?"activeChild":"lastChild";s.message=z(e),s.metadata={...s.metadata,[`${l}OperationId`]:e.id,[`${l}OperationName`]:e.name,[`${l}OperationKind`]:e.kind,[`${l}OperationStatus`]:n,[`${l}OperationSummary`]:e.summary||""},a.push(s),s=s.parentId?i.get(s.parentId):void 0}return a}}export async function timeOperation(t,r,i){if(!t)return i();const m=t.start(r);try{const d=await i(m);return t.finish(m,{status:"passed"}),d}catch(d){const f=t.finish(m,{status:"failed",error:N(d)});throw R(d,f),d}}function b(t,r){const i=y(t.startedAt)||new Date().toISOString(),m=t.status||"passed",d=m==="running"?null:y(t.finishedAt)||i,f=t.durationMs,A=Number(f),O=f!=null&&Number.isFinite(A)?Math.max(0,Math.round(A)):d?Math.max(0,Date.parse(d)-Date.parse(i)):null;return{id:t.id||`operation-${g(r)}`,source:t.source||"testkit",name:D(t.name),kind:t.kind||"operation",summary:t.summary||null,scope:h(t.scope),parentId:t.parentId||null,status:m,startedAt:i,updatedAt:y(t.updatedAt)||null,finishedAt:d,durationMs:O,error:t.error||null,message:t.message||null,logRefs:S(t.logRefs),metadata:h(t.metadata),_startedMonotonicMs:M.now()-(O||0)}}function p(t){return{id:t.id,source:t.source,name:t.name,kind:t.kind,summary:t.summary,scope:t.scope,parentId:t.parentId,status:t.status,startedAt:t.startedAt,updatedAt:t.updatedAt,finishedAt:t.finishedAt,durationMs:t.durationMs,error:t.error,message:t.message,logRefs:S(t.logRefs),metadata:t.metadata}}function D(t){const r=g(t||"").trim();if(!r)throw new Error("operation timing name is required");return r}function h(t){return k(t)?{...t}:{}}function S(t){return Array.isArray(t)?t.map(r=>k(r)?{...r}:r):[]}function z(t){const r=x(t),i=typeof r=="string"?r:"";return i?`${t.name} ${t.status||"unknown"} - ${i}`:`${t.name} ${t.status||"unknown"}`}function y(t){const r=Date.parse(t||"");return Number.isFinite(r)?new Date(r).toISOString():null}function N(t){return(typeof t!="object"||t===null)&&typeof t!="function"?g(t):Reflect.get(t,"message")||g(t)}
@@ -1 +1 @@
1
- import i from"path";export function requireObjectRecord(r,n){if(!isObjectRecord(r))throw new Error(`${n} must be an object`);return r}export function requireUnknownArray(r,n){if(!Array.isArray(r))throw new Error(`${n} must be an array`);return r}export function requireString(r,n){if(typeof r!="string"||r.length===0)throw new Error(`${n} must be a non-empty string`);return r}export function requireResultsReferencePath(r,n){const e=requireString(r,n),t=e.split("/");if(i.isAbsolute(e)||i.win32.isAbsolute(e)||e.includes("\\")||e.includes("\0")||i.posix.normalize(e)!==e||t.some(o=>o==="."||o==="..")||!e.startsWith(".testkit/results/"))throw new Error(`${n} must be a normalized relative path within .testkit/results`);return e}export function optionalStringValue(r,n){if(r!==void 0){if(typeof r!="string")throw new Error(`${n} must be a string`);return r}}export function optionalNullableStringValue(r,n){if(r!==void 0){if(r===null)return null;if(typeof r!="string")throw new Error(`${n} must be a string or null`);return r}}export function requireNumber(r,n){if(typeof r!="number"||!Number.isFinite(r))throw new Error(`${n} must be a finite number`);return r}export function optionalNumberOrStringValue(r,n){if(r!==void 0)return typeof r=="string"?r:requireNumber(r,n)}export function optionalNullableNumberValue(r,n){if(r!==void 0)return r===null?null:requireNumber(r,n)}export function isObjectRecord(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}export function requireExactString(r,n,e){const t=requireString(r,n);if(t!==e)throw new Error(`${n} must be "${e}"`);return t}export function requireSha256(r,n){const e=requireString(r,n);if(!/^[a-f0-9]{64}$/u.test(e))throw new Error(`${n} must be a lowercase SHA-256 digest`);return e}export function requireManifestRelativePath(r,n){const e=requireString(r,n),t=e.split("/");if(i.isAbsolute(e)||i.win32.isAbsolute(e)||e.includes("\\")||e.includes("\0")||i.posix.normalize(e)!==e||t.some(o=>o==="."||o===".."))throw new Error(`${n} must be a normalized relative bundle path`);return e}export function requireNonNegativeNumber(r,n){if(typeof r!="number"||!Number.isFinite(r)||r<0)throw new Error(`${n} must be a non-negative number`);return r}export function requireNonNegativeInteger(r,n){const e=requireNonNegativeNumber(r,n);if(!Number.isInteger(e))throw new Error(`${n} must be a non-negative integer`);return e}export function optionalNonNegativeNumber(r,n){if(r!==void 0)return requireNonNegativeNumber(r,n)}export function optionalNullableNumber(r,n){return r==null?null:requireNonNegativeNumber(r,n)}export function requireBoolean(r,n){if(typeof r!="boolean")throw new Error(`${n} must be a boolean`);return r}export function optionalBoolean(r,n){if(r!==void 0)return requireBoolean(r,n)}export function requireStringArray(r,n){if(!Array.isArray(r))throw new Error(`${n} must be an array of strings`);const e=[];for(const t of r){if(typeof t!="string")throw new Error(`${n} must be an array of strings`);e.push(t)}return e}
1
+ import i from"path";import{isUnknownRecord as u}from"../kernel/unknown-values.js";export function requireObjectRecord(r,n){if(!u(r))throw new Error(`${n} must be an object`);return r}export function requireUnknownArray(r,n){if(!Array.isArray(r))throw new Error(`${n} must be an array`);return r}export function requireString(r,n){if(typeof r!="string"||r.length===0)throw new Error(`${n} must be a non-empty string`);return r}export function requireResultsReferencePath(r,n){const e=requireString(r,n),t=e.split("/");if(i.isAbsolute(e)||i.win32.isAbsolute(e)||e.includes("\\")||e.includes("\0")||i.posix.normalize(e)!==e||t.some(o=>o==="."||o==="..")||!e.startsWith(".testkit/results/"))throw new Error(`${n} must be a normalized relative path within .testkit/results`);return e}export function optionalStringValue(r,n){if(r!==void 0){if(typeof r!="string")throw new Error(`${n} must be a string`);return r}}export function optionalNullableStringValue(r,n){if(r!==void 0){if(r===null)return null;if(typeof r!="string")throw new Error(`${n} must be a string or null`);return r}}export function requireNumber(r,n){if(typeof r!="number"||!Number.isFinite(r))throw new Error(`${n} must be a finite number`);return r}export function optionalNumberOrStringValue(r,n){if(r!==void 0)return typeof r=="string"?r:requireNumber(r,n)}export function optionalNullableNumberValue(r,n){if(r!==void 0)return r===null?null:requireNumber(r,n)}export function requireExactString(r,n,e){const t=requireString(r,n);if(t!==e)throw new Error(`${n} must be "${e}"`);return t}export function requireSha256(r,n){const e=requireString(r,n);if(!/^[a-f0-9]{64}$/u.test(e))throw new Error(`${n} must be a lowercase SHA-256 digest`);return e}export function requireManifestRelativePath(r,n){const e=requireString(r,n),t=e.split("/");if(i.isAbsolute(e)||i.win32.isAbsolute(e)||e.includes("\\")||e.includes("\0")||i.posix.normalize(e)!==e||t.some(o=>o==="."||o===".."))throw new Error(`${n} must be a normalized relative bundle path`);return e}export function requireNonNegativeNumber(r,n){if(typeof r!="number"||!Number.isFinite(r)||r<0)throw new Error(`${n} must be a non-negative number`);return r}export function requireNonNegativeInteger(r,n){const e=requireNonNegativeNumber(r,n);if(!Number.isInteger(e))throw new Error(`${n} must be a non-negative integer`);return e}export function optionalNonNegativeNumber(r,n){if(r!==void 0)return requireNonNegativeNumber(r,n)}export function optionalNullableNumber(r,n){return r==null?null:requireNonNegativeNumber(r,n)}export function requireBoolean(r,n){if(typeof r!="boolean")throw new Error(`${n} must be a boolean`);return r}export function optionalBoolean(r,n){if(r!==void 0)return requireBoolean(r,n)}export function requireStringArray(r,n){if(!Array.isArray(r))throw new Error(`${n} must be an array of strings`);const e=[];for(const t of r){if(typeof t!="string")throw new Error(`${n} must be an array of strings`);e.push(t)}return e}
@@ -1 +1 @@
1
- import{isEngineId as w,isPublicTestType as q,isRunnerProfileId as S}from"../domain/identifiers.js";import{isEngineProfileIdentity as T}from"../engines/definitions.js";import{requireObjectRecord as r,requireNumber as m,requireStringArray as B,optionalBoolean as y,optionalNonNegativeNumber as p,isObjectRecord as E,requireUnknownArray as h,requireString as c,requireResultsReferencePath as k,optionalStringValue as s,optionalNullableStringValue as a,optionalNumberOrStringValue as L,optionalNullableNumberValue as v}from"./read-fields.js";export function readRunDocument(n,t){const e=r(n,t);if(e.schemaVersion!==19)throw new Error(`${t}.schemaVersion must be 19`);const i=M(e.run,`${t}.run`),o=f(e.services,`${t}.services`,P)??[];e.archive!==void 0&&r(e.archive,`${t}.archive`),e.finalizationFailure!==void 0&&X(e.finalizationFailure,`${t}.finalizationFailure`),s(e.generatedAt,`${t}.generatedAt`);const d=K(e.summary,`${t}.summary`),u=e.logs===void 0?void 0:x(e.logs,`${t}.logs`),g=e.setup===void 0?void 0:V(e.setup,`${t}.setup`);return{...e,schemaVersion:19,...d===void 0?{}:{summary:d},run:i,services:o,...u===void 0?{}:{logs:u},...g===void 0?{}:{setup:g}}}function M(n,t){const e=r(n,t);return v(e.durationMs,`${t}.durationMs`),f(e.types,`${t}.types`,c),{...e,finishedAt:a(e.finishedAt,`${t}.finishedAt`)??null,id:a(e.id,`${t}.id`)??null,startedAt:c(e.startedAt,`${t}.startedAt`),status:c(e.status,`${t}.status`)}}function x(n,t){const e=r(n,t),i=f(e.services,`${t}.services`,H),o=f(e.setup,`${t}.setup`,F);return{...e,...i===void 0?{}:{services:i},...o===void 0?{}:{setup:o}}}function V(n,t){const e=r(n,t),i=f(e.operations,`${t}.operations`,J);return{...e,...i===void 0?{}:{operations:i}}}function P(n,t){const e=r(n,t),i=f(e.suites,`${t}.suites`,D)??[];return{...e,name:c(e.name,`${t}.name`),suites:i}}function D(n,t){const e=r(n,t);if(e.testType!=="scenario"&&!q(e.testType))throw new Error(`${t}.testType must be a public test type`);if(!w(e.engineId))throw new Error(`${t}.engineId must be a supported engine id`);if(!S(e.profileId))throw new Error(`${t}.profileId must be a supported runner profile id`);if(!(e.testType==="scenario"?e.engineId==="k6"&&e.profileId==="k6-http":T(e)))throw new Error(`${t}.profileId does not match ${e.engineId}/${e.testType}`);const o=f(e.files,`${t}.files`,O);return y(e.failed,`${t}.failed`),A(e.diagnostics,`${t}.diagnostics`),p(e.completedFileCount,`${t}.completedFileCount`),p(e.failedFileCount,`${t}.failedFileCount`),p(e.fileCount,`${t}.fileCount`),p(e.passedFileCount,`${t}.passedFileCount`),p(e.skippedFileCount,`${t}.skippedFileCount`),{...e,files:o,name:c(e.name,`${t}.name`),testType:e.testType,engineId:e.engineId,profileId:e.profileId}}function O(n,t){const e=r(n,t),i=f(e.artifacts,`${t}.artifacts`,j),o=f(e.failureDetails,`${t}.failureDetails`,z);return y(e.blockedByRuntime,`${t}.blockedByRuntime`),y(e.failed,`${t}.failed`),y(e.infraFailed,`${t}.infraFailed`),a(e.reason,`${t}.reason`),a(e.runtimeIsolation,`${t}.runtimeIsolation`),e.runtimeBatch!=null&&Q(e.runtimeBatch,`${t}.runtimeBatch`),f(e.runtimeResets,`${t}.runtimeResets`,W),{...e,error:a(e.error,`${t}.error`),artifacts:i,durationMs:v(e.durationMs,`${t}.durationMs`),failureDetails:o,path:c(e.path,`${t}.path`),status:c(e.status,`${t}.status`)}}function j(n,t){const e=r(n,t);return{...e,contentType:a(e.contentType,`${t}.contentType`),kind:a(e.kind,`${t}.kind`),summary:a(e.summary,`${t}.summary`),name:c(e.name,`${t}.name`),path:k(e.path,`${t}.path`)}}function z(n,t){const e=r(n,t),i=e.request===void 0?void 0:U(e.request,`${t}.request`),o=e.response===void 0?void 0:G(e.response,`${t}.response`),d=e.location===void 0?void 0:r(e.location,`${t}.location`);return d!==void 0&&(s(d.path,`${t}.location.path`),d.line!==void 0&&m(d.line,`${t}.location.line`),d.column!==void 0&&m(d.column,`${t}.location.column`)),{...e,key:s(e.key,`${t}.key`),kind:s(e.kind,`${t}.kind`),message:s(e.message,`${t}.message`),stack:s(e.stack,`${t}.stack`),location:d,request:i,response:o,title:c(e.title,`${t}.title`)}}function U(n,t){const e=r(n,t);return{...e,method:s(e.method,`${t}.method`),path:s(e.path,`${t}.path`),requestId:s(e.requestId,`${t}.requestId`)}}function G(n,t){const e=r(n,t);return{...e,bodyPreview:s(e.bodyPreview,`${t}.bodyPreview`),contentType:s(e.contentType,`${t}.contentType`),status:L(e.status,`${t}.status`)}}function H(n,t){const e=r(n,t);return{...e,path:k(e.path,`${t}.path`),runtimeLabel:c(e.runtimeLabel,`${t}.runtimeLabel`),serviceName:c(e.serviceName,`${t}.serviceName`)}}function J(n,t){const e=r(n,t),i=e.logRef==null?e.logRef:F(e.logRef,`${t}.logRef`);return{...e,durationMs:v(e.durationMs,`${t}.durationMs`),error:a(e.error,`${t}.error`),summary:a(e.summary,`${t}.summary`),logRef:i,serviceName:c(e.serviceName,`${t}.serviceName`),stage:c(e.stage,`${t}.stage`),startedAt:s(e.startedAt,`${t}.startedAt`),status:c(e.status,`${t}.status`)}}function F(n,t){const e=r(n,t);return s(e.runtimeLabel,`${t}.runtimeLabel`),s(e.serviceName,`${t}.serviceName`),s(e.stage,`${t}.stage`),{...e,path:k(e.path,`${t}.path`)}}function K(n,t){if(n===void 0)return;const e=r(n,t),i=e.files===void 0?{}:r(e.files,`${t}.files`),o=e.services===void 0?{}:r(e.services,`${t}.services`),d=e.suites===void 0?{}:r(e.suites,`${t}.suites`),u=(g,I,N)=>{const $=g[I];if($===void 0)return 0;if(typeof $!="number"||!Number.isFinite($)||$<0)throw new Error(`${t}.${N}.${I} must be a non-negative finite number`);return $};return A(e.diagnostics,`${t}.diagnostics`),{...e,files:{blockedByRuntime:u(i,"blockedByRuntime","files"),cancelled:u(i,"cancelled","files"),failed:u(i,"failed","files"),infraFailed:u(i,"infraFailed","files"),interrupted:u(i,"interrupted","files"),notRun:u(i,"notRun","files"),passed:u(i,"passed","files"),skipped:u(i,"skipped","files"),total:u(i,"total","files")},services:{blockedByRuntime:u(o,"blockedByRuntime","services"),failed:u(o,"failed","services"),infraFailed:u(o,"infraFailed","services"),passed:u(o,"passed","services"),skipped:u(o,"skipped","services"),total:u(o,"total","services")},suites:{completed:u(d,"completed","suites"),failed:u(d,"failed","suites"),passed:u(d,"passed","suites"),skipped:u(d,"skipped","suites"),total:u(d,"total","suites")}}}function A(n,t){if(n!==void 0)return h(n,t).map((e,i)=>{const o=`${t}[${String(i)}]`,d=r(e,o);return{...d,code:c(d.code,`${o}.code`),message:c(d.message,`${o}.message`),service:s(d.service,`${o}.service`),suite:s(d.suite,`${o}.suite`)}})}function Q(n,t){const e=r(n,t);return{...e,id:s(e.id,`${t}.id`),fileCount:p(e.fileCount,`${t}.fileCount`),index:p(e.index,`${t}.index`),files:e.files===void 0?void 0:B(e.files,`${t}.files`)}}function W(n,t){const e=r(n,t);return{...e,position:s(e.position,`${t}.position`),reason:s(e.reason,`${t}.reason`),runtimeIsolation:s(e.runtimeIsolation,`${t}.runtimeIsolation`),trigger:s(e.trigger,`${t}.trigger`)}}function X(n,t){const e=r(n,t),i=e.operation===void 0?void 0:r(e.operation,`${t}.operation`);return{...e,name:c(e.name,`${t}.name`),message:c(e.message,`${t}.message`),code:s(e.code,`${t}.code`),stack:s(e.stack,`${t}.stack`),phase:s(e.phase,`${t}.phase`),exitCode:e.exitCode===void 0?void 0:m(e.exitCode,`${t}.exitCode`),status:e.status===void 0?void 0:m(e.status,`${t}.status`),diagnostics:e.diagnostics===void 0?void 0:R(e.diagnostics,`${t}.diagnostics`),operation:i===void 0?void 0:{...i,id:s(i.id,`${t}.operation.id`),source:c(i.source,`${t}.operation.source`),name:c(i.name,`${t}.operation.name`),kind:c(i.kind,`${t}.operation.kind`),summary:s(i.summary,`${t}.operation.summary`),status:s(i.status,`${t}.operation.status`),error:s(i.error,`${t}.operation.error`),scope:R(i.scope,`${t}.operation.scope`)}}}function R(n,t){return Object.fromEntries(Object.entries(r(n,t)).map(([e,i])=>[e,C(i,`${t}.${e}`)]))}function C(n,t){return n===null||typeof n=="string"||typeof n=="boolean"?n:Array.isArray(n)?h(n,t).map((e,i)=>C(e,`${t}[${String(i)}]`)):E(n)?R(n,t):m(n,t)}function f(n,t,e){return n===void 0?void 0:h(n,t).map((i,o)=>e(i,`${t}[${String(o)}]`))}
1
+ import{isEngineId as O,isPublicTestType as U,isRunnerProfileId as x}from"../domain/identifiers.js";import{isEngineProfileIdentity as P}from"../engines/definitions.js";import{isUnknownRecord as z}from"../kernel/unknown-values.js";import{requireObjectRecord as u,requireNumber as g,requireStringArray as j,optionalBoolean as I,optionalNonNegativeNumber as y,requireUnknownArray as k,requireString as c,requireResultsReferencePath as R,optionalStringValue as o,optionalNullableStringValue as m,optionalNumberOrStringValue as _,optionalNullableNumberValue as F}from"./read-fields.js";export function readRunDocument(t,e){const n=u(t,e);if(n.schemaVersion===19)return H(n,e);if(n.schemaVersion===20)return G(n,e);throw new Error(`${e}.schemaVersion must be 19 or 20`)}function G(t,e){const n=w(t.run,`${e}.run`),i=a(t.groups,`${e}.groups`,(d,p)=>C(d,p,!0))??[];N(t,e);const s=t.summary===void 0?void 0:D(t.summary,`${e}.summary`,"group"),r=t.environment===void 0?void 0:J(t.environment,`${e}.environment`);return{...t,schemaVersion:20,...s===void 0?{}:{summary:{...s.record,files:s.files,groups:s.owners,suites:s.suites}},run:n,groups:i,...r===void 0?{}:{environment:r}}}function H(t,e){const n=w(t.run,`${e}.run`),i=a(t.services,`${e}.services`,C)??[];N(t,e);const s=t.summary===void 0?void 0:D(t.summary,`${e}.summary`,"service"),r=t.environment===void 0?void 0:K(t.environment,`${e}.environment`),d=t.logs===void 0?void 0:E(t.logs,`${e}.logs`),p=t.setup===void 0?void 0:Q(t.setup,`${e}.setup`);return{...t,schemaVersion:19,...s===void 0?{}:{summary:{...s.record,files:s.files,services:s.owners,suites:s.suites}},run:n,services:i,...r===void 0?{}:{environment:r},...d===void 0?{}:{logs:d},...p===void 0?{}:{setup:p}}}function w(t,e){const n=u(t,e);return F(n.durationMs,`${e}.durationMs`),a(n.types,`${e}.types`,c),{...n,finishedAt:m(n.finishedAt,`${e}.finishedAt`)??null,id:m(n.id,`${e}.id`)??null,startedAt:c(n.startedAt,`${e}.startedAt`),status:c(n.status,`${e}.status`)}}function N(t,e){t.archive!==void 0&&u(t.archive,`${e}.archive`),t.finalizationFailure!==void 0&&se(t.finalizationFailure,`${e}.finalizationFailure`),o(t.generatedAt,`${e}.generatedAt`)}function J(t,e){const n=u(t,e),i=n.capacity===void 0?void 0:u(n.capacity,`${e}.capacity`),s=i?.runtimeStats===void 0?void 0:k(i.runtimeStats,`${e}.capacity.runtimeStats`),r=n.logs===void 0?void 0:E(n.logs,`${e}.logs`),d=a(n.services,`${e}.services`,A),p=a(n.setupOperations,`${e}.setupOperations`,q);return{...n,...i===void 0?{}:{capacity:{...i,...s===void 0?{}:{runtimeStats:s}}},...r===void 0?{}:{logs:r},...d===void 0?{}:{services:d},...p===void 0?{}:{setupOperations:p}}}function K(t,e){const n=u(t,e),i=a(n.services,`${e}.services`,A);return{...n,...i===void 0?{}:{services:i}}}function A(t,e){const n=u(t,e);return{...n,attempts:a(n.attempts,`${e}.attempts`,(i,s)=>{const r=u(i,s);return{...r,outcome:c(r.outcome,`${s}.outcome`),port:g(r.port,`${s}.port`)}})??[],baseUrl:m(n.baseUrl,`${e}.baseUrl`)??null,port:g(n.port,`${e}.port`),readyUrl:m(n.readyUrl,`${e}.readyUrl`)??null,runtimeLabel:c(n.runtimeLabel,`${e}.runtimeLabel`),serviceName:c(n.serviceName,`${e}.serviceName`)}}function E(t,e){const n=u(t,e),i=a(n.services,`${e}.services`,ne),s=a(n.setup,`${e}.setup`,B);return{...n,...i===void 0?{}:{services:i},...s===void 0?{}:{setup:s}}}function Q(t,e){const n=u(t,e),i=a(n.operations,`${e}.operations`,q);return{...n,...i===void 0?{}:{operations:i}}}function C(t,e,n=!1){const i=u(t,e),s=a(i.suites,`${e}.suites`,(r,d)=>X(r,d,n))??[];return{...i,name:c(i.name,`${e}.name`),suites:s}}const W=Object.freeze([...["int","e2e","load","scenario"].map(t=>({engineId:"k6",profileId:"k6-http",testType:t})),{engineId:"k6",profileId:"k6-dal",testType:"dal"},{engineId:"node-vitest",profileId:"node-vitest-contract",testType:"contract"},{engineId:"node-vitest",profileId:"node-vitest-data",testType:"data"}]);function X(t,e,n){const i=u(t,e),s=W.find($=>$.testType===i.testType),r=s?.testType??(U(i.testType)?i.testType:void 0);if(r===void 0&&!(n&&i.testType===void 0))throw new Error(`${e}.testType must be a public test type`);const d=s!==void 0&&i.engineId===s.engineId?s.engineId:O(i.engineId)?i.engineId:void 0;if(d===void 0)throw new Error(`${e}.engineId must be a supported engine id`);const p=s!==void 0&&i.profileId===s.profileId?s.profileId:x(i.profileId)?i.profileId:void 0;if(p===void 0)throw new Error(`${e}.profileId must be a supported runner profile id`);if(!(s===void 0?P(i):d===s.engineId&&p===s.profileId))throw new Error(`${e}.profileId does not match ${d}/${r??"untyped"}`);const f=a(i.files,`${e}.files`,Y);return I(i.failed,`${e}.failed`),L(i.diagnostics,`${e}.diagnostics`),y(i.completedFileCount,`${e}.completedFileCount`),y(i.failedFileCount,`${e}.failedFileCount`),y(i.fileCount,`${e}.fileCount`),y(i.passedFileCount,`${e}.passedFileCount`),y(i.skippedFileCount,`${e}.skippedFileCount`),{...i,files:f,name:c(i.name,`${e}.name`),...r===void 0?{}:{testType:r},engineId:d,profileId:p}}function Y(t,e){const n=u(t,e),i=a(n.artifacts,`${e}.artifacts`,Z),s=a(n.failureDetails,`${e}.failureDetails`,l);return I(n.blockedByRuntime,`${e}.blockedByRuntime`),I(n.failed,`${e}.failed`),I(n.infraFailed,`${e}.infraFailed`),m(n.reason,`${e}.reason`),m(n.runtimeIsolation,`${e}.runtimeIsolation`),n.runtimeBatch!=null&&te(n.runtimeBatch,`${e}.runtimeBatch`),a(n.runtimeResets,`${e}.runtimeResets`,ie),{...n,error:m(n.error,`${e}.error`),artifacts:i,durationMs:F(n.durationMs,`${e}.durationMs`),failureDetails:s,path:c(n.path,`${e}.path`),status:c(n.status,`${e}.status`)}}function Z(t,e){const n=u(t,e);return{...n,contentType:m(n.contentType,`${e}.contentType`),kind:m(n.kind,`${e}.kind`),summary:m(n.summary,`${e}.summary`),name:c(n.name,`${e}.name`),path:R(n.path,`${e}.path`)}}function l(t,e){const n=u(t,e),i=n.request===void 0?void 0:b(n.request,`${e}.request`),s=n.response===void 0?void 0:ee(n.response,`${e}.response`),r=n.location===void 0?void 0:u(n.location,`${e}.location`);return r!==void 0&&(o(r.path,`${e}.location.path`),r.line!==void 0&&g(r.line,`${e}.location.line`),r.column!==void 0&&g(r.column,`${e}.location.column`)),{...n,key:o(n.key,`${e}.key`),kind:o(n.kind,`${e}.kind`),message:o(n.message,`${e}.message`),stack:o(n.stack,`${e}.stack`),location:r,request:i,response:s,title:c(n.title,`${e}.title`)}}function b(t,e){const n=u(t,e);return{...n,method:o(n.method,`${e}.method`),path:o(n.path,`${e}.path`),requestId:o(n.requestId,`${e}.requestId`)}}function ee(t,e){const n=u(t,e);return{...n,bodyPreview:o(n.bodyPreview,`${e}.bodyPreview`),contentType:o(n.contentType,`${e}.contentType`),status:_(n.status,`${e}.status`)}}function ne(t,e){const n=u(t,e);return{...n,path:R(n.path,`${e}.path`),runtimeLabel:c(n.runtimeLabel,`${e}.runtimeLabel`),serviceName:c(n.serviceName,`${e}.serviceName`)}}function q(t,e){const n=u(t,e),i=n.logRef==null?n.logRef:B(n.logRef,`${e}.logRef`);return{...n,durationMs:F(n.durationMs,`${e}.durationMs`),error:m(n.error,`${e}.error`),summary:m(n.summary,`${e}.summary`),logRef:i,serviceName:c(n.serviceName,`${e}.serviceName`),stage:c(n.stage,`${e}.stage`),startedAt:o(n.startedAt,`${e}.startedAt`),status:c(n.status,`${e}.status`)}}function B(t,e){const n=u(t,e);return o(n.runtimeLabel,`${e}.runtimeLabel`),o(n.serviceName,`${e}.serviceName`),o(n.stage,`${e}.stage`),{...n,path:R(n.path,`${e}.path`)}}function D(t,e,n){const i=u(t,e),s=n==="group"?"groups":"services",r=$=>i[$]===void 0?{}:u(i[$],`${e}.${$}`),[d,p,h]=[r("files"),r(s),r("suites")],f=($,T,M)=>{const v=$[T];if(v===void 0)return 0;if(typeof v!="number"||!Number.isFinite(v)||v<0)throw new Error(`${e}.${M}.${T} must be a non-negative finite number`);return v};return L(i.diagnostics,`${e}.diagnostics`),{record:i,files:{blockedByRuntime:f(d,"blockedByRuntime","files"),cancelled:f(d,"cancelled","files"),failed:f(d,"failed","files"),infraFailed:f(d,"infraFailed","files"),interrupted:f(d,"interrupted","files"),notRun:f(d,"notRun","files"),passed:f(d,"passed","files"),skipped:f(d,"skipped","files"),total:f(d,"total","files")},owners:{blockedByRuntime:f(p,"blockedByRuntime",s),failed:f(p,"failed",s),infraFailed:f(p,"infraFailed",s),passed:f(p,"passed",s),skipped:f(p,"skipped",s),total:f(p,"total",s)},suites:{completed:f(h,"completed","suites"),failed:f(h,"failed","suites"),passed:f(h,"passed","suites"),skipped:f(h,"skipped","suites"),total:f(h,"total","suites")}}}function L(t,e){if(t!==void 0)return k(t,e).map((n,i)=>{const s=`${e}[${String(i)}]`,r=u(n,s);return{...r,code:c(r.code,`${s}.code`),group:o(r.group,`${s}.group`),message:c(r.message,`${s}.message`),service:o(r.service,`${s}.service`),suite:o(r.suite,`${s}.suite`)}})}function te(t,e){const n=u(t,e);return{...n,id:o(n.id,`${e}.id`),fileCount:y(n.fileCount,`${e}.fileCount`),index:y(n.index,`${e}.index`),files:n.files===void 0?void 0:j(n.files,`${e}.files`)}}function ie(t,e){const n=u(t,e);return{...n,position:o(n.position,`${e}.position`),reason:o(n.reason,`${e}.reason`),runtimeIsolation:o(n.runtimeIsolation,`${e}.runtimeIsolation`),trigger:o(n.trigger,`${e}.trigger`)}}function se(t,e){const n=u(t,e),i=n.operation===void 0?void 0:u(n.operation,`${e}.operation`);return{...n,name:c(n.name,`${e}.name`),message:c(n.message,`${e}.message`),code:o(n.code,`${e}.code`),stack:o(n.stack,`${e}.stack`),phase:o(n.phase,`${e}.phase`),exitCode:n.exitCode===void 0?void 0:g(n.exitCode,`${e}.exitCode`),status:n.status===void 0?void 0:g(n.status,`${e}.status`),diagnostics:n.diagnostics===void 0?void 0:S(n.diagnostics,`${e}.diagnostics`),operation:i===void 0?void 0:{...i,id:o(i.id,`${e}.operation.id`),source:c(i.source,`${e}.operation.source`),name:c(i.name,`${e}.operation.name`),kind:c(i.kind,`${e}.operation.kind`),summary:o(i.summary,`${e}.operation.summary`),status:o(i.status,`${e}.operation.status`),error:o(i.error,`${e}.operation.error`),scope:S(i.scope,`${e}.operation.scope`)}}}function S(t,e){return Object.fromEntries(Object.entries(u(t,e)).map(([n,i])=>[n,V(i,`${e}.${n}`)]))}function V(t,e){return t===null||typeof t=="string"||typeof t=="boolean"?t:Array.isArray(t)?k(t,e).map((n,i)=>V(n,`${e}[${String(i)}]`)):z(t)?S(t,e):g(t,e)}function a(t,e,n){return t===void 0?void 0:k(t,e).map((i,s)=>n(i,`${e}[${String(s)}]`))}
@@ -1 +1 @@
1
- import{isWorkObserved as k,recordWork as h}from"../kernel/work-metrics.js";import a from"fs";import l from"path";import{normalizeEngineJsonValue as S}from"../engines/api/index.js";import{readJsonFile as p,normalizePath as g}from"./storage.js";import{loadRunBundleArtifact as P}from"./bundles.js";import{readRunDocument as y}from"./read-run.js";import{requireObjectRecord as R,requireResultsReferencePath as A,optionalStringValue as x,optionalNullableStringValue as f}from"./read-fields.js";export function loadLatestRunArtifact(r){const t=l.join(r,".testkit","results","latest.json");if(!a.existsSync(t))throw new Error(`No run artifact found at ${l.relative(r,t)}`);return y(p(t),t)}export function loadCurrentRunArtifact(r){const t=l.join(r,".testkit","results","live.json");return a.existsSync(t)?y(p(t),t):loadLatestRunArtifact(r)}export function loadRunArtifact(r,t=null){return t?P(r,t):loadLatestRunArtifact(r)}export function resolveFileSubject(r,t=null,e=null){const n=w(r,e);if(n.length===0)throw new Error("No file results were found in the latest run artifact.");if(!t)return n.find(s=>s.file.status==="failed")||n[0];const o=g(t),i=n.filter(s=>s.file.path===o);if(i.length===1)return i[0];if(i.length>1)throw new Error(`Multiple files matched "${t}". Re-run with --service to disambiguate.`);const u=n.filter(s=>s.file.path.endsWith(`/${o}`));if(u.length===1)return u[0];throw u.length>1?new Error(`Multiple files matched "${t}". Re-run with --service to disambiguate.`):new Error(`No file matched "${t}".`)}export function collectArtifactEntries(r,t,e=null,n=null,o,i=!0){const u=e?[resolveFileSubject(t,e,n)]:w(t,n),s=[];for(const d of u)for(const c of d.file.artifacts||[]){if(o&&c.kind!==o)continue;const m=T(r,c.path,`artifact "${c.name}" path`),$=i&&a.existsSync(m)?E(m,c):null;s.push({...d,artifactRef:c,absolutePath:m,payload:$})}return s}function E(r,t){let e;if(k()){const o=a.readFileSync(r);h("artifacts.payloadFilesRead",1),h("artifacts.payloadBytesRead",o.byteLength),e=o.toString("utf8")}else e=a.readFileSync(r,"utf8");const n=t.contentType||"";if(n==="text/markdown"||n==="text/plain")return{contentType:n,kind:t.kind||null,name:t.name||null,summary:t.summary||null,text:e};try{const o=JSON.parse(e);return j(o,r)}catch{return{contentType:n||"text/plain",kind:t.kind||null,name:t.name||null,summary:t.summary||null,text:e}}}function w(r,t=null){const e=[];for(const n of r.services)if(!(t&&n.name!==t))for(const o of n.suites)for(const i of o.files||[])e.push({service:n,suite:o,file:i});return e}function j(r,t){const e=R(r,t),n=x(e.emittedAt,`${t}.emittedAt`);return{...e,contentType:f(e.contentType,`${t}.contentType`),...e.data===void 0?{}:{data:S(e.data,`${t}.data`)},...n===void 0?{}:{emittedAt:n},kind:f(e.kind,`${t}.kind`),name:f(e.name,`${t}.name`),summary:f(e.summary,`${t}.summary`),text:x(e.text,`${t}.text`)}}function T(r,t,e){const n=A(t,e),o=l.resolve(r,".testkit","results"),i=l.resolve(r,n);if(v(o,i,e),a.existsSync(i)){const u=a.realpathSync(o),s=a.realpathSync(i);v(u,s,e)}return i}function v(r,t,e){const n=l.relative(r,t);if(n.length===0||n===".."||n.startsWith(`..${l.sep}`)||l.isAbsolute(n))throw new Error(`${e} must resolve within .testkit/results`)}
1
+ import{isWorkObserved as S,recordWork as p}from"../kernel/work-metrics.js";import a from"fs";import{posixPath as g}from"../process/files/paths.js";import u from"path";import{normalizeEngineJsonValue as R}from"../engines/api/index.js";import{readJsonFile as h}from"./storage.js";import{loadRunBundleArtifact as A}from"./bundles.js";import{readRunDocument as y}from"./read-run.js";import{runModel as x}from"./run-model.js";import{requireObjectRecord as P,requireResultsReferencePath as E,optionalStringValue as w,optionalNullableStringValue as f}from"./read-fields.js";export function loadLatestRunArtifact(e){const t=u.join(e,".testkit","results","latest.json");if(!a.existsSync(t))throw new Error(`No run artifact found at ${u.relative(e,t)}`);return y(h(t),t)}export function loadLatestRun(e){return x(loadLatestRunArtifact(e))}export function loadCurrentRunArtifact(e){const t=u.join(e,".testkit","results","live.json");return a.existsSync(t)?y(h(t),t):loadLatestRunArtifact(e)}export function loadRunArtifact(e,t=null){return t?A(e,t):loadLatestRunArtifact(e)}export function loadRun(e,t=null){return x(loadRunArtifact(e,t))}export function resolveFileSubject(e,t=null,n=null){const r=v(e,n);if(r.length===0)throw new Error("No file results were found in the latest run artifact.");if(!t)return r.find(s=>s.file.status==="failed")||r[0];const o=g(t),i=r.filter(s=>s.file.path===o);if(i.length===1)return i[0];if(i.length>1)throw new Error(`Multiple files matched "${t}". Re-run with --service to disambiguate.`);const l=r.filter(s=>s.file.path.endsWith(`/${o}`));if(l.length===1)return l[0];throw l.length>1?new Error(`Multiple files matched "${t}". Re-run with --service to disambiguate.`):new Error(`No file matched "${t}".`)}export function collectArtifactEntries(e,t,n=null,r=null,o,i=!0){const l=n?[resolveFileSubject(t,n,r)]:v(t,r),s=[];for(const d of l)for(const c of d.file.artifacts||[]){if(o&&c.kind!==o)continue;const m=N(e,c.path,`artifact "${c.name}" path`),k=i&&a.existsSync(m)?j(m,c):null;s.push({...d,artifactRef:c,absolutePath:m,payload:k})}return s}function j(e,t){let n;if(S()){const o=a.readFileSync(e);p("artifacts.payloadFilesRead",1),p("artifacts.payloadBytesRead",o.byteLength),n=o.toString("utf8")}else n=a.readFileSync(e,"utf8");const r=t.contentType||"";if(r==="text/markdown"||r==="text/plain")return{contentType:r,kind:t.kind||null,name:t.name||null,summary:t.summary||null,text:n};try{const o=JSON.parse(n);return T(o,e)}catch{return{contentType:r||"text/plain",kind:t.kind||null,name:t.name||null,summary:t.summary||null,text:n}}}function v(e,t=null){const n=[];for(const r of e.groups)if(!(t&&r.name!==t))for(const o of r.suites)for(const i of o.files)n.push({group:r,suite:o,file:i});return n}function T(e,t){const n=P(e,t),r=w(n.emittedAt,`${t}.emittedAt`);return{...n,contentType:f(n.contentType,`${t}.contentType`),...n.data===void 0?{}:{data:R(n.data,`${t}.data`)},...r===void 0?{}:{emittedAt:r},kind:f(n.kind,`${t}.kind`),name:f(n.name,`${t}.name`),summary:f(n.summary,`${t}.summary`),text:w(n.text,`${t}.text`)}}function N(e,t,n){const r=E(t,n),o=u.resolve(e,".testkit","results"),i=u.resolve(e,r);if($(o,i,n),a.existsSync(i)){const l=a.realpathSync(o),s=a.realpathSync(i);$(l,s,n)}return i}function $(e,t,n){const r=u.relative(e,t);if(r.length===0||r===".."||r.startsWith(`..${u.sep}`)||u.isAbsolute(r))throw new Error(`${n} must resolve within .testkit/results`)}
@@ -0,0 +1,4 @@
1
+ import{REDACTED as f,redactSensitiveText as m,SENSITIVE_KEY_PATTERN as E,sensitiveTextRanges as R}from"../kernel/redaction.js";import{isRedactionTarget as A,MIN_REDACTION_TARGET_LENGTH as N,orderRedactionTargets as _,redactionTargetSpans as S,replaceRedactionTargets as T,sensitiveKeyMatcher as I,urlRedactionTargets as L}from"../kernel/redaction-targets.js";import{isUnknownRecord as y}from"../kernel/unknown-values.js";import{recordWork as J}from"../kernel/work-metrics.js";const K=8,k="\uE010",P=new Set(["data","details","dimensions","metadata","native"]);export function runRedaction({env:e=process.env,redactKeys:n,redactionTargets:t}={}){const s=I(n),c=Object.entries(e).filter(r=>s(r[0])&&typeof r[1]=="string"&&A(r[1]));return{keys:c.map(([r])=>r).sort(),status:t===void 0?"source-targets-unavailable":"applied",targets:_([...c.flatMap(([,r])=>[r,...L(r)]),...t??[]])}}export function redactRunText(e,n){return redactJsonText(e,n)??W(e,n)}function W(e,n){const t=D(S(e,n)),s=[];let c=0,r=0;for(let a=0;a<e.length;){const l=e.indexOf(`
2
+ `,a),d=l===-1?e.length:l,p=e[d-1]==="\r"?d-1:d,o=C(e,a,p,n,t);if(o!==null){const u=b(e.slice(r,o.start),n);s.push(u.text,o.text),c+=u.replacements+o.replacements,r=p}a=d+1}const i=b(e.slice(r),n);return s.push(i.text),{replacements:c+i.replacements,text:s.join("")}}function C(e,n,t,s,c){const r=e.slice(n,t).search(/[[{]/u);if(r<0)return null;const i=n+r;if(c(i,t))return null;const a=e.slice(n,i),l=e.slice(i,t);if(m(a+l)!==m(a)+m(l))return null;const d=redactJsonText(l,s);return d===null?null:{...d,start:i}}function D(e){const n=[...e].sort((c,r)=>c.start-r.start);let t=0,s=-1;return(c,r)=>{let i=0;for(;t<n.length&&n[t].start<c;t+=1)s=Math.max(s,n[t].end),i+=1;let a=s>c;for(let l=t;!a&&l<n.length&&n[l].start<r;l+=1)a=n[l].end>r,i+=1;return J("redaction.spanEdgeSteps",i),a}}function b(e,n){let t=e,s=0;for(let c=0;c<K;c+=1){const r=G(t,n);if(r.text===t)return{replacements:s,text:t};s+=Math.max(r.replacements,1),t=r.text}return{replacements:s+1,text:f}}function G(e,n){const t=S(e,n),s=$(e,n);if(t.length===0&&s.length===0){const r=m(e);return{replacements:r===e?0:1,text:r}}const c=T(e,n,r=>k.repeat(r.length)).text;return F(e,[...R(e),...R(c),...t,...s])}const w=new WeakMap;function j(e){let n=w.get(e);return n===void 0&&(n=e.filter(t=>t.includes(k)||V(t)),w.set(e,n)),n}function V(e){if(e.includes(f)||f.includes(e))return!0;for(let n=1;n<f.length;n+=1)if(e.startsWith(f.slice(-n))||e.endsWith(f.slice(0,n)))return!0;return!1}function $(e,n){const t=j(n);if(t.length===0)return[];if(t.some(c=>/[\r\n]/u.test(c)))return g(e,n)?[O(e)]:[];const s=[];for(let c=0;c<=e.length;){const r=e.indexOf(`
3
+ `,c),i=r===-1?e.length:r,a=e[i-1]==="\r"?i-1:i;g(e.slice(c,a),n)&&s.push({end:a,start:c}),c=i+1}return s.length===0&&g(e,n)?[O(e)]:s}function O(e){const n=e.search(/[^\r\n]/u);let t=e.length;for(;t>n&&(e[t-1]===`
4
+ `||e[t-1]==="\r");)t-=1;return n<0?{end:0,start:0}:{end:t,start:n}}function g(e,n){const t=j(n);if(t.length===0||e.length===0)return!1;let s=!1;const c=r=>i=>(t.some(a=>a.startsWith(i))&&(s=!0),r(i));return T(e,n,c(()=>f)),T(m(e),n,c(()=>f)),T(e,n,c(r=>k.repeat(r.length))),s}function F(e,n){const t=[...n].sort((i,a)=>i.start-a.start||a.end-i.end),s=[];let c=0,r=0;for(let i=0;i<t.length;){const a=t[i].start;let l=t[i].end;for(i+=1;i<t.length&&t[i].start<=l;i+=1)l=Math.max(l,t[i].end);s.push(e.slice(c,a),f),e.slice(a,l)!==f&&(r+=1),c=l}return s.push(e.slice(c)),{replacements:r,text:s.join("")}}export function redactRunValue(e,n){let t=0;function s(l){const d=redactRunText(l,n);return t+=d.replacements,d.text}function c(l,d){if(Array.isArray(l))return l.map(p=>c(p,d));if(y(l)){const p=Object.entries(l),o=d?i(p.map(([u])=>u)):p.map(([u])=>u);return Object.fromEntries(p.map(([u,h],v)=>[o[v],d&&typeof h=="string"&&E.test(u)?r(h):c(h,d||P.has(u))]))}return typeof l=="string"?s(l):l}function r(l){return l!==f&&(t+=1),f}function i(l){const d=l.map(o=>redactRunText(o,n)),p=new Set(l.filter((o,u)=>d[u].text===o));return l.map((o,u)=>d[u].text===o?o:(t+=d[u].replacements,M(p,d[u].text)))}const a=c(e,!1);return{replacements:t,value:a}}export function redactedRunValue(e,n){return redactRunValue(e,n).value}export function redactJsonText(e,n){if(!/^\s*[[{"]/u.test(e))return null;try{JSON.parse(e)}catch{return null}const t=Y(e),s=new Set;for(const o of S(e,n)){const u=U(t,o.start,o.end);if(u===void 0)return null;H(e,o,n)||s.add(u)}const c=o=>s.has(o)||g(o.decoded,n)?{replacements:o.decoded===f?0:1,text:f}:redactRunText(o.decoded,n),r=new Map(t.filter(o=>o.key).map(o=>[o,c(o)])),i=new Map;for(const[o,u]of r)o.object===null||u.text!==o.decoded||i.set(o.object,(i.get(o.object)??new Set).add(o.decoded));const a=[];let l=0,d=0;for(const o of t){let u=r.get(o);if(u!==void 0&&u.text!==o.decoded&&o.object!==null){const h=i.get(o.object)??new Set;i.set(o.object,h),u={...u,text:M(h,u.text)}}else u===void 0&&o.member!==null&&E.test(o.member)?u={replacements:o.decoded===f?0:1,text:f}:u===void 0&&(u=c(o));u.text!==o.decoded&&(a.push(e.slice(l,o.start),JSON.stringify(u.text)),l=o.close+1,d+=u.replacements)}a.push(e.slice(l));const p=a.join("");return n.some(o=>p.includes(o))?null:{replacements:d,text:p}}function H(e,n,t){let s=0;for(;e[n.start-1-s]==="\\";)s+=1;if(s%2===1)return!1;const c=e.slice(n.start,n.end);if(!c.includes("\\"))return!0;let r;try{r=JSON.parse(`"${c}"`)}catch{return!1}return n.cut?r.length>=N&&t.some(i=>i.startsWith(r)):t.includes(r)}function U(e,n,t){let s=0,c=e.length-1;for(;s<=c;){const i=s+c>>1;e[i].start<n?s=i+1:c=i-1}const r=e.at(c);return r!==void 0&&r.start<n&&t<=r.close?r:void 0}function Y(e){const n=[],t=[];for(let s=0;s<e.length;s+=1){const c=e[s];if(c==="{"?t.push({id:s,key:null}):c==="["?t.push(null):(c==="}"||c==="]")&&t.pop(),c!=='"')continue;const r=q(e,s),i=JSON.parse(e.slice(s,r+1)),a=t.at(-1)??null,l=a!==null&&x(e,r+1)===":";n.push({close:r,decoded:i,key:l,member:l?null:a?.key??null,object:a?.id??null,start:s}),l&&(a.key=i),s=r}return n}function q(e,n){for(let t=n+1;t<e.length;t+=1)if(e[t]==="\\")t+=1;else if(e[t]==='"')return t;return e.length-1}function x(e,n){for(let t=n;t<e.length;t+=1)if(!/\s/u.test(e[t]))return e[t]}function M(e,n){let t=n;for(let s=2;e.has(t);s++)t=`${n} (${String(s)})`;return e.add(t),t}
@@ -1 +1 @@
1
- import Z from"path";import{DEFAULT_REPORTED_ARCHIVE_CONFIG as $}from"./reporting-types.js";export function buildRunArtifact({productDir:n,runId:e=null,results:i,startedAt:l,finishedAt:s,execution:o,workerCount:a,runtimeInstanceCount:d,runtimeStats:m,typeValues:g,suiteSelectors:k,fileNames:F,serviceFilter:C,planning:f=null,archiveConfig:S=null,declaredEnvironmentKeys:h=[],metadata:c,summarizeDbBackend:R,serviceLogs:y=[],setupLogs:b=[],setupOperations:v=[],operationTimings:D=[],runInterruptReason:M=null,runStatus:x=null}){const u=i.filter(t=>!t.skipped),E=u.filter(q),A=u.filter(t=>t.failed),B=u.filter(t=>t.infraFailed),z=u.filter(t=>t.blockedByRuntime),N=u.filter(t=>ee(t)),w=se(u),V=te(u),H=r(u,"totalFileCount"),_=r(u,"passedFileCount"),L=r(u,"failedFileCount"),P=r(u,"skippedFileCount"),j=r(u,"notRunFileCount"),I=p(u,t=>t.status==="cancelled"),O=p(u,t=>t.status==="interrupted"),G=Math.max(0,j-I-O),J=p(u,t=>t.infraFailed===!0),K=p(u,t=>t.blockedByRuntime===!0),T=R(i),U=typeof T=="string"?T:null,Q=new Date(s??Date.now()).toISOString(),W=s===null?null:new Date(s).toISOString(),X=s===null?null:s-l,Y=S??$;return{schemaVersion:19,source:"testkit",generatedAt:Q,product:{name:Z.basename(n),directory:n},git:{branch:c.git.branch??null,commitSha:c.git.commitSha??null,dirty:c.git.dirty===!0,pullRequest:c.git.pullRequest??null,pullRequestHeadSha:c.git.pullRequestHeadSha??null,repository:c.git.repository??null},host:c.host,run:{id:e,status:x||(A.length>0||B.length>0?"failed":"passed"),startedAt:new Date(l).toISOString(),finishedAt:W,durationMs:X,workers:o.taskConcurrency,fileTimeoutSeconds:o.fileTimeoutSeconds,workerCount:a,runtimeInstanceCount:d,runtimeStats:[...m??[]],dbBackend:U,types:[...g],suiteSelectors:k.map(t=>t.raw),fileNames:[...F],serviceFilter:C,testkitVersion:c.testkitVersion,...M===null?{}:{interruptReason:M}},archive:{request:Y,declaredEnvironmentKeys:[...new Set(h)].sort()},...f?{planning:f}:{},summary:{services:{total:u.length,passed:N.length,failed:A.length,infraFailed:B.length,blockedByRuntime:z.length,skipped:E.length},suites:V,files:{total:H,passed:_,failed:L,skipped:P,notRun:G,cancelled:I,interrupted:O,infraFailed:J,blockedByRuntime:K},...w.length>0?{diagnostics:w}:{}},logs:{services:[...y],setup:[...b]},setup:{operations:[...v]},timings:{operations:oe(D)},services:i.map(t=>({name:t.name,failed:t.failed,infraFailed:t.infraFailed===!0,blockedByRuntime:t.blockedByRuntime===!0,skipped:t.skipped,suiteCount:t.suiteCount,completedSuiteCount:t.completedSuiteCount,skippedSuiteCount:t.skippedSuiteCount,failedSuiteCount:t.failedSuiteCount,totalFileCount:t.totalFileCount,completedFileCount:t.completedFileCount,passedFileCount:t.passedFileCount,failedFileCount:t.failedFileCount,skippedFileCount:t.skippedFileCount,notRunFileCount:t.notRunFileCount,durationMs:t.durationMs,totalTaskDurationMs:t.totalTaskDurationMs,dbBackend:t.dbBackend,suites:t.suites,errors:t.errors,...t.diagnostics&&t.diagnostics.length>0?{diagnostics:t.diagnostics}:{},...t.errorDetails&&t.errorDetails.length>0?{errorDetails:t.errorDetails}:{}}))}}export function buildLiveRunArtifact({productDir:n,runId:e=null,results:i,startedAt:l,updatedAt:s,execution:o,workerCount:a,runtimeInstanceCount:d,runtimeStats:m,typeValues:g,suiteSelectors:k,fileNames:F,serviceFilter:C,planning:f=null,archiveConfig:S=null,declaredEnvironmentKeys:h=[],metadata:c,summarizeDbBackend:R,serviceLogs:y=[],setupLogs:b=[],setupOperations:v=[],operationTimings:D=[]}){return{...buildRunArtifact({productDir:n,runId:e,results:i,startedAt:l,finishedAt:null,execution:o,workerCount:a,runtimeInstanceCount:d,runtimeStats:m,typeValues:g,suiteSelectors:k,fileNames:F,serviceFilter:C,planning:f,archiveConfig:S,declaredEnvironmentKeys:h,metadata:c,summarizeDbBackend:R,serviceLogs:y,setupLogs:b,setupOperations:v,operationTimings:D,runStatus:"running"}),generatedAt:new Date(s).toISOString()}}function q(n){return!n.skipped&&!n.failed&&n.skippedSuiteCount>0&&n.skippedSuiteCount===n.suiteCount&&n.notRunFileCount===0}function ee(n){return!n.failed&&!n.infraFailed&&!q(n)&&n.notRunFileCount===0}function p(n,e){let i=0;for(const l of n)for(const s of l.suites)for(const o of s.files??[])e(o)&&(i+=1);return i}function te(n){const e={total:0,completed:0,passed:0,failed:0,skipped:0};for(const i of n){const l=i.suites,s=i.suiteCount;if(l.length===0){const o=ne(i,s);e.total+=o.total,e.completed+=o.completed,e.passed+=o.passed,e.failed+=o.failed,e.skipped+=o.skipped;continue}e.total+=s;for(const o of l){const a=ie(o);a==="passed"?(e.completed+=1,e.passed+=1):a==="failed"?(e.completed+=1,e.failed+=1):a==="skipped"&&(e.completed+=1,e.skipped+=1)}}return e}function ne(n,e){const i=n.failedSuiteCount,l=n.skippedSuiteCount,s=n.completedSuiteCount;return{total:e,completed:s,passed:Math.max(0,s-i-l),failed:i,skipped:l}}function ie(n){const e=n.files??[],i=e.length,l=Math.max(n.fileCount??0,i),s=e.length>0?e.filter(d=>d.status==="failed"||d.failed===!0).length:n.failedFileCount??0,o=e.length>0?e.filter(d=>d.status==="skipped").length:n.skippedFileCount??0,a=e.length>0?e.filter(d=>d.status==="passed").length:n.passedFileCount??0;return s>0||n.failed===!0?"failed":l>0&&o>=l?"skipped":l>0&&a+o>=l?"passed":"pending"}function r(n,e){return n.reduce((i,l)=>i+l[e],0)}function se(n){const e=[],i=new Set,l=s=>{const o=JSON.stringify(s);i.has(o)||(i.add(o),e.push(s))};for(const s of n){const o=s.diagnostics??[];for(const a of o)l({...a,service:a.service||s.name});if(!(o.length>0))for(const a of s.suites)for(const d of a.diagnostics??[])l({...d,service:d.service||s.name,suite:d.suite||a.name})}return e}function oe(n){return n.map(e=>({id:e.id||null,source:e.source||"testkit",name:e.name||"operation",kind:e.kind||"operation",summary:e.summary||null,scope:e.scope?{...e.scope}:{},parentId:e.parentId||null,status:e.status||"unknown",startedAt:e.startedAt||null,updatedAt:e.updatedAt||null,finishedAt:e.finishedAt||null,durationMs:e.durationMs!==null&&e.durationMs!==void 0&&Number.isFinite(e.durationMs)?Math.max(0,Math.round(e.durationMs)):null,error:e.error||null,message:e.message||null,logRefs:(e.logRefs??[]).map(i=>le(i)?{...i}:i),metadata:e.metadata?{...e.metadata}:{}}))}function le(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}
1
+ import J from"path";import{publishEnvironmentRecord as K}from"./environment-record.js";import{DEFAULT_REPORTED_ARCHIVE_CONFIG as U}from"./reporting-types.js";export function buildRunArtifact({productDir:n,runId:e=null,results:i,startedAt:l,finishedAt:s,execution:o,workerCount:a,typeValues:d,suiteSelectors:R,fileNames:y,groupFilter:b,planning:f=null,archiveConfig:D=null,declaredEnvironmentKeys:M=[],metadata:r,environment:A,operationTimings:w=[],runInterruptReason:m=null,runStatus:B=null}){const u=i.filter(t=>!t.skipped),G=u.filter(S),g=u.filter(t=>t.failed),F=u.filter(t=>t.infraFailed),I=u.filter(t=>t.blockedByRuntime),O=u.filter(t=>Q(t)),C=Z(u),v=W(u),E=c(u,"totalFileCount"),T=c(u,"passedFileCount"),q=c(u,"failedFileCount"),x=c(u,"skippedFileCount"),N=c(u,"notRunFileCount"),k=p(u,t=>t.status==="cancelled"),h=p(u,t=>t.status==="interrupted"),V=Math.max(0,N-k-h),z=p(u,t=>t.infraFailed===!0),H=p(u,t=>t.blockedByRuntime===!0),_=new Date(s??Date.now()).toISOString(),L=s===null?null:new Date(s).toISOString(),P=s===null?null:s-l,j=D??U;return{schemaVersion:20,source:"testkit",generatedAt:_,product:{name:J.basename(n),directory:n},git:{branch:r.git.branch??null,commitSha:r.git.commitSha??null,dirty:r.git.dirty===!0,pullRequest:r.git.pullRequest??null,pullRequestHeadSha:r.git.pullRequestHeadSha??null,repository:r.git.repository??null},host:r.host,run:{id:e,status:B||(g.length>0||F.length>0?"failed":"passed"),startedAt:new Date(l).toISOString(),finishedAt:L,durationMs:P,workers:o.taskConcurrency,fileTimeoutSeconds:o.fileTimeoutSeconds,workerCount:a,types:[...d],suiteSelectors:R.map(t=>t.raw),fileNames:[...y],groupFilter:b,testkitVersion:r.testkitVersion,...m===null?{}:{interruptReason:m}},archive:{request:j,declaredEnvironmentKeys:[...new Set(M)].sort()},...f?{planning:f}:{},summary:{groups:{total:u.length,passed:O.length,failed:g.length,infraFailed:F.length,blockedByRuntime:I.length,skipped:G.length},suites:v,files:{total:E,passed:T,failed:q,skipped:x,notRun:V,cancelled:k,interrupted:h,infraFailed:z,blockedByRuntime:H},...C.length>0?{diagnostics:C}:{}},environment:K(A),timings:{operations:$(w)},groups:i.map(t=>({name:t.name,failed:t.failed,infraFailed:t.infraFailed===!0,blockedByRuntime:t.blockedByRuntime===!0,skipped:t.skipped,suiteCount:t.suiteCount,completedSuiteCount:t.completedSuiteCount,skippedSuiteCount:t.skippedSuiteCount,failedSuiteCount:t.failedSuiteCount,totalFileCount:t.totalFileCount,completedFileCount:t.completedFileCount,passedFileCount:t.passedFileCount,failedFileCount:t.failedFileCount,skippedFileCount:t.skippedFileCount,notRunFileCount:t.notRunFileCount,durationMs:t.durationMs,totalTaskDurationMs:t.totalTaskDurationMs,suites:t.suites,errors:t.errors,...t.diagnostics&&t.diagnostics.length>0?{diagnostics:t.diagnostics}:{},...t.errorDetails&&t.errorDetails.length>0?{errorDetails:t.errorDetails}:{}}))}}export function buildLiveRunArtifact({updatedAt:n,...e}){return{...buildRunArtifact({...e,finishedAt:null,runStatus:"running"}),generatedAt:new Date(n).toISOString()}}function S(n){return!n.skipped&&!n.failed&&n.skippedSuiteCount>0&&n.skippedSuiteCount===n.suiteCount&&n.notRunFileCount===0}function Q(n){return!n.failed&&!n.infraFailed&&!S(n)&&n.notRunFileCount===0}function p(n,e){let i=0;for(const l of n)for(const s of l.suites)for(const o of s.files??[])e(o)&&(i+=1);return i}function W(n){const e={total:0,completed:0,passed:0,failed:0,skipped:0};for(const i of n){const l=i.suites,s=i.suiteCount;if(l.length===0){const o=X(i,s);e.total+=o.total,e.completed+=o.completed,e.passed+=o.passed,e.failed+=o.failed,e.skipped+=o.skipped;continue}e.total+=s;for(const o of l){const a=Y(o);a==="passed"?(e.completed+=1,e.passed+=1):a==="failed"?(e.completed+=1,e.failed+=1):a==="skipped"&&(e.completed+=1,e.skipped+=1)}}return e}function X(n,e){const i=n.failedSuiteCount,l=n.skippedSuiteCount,s=n.completedSuiteCount;return{total:e,completed:s,passed:Math.max(0,s-i-l),failed:i,skipped:l}}function Y(n){const e=n.files??[],i=e.length,l=Math.max(n.fileCount??0,i),s=e.length>0?e.filter(d=>d.status==="failed"||d.failed===!0).length:n.failedFileCount??0,o=e.length>0?e.filter(d=>d.status==="skipped").length:n.skippedFileCount??0,a=e.length>0?e.filter(d=>d.status==="passed").length:n.passedFileCount??0;return s>0||n.failed===!0?"failed":l>0&&o>=l?"skipped":l>0&&a+o>=l?"passed":"pending"}function c(n,e){return n.reduce((i,l)=>i+l[e],0)}function Z(n){const e=[],i=new Set,l=s=>{const o=JSON.stringify(s);i.has(o)||(i.add(o),e.push(s))};for(const s of n){const o=s.diagnostics??[];for(const a of o)l({...a,group:a.group||s.name});if(!(o.length>0))for(const a of s.suites)for(const d of a.diagnostics??[])l({...d,group:d.group||s.name,suite:d.suite||a.name})}return e}function $(n){return n.map(e=>({id:e.id||null,source:e.source||"testkit",name:e.name||"operation",kind:e.kind||"operation",summary:e.summary||null,scope:e.scope?{...e.scope}:{},parentId:e.parentId||null,status:e.status||"unknown",startedAt:e.startedAt||null,updatedAt:e.updatedAt||null,finishedAt:e.finishedAt||null,durationMs:e.durationMs!==null&&e.durationMs!==void 0&&Number.isFinite(e.durationMs)?Math.max(0,Math.round(e.durationMs)):null,error:e.error||null,message:e.message||null,logRefs:(e.logRefs??[]).map(i=>ee(i)?{...i}:i),metadata:e.metadata?{...e.metadata}:{}}))}function ee(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}
@@ -0,0 +1 @@
1
+ import{isUnknownRecord as e}from"../kernel/unknown-values.js";export function runModel(r){return r.schemaVersion===19?u(r):a(r)}function u(r){return{...n(r),groups:r.services.map(t),summary:r.summary===void 0?null:{files:r.summary.files,groups:r.summary.services,suites:r.summary.suites}}}function a(r){return{...n(r),groups:r.groups.map(t),summary:r.summary===void 0?null:{files:r.summary.files,groups:r.summary.groups,suites:r.summary.suites}}}function n(r){return{archive:f(r.archive),finalizationFailure:r.finalizationFailure??null,generatedAt:r.generatedAt??null,git:{commitSha:e(r.git)?p(r.git.commitSha):null},run:{durationMs:r.run.durationMs??null,finishedAt:r.run.finishedAt,id:r.run.id,startedAt:r.run.startedAt,status:r.run.status,types:r.run.types??[]},schemaVersion:r.schemaVersion}}function t(r){return{errors:Array.isArray(r.errors)?r.errors.filter(s=>typeof s=="string"):[],name:r.name,suites:r.suites.map(l)}}function l(r){return{engineId:r.engineId,files:r.files??[],name:r.name,profileId:r.profileId,...r.testType===void 0?{}:{testType:r.testType}}}function f(r){if(!e(r))return{cleanup:null,publication:null};const{cleanup:s,publication:i}=r;return{cleanup:e(s)&&typeof s.status=="string"?{status:s.status}:null,publication:e(i)&&typeof i.status=="string"?{required:i.required===!0,status:i.status}:null}}function p(r){return typeof r=="string"?r:null}