@gfdelarue/testkit 0.4.3 → 0.4.5

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 (276) hide show
  1. package/README.md +109 -22
  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/draft.js +3 -3
  6. package/dist/app/bugs/facts.d.ts +3 -2
  7. package/dist/app/bugs/facts.js +2 -2
  8. package/dist/app/bugs/guide.js +1 -1
  9. package/dist/app/bugs/run-reading.js +1 -1
  10. package/dist/app/db-schema/prepare.js +1 -1
  11. package/dist/app/destroy/index.js +1 -1
  12. package/dist/app/doctor/index.js +1 -1
  13. package/dist/app/environments/config-driven.d.ts +5 -0
  14. package/dist/app/environments/config-driven.js +1 -0
  15. package/dist/app/environments/routing.d.ts +6 -0
  16. package/dist/app/environments/routing.js +1 -0
  17. package/dist/app/environments/supplied.d.ts +3 -0
  18. package/dist/app/environments/supplied.js +1 -0
  19. package/dist/app/file-selection.js +1 -1
  20. package/dist/app/lint/native.js +1 -1
  21. package/dist/app/lint/options.d.ts +0 -1
  22. package/dist/app/lint/options.js +1 -1
  23. package/dist/app/lint/shared.d.ts +0 -2
  24. package/dist/app/lint/shared.js +1 -1
  25. package/dist/app/package-inspection.js +1 -1
  26. package/dist/app/reports/files.d.ts +13 -0
  27. package/dist/app/reports/files.js +1 -0
  28. package/dist/app/reports/prepare.d.ts +20 -0
  29. package/dist/app/reports/prepare.js +2 -0
  30. package/dist/app/reports/publish.d.ts +21 -0
  31. package/dist/app/reports/publish.js +1 -0
  32. package/dist/app/run/engine-evidence-persistence.js +1 -1
  33. package/dist/app/run/engine-execution-cleanup.js +1 -1
  34. package/dist/app/run/engine-execution-failures.js +1 -1
  35. package/dist/app/run/engine-execution.d.ts +10 -8
  36. package/dist/app/run/engine-execution.js +1 -1
  37. package/dist/app/run/engine-orchestration.d.ts +15 -34
  38. package/dist/app/run/engine-orchestration.js +1 -1
  39. package/dist/app/run/environment.d.ts +33 -0
  40. package/dist/app/run/environment.js +1 -0
  41. package/dist/app/run/failure-details.js +1 -1
  42. package/dist/app/run/live-run.d.ts +3 -1
  43. package/dist/app/run/live-run.js +1 -1
  44. package/dist/app/run/orchestrator.d.ts +8 -1
  45. package/dist/app/run/orchestrator.js +1 -1
  46. package/dist/app/run/planning.d.ts +1 -2
  47. package/dist/app/run/planning.js +1 -1
  48. package/dist/app/run/results.d.ts +1 -1
  49. package/dist/app/run/results.js +1 -1
  50. package/dist/app/run/run-finalization.d.ts +6 -2
  51. package/dist/app/run/run-finalization.js +1 -1
  52. package/dist/app/run/runtime-fixtures.js +1 -1
  53. package/dist/app/run/runtime-task-types.d.ts +1 -1
  54. package/dist/app/run/scheduler/index.js +1 -1
  55. package/dist/app/run/scheduler/locks.d.ts +6 -0
  56. package/dist/app/run/scheduler/locks.js +1 -0
  57. package/dist/app/run/selection.d.ts +0 -1
  58. package/dist/app/run/selection.js +1 -1
  59. package/dist/app/run/setup/runtime-node-setup-protocol.js +1 -1
  60. package/dist/app/run/setup/runtime-node-setup-worker.js +1 -1
  61. package/dist/app/run/task-leases.d.ts +15 -0
  62. package/dist/app/run/task-leases.js +1 -0
  63. package/dist/app/run/worker-loop.d.ts +13 -4
  64. package/dist/app/run/worker-loop.js +1 -1
  65. package/dist/app/tracker/index.d.ts +6 -1
  66. package/dist/app/tracker/index.js +1 -1
  67. package/dist/app/typecheck/index.js +4 -4
  68. package/dist/cli/command-catalog.d.ts +19 -0
  69. package/dist/cli/command-catalog.js +1 -1
  70. package/dist/cli/command-registry.js +1 -1
  71. package/dist/cli/commands/report/prepare.d.ts +12 -0
  72. package/dist/cli/commands/report/prepare.js +5 -0
  73. package/dist/cli/commands/report/publish.d.ts +13 -0
  74. package/dist/cli/commands/report/publish.js +2 -0
  75. package/dist/cli/json-errors.js +1 -1
  76. package/dist/cli/operations/run/operation.d.ts +3 -1
  77. package/dist/cli/operations/run/operation.js +2 -2
  78. package/dist/cli/renderers/doctor/text.js +1 -1
  79. package/dist/cli/renderers/run/formatting.js +1 -1
  80. package/dist/config/authoring/index.d.ts +4 -13
  81. package/dist/config/authoring/index.js +1 -1
  82. package/dist/config/authoring/preset-env.js +1 -1
  83. package/dist/config/loader/config-loader.js +1 -1
  84. package/dist/config/loader/database.js +1 -1
  85. package/dist/config/loader/decode-execution.d.ts +0 -2
  86. package/dist/config/loader/decode-execution.js +1 -1
  87. package/dist/config/loader/discover-tests.js +1 -1
  88. package/dist/config/loader/discovery.d.ts +0 -1
  89. package/dist/config/loader/discovery.js +2 -2
  90. package/dist/config/loader/env.js +1 -1
  91. package/dist/config/loader/execution-model.d.ts +0 -1
  92. package/dist/config/loader/execution-model.js +1 -1
  93. package/dist/config/loader/file-metadata.d.ts +1 -1
  94. package/dist/config/loader/file-metadata.js +1 -1
  95. package/dist/config/loader/groups.d.ts +33 -0
  96. package/dist/config/loader/groups.js +1 -0
  97. package/dist/config/loader/load.d.ts +0 -2
  98. package/dist/config/loader/load.js +1 -1
  99. package/dist/config/loader/runtime-isolation.js +1 -1
  100. package/dist/config/loader/runtime.d.ts +0 -9
  101. package/dist/config/loader/runtime.js +1 -1
  102. package/dist/config/loader/skip-config.js +1 -1
  103. package/dist/config/loader/validation.d.ts +1 -2
  104. package/dist/config/loader/validation.js +1 -1
  105. package/dist/config/loader/values.d.ts +0 -1
  106. package/dist/config/loader/values.js +1 -1
  107. package/dist/database/activity-gate.js +1 -1
  108. package/dist/database/admin.js +2 -2
  109. package/dist/database/lifecycle-cleanup.d.ts +1 -0
  110. package/dist/database/lifecycle-cleanup.js +1 -1
  111. package/dist/database/local-postgres.js +1 -1
  112. package/dist/database/naming.js +1 -1
  113. package/dist/database/schema-operations.d.ts +1 -1
  114. package/dist/database/schema-operations.js +1 -1
  115. package/dist/database/schema-source.js +3 -3
  116. package/dist/database/source-url.d.ts +0 -1
  117. package/dist/database/source-url.js +2 -2
  118. package/dist/database/state.js +1 -1
  119. package/dist/database/steps.js +3 -3
  120. package/dist/domain/file-timeout.d.ts +0 -3
  121. package/dist/domain/file-timeout.js +1 -1
  122. package/dist/domain/operation-display.js +1 -1
  123. package/dist/domain/test-outcomes.d.ts +0 -1
  124. package/dist/domain/test-outcomes.js +1 -1
  125. package/dist/engines/adapters/evidence-identity.js +1 -1
  126. package/dist/engines/adapters/execution.d.ts +0 -1
  127. package/dist/engines/adapters/execution.js +1 -1
  128. package/dist/engines/api/capabilities.d.ts +0 -10
  129. package/dist/engines/api/capabilities.js +1 -1
  130. package/dist/engines/api/execution-scope.js +1 -1
  131. package/dist/engines/api/k6-runtime-input.js +1 -1
  132. package/dist/engines/bundle-cache.js +1 -1
  133. package/dist/engines/contracts/fixture-manifest.js +1 -1
  134. package/dist/engines/definitions.d.ts +1 -0
  135. package/dist/engines/definitions.js +1 -1
  136. package/dist/engines/installations/playwright-resolution-child.js +1 -1
  137. package/dist/engines/installations/playwright.js +1 -1
  138. package/dist/engines/k6/adapter/evidence.js +4 -4
  139. package/dist/engines/k6/adapter/executor.js +1 -1
  140. package/dist/engines/k6/adapter/native-summary.js +1 -1
  141. package/dist/engines/k6/runtime/checks.js +1 -1
  142. package/dist/engines/k6/runtime/dal-fixtures.js +1 -1
  143. package/dist/engines/k6/runtime/dal-suite.js +1 -1
  144. package/dist/engines/k6/runtime/http-suite-runtime.js +1 -1
  145. package/dist/engines/k6/runtime/http.js +1 -1
  146. package/dist/engines/k6/runtime/shared/db-normalization.js +1 -1
  147. package/dist/engines/k6/runtime/shared/fixture-engine.js +2 -2
  148. package/dist/engines/k6/runtime/shared/http-parsing.js +3 -3
  149. package/dist/engines/managed-module-resolution-policy-input.d.ts +0 -1
  150. package/dist/engines/managed-module-resolution-policy-input.js +1 -1
  151. package/dist/engines/managed-module-resolution-policy.js +1 -1
  152. package/dist/engines/node-vitest/adapter/adapter.js +1 -1
  153. package/dist/engines/node-vitest/adapter/evidence.js +2 -2
  154. package/dist/engines/node-vitest/adapter/workspace.js +22 -21
  155. package/dist/engines/node-vitest/runtime/contract/index.js +1 -1
  156. package/dist/engines/node-vitest/runtime/data/http.js +1 -1
  157. package/dist/engines/node-vitest/runtime/data/index.d.ts +2 -2
  158. package/dist/engines/node-vitest/runtime/data/index.js +1 -1
  159. package/dist/engines/node-vitest/runtime/data/report.js +5 -5
  160. package/dist/engines/node-vitest/runtime/data/scenario.d.ts +0 -1
  161. package/dist/engines/node-vitest/runtime/data/scenario.js +2 -2
  162. package/dist/engines/node-vitest/runtime/data/types.d.ts +1 -29
  163. package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
  164. package/dist/engines/playwright/adapter/adapter.js +1 -1
  165. package/dist/engines/playwright/adapter/config.d.ts +1 -1
  166. package/dist/engines/playwright/adapter/config.js +4 -4
  167. package/dist/engines/playwright/adapter/evidence-validation.d.ts +0 -3
  168. package/dist/engines/playwright/adapter/evidence-validation.js +1 -1
  169. package/dist/engines/playwright/adapter/evidence.js +1 -1
  170. package/dist/engines/playwright/runtime/config-file.js +1 -1
  171. package/dist/engines/playwright/runtime/config.js +1 -1
  172. package/dist/engines/playwright/runtime/runtime-input.d.ts +2 -2
  173. package/dist/engines/playwright/runtime/runtime-input.js +16 -12
  174. package/dist/environment/lifecycle-artifacts.js +1 -1
  175. package/dist/environment/lifecycle-controller.d.ts +1 -11
  176. package/dist/environment/lifecycle-controller.js +1 -1
  177. package/dist/environment/lifecycle.d.ts +14 -11
  178. package/dist/environment/lifecycle.js +1 -1
  179. package/dist/environment/planning-types.d.ts +0 -2
  180. package/dist/environment/ports.d.ts +10 -0
  181. package/dist/environment/ports.js +1 -0
  182. package/dist/environment/ready-environment.d.ts +2 -5
  183. package/dist/environment/ready-environment.js +1 -1
  184. package/dist/environment/run-environment.d.ts +1 -0
  185. package/dist/environment/run-environment.js +1 -1
  186. package/dist/environment/runtime-contexts.d.ts +11 -7
  187. package/dist/environment/runtime-contexts.js +1 -1
  188. package/dist/environment/runtime-manager.d.ts +1 -9
  189. package/dist/environment/runtime-manager.js +1 -1
  190. package/dist/environment/runtime-planning.js +1 -1
  191. package/dist/environment/runtime-preparation.js +1 -1
  192. package/dist/environment/runtime-service.d.ts +0 -6
  193. package/dist/environment/services.d.ts +11 -3
  194. package/dist/environment/services.js +3 -1
  195. package/dist/environment/state.d.ts +1 -4
  196. package/dist/environment/state.js +1 -1
  197. package/dist/environment/template.d.ts +6 -22
  198. package/dist/environment/template.js +1 -1
  199. package/dist/evidence/artifact-config.js +1 -1
  200. package/dist/evidence/artifact-validation.d.ts +1 -2
  201. package/dist/evidence/artifact-validation.js +1 -1
  202. package/dist/evidence/artifacts.js +2 -2
  203. package/dist/evidence/bundles.js +1 -1
  204. package/dist/evidence/environment-record.d.ts +22 -0
  205. package/dist/evidence/environment-record.js +1 -0
  206. package/dist/evidence/index.d.ts +1 -1
  207. package/dist/evidence/logs.js +2 -2
  208. package/dist/evidence/operation-timings.js +1 -1
  209. package/dist/evidence/read-fields.d.ts +0 -1
  210. package/dist/evidence/read-fields.js +1 -1
  211. package/dist/evidence/read-run.js +1 -1
  212. package/dist/evidence/reading.js +1 -1
  213. package/dist/evidence/reporting-types.d.ts +19 -0
  214. package/dist/evidence/reporting.d.ts +2 -2
  215. package/dist/evidence/reporting.js +1 -1
  216. package/dist/evidence/storage.d.ts +0 -2
  217. package/dist/evidence/storage.js +2 -2
  218. package/dist/evidence/timing.js +1 -1
  219. package/dist/kernel/error-serialization.d.ts +2 -0
  220. package/dist/kernel/error-serialization.js +1 -1
  221. package/dist/kernel/unknown-values.d.ts +5 -0
  222. package/dist/kernel/unknown-values.js +1 -1
  223. package/dist/process/environment.js +1 -1
  224. package/dist/process/execa-bundle.json +3 -3
  225. package/dist/process/files/json-file.d.ts +0 -1
  226. package/dist/process/files/json-file.js +1 -1
  227. package/dist/process/files/paths.d.ts +2 -0
  228. package/dist/process/files/paths.js +1 -1
  229. package/dist/process/host/metadata.js +1 -1
  230. package/dist/process/host/platform.js +1 -1
  231. package/dist/process/host-process.js +1 -1
  232. package/dist/process/lifecycle-fence.d.ts +1 -2
  233. package/dist/process/lifecycle-fence.js +1 -1
  234. package/dist/process/locks.js +2 -2
  235. package/dist/process/process-group.js +1 -1
  236. package/dist/process/process-identity.js +1 -1
  237. package/dist/process/process.js +30 -30
  238. package/dist/process/readiness.d.ts +7 -1
  239. package/dist/process/readiness.js +1 -1
  240. package/dist/process/recovery.js +1 -1
  241. package/dist/process/runs/manifest.js +1 -1
  242. package/dist/process/runs/ownership.js +1 -1
  243. package/dist/process/runs/product-state.js +1 -1
  244. package/dist/process/runs/stop.js +1 -1
  245. package/dist/process/stoppable-settlement.d.ts +26 -0
  246. package/dist/process/stoppable-settlement.js +1 -0
  247. package/dist/process/url-redaction.d.ts +1 -0
  248. package/dist/process/url-redaction.js +1 -0
  249. package/dist/process/windows-native.d.ts +6 -0
  250. package/dist/process/windows-native.js +1 -1
  251. package/dist/repo/ci-environment.js +1 -1
  252. package/dist/repo/fingerprint-policy.d.ts +0 -2
  253. package/dist/repo/fingerprint-policy.js +1 -1
  254. package/dist/repo/physical-tree.js +1 -1
  255. package/dist/repo/publish-directory.d.ts +20 -0
  256. package/dist/repo/publish-directory.js +3 -0
  257. package/dist/repo/state.js +4 -4
  258. package/dist/steps/build-config.d.ts +0 -1
  259. package/dist/steps/build-config.js +1 -1
  260. package/dist/steps/configured-steps.js +1 -1
  261. package/dist/steps/environment.d.ts +0 -2
  262. package/dist/steps/environment.js +1 -1
  263. package/dist/steps/index.d.ts +1 -1
  264. package/dist/steps/run.js +2 -2
  265. package/dist/toolchains/archive.js +1 -1
  266. package/dist/toolchains/index.js +3 -3
  267. package/dist/toolchains/node-provisioning.js +2 -2
  268. package/dist/toolchains/vitest/index.js +1 -1
  269. package/docs/bug-records.md +54 -52
  270. package/docs/engine-architecture.md +39 -11
  271. package/package.json +1 -1
  272. package/testkit-config-schema.md +43 -5
  273. package/dist/app/run/playwright-configuration.d.ts +0 -2
  274. package/dist/app/run/playwright-configuration.js +0 -1
  275. package/dist/environment/readiness.d.ts +0 -12
  276. package/dist/environment/readiness.js +0 -1
@@ -8,7 +8,6 @@ export declare function optionalNullableStringValue(value: unknown, label: strin
8
8
  export declare function requireNumber(value: unknown, label: string): number;
9
9
  export declare function optionalNumberOrStringValue(value: unknown, label: string): number | string | undefined;
10
10
  export declare function optionalNullableNumberValue(value: unknown, label: string): null | number | undefined;
11
- export declare function isObjectRecord(value: unknown): value is UnknownRecord;
12
11
  export declare function requireExactString(value: unknown, label: string, expected: string): string;
13
12
  export declare function requireSha256(value: unknown, label: string): string;
14
13
  export declare function requireManifestRelativePath(value: unknown, label: string): string;
@@ -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 C,isPublicTestType as S,isRunnerProfileId as q}from"../domain/identifiers.js";import{isEngineProfileIdentity as T}from"../engines/definitions.js";import{isUnknownRecord as E}from"../kernel/unknown-values.js";import{requireObjectRecord as s,requireNumber as p,requireStringArray as B,optionalBoolean as h,optionalNonNegativeNumber as m,requireUnknownArray as v,requireString as d,requireResultsReferencePath as k,optionalStringValue as o,optionalNullableStringValue as f,optionalNumberOrStringValue as L,optionalNullableNumberValue as R}from"./read-fields.js";export function readRunDocument(t,n){const e=s(t,n);if(e.schemaVersion!==19)throw new Error(`${n}.schemaVersion must be 19`);const i=M(e.run,`${n}.run`),r=a(e.services,`${n}.services`,D)??[];e.archive!==void 0&&s(e.archive,`${n}.archive`),e.finalizationFailure!==void 0&&Z(e.finalizationFailure,`${n}.finalizationFailure`),o(e.generatedAt,`${n}.generatedAt`);const u=W(e.summary,`${n}.summary`),c=e.environment===void 0?void 0:x(e.environment,`${n}.environment`),y=e.logs===void 0?void 0:V(e.logs,`${n}.logs`),$=e.setup===void 0?void 0:P(e.setup,`${n}.setup`);return{...e,schemaVersion:19,...u===void 0?{}:{summary:u},run:i,services:r,...c===void 0?{}:{environment:c},...y===void 0?{}:{logs:y},...$===void 0?{}:{setup:$}}}function M(t,n){const e=s(t,n);return R(e.durationMs,`${n}.durationMs`),a(e.types,`${n}.types`,d),{...e,finishedAt:f(e.finishedAt,`${n}.finishedAt`)??null,id:f(e.id,`${n}.id`)??null,startedAt:d(e.startedAt,`${n}.startedAt`),status:d(e.status,`${n}.status`)}}function x(t,n){const e=s(t,n),i=a(e.services,`${n}.services`,U);return{...e,...i===void 0?{}:{services:i}}}function U(t,n){const e=s(t,n);return{...e,attempts:a(e.attempts,`${n}.attempts`,(i,r)=>{const u=s(i,r);return{...u,outcome:d(u.outcome,`${r}.outcome`),port:p(u.port,`${r}.port`)}})??[],baseUrl:d(e.baseUrl,`${n}.baseUrl`),port:p(e.port,`${n}.port`),readyUrl:f(e.readyUrl,`${n}.readyUrl`)??null,runtimeLabel:d(e.runtimeLabel,`${n}.runtimeLabel`),serviceName:d(e.serviceName,`${n}.serviceName`)}}function V(t,n){const e=s(t,n),i=a(e.services,`${n}.services`,K),r=a(e.setup,`${n}.setup`,F);return{...e,...i===void 0?{}:{services:i},...r===void 0?{}:{setup:r}}}function P(t,n){const e=s(t,n),i=a(e.operations,`${n}.operations`,Q);return{...e,...i===void 0?{}:{operations:i}}}function D(t,n){const e=s(t,n),i=a(e.suites,`${n}.suites`,O)??[];return{...e,name:d(e.name,`${n}.name`),suites:i}}function O(t,n){const e=s(t,n);if(e.testType!=="scenario"&&!S(e.testType))throw new Error(`${n}.testType must be a public test type`);if(!C(e.engineId))throw new Error(`${n}.engineId must be a supported engine id`);if(!q(e.profileId))throw new Error(`${n}.profileId must be a supported runner profile id`);if(!(e.testType==="scenario"?e.engineId==="k6"&&e.profileId==="k6-http":T(e)))throw new Error(`${n}.profileId does not match ${e.engineId}/${e.testType}`);const r=a(e.files,`${n}.files`,z);return h(e.failed,`${n}.failed`),N(e.diagnostics,`${n}.diagnostics`),m(e.completedFileCount,`${n}.completedFileCount`),m(e.failedFileCount,`${n}.failedFileCount`),m(e.fileCount,`${n}.fileCount`),m(e.passedFileCount,`${n}.passedFileCount`),m(e.skippedFileCount,`${n}.skippedFileCount`),{...e,files:r,name:d(e.name,`${n}.name`),testType:e.testType,engineId:e.engineId,profileId:e.profileId}}function z(t,n){const e=s(t,n),i=a(e.artifacts,`${n}.artifacts`,j),r=a(e.failureDetails,`${n}.failureDetails`,G);return h(e.blockedByRuntime,`${n}.blockedByRuntime`),h(e.failed,`${n}.failed`),h(e.infraFailed,`${n}.infraFailed`),f(e.reason,`${n}.reason`),f(e.runtimeIsolation,`${n}.runtimeIsolation`),e.runtimeBatch!=null&&X(e.runtimeBatch,`${n}.runtimeBatch`),a(e.runtimeResets,`${n}.runtimeResets`,Y),{...e,error:f(e.error,`${n}.error`),artifacts:i,durationMs:R(e.durationMs,`${n}.durationMs`),failureDetails:r,path:d(e.path,`${n}.path`),status:d(e.status,`${n}.status`)}}function j(t,n){const e=s(t,n);return{...e,contentType:f(e.contentType,`${n}.contentType`),kind:f(e.kind,`${n}.kind`),summary:f(e.summary,`${n}.summary`),name:d(e.name,`${n}.name`),path:k(e.path,`${n}.path`)}}function G(t,n){const e=s(t,n),i=e.request===void 0?void 0:H(e.request,`${n}.request`),r=e.response===void 0?void 0:J(e.response,`${n}.response`),u=e.location===void 0?void 0:s(e.location,`${n}.location`);return u!==void 0&&(o(u.path,`${n}.location.path`),u.line!==void 0&&p(u.line,`${n}.location.line`),u.column!==void 0&&p(u.column,`${n}.location.column`)),{...e,key:o(e.key,`${n}.key`),kind:o(e.kind,`${n}.kind`),message:o(e.message,`${n}.message`),stack:o(e.stack,`${n}.stack`),location:u,request:i,response:r,title:d(e.title,`${n}.title`)}}function H(t,n){const e=s(t,n);return{...e,method:o(e.method,`${n}.method`),path:o(e.path,`${n}.path`),requestId:o(e.requestId,`${n}.requestId`)}}function J(t,n){const e=s(t,n);return{...e,bodyPreview:o(e.bodyPreview,`${n}.bodyPreview`),contentType:o(e.contentType,`${n}.contentType`),status:L(e.status,`${n}.status`)}}function K(t,n){const e=s(t,n);return{...e,path:k(e.path,`${n}.path`),runtimeLabel:d(e.runtimeLabel,`${n}.runtimeLabel`),serviceName:d(e.serviceName,`${n}.serviceName`)}}function Q(t,n){const e=s(t,n),i=e.logRef==null?e.logRef:F(e.logRef,`${n}.logRef`);return{...e,durationMs:R(e.durationMs,`${n}.durationMs`),error:f(e.error,`${n}.error`),summary:f(e.summary,`${n}.summary`),logRef:i,serviceName:d(e.serviceName,`${n}.serviceName`),stage:d(e.stage,`${n}.stage`),startedAt:o(e.startedAt,`${n}.startedAt`),status:d(e.status,`${n}.status`)}}function F(t,n){const e=s(t,n);return o(e.runtimeLabel,`${n}.runtimeLabel`),o(e.serviceName,`${n}.serviceName`),o(e.stage,`${n}.stage`),{...e,path:k(e.path,`${n}.path`)}}function W(t,n){if(t===void 0)return;const e=s(t,n),i=e.files===void 0?{}:s(e.files,`${n}.files`),r=e.services===void 0?{}:s(e.services,`${n}.services`),u=e.suites===void 0?{}:s(e.suites,`${n}.suites`),c=(y,$,A)=>{const g=y[$];if(g===void 0)return 0;if(typeof g!="number"||!Number.isFinite(g)||g<0)throw new Error(`${n}.${A}.${$} must be a non-negative finite number`);return g};return N(e.diagnostics,`${n}.diagnostics`),{...e,files:{blockedByRuntime:c(i,"blockedByRuntime","files"),cancelled:c(i,"cancelled","files"),failed:c(i,"failed","files"),infraFailed:c(i,"infraFailed","files"),interrupted:c(i,"interrupted","files"),notRun:c(i,"notRun","files"),passed:c(i,"passed","files"),skipped:c(i,"skipped","files"),total:c(i,"total","files")},services:{blockedByRuntime:c(r,"blockedByRuntime","services"),failed:c(r,"failed","services"),infraFailed:c(r,"infraFailed","services"),passed:c(r,"passed","services"),skipped:c(r,"skipped","services"),total:c(r,"total","services")},suites:{completed:c(u,"completed","suites"),failed:c(u,"failed","suites"),passed:c(u,"passed","suites"),skipped:c(u,"skipped","suites"),total:c(u,"total","suites")}}}function N(t,n){if(t!==void 0)return v(t,n).map((e,i)=>{const r=`${n}[${String(i)}]`,u=s(e,r);return{...u,code:d(u.code,`${r}.code`),message:d(u.message,`${r}.message`),service:o(u.service,`${r}.service`),suite:o(u.suite,`${r}.suite`)}})}function X(t,n){const e=s(t,n);return{...e,id:o(e.id,`${n}.id`),fileCount:m(e.fileCount,`${n}.fileCount`),index:m(e.index,`${n}.index`),files:e.files===void 0?void 0:B(e.files,`${n}.files`)}}function Y(t,n){const e=s(t,n);return{...e,position:o(e.position,`${n}.position`),reason:o(e.reason,`${n}.reason`),runtimeIsolation:o(e.runtimeIsolation,`${n}.runtimeIsolation`),trigger:o(e.trigger,`${n}.trigger`)}}function Z(t,n){const e=s(t,n),i=e.operation===void 0?void 0:s(e.operation,`${n}.operation`);return{...e,name:d(e.name,`${n}.name`),message:d(e.message,`${n}.message`),code:o(e.code,`${n}.code`),stack:o(e.stack,`${n}.stack`),phase:o(e.phase,`${n}.phase`),exitCode:e.exitCode===void 0?void 0:p(e.exitCode,`${n}.exitCode`),status:e.status===void 0?void 0:p(e.status,`${n}.status`),diagnostics:e.diagnostics===void 0?void 0:I(e.diagnostics,`${n}.diagnostics`),operation:i===void 0?void 0:{...i,id:o(i.id,`${n}.operation.id`),source:d(i.source,`${n}.operation.source`),name:d(i.name,`${n}.operation.name`),kind:d(i.kind,`${n}.operation.kind`),summary:o(i.summary,`${n}.operation.summary`),status:o(i.status,`${n}.operation.status`),error:o(i.error,`${n}.operation.error`),scope:I(i.scope,`${n}.operation.scope`)}}}function I(t,n){return Object.fromEntries(Object.entries(s(t,n)).map(([e,i])=>[e,w(i,`${n}.${e}`)]))}function w(t,n){return t===null||typeof t=="string"||typeof t=="boolean"?t:Array.isArray(t)?v(t,n).map((e,i)=>w(e,`${n}[${String(i)}]`)):E(t)?I(t,n):p(t,n)}function a(t,n,e){return t===void 0?void 0:v(t,n).map((i,r)=>e(i,`${n}[${String(r)}]`))}
@@ -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 k,recordWork as h}from"../kernel/work-metrics.js";import a from"fs";import{posixPath as S}from"../process/files/paths.js";import l from"path";import{normalizeEngineJsonValue as g}from"../engines/api/index.js";import{readJsonFile as p}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=S(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:g(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`)}
@@ -118,6 +118,18 @@ export interface ReportingServiceLogReference extends ReportingRecord {
118
118
  runtimeLabel: string;
119
119
  serviceName: string;
120
120
  }
121
+ export interface ReportingEnvironmentServiceAttempt extends ReportingRecord {
122
+ outcome: string;
123
+ port: number;
124
+ }
125
+ export interface ReportingEnvironmentService extends ReportingRecord {
126
+ attempts: ReportingEnvironmentServiceAttempt[];
127
+ baseUrl: string;
128
+ port: number;
129
+ readyUrl: null | string;
130
+ runtimeLabel: string;
131
+ serviceName: string;
132
+ }
121
133
  export interface ReportingSetupLogReference extends ReportingRecord {
122
134
  path: string;
123
135
  runtimeLabel?: string;
@@ -215,6 +227,9 @@ export interface RunArtifactDocument extends ReportingRecord {
215
227
  summary?: RunArtifactSummary;
216
228
  schemaVersion: 19;
217
229
  archive?: ReportingRecord;
230
+ environment?: {
231
+ services?: ReportingEnvironmentService[];
232
+ };
218
233
  finalizationFailure?: SerializedError;
219
234
  logs?: {
220
235
  services?: ReportingServiceLogReference[];
@@ -231,6 +246,9 @@ export interface ReportedRunArtifact extends RunArtifactDocument {
231
246
  declaredEnvironmentKeys: string[];
232
247
  request: NormalizedArtifactArchiveConfig;
233
248
  };
249
+ environment: {
250
+ services: ReportingEnvironmentService[];
251
+ };
234
252
  generatedAt: string;
235
253
  git: ReportingRunGitMetadata;
236
254
  logs: {
@@ -301,6 +319,7 @@ export interface RunArtifactSummary extends ReportingRecord {
301
319
  export interface BuildRunArtifactOptions {
302
320
  archiveConfig?: NormalizedArtifactArchiveConfig | null;
303
321
  declaredEnvironmentKeys?: readonly string[];
322
+ environmentServices?: readonly ReportingEnvironmentService[];
304
323
  execution: ReportingExecution;
305
324
  fileNames: readonly string[];
306
325
  finishedAt: null | number;
@@ -1,3 +1,3 @@
1
1
  import { type BuildLiveRunArtifactOptions, type BuildRunArtifactOptions, type ReportedRunArtifact } from "./reporting-types.js";
2
- export declare function buildRunArtifact({ productDir, runId, results, startedAt, finishedAt, execution, workerCount, runtimeInstanceCount, runtimeStats, typeValues, suiteSelectors, fileNames, serviceFilter, planning, archiveConfig, declaredEnvironmentKeys, metadata, summarizeDbBackend, serviceLogs, setupLogs, setupOperations, operationTimings, runInterruptReason, runStatus, }: BuildRunArtifactOptions): ReportedRunArtifact;
3
- export declare function buildLiveRunArtifact({ productDir, runId, results, startedAt, updatedAt, execution, workerCount, runtimeInstanceCount, runtimeStats, typeValues, suiteSelectors, fileNames, serviceFilter, planning, archiveConfig, declaredEnvironmentKeys, metadata, summarizeDbBackend, serviceLogs, setupLogs, setupOperations, operationTimings, }: BuildLiveRunArtifactOptions): ReportedRunArtifact;
2
+ export declare function buildRunArtifact({ productDir, runId, results, startedAt, finishedAt, execution, workerCount, runtimeInstanceCount, runtimeStats, typeValues, suiteSelectors, fileNames, serviceFilter, planning, archiveConfig, declaredEnvironmentKeys, metadata, summarizeDbBackend, environmentServices, serviceLogs, setupLogs, setupOperations, operationTimings, runInterruptReason, runStatus, }: BuildRunArtifactOptions): ReportedRunArtifact;
3
+ export declare function buildLiveRunArtifact({ productDir, runId, results, startedAt, updatedAt, execution, workerCount, runtimeInstanceCount, runtimeStats, typeValues, suiteSelectors, fileNames, serviceFilter, planning, archiveConfig, declaredEnvironmentKeys, metadata, summarizeDbBackend, environmentServices, serviceLogs, setupLogs, setupOperations, operationTimings, }: BuildLiveRunArtifactOptions): ReportedRunArtifact;
@@ -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 $ from"path";import{DEFAULT_REPORTED_ARCHIVE_CONFIG as ee}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,environmentServices:y=[],serviceLogs:v=[],setupLogs:b=[],setupOperations:D=[],operationTimings:M=[],runInterruptReason:A=null,runStatus:E=null}){const u=i.filter(t=>!t.skipped),z=u.filter(x),B=u.filter(t=>t.failed),w=u.filter(t=>t.infraFailed),N=u.filter(t=>t.blockedByRuntime),V=u.filter(t=>te(t)),I=oe(u),H=ne(u),_=r(u,"totalFileCount"),L=r(u,"passedFileCount"),P=r(u,"failedFileCount"),j=r(u,"skippedFileCount"),G=r(u,"notRunFileCount"),O=p(u,t=>t.status==="cancelled"),T=p(u,t=>t.status==="interrupted"),J=Math.max(0,G-O-T),K=p(u,t=>t.infraFailed===!0),U=p(u,t=>t.blockedByRuntime===!0),q=R(i),Q=typeof q=="string"?q:null,W=new Date(s??Date.now()).toISOString(),X=s===null?null:new Date(s).toISOString(),Y=s===null?null:s-l,Z=S??ee;return{schemaVersion:19,source:"testkit",generatedAt:W,product:{name:$.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:E||(B.length>0||w.length>0?"failed":"passed"),startedAt:new Date(l).toISOString(),finishedAt:X,durationMs:Y,workers:o.taskConcurrency,fileTimeoutSeconds:o.fileTimeoutSeconds,workerCount:a,runtimeInstanceCount:d,runtimeStats:[...m??[]],dbBackend:Q,types:[...g],suiteSelectors:k.map(t=>t.raw),fileNames:[...F],serviceFilter:C,testkitVersion:c.testkitVersion,...A===null?{}:{interruptReason:A}},archive:{request:Z,declaredEnvironmentKeys:[...new Set(h)].sort()},...f?{planning:f}:{},summary:{services:{total:u.length,passed:V.length,failed:B.length,infraFailed:w.length,blockedByRuntime:N.length,skipped:z.length},suites:H,files:{total:_,passed:L,failed:P,skipped:j,notRun:J,cancelled:O,interrupted:T,infraFailed:K,blockedByRuntime:U},...I.length>0?{diagnostics:I}:{}},environment:{services:[...y]},logs:{services:[...v],setup:[...b]},setup:{operations:[...D]},timings:{operations:le(M)},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,environmentServices:y=[],serviceLogs:v=[],setupLogs:b=[],setupOperations:D=[],operationTimings:M=[]}){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,environmentServices:y,serviceLogs:v,setupLogs:b,setupOperations:D,operationTimings:M,runStatus:"running"}),generatedAt:new Date(s).toISOString()}}function x(n){return!n.skipped&&!n.failed&&n.skippedSuiteCount>0&&n.skippedSuiteCount===n.suiteCount&&n.notRunFileCount===0}function te(n){return!n.failed&&!n.infraFailed&&!x(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 ne(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=ie(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=se(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 ie(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 se(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 oe(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 le(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=>ue(i)?{...i}:i),metadata:e.metadata?{...e.metadata}:{}}))}function ue(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}
@@ -1,7 +1,6 @@
1
1
  import crypto from "crypto";
2
2
  import type { RunArtifactDocument } from "./reporting-types.js";
3
3
  import { type RunBundleArtifact, type UnknownRecord } from "./contracts.js";
4
- export { isObjectRecord } from "./read-fields.js";
5
4
  export declare function readJsonFile(filePath: string): unknown;
6
5
  export declare function runIncludesFile(artifact: RunBundleArtifact, selector: string): boolean;
7
6
  export declare function requireRunId(artifact: RunArtifactDocument): string;
@@ -23,5 +22,4 @@ export declare function optionalUnknownArray(value: unknown): unknown[];
23
22
  export declare function errorMessage(error: unknown): string;
24
23
  export declare function bundleRelativePath(runId: string, child: string): string;
25
24
  export declare function resultsRoot(productDir: string): string;
26
- export declare function normalizePath(filePath: string): string;
27
25
  export declare function sanitizeSegment(value: string): string;
@@ -1,2 +1,2 @@
1
- import{isWorkObserved as f,recordWork as l}from"../kernel/work-metrics.js";import{isPathWithin as p}from"../process/files/paths.js";import x from"crypto";import i from"fs";import o from"path";import{RUNS_DIRNAME as m}from"./contracts.js";import{isObjectRecord as w,requireManifestRelativePath as v}from"./read-fields.js";export{isObjectRecord}from"./read-fields.js";export function readJsonFile(r){try{let t;if(f()){const n=i.readFileSync(r);l("json.filesRead",1),l("json.bytesRead",n.byteLength),t=n.toString("utf8")}else t=i.readFileSync(r,"utf8");return JSON.parse(t)}catch(t){throw new Error(`Invalid JSON in ${r}: ${errorMessage(t)}`,{cause:t})}}export function runIncludesFile(r,t){const e=normalizePath(t);return r.services.some(n=>n.suites.some(u=>u.files?.some(s=>s.path===e||s.path.endsWith(e))))}export function requireRunId(r){const t=r.run.id==null?null:normalizeRunId(r.run.id);if(t===null)throw new Error("Cannot seal a run bundle without a run id");return t}export function normalizeRunId(r){const t=typeof r=="string"?r:"";if(!t||t==="."||t===".."||t.includes("\0")||t.includes("/")||t.includes("\\"))throw new Error(`Invalid Testkit run id: ${t||"<empty>"}`);return t}export function walkFiles(r){if(!i.existsSync(r))return[];const t=[];for(const e of i.readdirSync(r,{withFileTypes:!0})){const n=o.join(r,e.name);e.isDirectory()?t.push(...walkFiles(n)):e.isFile()&&t.push(n)}return t}export function treeBytes(r){return walkFiles(r).reduce((t,e)=>t+i.statSync(e).size,0)}export function writeBufferAtomic(r,t){i.mkdirSync(o.dirname(r),{recursive:!0});const e=`${r}.${String(process.pid)}.${String(Date.now())}.tmp`;i.writeFileSync(e,t);try{i.renameSync(e,r)}catch(n){if(i.rmSync(e,{force:!0}),!i.existsSync(r))throw n}}export function writeJson(r,t){i.mkdirSync(o.dirname(r),{recursive:!0});const e=JSON.stringify(t,null,2);l("json.serializations"),f()&&l("json.bytesSerialized",Buffer.byteLength(e)),i.writeFileSync(r,`${e}
2
- `)}export function hashFile(r){const t=i.readFileSync(r);return l("evidence.hashFilesRead",1),l("evidence.hashBytesRead",t.byteLength),sha256(t)}export function sha256(r){return x.createHash("sha256").update(r).digest("hex")}export function stableJson(r){const t=JSON.stringify(d(r));return l("json.canonicalSerializations"),f()&&l("json.canonicalBytesSerialized",Buffer.byteLength(t)),t}function d(r){return Array.isArray(r)?r.map(d):w(r)?Object.fromEntries(Object.keys(r).sort().map(t=>[t,d(r[t])])):r}export function objectRecords(r){return Array.isArray(r)?r.filter(w):[]}export function resolveRunBundleDirectory(r,t){const e=resolveRunsRoot(r,!1),n=o.join(e,t),u=i.lstatSync(n,{throwIfNoEntry:!1});if(u===void 0)return n;if(u.isSymbolicLink())throw new Error(`Immutable run bundle directory must not be a symbolic link: ${t}`);if(!u.isDirectory())throw new Error(`Immutable run bundle path must be a directory: ${t}`);const s=i.realpathSync(e),c=i.realpathSync(n),a=o.relative(s,c);if(a.length===0||a===".."||a.startsWith(`..${o.sep}`)||o.isAbsolute(a))throw new Error(`Immutable run bundle directory must resolve within the runs root: ${t}`);return n}export function resolveRunsRoot(r,t){const e=o.resolve(r),n=resultsRoot(e),u=o.join(n,m);if(t)g(e,n,"Testkit results root"),i.mkdirSync(n,{recursive:!0});else if(!i.existsSync(n))return u;const s=S(n,"Testkit results root");if(y(i.realpathSync(e),s,"Testkit results root must resolve within the product directory"),t)i.mkdirSync(u,{recursive:!0});else if(!i.existsSync(u))return u;const c=S(u,"Immutable run bundles root");return y(s,c,"Immutable run bundles root must resolve within .testkit/results"),u}function g(r,t,e){const n=o.resolve(r),u=i.realpathSync(n);let s=o.resolve(t),c=i.lstatSync(s,{throwIfNoEntry:!1});for(;c===void 0;){const a=o.dirname(s);if(a===s)throw new Error(`${e} has no existing parent directory`);s=a,c=i.lstatSync(s,{throwIfNoEntry:!1})}if(s!==n&&c.isSymbolicLink())throw new Error(`${e} must not traverse a symbolic link`);if(!c.isDirectory())throw new Error(`${e} parent must be a directory`);y(u,i.realpathSync(s),`${e} must resolve within the product directory`,!0)}function S(r,t){const e=i.lstatSync(r,{throwIfNoEntry:!1});if(e===void 0)throw new Error(`${t} does not exist`);if(e.isSymbolicLink())throw new Error(`${t} must not be a symbolic link`);if(!e.isDirectory())throw new Error(`${t} must be a directory`);return i.realpathSync(r)}function y(r,t,e,n=!1){const u=o.relative(r,t);if(!n&&u.length===0||u===".."||u.startsWith(`..${o.sep}`)||o.isAbsolute(u))throw new Error(e)}export function requirePublicationPathOutsideResults(r,t){const e=o.resolve(resultsRoot(r)),n=o.resolve(t);if(p(e,n))throw new Error("Publication directory must be outside .testkit/results");const u=i.realpathSync(e);let s=n,c=i.lstatSync(s,{throwIfNoEntry:!1});for(;c===void 0;){const h=o.dirname(s);if(h===s)throw new Error("Publication directory has no existing parent");s=h,c=i.lstatSync(s,{throwIfNoEntry:!1})}const a=i.realpathSync(s);if(p(u,a))throw new Error("Publication directory must be outside .testkit/results")}export function resolveManifestEntryPath(r,t){const e=o.resolve(r),n=o.resolve(e,v(t,"manifest entry path"));return b(e,n,t),i.existsSync(n)&&b(i.realpathSync(e),i.realpathSync(n),t),n}function b(r,t,e){const n=o.relative(r,t);if(n.length===0||n===".."||n.startsWith(`..${o.sep}`)||o.isAbsolute(n))throw new Error(`manifest path escapes bundle directory: ${e}`)}export function optionalStringArray(r){return Array.isArray(r)?r.filter(t=>typeof t=="string"):[]}export function optionalUnknownArray(r){return Array.isArray(r)?r:[]}export function errorMessage(r){return r instanceof Error?r.message:String(r)}export function bundleRelativePath(r,t){return normalizePath(o.join(".testkit","results",m,r,t))}export function resultsRoot(r){return o.join(r,".testkit","results")}export function normalizePath(r){return r.split(o.sep).join("/")}export function sanitizeSegment(r){return r.toLowerCase().replace(/[^a-z0-9._-]+/gu,"-").replace(/^-+|-+$/gu,"")||"product"}
1
+ import{isWorkObserved as f,recordWork as l}from"../kernel/work-metrics.js";import{isPathWithin as p}from"../process/files/paths.js";import{isUnknownRecord as m}from"../kernel/unknown-values.js";import v from"crypto";import i from"fs";import o from"path";import{RUNS_DIRNAME as w}from"./contracts.js";import{requireManifestRelativePath as g}from"./read-fields.js";import{posixPath as S}from"../process/files/paths.js";export function readJsonFile(r){try{let t;if(f()){const n=i.readFileSync(r);l("json.filesRead",1),l("json.bytesRead",n.byteLength),t=n.toString("utf8")}else t=i.readFileSync(r,"utf8");return JSON.parse(t)}catch(t){throw new Error(`Invalid JSON in ${r}: ${errorMessage(t)}`,{cause:t})}}export function runIncludesFile(r,t){const e=S(t);return r.services.some(n=>n.suites.some(u=>u.files?.some(s=>s.path===e||s.path.endsWith(e))))}export function requireRunId(r){const t=r.run.id==null?null:normalizeRunId(r.run.id);if(t===null)throw new Error("Cannot seal a run bundle without a run id");return t}export function normalizeRunId(r){const t=typeof r=="string"?r:"";if(!t||t==="."||t===".."||t.includes("\0")||t.includes("/")||t.includes("\\"))throw new Error(`Invalid Testkit run id: ${t||"<empty>"}`);return t}export function walkFiles(r){if(!i.existsSync(r))return[];const t=[];for(const e of i.readdirSync(r,{withFileTypes:!0})){const n=o.join(r,e.name);e.isDirectory()?t.push(...walkFiles(n)):e.isFile()&&t.push(n)}return t}export function treeBytes(r){return walkFiles(r).reduce((t,e)=>t+i.statSync(e).size,0)}export function writeBufferAtomic(r,t){i.mkdirSync(o.dirname(r),{recursive:!0});const e=`${r}.${String(process.pid)}.${String(Date.now())}.tmp`;i.writeFileSync(e,t);try{i.renameSync(e,r)}catch(n){if(i.rmSync(e,{force:!0}),!i.existsSync(r))throw n}}export function writeJson(r,t){i.mkdirSync(o.dirname(r),{recursive:!0});const e=JSON.stringify(t,null,2);l("json.serializations"),f()&&l("json.bytesSerialized",Buffer.byteLength(e)),i.writeFileSync(r,`${e}
2
+ `)}export function hashFile(r){const t=i.readFileSync(r);return l("evidence.hashFilesRead",1),l("evidence.hashBytesRead",t.byteLength),sha256(t)}export function sha256(r){return v.createHash("sha256").update(r).digest("hex")}export function stableJson(r){const t=JSON.stringify(d(r));return l("json.canonicalSerializations"),f()&&l("json.canonicalBytesSerialized",Buffer.byteLength(t)),t}function d(r){return Array.isArray(r)?r.map(d):m(r)?Object.fromEntries(Object.keys(r).sort().map(t=>[t,d(r[t])])):r}export function objectRecords(r){return Array.isArray(r)?r.filter(m):[]}export function resolveRunBundleDirectory(r,t){const e=resolveRunsRoot(r,!1),n=o.join(e,t),u=i.lstatSync(n,{throwIfNoEntry:!1});if(u===void 0)return n;if(u.isSymbolicLink())throw new Error(`Immutable run bundle directory must not be a symbolic link: ${t}`);if(!u.isDirectory())throw new Error(`Immutable run bundle path must be a directory: ${t}`);const s=i.realpathSync(e),c=i.realpathSync(n),a=o.relative(s,c);if(a.length===0||a===".."||a.startsWith(`..${o.sep}`)||o.isAbsolute(a))throw new Error(`Immutable run bundle directory must resolve within the runs root: ${t}`);return n}export function resolveRunsRoot(r,t){const e=o.resolve(r),n=resultsRoot(e),u=o.join(n,w);if(t)E(e,n,"Testkit results root"),i.mkdirSync(n,{recursive:!0});else if(!i.existsSync(n))return u;const s=b(n,"Testkit results root");if(y(i.realpathSync(e),s,"Testkit results root must resolve within the product directory"),t)i.mkdirSync(u,{recursive:!0});else if(!i.existsSync(u))return u;const c=b(u,"Immutable run bundles root");return y(s,c,"Immutable run bundles root must resolve within .testkit/results"),u}function E(r,t,e){const n=o.resolve(r),u=i.realpathSync(n);let s=o.resolve(t),c=i.lstatSync(s,{throwIfNoEntry:!1});for(;c===void 0;){const a=o.dirname(s);if(a===s)throw new Error(`${e} has no existing parent directory`);s=a,c=i.lstatSync(s,{throwIfNoEntry:!1})}if(s!==n&&c.isSymbolicLink())throw new Error(`${e} must not traverse a symbolic link`);if(!c.isDirectory())throw new Error(`${e} parent must be a directory`);y(u,i.realpathSync(s),`${e} must resolve within the product directory`,!0)}function b(r,t){const e=i.lstatSync(r,{throwIfNoEntry:!1});if(e===void 0)throw new Error(`${t} does not exist`);if(e.isSymbolicLink())throw new Error(`${t} must not be a symbolic link`);if(!e.isDirectory())throw new Error(`${t} must be a directory`);return i.realpathSync(r)}function y(r,t,e,n=!1){const u=o.relative(r,t);if(!n&&u.length===0||u===".."||u.startsWith(`..${o.sep}`)||o.isAbsolute(u))throw new Error(e)}export function requirePublicationPathOutsideResults(r,t){const e=o.resolve(resultsRoot(r)),n=o.resolve(t);if(p(e,n))throw new Error("Publication directory must be outside .testkit/results");const u=i.realpathSync(e);let s=n,c=i.lstatSync(s,{throwIfNoEntry:!1});for(;c===void 0;){const h=o.dirname(s);if(h===s)throw new Error("Publication directory has no existing parent");s=h,c=i.lstatSync(s,{throwIfNoEntry:!1})}const a=i.realpathSync(s);if(p(u,a))throw new Error("Publication directory must be outside .testkit/results")}export function resolveManifestEntryPath(r,t){const e=o.resolve(r),n=o.resolve(e,g(t,"manifest entry path"));return x(e,n,t),i.existsSync(n)&&x(i.realpathSync(e),i.realpathSync(n),t),n}function x(r,t,e){const n=o.relative(r,t);if(n.length===0||n===".."||n.startsWith(`..${o.sep}`)||o.isAbsolute(n))throw new Error(`manifest path escapes bundle directory: ${e}`)}export function optionalStringArray(r){return Array.isArray(r)?r.filter(t=>typeof t=="string"):[]}export function optionalUnknownArray(r){return Array.isArray(r)?r:[]}export function errorMessage(r){return r instanceof Error?r.message:String(r)}export function bundleRelativePath(r,t){return S(o.join(".testkit","results",w,r,t))}export function resultsRoot(r){return o.join(r,".testkit","results")}export function sanitizeSegment(r){return r.toLowerCase().replace(/[^a-z0-9._-]+/gu,"-").replace(/^-+|-+$/gu,"")||"product"}
@@ -1 +1 @@
1
- export function createEmptyTimings(){return{version:2,files:{}}}export function normalizeTimings(t){if(!m(t)||t.version!==2||!m(t.files))return createEmptyTimings();const n={};for(const[e,r]of Object.entries(t.files)){if(!m(r))continue;const u=D(r);u&&(n[e]=u)}return{version:2,files:n}}export function applyTimingUpdates(t,n,e=new Date().toISOString()){const r={...t.files},u=e||null;for(const o of n){const i=Math.max(1,Math.round(o.durationMs)),s=r[o.key];if(!s){r[o.key]={durationMs:i,avgDurationMs:i,lastDurationMs:i,minDurationMs:i,maxDurationMs:i,runs:1,lastStatus:o.status||null,updatedAt:u};continue}const M=s.runs,c=M+1,d=s.avgDurationMs||s.durationMs||i,f=Math.max(1,Math.round((d*M+i)/c));r[o.key]={durationMs:f,avgDurationMs:f,lastDurationMs:i,minDurationMs:Math.min(s.minDurationMs||i,i),maxDurationMs:Math.max(s.maxDurationMs||i,i),runs:c,lastStatus:(o.status||null)??s.lastStatus,updatedAt:u}}return{version:2,files:r}}function D(t){if(!p(t.durationMs))return null;const n=a(t.durationMs);return{durationMs:n,avgDurationMs:a(t.avgDurationMs,n),lastDurationMs:a(t.lastDurationMs,n),minDurationMs:a(t.minDurationMs,n),maxDurationMs:a(t.maxDurationMs,n),runs:g(t.runs),lastStatus:l(t.lastStatus),updatedAt:l(t.updatedAt)}}function p(t){return typeof t=="number"?Number.isFinite(t):typeof t!="string"||t.trim().length===0?!1:Number.isFinite(Number(t))}function a(t,n=0){const r=Number(t||n);return Number.isFinite(r)?Math.max(0,Math.round(r)):n}function g(t){const n=Number(t||0);return Number.isFinite(n)?Math.max(0,Math.floor(n)):0}function l(t){return typeof t=="string"&&t.length>0?t:null}function m(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}
1
+ import{isUnknownRecord as m}from"../kernel/unknown-values.js";export function createEmptyTimings(){return{version:2,files:{}}}export function normalizeTimings(t){if(!m(t)||t.version!==2||!m(t.files))return createEmptyTimings();const n={};for(const[e,r]of Object.entries(t.files)){if(!m(r))continue;const u=D(r);u&&(n[e]=u)}return{version:2,files:n}}export function applyTimingUpdates(t,n,e=new Date().toISOString()){const r={...t.files},u=e||null;for(const o of n){const i=Math.max(1,Math.round(o.durationMs)),s=r[o.key];if(!s){r[o.key]={durationMs:i,avgDurationMs:i,lastDurationMs:i,minDurationMs:i,maxDurationMs:i,runs:1,lastStatus:o.status||null,updatedAt:u};continue}const M=s.runs,f=M+1,d=s.avgDurationMs||s.durationMs||i,l=Math.max(1,Math.round((d*M+i)/f));r[o.key]={durationMs:l,avgDurationMs:l,lastDurationMs:i,minDurationMs:Math.min(s.minDurationMs||i,i),maxDurationMs:Math.max(s.maxDurationMs||i,i),runs:f,lastStatus:(o.status||null)??s.lastStatus,updatedAt:u}}return{version:2,files:r}}function D(t){if(!p(t.durationMs))return null;const n=a(t.durationMs);return{durationMs:n,avgDurationMs:a(t.avgDurationMs,n),lastDurationMs:a(t.lastDurationMs,n),minDurationMs:a(t.minDurationMs,n),maxDurationMs:a(t.maxDurationMs,n),runs:g(t.runs),lastStatus:c(t.lastStatus),updatedAt:c(t.updatedAt)}}function p(t){return typeof t=="number"?Number.isFinite(t):typeof t!="string"||t.trim().length===0?!1:Number.isFinite(Number(t))}function a(t,n=0){const r=Number(t||n);return Number.isFinite(r)?Math.max(0,Math.round(r)):n}function g(t){const n=Number(t||0);return Number.isFinite(n)?Math.max(0,Math.floor(n)):0}function c(t){return typeof t=="string"&&t.length>0?t:null}
@@ -36,3 +36,5 @@ export declare function formatError(error: unknown): string;
36
36
  export declare function sanitizeErrorMessage(message: string): string;
37
37
  export declare function errorDetail(error: unknown): string;
38
38
  export declare function serializeError(error: unknown, { includeStack }?: Readonly<SerializeErrorOptions>): SerializedError;
39
+ export declare function toError(value: unknown): Error;
40
+ export declare function hasErrorCode(error: unknown, code: string): boolean;
@@ -1 +1 @@
1
- const g="testkitOperation",m="testkitDiagnostics",c=String;export function attachErrorOperation(t,n){if(!r(t)||!r(n)||s(t,g))return t;const e=y(n);return e!==null&&d(t,g,e),t}export function attachErrorDiagnostics(t,n){if(!r(t)||!r(n))return t;const e=getErrorDiagnostics(t),i={...f(e),...f(n)};return d(t,m,i),t}export function getErrorOperation(t){return r(t)?y(s(t,g)||s(t,"operation")):null}export function getErrorDiagnostics(t){return r(t)?f(s(t,m)||s(t,"diagnostics")):{}}export function errorMessage(t){return t instanceof Error?t.message:c(t)}export function formatError(t){return sanitizeErrorMessage(errorMessage(t))}export function sanitizeErrorMessage(t){return t.replace(/(postgres(?:ql)?:\/\/[^:\s"'@]+:)[^@\s"']+(@)/gi,"$1<redacted>$2").replace(/("password"\s*:\s*")[^"]*(")/gi,"$1<redacted>$2").replace(/('password'\s*:\s*')[^']*(')/gi,"$1<redacted>$2").replace(/(PGPASSWORD=)[^\s'"\\]+/g,"$1<redacted>")}export function errorDetail(t){if(r(t)){const n=s(t,"stack");if(typeof n=="string"&&n.length>0)return n;const e=s(t,"message");if(typeof e=="string"&&e.length>0)return e}return t instanceof Error?t.stack||t.message:c(t)}export function serializeError(t,{includeStack:n=!1}={}){if(t instanceof Error){const e=getErrorOperation(t),i=getErrorDiagnostics(t),o=s(t,"code"),u=s(t,"exitCode"),a=s(t,"status");return{name:t.name||"Error",message:t.message||c(t),...typeof o=="string"?{code:o}:{},...typeof u=="number"&&Number.isInteger(u)?{exitCode:u}:{},...typeof a=="number"&&Number.isInteger(a)?{status:a}:{},...e?{phase:e.name,operation:e}:{},...Object.keys(i).length>0?{diagnostics:i}:{},...n&&typeof t.stack=="string"?{stack:t.stack}:{}}}return{name:"Error",message:c(t)}}function d(t,n,e){Object.defineProperty(t,n,{value:e,configurable:!0,enumerable:!1,writable:!0})}function y(t){if(!r(t))return null;const n=s(t,"id"),e=s(t,"source"),i=s(t,"name"),o=s(t,"kind"),u=s(t,"summary"),a=s(t,"status"),p=s(t,"error");return{...n?{id:c(n)}:{},source:typeof e=="string"?e:"testkit",name:typeof i=="string"&&i?i:"operation",kind:typeof o=="string"&&o?o:"operation",...u?{summary:c(u)}:{},scope:f(s(t,"scope")),...a?{status:c(a)}:{},...p?{error:c(p)}:{}}}function f(t){if(!r(t)||E(t))return{};const n=[];for(const e of Object.keys(t)){const i=s(t,e);i!==void 0&&n.push([e,l(i)])}return Object.fromEntries(n)}function l(t){return t===null?null:typeof t=="string"||typeof t=="number"||typeof t=="boolean"?t:E(t)?t.map(n=>l(n)):r(t)?f(t):c(t)}function s(t,n){return Reflect.get(t,n)}function E(t){return Array.isArray(t)}function r(t){return t!==null&&typeof t=="object"}
1
+ import{isPropertyContainer as O}from"./unknown-values.js";const g="testkitOperation",m="testkitDiagnostics",o=String;export function attachErrorOperation(t,n){if(!i(t)||!i(n)||s(t,g))return t;const e=y(n);return e!==null&&d(t,g,e),t}export function attachErrorDiagnostics(t,n){if(!i(t)||!i(n))return t;const e=getErrorDiagnostics(t),r={...a(e),...a(n)};return d(t,m,r),t}export function getErrorOperation(t){return i(t)?y(s(t,g)||s(t,"operation")):null}export function getErrorDiagnostics(t){return i(t)?a(s(t,m)||s(t,"diagnostics")):{}}export function errorMessage(t){return t instanceof Error?t.message:o(t)}export function formatError(t){return sanitizeErrorMessage(errorMessage(t))}export function sanitizeErrorMessage(t){return t.replace(/(postgres(?:ql)?:\/\/[^:\s"'@]+:)[^@\s"']+(@)/gi,"$1<redacted>$2").replace(/("password"\s*:\s*")[^"]*(")/gi,"$1<redacted>$2").replace(/('password'\s*:\s*')[^']*(')/gi,"$1<redacted>$2").replace(/(PGPASSWORD=)[^\s'"\\]+/g,"$1<redacted>")}export function errorDetail(t){if(i(t)){const n=s(t,"stack");if(typeof n=="string"&&n.length>0)return n;const e=s(t,"message");if(typeof e=="string"&&e.length>0)return e}return t instanceof Error?t.stack||t.message:o(t)}export function serializeError(t,{includeStack:n=!1}={}){if(t instanceof Error){const e=getErrorOperation(t),r=getErrorDiagnostics(t),c=s(t,"code"),u=s(t,"exitCode"),f=s(t,"status");return{name:t.name||"Error",message:t.message||o(t),...typeof c=="string"?{code:c}:{},...typeof u=="number"&&Number.isInteger(u)?{exitCode:u}:{},...typeof f=="number"&&Number.isInteger(f)?{status:f}:{},...e?{phase:e.name,operation:e}:{},...Object.keys(r).length>0?{diagnostics:r}:{},...n&&typeof t.stack=="string"?{stack:t.stack}:{}}}return{name:"Error",message:o(t)}}function d(t,n,e){Object.defineProperty(t,n,{value:e,configurable:!0,enumerable:!1,writable:!0})}function y(t){if(!i(t))return null;const n=s(t,"id"),e=s(t,"source"),r=s(t,"name"),c=s(t,"kind"),u=s(t,"summary"),f=s(t,"status"),p=s(t,"error");return{...n?{id:o(n)}:{},source:typeof e=="string"?e:"testkit",name:typeof r=="string"&&r?r:"operation",kind:typeof c=="string"&&c?c:"operation",...u?{summary:o(u)}:{},scope:a(s(t,"scope")),...f?{status:o(f)}:{},...p?{error:o(p)}:{}}}function a(t){if(!i(t)||E(t))return{};const n=[];for(const e of Object.keys(t)){const r=s(t,e);r!==void 0&&n.push([e,l(r)])}return Object.fromEntries(n)}function l(t){return t===null?null:typeof t=="string"||typeof t=="number"||typeof t=="boolean"?t:E(t)?t.map(n=>l(n)):i(t)?a(t):o(t)}function s(t,n){return Reflect.get(t,n)}function E(t){return Array.isArray(t)}function i(t){return t!==null&&typeof t=="object"}export function toError(t){return t instanceof Error?t:new Error(String(t))}export function hasErrorCode(t,n){return O(t)&&Reflect.get(t,"code")===n}
@@ -4,3 +4,8 @@ export declare function asUnknownRecord(value: unknown): UnknownRecord | null;
4
4
  /** A non-empty string, or null for an empty string and every other value. */
5
5
  export declare function optionalString(value: unknown): string | null;
6
6
  export declare function displayString(value: unknown, fallback: string): string;
7
+ export declare function isUnknownArray(value: unknown): value is unknown[];
8
+ /** Objects and functions: the values Reflect.get accepts as a target. */
9
+ export declare function isPropertyContainer(value: unknown): value is object;
10
+ export declare function readDynamicProperty(value: unknown, key: string): unknown;
11
+ export declare function isNullableString(value: unknown): value is string | null;
@@ -1 +1 @@
1
- export function isUnknownRecord(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}export function asUnknownRecord(n){return isUnknownRecord(n)?n:null}export function optionalString(n){return typeof n=="string"&&n.length>0?n:null}export function displayString(n,r){return optionalString(n)??r}
1
+ export function isUnknownRecord(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}export function asUnknownRecord(n){return isUnknownRecord(n)?n:null}export function optionalString(n){return typeof n=="string"&&n.length>0?n:null}export function displayString(n,r){return optionalString(n)??r}export function isUnknownArray(n){return Array.isArray(n)}export function isPropertyContainer(n){return typeof n=="object"&&n!==null||typeof n=="function"}export function readDynamicProperty(n,r){return isPropertyContainer(n)?Reflect.get(n,r):void 0}export function isNullableString(n){return n===null||typeof n=="string"}
@@ -1 +1 @@
1
- import c from"node:fs/promises";import A from"node:os";import n from"node:path";export const ENGINE_PROCESS_RESERVED_ENVIRONMENT_KEYS=Object.freeze(["APPDATA","ComSpec","HOME","LANG","LC_ALL","LOCALAPPDATA","PATH","PATHEXT","SystemRoot","TEMP","TMP","TMPDIR","USERPROFILE","XDG_CACHE_HOME","XDG_CONFIG_HOME","XDG_DATA_HOME"]);export function nativeTemporaryRoot(t=process.env,o=process.platform){return T(t,o)}export async function createInvocationProcessEnvironment(t,o=process.env,r=process.platform){const e=n.join(t,"tmp");return w(t,e,!0,o,r)}export async function createNativeInvocationProcessEnvironment(t,o={}){const r=o.platform??process.platform,e=o.ambientEnvironment??process.env,s=await v(o.nativeTemporaryRootDirectory??nativeTemporaryRoot(e,r));let a=null;try{const i=await c.mkdtemp(n.join(s,"testkit-engine-"));return a=i,r!=="win32"&&await c.chmod(i,448),a=await P(i,s,r),await w(t,a,!1,e,r)}catch(i){if(a===null)throw i;try{await c.rm(a,{force:!0,recursive:!0})}catch(p){throw new AggregateError([d(i),d(p)],`Could not initialize or remove native invocation temporary directory ${a}`,{cause:p})}throw i}}async function w(t,o,r,e,s){if(!n.isAbsolute(t))throw new Error("Engine invocation directory must be absolute");if(!n.isAbsolute(o))throw new Error("Engine invocation temporary directory must be absolute");const a=n.join(t,"home"),i=n.join(t,"cache"),p=n.join(t,"config"),l=n.join(t,"data"),f=n.join(t,"local-app-data"),E=n.join(t,"app-data");await Promise.all([a,...r?[o]:[],i,p,l,f,E].map(y=>c.mkdir(y,{mode:448})));const m={APPDATA:E,HOME:a,LOCALAPPDATA:f,TEMP:o,TMP:o,TMPDIR:o,USERPROFILE:a,XDG_CACHE_HOME:i,XDG_CONFIG_HOME:p,XDG_DATA_HOME:l};return u(m,e,"LANG"),u(m,e,"LC_ALL"),s==="win32"&&(m.PATH="",u(m,e,"ComSpec"),u(m,e,"SystemRoot")),Object.freeze({environment:Object.freeze(m),homeDirectory:a,temporaryDirectory:o})}async function v(t){if(!n.isAbsolute(t))throw new Error("Native invocation temporary root must be absolute");const o=await c.realpath(t);if(!(await c.stat(o)).isDirectory())throw new Error("Native invocation temporary root must be a directory");return o}async function P(t,o,r){const e=await c.lstat(t);if(!e.isDirectory()||e.isSymbolicLink())throw new Error("Native invocation temporary directory must be a non-symbolic-link directory");if(r!=="win32"&&(e.mode&63)!==0)throw new Error("Native invocation temporary directory must not grant group or other access");const s=await c.realpath(t);if(n.dirname(s)!==o)throw new Error("Native invocation temporary directory escaped its operating-system root");return s}function T(t,o){if(o!=="win32")return"/tmp";const r=t.TEMP??t.TMP;return r===void 0||r.length===0?A.tmpdir():r}function u(t,o,r){const e=o[r];e!==void 0&&(t[r]=e)}function d(t){return t instanceof Error?t:new Error(String(t))}
1
+ import c from"node:fs/promises";import A from"node:os";import n from"node:path";import{toError as w}from"../kernel/error-serialization.js";export const ENGINE_PROCESS_RESERVED_ENVIRONMENT_KEYS=Object.freeze(["APPDATA","ComSpec","HOME","LANG","LC_ALL","LOCALAPPDATA","PATH","PATHEXT","SystemRoot","TEMP","TMP","TMPDIR","USERPROFILE","XDG_CACHE_HOME","XDG_CONFIG_HOME","XDG_DATA_HOME"]);export function nativeTemporaryRoot(t=process.env,o=process.platform){return T(t,o)}export async function createInvocationProcessEnvironment(t,o=process.env,r=process.platform){const e=n.join(t,"tmp");return d(t,e,!0,o,r)}export async function createNativeInvocationProcessEnvironment(t,o={}){const r=o.platform??process.platform,e=o.ambientEnvironment??process.env,s=await v(o.nativeTemporaryRootDirectory??nativeTemporaryRoot(e,r));let a=null;try{const i=await c.mkdtemp(n.join(s,"testkit-engine-"));return a=i,r!=="win32"&&await c.chmod(i,448),a=await P(i,s,r),await d(t,a,!1,e,r)}catch(i){if(a===null)throw i;try{await c.rm(a,{force:!0,recursive:!0})}catch(p){throw new AggregateError([w(i),w(p)],`Could not initialize or remove native invocation temporary directory ${a}`,{cause:p})}throw i}}async function d(t,o,r,e,s){if(!n.isAbsolute(t))throw new Error("Engine invocation directory must be absolute");if(!n.isAbsolute(o))throw new Error("Engine invocation temporary directory must be absolute");const a=n.join(t,"home"),i=n.join(t,"cache"),p=n.join(t,"config"),l=n.join(t,"data"),f=n.join(t,"local-app-data"),E=n.join(t,"app-data");await Promise.all([a,...r?[o]:[],i,p,l,f,E].map(y=>c.mkdir(y,{mode:448})));const m={APPDATA:E,HOME:a,LOCALAPPDATA:f,TEMP:o,TMP:o,TMPDIR:o,USERPROFILE:a,XDG_CACHE_HOME:i,XDG_CONFIG_HOME:p,XDG_DATA_HOME:l};return u(m,e,"LANG"),u(m,e,"LC_ALL"),s==="win32"&&(m.PATH="",u(m,e,"ComSpec"),u(m,e,"SystemRoot")),Object.freeze({environment:Object.freeze(m),homeDirectory:a,temporaryDirectory:o})}async function v(t){if(!n.isAbsolute(t))throw new Error("Native invocation temporary root must be absolute");const o=await c.realpath(t);if(!(await c.stat(o)).isDirectory())throw new Error("Native invocation temporary root must be a directory");return o}async function P(t,o,r){const e=await c.lstat(t);if(!e.isDirectory()||e.isSymbolicLink())throw new Error("Native invocation temporary directory must be a non-symbolic-link directory");if(r!=="win32"&&(e.mode&63)!==0)throw new Error("Native invocation temporary directory must not grant group or other access");const s=await c.realpath(t);if(n.dirname(s)!==o)throw new Error("Native invocation temporary directory escaped its operating-system root");return s}function T(t,o){if(o!=="win32")return"/tmp";const r=t.TEMP??t.TMP;return r===void 0||r.length===0?A.tmpdir():r}function u(t,o,r){const e=o[r];e!==void 0&&(t[r]=e)}
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "entrypoint": "dist/process/process.js",
4
- "sourceSha256": "a54f01864b603cee568b2945390dff35d578e07f6d26b5add06014169c3d17b0",
5
- "bundleSha256": "62f76cf9fd019f6c552bfde2787f058917caf279670a62e7a6bfa12be34cb4b1",
6
- "packageLockSha256": "859b2eca6e5ac18991a35fcc343cd3d05d7995c90af5383db58b5ef581f1b3b4",
4
+ "sourceSha256": "6ad324171090dad3d43ff3b3356edce675b04fe12550b59db3a08f0593e0ebe5",
5
+ "bundleSha256": "38b6bf24433229155a2b0b82062feb2d57b5f4d2bc17081167a38e9088707269",
6
+ "packageLockSha256": "2197c742d835b790241553916187f6f45f27a14d62f6d793411aa285d4bd9779",
7
7
  "esbuildVersion": "0.28.1",
8
8
  "options": {
9
9
  "format": "esm",
@@ -1,4 +1,3 @@
1
- export declare function isPropertyContainer(value: unknown): value is object;
2
1
  export declare function readProperty(value: object, key: PropertyKey): unknown;
3
2
  export declare function serializeJson(value: unknown, label: string): string;
4
3
  export declare function errorMessage(error: unknown): string;
@@ -1 +1 @@
1
- import s from"node:fs";import c from"node:path";const p=String;export function isPropertyContainer(t){return typeof t=="object"&&t!==null||typeof t=="function"}export function readProperty(t,r){return Reflect.get(t,r)}export function serializeJson(t,r){let e;try{e=JSON.stringify(t,null,2)}catch(o){throw new Error(`${r} is not JSON serializable`,{cause:o})}if(typeof e!="string")throw new Error(`${r} is not JSON serializable`);return e}export function errorMessage(t){if(t instanceof Error)return t.message;if(isPropertyContainer(t)){const r=readProperty(t,"message");if(typeof r=="string"&&r.length>0)return r}return p(t)}const y=new Set(["EPERM","EACCES","EBUSY"]),u=process.platform==="win32"?100:25,l=10,A=100;class S extends Error{attempts;code="TESTKIT_ATOMIC_WRITE_FAILED";cause;path;tempPath;constructor(r,e,o,n){super(`Failed to atomically replace ${r} after ${o.toString()} attempt${o===1?"":"s"}: ${errorMessage(n)}`,{cause:n}),this.name="AtomicWriteError",this.attempts=o,this.cause=n,this.path=r,this.tempPath=e}}export function writeJsonFileAtomicWithRetry(t,r,e={}){writeTextFileAtomicWithRetry(t,serializeJson(r,`atomic JSON file ${t}`),e)}export function writeTextFileAtomicWithRetry(t,r,e={}){const o=c.dirname(t),n=c.join(o,`.${c.basename(t)}.${process.pid.toString()}.${Date.now().toString()}.${Math.random().toString(16).slice(2)}.tmp`),a=e.attempts??u,E=e.baseDelayMs??l,m=e.maxDelayMs??A;s.writeFileSync(n,r);try{for(let i=1;i<=a;i+=1)try{s.renameSync(n,t);return}catch(f){if(!isRetryableAtomicReplaceError(f)||i>=a||R(t))throw new S(t,n,i,f);T(Math.min(m,E*i))}}finally{s.rmSync(n,{force:!0})}}export function isRetryableAtomicReplaceError(t){if(!isPropertyContainer(t))return!1;const r=readProperty(t,"code");return typeof r=="string"&&y.has(r)}function R(t){try{return s.lstatSync(t).isDirectory()}catch{return!1}}function T(t){if(t<=0)return;const r=new SharedArrayBuffer(4);Atomics.wait(new Int32Array(r),0,0,t)}
1
+ import s from"node:fs";import a from"node:path";import{isPropertyContainer as E}from"../../kernel/unknown-values.js";const y=String;export function readProperty(t,r){return Reflect.get(t,r)}export function serializeJson(t,r){let e;try{e=JSON.stringify(t,null,2)}catch(o){throw new Error(`${r} is not JSON serializable`,{cause:o})}if(typeof e!="string")throw new Error(`${r} is not JSON serializable`);return e}export function errorMessage(t){if(t instanceof Error)return t.message;if(E(t)){const r=readProperty(t,"message");if(typeof r=="string"&&r.length>0)return r}return y(t)}const u=new Set(["EPERM","EACCES","EBUSY"]),l=process.platform==="win32"?100:25,A=10,S=100;class R extends Error{attempts;code="TESTKIT_ATOMIC_WRITE_FAILED";cause;path;tempPath;constructor(r,e,o,n){super(`Failed to atomically replace ${r} after ${o.toString()} attempt${o===1?"":"s"}: ${errorMessage(n)}`,{cause:n}),this.name="AtomicWriteError",this.attempts=o,this.cause=n,this.path=r,this.tempPath=e}}export function writeJsonFileAtomicWithRetry(t,r,e={}){writeTextFileAtomicWithRetry(t,serializeJson(r,`atomic JSON file ${t}`),e)}export function writeTextFileAtomicWithRetry(t,r,e={}){const o=a.dirname(t),n=a.join(o,`.${a.basename(t)}.${process.pid.toString()}.${Date.now().toString()}.${Math.random().toString(16).slice(2)}.tmp`),c=e.attempts??l,f=e.baseDelayMs??A,p=e.maxDelayMs??S;s.writeFileSync(n,r);try{for(let i=1;i<=c;i+=1)try{s.renameSync(n,t);return}catch(m){if(!isRetryableAtomicReplaceError(m)||i>=c||T(t))throw new R(t,n,i,m);_(Math.min(p,f*i))}}finally{s.rmSync(n,{force:!0})}}export function isRetryableAtomicReplaceError(t){if(!E(t))return!1;const r=readProperty(t,"code");return typeof r=="string"&&u.has(r)}function T(t){try{return s.lstatSync(t).isDirectory()}catch{return!1}}function _(t){if(t<=0)return;const r=new SharedArrayBuffer(4);Atomics.wait(new Int32Array(r),0,0,t)}
@@ -1 +1,3 @@
1
1
  export declare function isPathWithin(root: string, candidate: string): boolean;
2
+ /** The platform path with forward-slash separators. */
3
+ export declare function posixPath(value: string): string;
@@ -1 +1 @@
1
- import t from"node:path";export function isPathWithin(r,i){const e=t.relative(t.resolve(r),t.resolve(i));return e===""||!e.startsWith(`..${t.sep}`)&&e!==".."&&!t.isAbsolute(e)}
1
+ import t from"node:path";export function isPathWithin(i,r){const e=t.relative(t.resolve(i),t.resolve(r));return e===""||!e.startsWith(`..${t.sep}`)&&e!==".."&&!t.isAbsolute(e)}export function posixPath(i){return i.split(t.sep).join("/")}
@@ -1 +1 @@
1
- import t from"node:fs";import n from"node:os";export function readPackageMetadata(){try{const r=new URL("../../../package.json",import.meta.url),e=JSON.parse(t.readFileSync(r,"utf8"));return o(e)&&typeof e.version=="string"?{...e,version:e.version}:{version:"unknown"}}catch{return{version:"unknown"}}}export function safeHostname(){try{return n.hostname()}catch{return null}}export function safeUsername(){try{return n.userInfo().username}catch{return process.env.USER||process.env.USERNAME||null}}function o(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}
1
+ import t from"node:fs";import n from"node:os";import{isUnknownRecord as o}from"../../kernel/unknown-values.js";export function readPackageMetadata(){try{const e=new URL("../../../package.json",import.meta.url),r=JSON.parse(t.readFileSync(e,"utf8"));return o(r)&&typeof r.version=="string"?{...r,version:r.version}:{version:"unknown"}}catch{return{version:"unknown"}}}export function safeHostname(){try{return n.hostname()}catch{return null}}export function safeUsername(){try{return n.userInfo().username}catch{return process.env.USER||process.env.USERNAME||null}}
@@ -1 +1 @@
1
- import u from"node:fs";import a from"node:path";export const SUPPORTED_PLATFORMS=["darwin","linux","win32"],SUPPORTED_ARCHITECTURES=["arm64","x64"],SUPPORTED_PLATFORM_TARGETS=Object.freeze([Object.freeze({arch:"arm64",platform:"darwin"}),Object.freeze({arch:"x64",platform:"darwin"}),Object.freeze({arch:"arm64",platform:"linux"}),Object.freeze({arch:"x64",platform:"linux"}),Object.freeze({arch:"x64",platform:"win32"})]);export class UnsupportedPlatformTargetError extends Error{arch;code="TESTKIT_PLATFORM_TARGET_UNSUPPORTED";platform;constructor(t,e,o="platform target"){super(`${o} does not support ${t}-${e}`),this.name="UnsupportedPlatformTargetError",this.platform=t,this.arch=e}}export function platformTargetKey(r){return`${r.platform}-${r.arch}`}export function currentPlatformTarget(r=process.platform,t=process.arch){if(!isSupportedPlatform(r)||!isSupportedArchitecture(t))throw new UnsupportedPlatformTargetError(r,t);const e={platform:r,arch:t};return assertSupportedPlatformTarget(e,"current platform target"),e}export function currentLinuxLibc(){if(process.platform!=="linux")return null;const r=process.report.getReport(),t=f(r)?r.header:null,e=f(t)?t.glibcVersionRuntime:null;return typeof e=="string"&&e.trim().length>0?"glibc":"musl"}export function assertSupportedPlatformTarget(r,t="platform target"){if(r.platform==="win32"&&r.arch!=="x64")throw new UnsupportedPlatformTargetError(r.platform,r.arch,t)}export function isSupportedPlatform(r){return SUPPORTED_PLATFORMS.includes(r)}export function isSupportedArchitecture(r){return SUPPORTED_ARCHITECTURES.includes(r)}function f(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}export function isWindows(r=process.platform){return r==="win32"}export function commandName(r,t=process.platform){const e=i(r||"").trim();if(!e)throw new Error("commandName requires a non-empty command name");return!isWindows(t)||/\.(?:cmd|bat|exe)$/i.test(e)?e:`${e}.cmd`}export function executableName(r,t=process.platform){const e=i(r||"").trim();if(!e)throw new Error("executableName requires a non-empty command name");return!isWindows(t)||/\.exe$/i.test(e)?e:`${e}.exe`}export function resolveCommandForSpawn(r,t={}){const e=t.platform||process.platform,o=t.env||process.env,n=i(r||"").trim();if(!n)throw new Error("resolveCommandForSpawn requires a non-empty command name");if(!isWindows(e))return n;if(/[\\/]/u.test(n)||a.win32.isAbsolute(n))return A(n);const s=P(n,o),c=[...i(o.PATH||o.Path||"").split(d(e)).map(l=>l.trim()).filter(Boolean),...t.extraWindowsDirs||[],...g(n,o)];for(const l of c)for(const x of s){const m=a.join(l,`${n}${x}`);if(u.existsSync(m))return m}return commandName(n,e)}export function prepareCommandForSpawn(r,t=[],e={}){const o=e.platform||process.platform,n=e.env||process.env,s=resolveCommandForSpawn(r,{...e,platform:o,env:n}),c=E(t)?t.map(l=>i(l)):[];return!isWindows(o)||!/\.(?:cmd|bat)$/i.test(s)?{command:s,args:c,windowsVerbatimArguments:!1}:{command:n.ComSpec||n.COMSPEC||"cmd.exe",args:["/d","/s","/c",h([s,...c])],windowsVerbatimArguments:!0}}export function packageBinPath(r,t,e=process.platform){const o=a.resolve(r||process.cwd()),n=i(t||"").trim();if(!/^[A-Za-z0-9@._/-]+$/.test(n))throw new Error(`Invalid package bin name: ${i(t)}`);const s=a.basename(n);return a.join(o,"node_modules",".bin",commandName(s,e))}export function shellQuote(r,t=process.platform){const e=i(r);return isWindows(t)?w(e):/^[A-Za-z0-9_/:.,@%+=-]*$/.test(e)?e:`'${e.replaceAll("'","'\\''")}'`}function w(r){return/^[A-Za-z0-9_/:.,@%+=\\-]*$/.test(r)?r:`"${r.replaceAll('"','\\"')}"`}function h(r){const[t,...e]=r;return`"${[p(t,{force:!0}),...e.map(o=>p(o))].join(" ")}"`}function p(r,t={}){const e=i(r);return!t.force&&e.length>0&&!/[\s&()<>^|"]/u.test(e)?e:`"${e.replace(/(\\*)"/gu,'$1$1\\"').replace(/\\+$/u,"$&$&")}"`}export function joinPathList(r,t=process.platform){const e=r.filter(Boolean).map(c=>i(c)),n=T(t)||d(t),s=Reflect.apply(Array.prototype.join,e,[n]);if(typeof s!="string")throw new Error("Path-list construction returned an invalid result");return s}function d(r){return isWindows(r)?";":":"}function P(r,t){if(/\.(?:cmd|bat|exe|com)$/i.test(r))return[""];const e=i(t.PATHEXT||".COM;.EXE;.BAT;.CMD").split(";").map(o=>o.trim().toLowerCase()).filter(Boolean);return[...new Set([".cmd",".exe",".bat",".com",...e])]}function A(r){if(u.existsSync(r)||/\.(?:cmd|bat|exe|com)$/i.test(r))return r;for(const t of[".cmd",".exe",".bat",".com"]){const e=`${r}${t}`;if(u.existsSync(e))return e}return commandName(r)}function g(r,t){return r.toLowerCase()!=="volta"?[]:[t.VOLTA_HOME,t.ProgramFiles?a.join(t.ProgramFiles,"Volta"):null,t["ProgramFiles(x86)"]?a.join(t["ProgramFiles(x86)"],"Volta"):null,t.LOCALAPPDATA?a.join(t.LOCALAPPDATA,"Volta","bin"):null,t.USERPROFILE?a.join(t.USERPROFILE,"AppData","Local","Volta","bin"):null].filter(e=>!!e)}export function dockerHostAddress(r,t=process.platform){const e=i(r||"").trim().toLowerCase();return["win32","darwin"].includes(t)&&(e==="127.0.0.1"||e==="localhost"||e==="::1")?"host.docker.internal":r}export function shouldUseDockerHostNetwork(r=process.platform){return r==="linux"}function i(r){const t=Reflect.apply(String,void 0,[r]);if(typeof t!="string")throw new Error("String conversion returned an invalid result");return t}function E(r){return Array.isArray(r)}function T(r){const t=a;if(!f(t))return;const e=t.delimiterForPlatform;if(e!=null){if(typeof e!="function")throw new TypeError("path.delimiterForPlatform is not a function");return Reflect.apply(e,t,[r])}}
1
+ import u from"node:fs";import a from"node:path";import{isUnknownArray as w,isUnknownRecord as m}from"../../kernel/unknown-values.js";export const SUPPORTED_PLATFORMS=["darwin","linux","win32"],SUPPORTED_ARCHITECTURES=["arm64","x64"],SUPPORTED_PLATFORM_TARGETS=Object.freeze([Object.freeze({arch:"arm64",platform:"darwin"}),Object.freeze({arch:"x64",platform:"darwin"}),Object.freeze({arch:"arm64",platform:"linux"}),Object.freeze({arch:"x64",platform:"linux"}),Object.freeze({arch:"x64",platform:"win32"})]);export class UnsupportedPlatformTargetError extends Error{arch;code="TESTKIT_PLATFORM_TARGET_UNSUPPORTED";platform;constructor(t,e,o="platform target"){super(`${o} does not support ${t}-${e}`),this.name="UnsupportedPlatformTargetError",this.platform=t,this.arch=e}}export function platformTargetKey(r){return`${r.platform}-${r.arch}`}export function currentPlatformTarget(r=process.platform,t=process.arch){if(!isSupportedPlatform(r)||!isSupportedArchitecture(t))throw new UnsupportedPlatformTargetError(r,t);const e={platform:r,arch:t};return assertSupportedPlatformTarget(e,"current platform target"),e}export function currentLinuxLibc(){if(process.platform!=="linux")return null;const r=process.report.getReport(),t=m(r)?r.header:null,e=m(t)?t.glibcVersionRuntime:null;return typeof e=="string"&&e.trim().length>0?"glibc":"musl"}export function assertSupportedPlatformTarget(r,t="platform target"){if(r.platform==="win32"&&r.arch!=="x64")throw new UnsupportedPlatformTargetError(r.platform,r.arch,t)}export function isSupportedPlatform(r){return SUPPORTED_PLATFORMS.includes(r)}export function isSupportedArchitecture(r){return SUPPORTED_ARCHITECTURES.includes(r)}export function isWindows(r=process.platform){return r==="win32"}export function commandName(r,t=process.platform){const e=i(r||"").trim();if(!e)throw new Error("commandName requires a non-empty command name");return!isWindows(t)||/\.(?:cmd|bat|exe)$/i.test(e)?e:`${e}.cmd`}export function executableName(r,t=process.platform){const e=i(r||"").trim();if(!e)throw new Error("executableName requires a non-empty command name");return!isWindows(t)||/\.exe$/i.test(e)?e:`${e}.exe`}export function resolveCommandForSpawn(r,t={}){const e=t.platform||process.platform,o=t.env||process.env,n=i(r||"").trim();if(!n)throw new Error("resolveCommandForSpawn requires a non-empty command name");if(!isWindows(e))return n;if(/[\\/]/u.test(n)||a.win32.isAbsolute(n))return A(n);const s=g(n,o),c=[...i(o.PATH||o.Path||"").split(d(e)).map(l=>l.trim()).filter(Boolean),...t.extraWindowsDirs||[],...E(n,o)];for(const l of c)for(const x of s){const f=a.join(l,`${n}${x}`);if(u.existsSync(f))return f}return commandName(n,e)}export function prepareCommandForSpawn(r,t=[],e={}){const o=e.platform||process.platform,n=e.env||process.env,s=resolveCommandForSpawn(r,{...e,platform:o,env:n}),c=w(t)?t.map(l=>i(l)):[];return!isWindows(o)||!/\.(?:cmd|bat)$/i.test(s)?{command:s,args:c,windowsVerbatimArguments:!1}:{command:n.ComSpec||n.COMSPEC||"cmd.exe",args:["/d","/s","/c",P([s,...c])],windowsVerbatimArguments:!0}}export function packageBinPath(r,t,e=process.platform){const o=a.resolve(r||process.cwd()),n=i(t||"").trim();if(!/^[A-Za-z0-9@._/-]+$/.test(n))throw new Error(`Invalid package bin name: ${i(t)}`);const s=a.basename(n);return a.join(o,"node_modules",".bin",commandName(s,e))}export function shellQuote(r,t=process.platform){const e=i(r);return isWindows(t)?h(e):/^[A-Za-z0-9_/:.,@%+=-]*$/.test(e)?e:`'${e.replaceAll("'","'\\''")}'`}function h(r){return/^[A-Za-z0-9_/:.,@%+=\\-]*$/.test(r)?r:`"${r.replaceAll('"','\\"')}"`}function P(r){const[t,...e]=r;return`"${[p(t,{force:!0}),...e.map(o=>p(o))].join(" ")}"`}function p(r,t={}){const e=i(r);return!t.force&&e.length>0&&!/[\s&()<>^|"]/u.test(e)?e:`"${e.replace(/(\\*)"/gu,'$1$1\\"').replace(/\\+$/u,"$&$&")}"`}export function joinPathList(r,t=process.platform){const e=r.filter(Boolean).map(c=>i(c)),n=T(t)||d(t),s=Reflect.apply(Array.prototype.join,e,[n]);if(typeof s!="string")throw new Error("Path-list construction returned an invalid result");return s}function d(r){return isWindows(r)?";":":"}function g(r,t){if(/\.(?:cmd|bat|exe|com)$/i.test(r))return[""];const e=i(t.PATHEXT||".COM;.EXE;.BAT;.CMD").split(";").map(o=>o.trim().toLowerCase()).filter(Boolean);return[...new Set([".cmd",".exe",".bat",".com",...e])]}function A(r){if(u.existsSync(r)||/\.(?:cmd|bat|exe|com)$/i.test(r))return r;for(const t of[".cmd",".exe",".bat",".com"]){const e=`${r}${t}`;if(u.existsSync(e))return e}return commandName(r)}function E(r,t){return r.toLowerCase()!=="volta"?[]:[t.VOLTA_HOME,t.ProgramFiles?a.join(t.ProgramFiles,"Volta"):null,t["ProgramFiles(x86)"]?a.join(t["ProgramFiles(x86)"],"Volta"):null,t.LOCALAPPDATA?a.join(t.LOCALAPPDATA,"Volta","bin"):null,t.USERPROFILE?a.join(t.USERPROFILE,"AppData","Local","Volta","bin"):null].filter(e=>!!e)}export function dockerHostAddress(r,t=process.platform){const e=i(r||"").trim().toLowerCase();return["win32","darwin"].includes(t)&&(e==="127.0.0.1"||e==="localhost"||e==="::1")?"host.docker.internal":r}export function shouldUseDockerHostNetwork(r=process.platform){return r==="linux"}function i(r){const t=Reflect.apply(String,void 0,[r]);if(typeof t!="string")throw new Error("String conversion returned an invalid result");return t}function T(r){const t=a;if(!m(t))return;const e=t.delimiterForPlatform;if(e!=null){if(typeof e!="function")throw new TypeError("path.delimiterForPlatform is not a function");return Reflect.apply(e,t,[r])}}
@@ -1 +1 @@
1
- import l from"node:fs";import s from"node:path";import{runManagedProcess as E,startSupervisedProcess as f}from"./process.js";export function runManagedHostProcess(e){const t=m(e);return E(t)}export function startManagedHostProcess(e){const t=m(e);return e.recoveryIdentity==="none"?f({...t,outputMode:e.outputMode,recoveryIdentity:"none"}):f({...t,outputMode:e.outputMode})}export function managedHostProcessInfrastructureError(e,t){const o=[];if(t.terminationError&&o.push(`process-scope termination was incomplete: ${t.terminationError.message}`),t.error&&o.push(`could not execute: ${t.error.message}`),t.timedOut&&o.push("exceeded its managed deadline"),t.cancelled&&o.push("was cancelled"),t.outputLimitExceeded&&o.push("exceeded the managed stdout/stderr capture limit"),o.length===0)return null;const r=new Error(`${e} ${o.join("; ")}`);return Object.defineProperty(r,"result",{enumerable:!1,value:Object.freeze({...t})}),r}export function normalizeManagedHostEnvironment(e=process.env,t=process.platform){const o=Object.entries(e).filter(n=>typeof n[1]=="string");if(t!=="win32")return Object.fromEntries(o);const r=new Map;for(const[n,a]of o){const c=n.toLowerCase();r.set(c,{key:y(c,n),value:a})}return Object.fromEntries([...r.entries()].sort(([n],[a])=>n.localeCompare(a)).map(([,n])=>[n.key,n.value]))}export function resolveManagedHostExecutable(e,t,o,r=process.platform){const n=resolveManagedHostExecutableIfAvailable(e,t,o,r);if(n)return n;throw o.PATH?new Error(`Could not resolve managed host executable ${JSON.stringify(e)}`):new Error(`Could not resolve managed host executable ${JSON.stringify(e)} because PATH is unavailable`)}export function resolveManagedHostExecutableIfAvailable(e,t,o,r=process.platform){if(e.trim().length===0)throw new Error("Managed host process executable must be non-empty");if(!s.isAbsolute(t))throw new Error("Managed host process working directory must be absolute");if(s.isAbsolute(e))return p(e,r);if(e.includes("/")||e.includes("\\"))throw new Error(`Managed host process executable paths must be absolute, got ${JSON.stringify(e)}`);const n=o.PATH;if(!n)return null;const a=b(e,o,r),c=r==="win32"?";":":";for(const u of n.split(c)){if(u.length===0)continue;const g=s.isAbsolute(u)?u:s.resolve(t,u);for(const h of a){const d=s.join(g,`${e}${h}`);try{const i=l.statSync(d,{throwIfNoEntry:!1});if(i!==void 0&&i.isFile()&&(r==="win32"||(i.mode&73)!==0))return p(d,r)}catch(i){if(!w(i,"ENOENT")&&!w(i,"ENOTDIR"))throw i}}}return null}function m(e){const t=s.resolve(e.cwd),o=normalizeManagedHostEnvironment(e.env);return{args:e.args,cwd:t,displayLabel:e.displayLabel,env:o,executable:resolveManagedHostExecutable(e.executable,t,o),signal:e.signal??new AbortController().signal,timeoutMs:e.timeoutMs,windowsVerbatimArguments:e.windowsVerbatimArguments}}function b(e,t,o){return o!=="win32"?[""]:s.extname(e).length>0?[""]:(t.PATHEXT||".COM;.EXE").split(";").map(n=>n.trim()).filter(n=>[".com",".exe"].includes(n.toLowerCase()))}function p(e,t){if(t==="win32"&&[".bat",".cmd"].includes(s.extname(e).toLowerCase()))throw new Error(`Windows batch wrappers are not managed host executables: ${e}`);const o=l.statSync(e);if(!o.isFile())throw new Error(`Managed host executable is not a regular file: ${e}`);if(t!=="win32"&&(o.mode&73)===0)throw new Error(`Managed host executable is not executable: ${e}`);return e}function y(e,t){return e==="path"?"PATH":e==="pathext"?"PATHEXT":e==="comspec"?"ComSpec":t}function w(e,t){return e!==null&&typeof e=="object"&&"code"in e&&Reflect.get(e,"code")===t}
1
+ import l from"node:fs";import s from"node:path";import{runManagedProcess as E,startSupervisedProcess as f}from"./process.js";import{hasErrorCode as m}from"../kernel/error-serialization.js";export function runManagedHostProcess(e){const r=p(e);return E(r)}export function startManagedHostProcess(e){const r=p(e);return e.recoveryIdentity==="none"?f({...r,outputMode:e.outputMode,recoveryIdentity:"none"}):f({...r,outputMode:e.outputMode})}export function managedHostProcessInfrastructureError(e,r){const o=[];if(r.terminationError&&o.push(`process-scope termination was incomplete: ${r.terminationError.message}`),r.error&&o.push(`could not execute: ${r.error.message}`),r.timedOut&&o.push("exceeded its managed deadline"),r.cancelled&&o.push("was cancelled"),r.outputLimitExceeded&&o.push("exceeded the managed stdout/stderr capture limit"),o.length===0)return null;const n=new Error(`${e} ${o.join("; ")}`);return Object.defineProperty(n,"result",{enumerable:!1,value:Object.freeze({...r})}),n}export function normalizeManagedHostEnvironment(e=process.env,r=process.platform){const o=Object.entries(e).filter(t=>typeof t[1]=="string");if(r!=="win32")return Object.fromEntries(o);const n=new Map;for(const[t,a]of o){const c=t.toLowerCase();n.set(c,{key:y(c,t),value:a})}return Object.fromEntries([...n.entries()].sort(([t],[a])=>t.localeCompare(a)).map(([,t])=>[t.key,t.value]))}export function resolveManagedHostExecutable(e,r,o,n=process.platform){const t=resolveManagedHostExecutableIfAvailable(e,r,o,n);if(t)return t;throw o.PATH?new Error(`Could not resolve managed host executable ${JSON.stringify(e)}`):new Error(`Could not resolve managed host executable ${JSON.stringify(e)} because PATH is unavailable`)}export function resolveManagedHostExecutableIfAvailable(e,r,o,n=process.platform){if(e.trim().length===0)throw new Error("Managed host process executable must be non-empty");if(!s.isAbsolute(r))throw new Error("Managed host process working directory must be absolute");if(s.isAbsolute(e))return w(e,n);if(e.includes("/")||e.includes("\\"))throw new Error(`Managed host process executable paths must be absolute, got ${JSON.stringify(e)}`);const t=o.PATH;if(!t)return null;const a=b(e,o,n),c=n==="win32"?";":":";for(const u of t.split(c)){if(u.length===0)continue;const g=s.isAbsolute(u)?u:s.resolve(r,u);for(const h of a){const d=s.join(g,`${e}${h}`);try{const i=l.statSync(d,{throwIfNoEntry:!1});if(i!==void 0&&i.isFile()&&(n==="win32"||(i.mode&73)!==0))return w(d,n)}catch(i){if(!m(i,"ENOENT")&&!m(i,"ENOTDIR"))throw i}}}return null}function p(e){const r=s.resolve(e.cwd),o=normalizeManagedHostEnvironment(e.env);return{args:e.args,cwd:r,displayLabel:e.displayLabel,env:o,executable:resolveManagedHostExecutable(e.executable,r,o),signal:e.signal??new AbortController().signal,timeoutMs:e.timeoutMs,windowsVerbatimArguments:e.windowsVerbatimArguments}}function b(e,r,o){return o!=="win32"?[""]:s.extname(e).length>0?[""]:(r.PATHEXT||".COM;.EXE").split(";").map(t=>t.trim()).filter(t=>[".com",".exe"].includes(t.toLowerCase()))}function w(e,r){if(r==="win32"&&[".bat",".cmd"].includes(s.extname(e).toLowerCase()))throw new Error(`Windows batch wrappers are not managed host executables: ${e}`);const o=l.statSync(e);if(!o.isFile())throw new Error(`Managed host executable is not a regular file: ${e}`);if(r!=="win32"&&(o.mode&73)===0)throw new Error(`Managed host executable is not executable: ${e}`);return e}function y(e,r){return e==="path"?"PATH":e==="pathext"?"PATHEXT":e==="comspec"?"ComSpec":r}
@@ -1,4 +1,4 @@
1
- import { type ProcessLockAttempt, type ProcessLockOptions } from "./locks.js";
1
+ import { type ProcessLockOptions } from "./locks.js";
2
2
  declare const PRODUCT_LIFECYCLE_FENCE_BRAND: unique symbol;
3
3
  export interface ProductLifecycleFence {
4
4
  readonly [PRODUCT_LIFECYCLE_FENCE_BRAND]: true;
@@ -6,6 +6,5 @@ export interface ProductLifecycleFence {
6
6
  }
7
7
  export declare function resolveProductLifecycleLockPath(productDir: string): string;
8
8
  export declare function withProductLifecycleFence<Result>(productDir: string, operation: (fence: ProductLifecycleFence) => Result | PromiseLike<Result>, options?: Readonly<Pick<ProcessLockOptions, "signal">>): Promise<Result>;
9
- export declare function tryWithProductLifecycleFence<Result>(productDir: string, operation: (fence: ProductLifecycleFence) => Result | PromiseLike<Result>): Promise<ProcessLockAttempt<Result>>;
10
9
  export declare function requireProductLifecycleFenceProductDir(fence: Readonly<ProductLifecycleFence>): string;
11
10
  export {};
@@ -1 +1 @@
1
- import o from"node:fs";import c from"node:path";import{tryWithProcessLock as l,withProcessLock as f}from"./locks.js";const d=Object.freeze([".testkit","_locks"]),y="run-maintenance.lock",L=Symbol("ProductLifecycleFence"),i=new WeakSet;export function resolveProductLifecycleLockPath(e){const r=o.realpathSync.native(c.resolve(e));return c.join(r,...d,y)}export async function withProductLifecycleFence(e,r,n={}){const t=a(e),u=resolveProductLifecycleLockPath(t.productDir);return o.mkdirSync(c.dirname(u),{recursive:!0}),f(u,()=>s(t,r),{signal:n.signal,timeoutMs:null})}export async function tryWithProductLifecycleFence(e,r){const n=a(e),t=resolveProductLifecycleLockPath(n.productDir);return o.mkdirSync(c.dirname(t),{recursive:!0}),l(t,()=>s(n,r))}export function requireProductLifecycleFenceProductDir(e){if(!i.has(e))throw new Error("Product lifecycle mutation requires an active lifecycle fence");return e.productDir}function a(e){return Object.freeze({[L]:!0,productDir:o.realpathSync.native(c.resolve(e))})}async function s(e,r){i.add(e);try{return await r(e)}finally{i.delete(e)}}
1
+ import c from"node:fs";import r from"node:path";import{withProcessLock as a}from"./locks.js";const l=Object.freeze([".testkit","_locks"]),s="run-maintenance.lock",f=Symbol("ProductLifecycleFence"),n=new WeakSet;export function resolveProductLifecycleLockPath(e){const t=c.realpathSync.native(r.resolve(e));return r.join(t,...l,s)}export async function withProductLifecycleFence(e,t,u={}){const o=E(e),i=resolveProductLifecycleLockPath(o.productDir);return c.mkdirSync(r.dirname(i),{recursive:!0}),a(i,()=>L(o,t),{signal:u.signal,timeoutMs:null})}export function requireProductLifecycleFenceProductDir(e){if(!n.has(e))throw new Error("Product lifecycle mutation requires an active lifecycle fence");return e.productDir}function E(e){return Object.freeze({[f]:!0,productDir:c.realpathSync.native(r.resolve(e))})}async function L(e,t){n.add(e);try{return await t(e)}finally{n.delete(e)}}
@@ -1,4 +1,4 @@
1
- import{AsyncLocalStorage as te}from"node:async_hooks";import{randomUUID as re}from"node:crypto";import i from"node:fs";import ne from"node:os";import a from"node:path";import{setTimeout as oe}from"node:timers/promises";import{captureProcessCreationIdentity as j}from"./process-identity.js";import{channel as se}from"node:diagnostics_channel";const x=se("testkit.work");function ie(e){try{i.mkdirSync(e,{mode:448})}catch(t){if(!c(t,"EEXIST"))throw t}return V(e)}function ce(e){try{const t=i.lstatSync(e);return t.isDirectory()&&!t.isSymbolicLink()?"real":"unsafe"}catch(t){if(c(t,"ENOENT"))return"absent";throw t}}function K(e){const t=i.lstatSync(e,{bigint:!0});if(!t.isDirectory()||t.isSymbolicLink())throw new Error(`Process lock path is not a real directory: ${e}`);return{birthtimeNs:t.birthtimeNs,dev:t.dev,ino:t.ino}}function V(e){try{return K(e)}catch(t){if(c(t,"ENOENT")||ue(t))return null;throw t}}function h(e,t){const n=V(e);return n!==null&&n.birthtimeNs===t.birthtimeNs&&n.dev===t.dev&&n.ino===t.ino}function ae(e,t,n){return h(e,t)?v(n)?"unsafe":"retry":h(n,t)?"published":"unsafe"}function ue(e){return e instanceof Error&&e.message.startsWith("Process lock path is not a real directory:")}const U="owner.json",g=1,T="claim-",M="choosing",W="ticket",le=100,q=65e3,fe=100,me=new Set(["EACCES","EBUSY","EPERM"]),de=5e3,Y=ne.hostname(),he=process.platform==="win32"?de:0,O=new te;class H extends Error{constructor(t,n){super(`Timed out waiting for process lock ${a.basename(t)}${Fe(n)}`),this.name="ProcessLockTimeoutError"}}export async function withProcessLock(e,t,n={}){const r=J(e);_e(r);const o=await ye(r,n),s=O.getStore(),u=new Set(s??[]);u.add(r);try{return await O.run(u,t)}finally{o()}}export async function tryWithProcessLock(e,t,n={}){let r;try{r=await withProcessLock(e,async()=>{try{return{ok:!0,value:await t()}}catch(o){return{error:o,ok:!1}}},{...n,timeoutMs:0})}catch(o){if(o instanceof H)return{acquired:!1};throw o}if(!r.ok)throw r.error;return{acquired:!0,value:r.value}}export function probeProcessLock(e,t={}){const n=J(e),r=G(n);if(!v(r))return"absent";const o=t.identityObservations??new Map,s=R(r,o,t);return s.rootAvailable&&s.claims.length===0?(_(r),"absent"):"active"}async function ye(e,t){const n=je(t.timeoutMs,null,"process lock timeout"),r=xe(t.retryIntervalMs,le,"process lock retry interval");let o=t.retryIntervalMs===void 0?10:r;async function s(){const b=o;o=Math.min(r,o*2),await $e(b,t.signal,e)}const u=t.identityObservations??new Map,f=j(process.pid);if(f===null)throw new Error(`Cannot acquire process lock ${e}: current process creation identity is unavailable`);const E=Date.now(),y={createdAt:new Date(E).toISOString(),hostname:Y,pid:process.pid,processIdentity:f,schemaVersion:g,token:re()},m=G(e),l=a.join(m,`${T}${y.token}`),k=`${m}.preparing-${y.token}`;we(k,y);let w=null,D=!1,S=null,I=!1,F=0;try{for(w=K(k);;){L(t.signal,e);const p=ie(m);if(p!==null){try{i.renameSync(k,l),I=!0,S=p}catch(d){if(!c(d,"ENOENT"))if(Ee(d)){const N=ae(k,w,l);if(N==="published")I=!0,S=p;else if(N==="retry"&&F<fe)F+=1;else throw d}else throw d}if(I){if(!h(m,p))throw new Error(`Process lock directory changed during claim publication: ${m}`);if(!h(l,w))throw new Error(`Process lock claim changed during publication: ${l}`);break}}else R(m,u,t);Q(e,null,E,n),await s()}if(S===null)throw new Error(`Process lock claim was published without its directory identity: ${l}`);const b=S,Z=R(m,u,t,b),A=ke(Z.claims);for(pe(l,A);;){L(t.signal,e);const p=R(m,u,t,b),d=p.claims.find(ee=>ee.claimDirectory===l);if(d?.state!=="ready"||d.ticket!==A||d.ownerRecord===null||!X(d.ownerRecord,y))throw new Error(`Process lock claim disappeared or changed before acquisition: ${l}`);const N=Se(p.claims,d);if(N===null)return D=!0,()=>{Ae(l,m,b,y,A)};Q(e,N.ownerRecord,E,n),await s()}}finally{I?!D&&S!==null&&w!==null&&h(m,S)&&h(l,w)&&(i.rmSync(l,{force:!0,recursive:!0}),u.delete(l),_(m)):w!==null&&h(k,w)&&i.rmSync(k,{force:!0,recursive:!0})}}function Ee(e){return process.platform==="win32"&&$(e)&&typeof e.code=="string"&&me.has(e.code)}function we(e,t){i.mkdirSync(e,{mode:448});try{i.writeFileSync(a.join(e,U),`${JSON.stringify(t)}
1
+ import{AsyncLocalStorage as te}from"node:async_hooks";import{randomUUID as re}from"node:crypto";import i from"node:fs";import ne from"node:os";import a from"node:path";import{setTimeout as oe}from"node:timers/promises";import{captureProcessCreationIdentity as F}from"./process-identity.js";import{channel as se}from"node:diagnostics_channel";const x=se("testkit.work");import{isUnknownRecord as j}from"../kernel/unknown-values.js";import{hasErrorCode as c}from"../kernel/error-serialization.js";function ie(e){try{i.mkdirSync(e,{mode:448})}catch(t){if(!c(t,"EEXIST"))throw t}return U(e)}function ce(e){try{const t=i.lstatSync(e);return t.isDirectory()&&!t.isSymbolicLink()?"real":"unsafe"}catch(t){if(c(t,"ENOENT"))return"absent";throw t}}function K(e){const t=i.lstatSync(e,{bigint:!0});if(!t.isDirectory()||t.isSymbolicLink())throw new Error(`Process lock path is not a real directory: ${e}`);return{birthtimeNs:t.birthtimeNs,dev:t.dev,ino:t.ino}}function U(e){try{return K(e)}catch(t){if(c(t,"ENOENT")||ue(t))return null;throw t}}function h(e,t){const n=U(e);return n!==null&&n.birthtimeNs===t.birthtimeNs&&n.dev===t.dev&&n.ino===t.ino}function ae(e,t,n){return h(e,t)?v(n)?"unsafe":"retry":h(n,t)?"published":"unsafe"}function ue(e){return e instanceof Error&&e.message.startsWith("Process lock path is not a real directory:")}const V="owner.json",A=1,T="claim-",M="choosing",W="ticket",le=100,q=65e3,fe=100,me=new Set(["EACCES","EBUSY","EPERM"]),de=5e3,Y=ne.hostname(),he=process.platform==="win32"?de:0,O=new te;class H extends Error{constructor(t,n){super(`Timed out waiting for process lock ${a.basename(t)}${Fe(n)}`),this.name="ProcessLockTimeoutError"}}export async function withProcessLock(e,t,n={}){const r=J(e);_e(r);const o=await ye(r,n),s=O.getStore(),u=new Set(s??[]);u.add(r);try{return await O.run(u,t)}finally{o()}}export async function tryWithProcessLock(e,t,n={}){let r;try{r=await withProcessLock(e,async()=>{try{return{ok:!0,value:await t()}}catch(o){return{error:o,ok:!1}}},{...n,timeoutMs:0})}catch(o){if(o instanceof H)return{acquired:!1};throw o}if(!r.ok)throw r.error;return{acquired:!0,value:r.value}}export function probeProcessLock(e,t={}){const n=J(e),r=G(n);if(!v(r))return"absent";const o=t.identityObservations??new Map,s=R(r,o,t);return s.rootAvailable&&s.claims.length===0?(_(r),"absent"):"active"}async function ye(e,t){const n=xe(t.timeoutMs,null,"process lock timeout"),r=je(t.retryIntervalMs,le,"process lock retry interval");let o=t.retryIntervalMs===void 0?10:r;async function s(){const b=o;o=Math.min(r,o*2),await $e(b,t.signal,e)}const u=t.identityObservations??new Map,f=F(process.pid);if(f===null)throw new Error(`Cannot acquire process lock ${e}: current process creation identity is unavailable`);const E=Date.now(),y={createdAt:new Date(E).toISOString(),hostname:Y,pid:process.pid,processIdentity:f,schemaVersion:A,token:re()},m=G(e),l=a.join(m,`${T}${y.token}`),k=`${m}.preparing-${y.token}`;we(k,y);let w=null,$=!1,S=null,I=!1,D=0;try{for(w=K(k);;){L(t.signal,e);const p=ie(m);if(p!==null){try{i.renameSync(k,l),I=!0,S=p}catch(d){if(!c(d,"ENOENT"))if(Ee(d)){const N=ae(k,w,l);if(N==="published")I=!0,S=p;else if(N==="retry"&&D<fe)D+=1;else throw d}else throw d}if(I){if(!h(m,p))throw new Error(`Process lock directory changed during claim publication: ${m}`);if(!h(l,w))throw new Error(`Process lock claim changed during publication: ${l}`);break}}else R(m,u,t);Q(e,null,E,n),await s()}if(S===null)throw new Error(`Process lock claim was published without its directory identity: ${l}`);const b=S,Z=R(m,u,t,b),g=ke(Z.claims);for(pe(l,g);;){L(t.signal,e);const p=R(m,u,t,b),d=p.claims.find(ee=>ee.claimDirectory===l);if(d?.state!=="ready"||d.ticket!==g||d.ownerRecord===null||!X(d.ownerRecord,y))throw new Error(`Process lock claim disappeared or changed before acquisition: ${l}`);const N=Se(p.claims,d);if(N===null)return $=!0,()=>{ge(l,m,b,y,g)};Q(e,N.ownerRecord,E,n),await s()}}finally{I?!$&&S!==null&&w!==null&&h(m,S)&&h(l,w)&&(i.rmSync(l,{force:!0,recursive:!0}),u.delete(l),_(m)):w!==null&&h(k,w)&&i.rmSync(k,{force:!0,recursive:!0})}}function Ee(e){return process.platform==="win32"&&j(e)&&typeof e.code=="string"&&me.has(e.code)}function we(e,t){i.mkdirSync(e,{mode:448});try{i.writeFileSync(a.join(e,V),`${JSON.stringify(t)}
2
2
  `,{encoding:"utf8",flag:"wx",mode:384}),i.writeFileSync(a.join(e,M),`${t.token}
3
3
  `,{encoding:"utf8",flag:"wx",mode:384})}catch(n){throw i.rmSync(e,{force:!0,recursive:!0}),n}}function pe(e,t){i.writeFileSync(a.join(e,W),`${t.toString()}
4
- `,{encoding:"utf8",flag:"wx",mode:384}),i.rmSync(a.join(e,M))}function ke(e){const t=e.reduce((n,r)=>r.ticket===null?n:Math.max(n,r.ticket),0);if(t>=Number.MAX_SAFE_INTEGER)throw new Error("Process lock ticket space is exhausted");return t+1}function Se(e,t){if(t.ticket===null||t.ownerRecord===null)return t;const n=t.ownerRecord.token;for(const r of e){if(r.claimDirectory===t.claimDirectory)continue;if(r.state!=="ready"||r.ticket===null||r.ownerRecord===null)return r;const o=r.ownerRecord.token;if(be(r.ticket,o,t.ticket,n)<0)return r}return null}function be(e,t,n,r){return e===n?t.localeCompare(r):e-n}function R(e,t,n,r=null){const o=ce(e);if(o==="absent")return{claims:[],rootAvailable:!0};if(o==="unsafe"){const f=P(e);return Le(e,t,n)?{claims:[],rootAvailable:!0}:{claims:[f],rootAvailable:!1}}if(r!==null&&!h(e,r))return{claims:[P(e)],rootAvailable:!1};let s;try{s=i.readdirSync(e,{withFileTypes:!0})}catch(f){if(c(f,"ENOENT"))return{claims:[],rootAvailable:!0};throw f}const u=[];for(const f of s){const E=a.join(e,f.name),y=!f.name.startsWith(T)||!f.isDirectory()?P(E):z(E);Ie(y,t,n)?Re(E,t):u.push(y)}return{claims:u,rootAvailable:!0}}function P(e){return{claimDirectory:e,ownerRecord:null,state:"malformed",ticket:null}}function z(e){const t=Me(e),n=v(a.join(e,M)),r=Ne(e),o=a.basename(e).slice(T.length),s=t===null||t.token===o;return{claimDirectory:e,ownerRecord:t,state:t===null||!s?"malformed":n?"choosing":r===null?"malformed":"ready",ticket:r}}function Ne(e){try{const t=i.readFileSync(a.join(e,W),"utf8").trim(),n=Number(t);return Number.isSafeInteger(n)&&n>0?n:null}catch{return null}}function Ie(e,t,n){const r=e.ownerRecord;if(r===null||r.hostname!==Y)return n.hostScope==="current-host"&&Ce(e.claimDirectory)>=q;if(ve(r.pid)==="absent")return!0;const o=C(r),s=t.get(e.claimDirectory);if(s?.ownerKey===o&&Date.now()-s.checkedAtMs<he)return!1;const u=j(r.pid);return t.set(e.claimDirectory,{checkedAtMs:Date.now(),ownerKey:o}),u!==null&&u!==r.processIdentity}function Re(e,t){t.delete(e),i.rmSync(e,{force:!0,recursive:!0})}function Le(e,t,n){if(n.hostScope!=="current-host")return!1;const r=B(e);if(r==="absent")return!0;if(r==="real-directory"||Te(r)<q)return!1;const o=B(e);if(o==="absent")return!0;if(o==="real-directory"||!ge(o,r))return!1;try{return i.unlinkSync(e),t.delete(e),!0}catch(s){if(c(s,"ENOENT"))return!0;if(c(s,"EISDIR")||c(s,"EPERM"))return!1;throw s}}function Ae(e,t,n,r,o){if(!h(t,n))throw new Error(`Process lock directory changed before release: ${t}`);const s=z(e);if(s.state!=="ready"||s.ticket!==o||s.ownerRecord===null||!X(s.ownerRecord,r))throw new Error(`Process lock ownership changed before release: ${e}`);i.rmSync(e,{force:!0,recursive:!0}),_(t)}function B(e){try{const t=i.lstatSync(e,{bigint:!0});return t.isDirectory()&&!t.isSymbolicLink()?"real-directory":{birthtimeNs:t.birthtimeNs,ctimeNs:t.ctimeNs,dev:t.dev,ino:t.ino,mode:t.mode,mtimeNs:t.mtimeNs,size:t.size}}catch(t){if(c(t,"ENOENT"))return"absent";throw t}}function ge(e,t){return e.birthtimeNs===t.birthtimeNs&&e.ctimeNs===t.ctimeNs&&e.dev===t.dev&&e.ino===t.ino&&e.mode===t.mode&&e.mtimeNs===t.mtimeNs&&e.size===t.size}function Te(e){return Math.max(0,Date.now()-Number(e.mtimeNs)/1e6)}function _(e){try{i.rmdirSync(e)}catch(t){if(!c(t,"ENOENT")&&!c(t,"ENOTEMPTY")&&!c(t,"EEXIST"))throw t}}function Me(e){let t;try{t=JSON.parse(i.readFileSync(a.join(e,U),"utf8"))}catch{return null}return $(t)?Oe(t):null}function Oe(e){const t=Object.keys(e).sort(),n=["createdAt","hostname","pid","processIdentity","schemaVersion","token"];return t.length!==n.length||t.some((r,o)=>r!==n[o])||e.schemaVersion!==g||!Ke(e.createdAt)||typeof e.hostname!="string"||e.hostname.length===0||!Ve(e.pid)||typeof e.processIdentity!="string"||e.processIdentity.length===0||typeof e.token!="string"||e.token.length===0?null:{createdAt:e.createdAt,hostname:e.hostname,pid:e.pid,processIdentity:e.processIdentity,schemaVersion:g,token:e.token}}function X(e,t){return C(e)===C(t)}function C(e){return[e.hostname,e.pid.toString(),e.processIdentity,e.token,e.createdAt].join("\0")}function G(e){return`${e}.dir`}function J(e){const t=a.resolve(Pe(e)),n=i.realpathSync.native(a.dirname(t));return a.join(n,a.basename(t))}function Pe(e){if(e.trim().length===0)throw new Error("Process lock path must not be empty");return e}function _e(e){if(O.getStore()?.has(e))throw new Error(`Reentrant process lock acquisition is not allowed: ${e}`)}function Q(e,t,n,r){if(r!==null&&Date.now()-n>=r)throw new H(e,t)}function Ce(e){try{return Math.max(0,Date.now()-i.lstatSync(e).mtimeMs)}catch(t){if(c(t,"ENOENT"))return Number.POSITIVE_INFINITY;throw t}}function ve(e){try{return process.kill(e,0),"alive"}catch(t){return c(t,"ESRCH")?"absent":c(t,"EPERM")?"alive":"unknown"}}async function $e(e,t,n){L(t,n),x.hasSubscribers&&x.publish({metric:"locks.contentionRetries",amount:1});try{await oe(e,void 0,{signal:t})}catch(r){throw L(t,n),r}}function L(e,t){if(e?.aborted)throw De(e,t)}function De(e,t){return e.reason instanceof Error?e.reason:new Error(`Waiting for process lock was aborted: ${t}`)}function Fe(e){return e===null?"":` (host=${e.hostname} pid=${e.pid.toString()} identity=${e.processIdentity} createdAt=${e.createdAt})`}function je(e,t,n){const r=e===void 0?t:e;if(r!==null&&(!Number.isSafeInteger(r)||r<0))throw new Error(`${n} must be null or a non-negative safe integer`);return r}function xe(e,t,n){const r=e??t;if(!Number.isSafeInteger(r)||r<=0)throw new Error(`${n} must be a positive safe integer`);return r}function Ke(e){return typeof e=="string"&&e.length>0&&Number.isFinite(Date.parse(e))}function Ve(e){return Number.isSafeInteger(e)&&Number(e)>0}function v(e){try{return i.lstatSync(e),!0}catch(t){if(c(t,"ENOENT"))return!1;throw t}}function c(e,t){return $(e)&&e.code===t}function $(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}
4
+ `,{encoding:"utf8",flag:"wx",mode:384}),i.rmSync(a.join(e,M))}function ke(e){const t=e.reduce((n,r)=>r.ticket===null?n:Math.max(n,r.ticket),0);if(t>=Number.MAX_SAFE_INTEGER)throw new Error("Process lock ticket space is exhausted");return t+1}function Se(e,t){if(t.ticket===null||t.ownerRecord===null)return t;const n=t.ownerRecord.token;for(const r of e){if(r.claimDirectory===t.claimDirectory)continue;if(r.state!=="ready"||r.ticket===null||r.ownerRecord===null)return r;const o=r.ownerRecord.token;if(be(r.ticket,o,t.ticket,n)<0)return r}return null}function be(e,t,n,r){return e===n?t.localeCompare(r):e-n}function R(e,t,n,r=null){const o=ce(e);if(o==="absent")return{claims:[],rootAvailable:!0};if(o==="unsafe"){const f=P(e);return Le(e,t,n)?{claims:[],rootAvailable:!0}:{claims:[f],rootAvailable:!1}}if(r!==null&&!h(e,r))return{claims:[P(e)],rootAvailable:!1};let s;try{s=i.readdirSync(e,{withFileTypes:!0})}catch(f){if(c(f,"ENOENT"))return{claims:[],rootAvailable:!0};throw f}const u=[];for(const f of s){const E=a.join(e,f.name),y=!f.name.startsWith(T)||!f.isDirectory()?P(E):z(E);Ie(y,t,n)?Re(E,t):u.push(y)}return{claims:u,rootAvailable:!0}}function P(e){return{claimDirectory:e,ownerRecord:null,state:"malformed",ticket:null}}function z(e){const t=Me(e),n=v(a.join(e,M)),r=Ne(e),o=a.basename(e).slice(T.length),s=t===null||t.token===o;return{claimDirectory:e,ownerRecord:t,state:t===null||!s?"malformed":n?"choosing":r===null?"malformed":"ready",ticket:r}}function Ne(e){try{const t=i.readFileSync(a.join(e,W),"utf8").trim(),n=Number(t);return Number.isSafeInteger(n)&&n>0?n:null}catch{return null}}function Ie(e,t,n){const r=e.ownerRecord;if(r===null||r.hostname!==Y)return n.hostScope==="current-host"&&Ce(e.claimDirectory)>=q;if(ve(r.pid)==="absent")return!0;const o=C(r),s=t.get(e.claimDirectory);if(s?.ownerKey===o&&Date.now()-s.checkedAtMs<he)return!1;const u=F(r.pid);return t.set(e.claimDirectory,{checkedAtMs:Date.now(),ownerKey:o}),u!==null&&u!==r.processIdentity}function Re(e,t){t.delete(e),i.rmSync(e,{force:!0,recursive:!0})}function Le(e,t,n){if(n.hostScope!=="current-host")return!1;const r=B(e);if(r==="absent")return!0;if(r==="real-directory"||Te(r)<q)return!1;const o=B(e);if(o==="absent")return!0;if(o==="real-directory"||!Ae(o,r))return!1;try{return i.unlinkSync(e),t.delete(e),!0}catch(s){if(c(s,"ENOENT"))return!0;if(c(s,"EISDIR")||c(s,"EPERM"))return!1;throw s}}function ge(e,t,n,r,o){if(!h(t,n))throw new Error(`Process lock directory changed before release: ${t}`);const s=z(e);if(s.state!=="ready"||s.ticket!==o||s.ownerRecord===null||!X(s.ownerRecord,r))throw new Error(`Process lock ownership changed before release: ${e}`);i.rmSync(e,{force:!0,recursive:!0}),_(t)}function B(e){try{const t=i.lstatSync(e,{bigint:!0});return t.isDirectory()&&!t.isSymbolicLink()?"real-directory":{birthtimeNs:t.birthtimeNs,ctimeNs:t.ctimeNs,dev:t.dev,ino:t.ino,mode:t.mode,mtimeNs:t.mtimeNs,size:t.size}}catch(t){if(c(t,"ENOENT"))return"absent";throw t}}function Ae(e,t){return e.birthtimeNs===t.birthtimeNs&&e.ctimeNs===t.ctimeNs&&e.dev===t.dev&&e.ino===t.ino&&e.mode===t.mode&&e.mtimeNs===t.mtimeNs&&e.size===t.size}function Te(e){return Math.max(0,Date.now()-Number(e.mtimeNs)/1e6)}function _(e){try{i.rmdirSync(e)}catch(t){if(!c(t,"ENOENT")&&!c(t,"ENOTEMPTY")&&!c(t,"EEXIST"))throw t}}function Me(e){let t;try{t=JSON.parse(i.readFileSync(a.join(e,V),"utf8"))}catch{return null}return j(t)?Oe(t):null}function Oe(e){const t=Object.keys(e).sort(),n=["createdAt","hostname","pid","processIdentity","schemaVersion","token"];return t.length!==n.length||t.some((r,o)=>r!==n[o])||e.schemaVersion!==A||!Ke(e.createdAt)||typeof e.hostname!="string"||e.hostname.length===0||!Ue(e.pid)||typeof e.processIdentity!="string"||e.processIdentity.length===0||typeof e.token!="string"||e.token.length===0?null:{createdAt:e.createdAt,hostname:e.hostname,pid:e.pid,processIdentity:e.processIdentity,schemaVersion:A,token:e.token}}function X(e,t){return C(e)===C(t)}function C(e){return[e.hostname,e.pid.toString(),e.processIdentity,e.token,e.createdAt].join("\0")}function G(e){return`${e}.dir`}function J(e){const t=a.resolve(Pe(e)),n=i.realpathSync.native(a.dirname(t));return a.join(n,a.basename(t))}function Pe(e){if(e.trim().length===0)throw new Error("Process lock path must not be empty");return e}function _e(e){if(O.getStore()?.has(e))throw new Error(`Reentrant process lock acquisition is not allowed: ${e}`)}function Q(e,t,n,r){if(r!==null&&Date.now()-n>=r)throw new H(e,t)}function Ce(e){try{return Math.max(0,Date.now()-i.lstatSync(e).mtimeMs)}catch(t){if(c(t,"ENOENT"))return Number.POSITIVE_INFINITY;throw t}}function ve(e){try{return process.kill(e,0),"alive"}catch(t){return c(t,"ESRCH")?"absent":c(t,"EPERM")?"alive":"unknown"}}async function $e(e,t,n){L(t,n),x.hasSubscribers&&x.publish({metric:"locks.contentionRetries",amount:1});try{await oe(e,void 0,{signal:t})}catch(r){throw L(t,n),r}}function L(e,t){if(e?.aborted)throw De(e,t)}function De(e,t){return e.reason instanceof Error?e.reason:new Error(`Waiting for process lock was aborted: ${t}`)}function Fe(e){return e===null?"":` (host=${e.hostname} pid=${e.pid.toString()} identity=${e.processIdentity} createdAt=${e.createdAt})`}function xe(e,t,n){const r=e===void 0?t:e;if(r!==null&&(!Number.isSafeInteger(r)||r<0))throw new Error(`${n} must be null or a non-negative safe integer`);return r}function je(e,t,n){const r=e??t;if(!Number.isSafeInteger(r)||r<=0)throw new Error(`${n} must be a positive safe integer`);return r}function Ke(e){return typeof e=="string"&&e.length>0&&Number.isFinite(Date.parse(e))}function Ue(e){return Number.isSafeInteger(e)&&Number(e)>0}function v(e){try{return i.lstatSync(e),!0}catch(t){if(c(t,"ENOENT"))return!1;throw t}}
@@ -1 +1 @@
1
- import{DEFAULT_SHUTDOWN_TIMEOUT_MS as f,FORCE_TERMINATION_WAIT_MS as E}from"./shutdown.js";export async function cleanupExitedProcessGroup(r,t={}){if((t.platform??process.platform)==="win32")return null;const n=t.groupExists??processGroupExists,e=t.sendSignal??g,o=t.sleep??m,c=t.graceMs??f,l=t.forceWaitMs??E;try{return!n(r)||(t.initialSignalSent||e(r,"SIGTERM"),await i(r,c,n,o,t.remainingMs))?null:(e(r,"SIGKILL"),await i(r,l,n,o)?null:new Error(`Managed process group ${r.toString()} did not stop`))}catch(u){return a(u,"ESRCH")?null:M(u)}}async function i(r,t,s,n,e){const o=performance.now(),c=e??(()=>t-(performance.now()-o));for(;c()>0;){if(!s(r))return!0;await n(Math.min(25,Math.max(1,c())))}return!s(r)}function g(r,t){process.kill(-r,t)}function m(r){return new Promise(t=>setTimeout(t,r))}export function processGroupExists(r){try{return process.kill(-r,0),!0}catch(t){if(a(t,"ESRCH"))return!1;if(a(t,"EPERM"))return!0;throw t}}function M(r){return r instanceof Error?r:new Error(String(r))}function a(r,t){return typeof r=="object"&&r!==null&&Reflect.get(r,"code")===t}
1
+ import{DEFAULT_SHUTDOWN_TIMEOUT_MS as f,FORCE_TERMINATION_WAIT_MS as m}from"./shutdown.js";import{hasErrorCode as c,toError as E}from"../kernel/error-serialization.js";export async function cleanupExitedProcessGroup(e,r={}){if((r.platform??process.platform)==="win32")return null;const t=r.groupExists??processGroupExists,n=r.sendSignal??M,o=r.sleep??g,s=r.graceMs??f,l=r.forceWaitMs??m;try{return!t(e)||(r.initialSignalSent||n(e,"SIGTERM"),await i(e,s,t,o,r.remainingMs))?null:(n(e,"SIGKILL"),await i(e,l,t,o)?null:new Error(`Managed process group ${e.toString()} did not stop`))}catch(u){return c(u,"ESRCH")?null:E(u)}}async function i(e,r,a,t,n){const o=performance.now(),s=n??(()=>r-(performance.now()-o));for(;s()>0;){if(!a(e))return!0;await t(Math.min(25,Math.max(1,s())))}return!a(e)}function M(e,r){process.kill(-e,r)}function g(e){return new Promise(r=>setTimeout(r,e))}export function processGroupExists(e){try{return process.kill(-e,0),!0}catch(r){if(c(r,"ESRCH"))return!1;if(c(r,"EPERM"))return!0;throw r}}
@@ -1 +1 @@
1
- import{execFileSync as a}from"node:child_process";import d from"node:fs";import{DARWIN_PS_EXECUTABLE as l,HOST_POSIX_INSPECTION_ENVIRONMENT as f,requireWindowsHostPowerShellCommand as m}from"./host-inspection-command.js";import{formatWindowsKernelProcessIdentity as p,parseWindowsKernelProcessIdentity as w}from"./windows-process-identity.js";import{windowsOwnerExecutable as I}from"./windows-native.js";const S=3e3,E=16*1024,T=8e3;let o;export function captureProcessCreationIdentity(e){const t=Number(e);if(!Number.isSafeInteger(t)||t<=0)return null;if(t===process.pid&&o!==void 0)return o;try{let r=null;return process.platform==="linux"?r=y(t):process.platform==="darwin"?r=P(t):process.platform==="win32"&&(r=g(t)),t===process.pid&&r!==null&&(o=r),r}catch{return null}}export function processCreationIdentityMatches(e,t){return observeProcessCreationIdentity(e,t)==="matches"}export function observeProcessCreationIdentity(e,t,r={}){const n=Number(e);if(!Number.isSafeInteger(n)||n<=0||typeof t!="string"||t.length===0)return"unknown";const i=(r.captureIdentity??captureProcessCreationIdentity)(n);return i!==null?i===t?"matches":"different":(r.inspectLiveness??inspectProcessLiveness)(n)==="absent"?"different":"unknown"}export function parseWindowsProcessCreationIdentity(e){return w(e)}function y(e){return parseLinuxProcessCreationIdentity(e,d.readFileSync(`/proc/${e.toString()}/stat`,"utf8"))}export function parseLinuxProcessCreationIdentity(e,t){if(!Number.isSafeInteger(e)||e<=0)throw new Error("Linux process stat identity requires a positive pid");const r=t.trim(),n=r.lastIndexOf(")"),i=r.indexOf(" ");if(n<0||i<1||Number(r.slice(0,i))!==e)throw new Error("Linux process stat identity is malformed");const s=r.slice(n+1).trim().split(/\s+/u)[19];if(!/^\d+$/u.test(s))throw new Error("Linux process stat start time is malformed");return`linux-proc-start:${s}`}function P(e){const t=runBoundedProcessIdentityQuery({args:["-p",e.toString(),"-o","pid=,lstart="],environment:f,executable:l,timeoutMs:S,windowsHide:!1});return parseDarwinProcessCreationIdentity(e,t)}export function parseDarwinProcessCreationIdentity(e,t){if(!Number.isSafeInteger(e)||e<=0)throw new Error("Darwin process start identity requires a positive pid");const r=t.trim().replace(/\s+/gu," "),n=/^(\d+) ((?:Sun|Mon|Tue|Wed|Thu|Fri|Sat) (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (?:[1-9]|[12]\d|3[01]) (?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d \d{4})$/u.exec(r);if(n===null||Number(n[1])!==e)throw new Error("Darwin process start identity is malformed");return`darwin-ps-start:${n[2]}`}function g(e){const t=runBoundedProcessIdentityQuery({args:["process-identity",e.toString()],environment:m().environment,executable:I(),timeoutMs:T,windowsHide:!0});if(!/^\d+$/u.test(t))throw new Error("Windows process creation identity is malformed");return p(t)}export function windowsProcessCreationIdentityScript(e){if(!Number.isSafeInteger(e)||e<=0)throw new Error("Windows process creation identity script requires a positive pid");return`$ErrorActionPreference = "Stop"; $p = [Diagnostics.Process]::GetProcessById(${e.toString()}); try { $fileTime = [Int64]$p.StartTime.ToUniversalTime().ToFileTimeUtc(); if ($fileTime -le 0) { exit 3 }; [Console]::Write($fileTime.ToString([Globalization.CultureInfo]::InvariantCulture)) } finally { $p.Dispose() }`}export function runBoundedProcessIdentityQuery(e){if(!Number.isSafeInteger(e.timeoutMs)||e.timeoutMs<=0)throw new Error("Process identity query timeout must be a positive safe integer in milliseconds");return a(e.executable,[...e.args],{encoding:"utf8",env:e.environment,killSignal:"SIGKILL",maxBuffer:E,stdio:["ignore","pipe","ignore"],timeout:e.timeoutMs,windowsHide:e.windowsHide}).trim()}export function inspectProcessLiveness(e){try{return process.kill(e,0),"alive"}catch(t){return u(t,"ESRCH")?"absent":u(t,"EPERM")?"alive":"unknown"}}function u(e,t){return typeof e=="object"&&e!==null&&Reflect.get(e,"code")===t}
1
+ import{execFileSync as c}from"node:child_process";import d from"node:fs";import{DARWIN_PS_EXECUTABLE as f,HOST_POSIX_INSPECTION_ENVIRONMENT as l,requireWindowsHostPowerShellCommand as m}from"./host-inspection-command.js";import{formatWindowsKernelProcessIdentity as p,parseWindowsKernelProcessIdentity as w}from"./windows-process-identity.js";import{windowsOwnerExecutable as I}from"./windows-native.js";import{hasErrorCode as u}from"../kernel/error-serialization.js";const S=3e3,E=16*1024,T=8e3;let o;export function captureProcessCreationIdentity(e){const t=Number(e);if(!Number.isSafeInteger(t)||t<=0)return null;if(t===process.pid&&o!==void 0)return o;try{let r=null;return process.platform==="linux"?r=P(t):process.platform==="darwin"?r=y(t):process.platform==="win32"&&(r=g(t)),t===process.pid&&r!==null&&(o=r),r}catch{return null}}export function processCreationIdentityMatches(e,t){return observeProcessCreationIdentity(e,t)==="matches"}export function observeProcessCreationIdentity(e,t,r={}){const n=Number(e);if(!Number.isSafeInteger(n)||n<=0||typeof t!="string"||t.length===0)return"unknown";const i=(r.captureIdentity??captureProcessCreationIdentity)(n);return i!==null?i===t?"matches":"different":(r.inspectLiveness??inspectProcessLiveness)(n)==="absent"?"different":"unknown"}export function parseWindowsProcessCreationIdentity(e){return w(e)}function P(e){return parseLinuxProcessCreationIdentity(e,d.readFileSync(`/proc/${e.toString()}/stat`,"utf8"))}export function parseLinuxProcessCreationIdentity(e,t){if(!Number.isSafeInteger(e)||e<=0)throw new Error("Linux process stat identity requires a positive pid");const r=t.trim(),n=r.lastIndexOf(")"),i=r.indexOf(" ");if(n<0||i<1||Number(r.slice(0,i))!==e)throw new Error("Linux process stat identity is malformed");const s=r.slice(n+1).trim().split(/\s+/u)[19];if(!/^\d+$/u.test(s))throw new Error("Linux process stat start time is malformed");return`linux-proc-start:${s}`}function y(e){const t=runBoundedProcessIdentityQuery({args:["-p",e.toString(),"-o","pid=,lstart="],environment:l,executable:f,timeoutMs:S,windowsHide:!1});return parseDarwinProcessCreationIdentity(e,t)}export function parseDarwinProcessCreationIdentity(e,t){if(!Number.isSafeInteger(e)||e<=0)throw new Error("Darwin process start identity requires a positive pid");const r=t.trim().replace(/\s+/gu," "),n=/^(\d+) ((?:Sun|Mon|Tue|Wed|Thu|Fri|Sat) (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (?:[1-9]|[12]\d|3[01]) (?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d \d{4})$/u.exec(r);if(n===null||Number(n[1])!==e)throw new Error("Darwin process start identity is malformed");return`darwin-ps-start:${n[2]}`}function g(e){const t=runBoundedProcessIdentityQuery({args:["process-identity",e.toString()],environment:m().environment,executable:I(),timeoutMs:T,windowsHide:!0});if(!/^\d+$/u.test(t))throw new Error("Windows process creation identity is malformed");return p(t)}export function windowsProcessCreationIdentityScript(e){if(!Number.isSafeInteger(e)||e<=0)throw new Error("Windows process creation identity script requires a positive pid");return`$ErrorActionPreference = "Stop"; $p = [Diagnostics.Process]::GetProcessById(${e.toString()}); try { $fileTime = [Int64]$p.StartTime.ToUniversalTime().ToFileTimeUtc(); if ($fileTime -le 0) { exit 3 }; [Console]::Write($fileTime.ToString([Globalization.CultureInfo]::InvariantCulture)) } finally { $p.Dispose() }`}export function runBoundedProcessIdentityQuery(e){if(!Number.isSafeInteger(e.timeoutMs)||e.timeoutMs<=0)throw new Error("Process identity query timeout must be a positive safe integer in milliseconds");return c(e.executable,[...e.args],{encoding:"utf8",env:e.environment,killSignal:"SIGKILL",maxBuffer:E,stdio:["ignore","pipe","ignore"],timeout:e.timeoutMs,windowsHide:e.windowsHide}).trim()}export function inspectProcessLiveness(e){try{return process.kill(e,0),"alive"}catch(t){return u(t,"ESRCH")?"absent":u(t,"EPERM")?"alive":"unknown"}}