@bjoernrochel/sevro 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (403) hide show
  1. package/CONTRIBUTING.md +34 -4
  2. package/README.md +7 -6
  3. package/dist/examples/basic/graded.json +13 -0
  4. package/dist/examples/basic/host.js +9 -0
  5. package/dist/examples/basic/host.js.map +1 -0
  6. package/dist/examples/basic/prompt-only.json +7 -0
  7. package/dist/examples/recipes/candidate.js +23 -0
  8. package/dist/examples/recipes/candidate.js.map +1 -0
  9. package/dist/examples/recipes/cases/coding-change.json +21 -0
  10. package/dist/examples/recipes/cases/host-tools.json +21 -0
  11. package/dist/examples/recipes/cases/mise.json +21 -0
  12. package/dist/examples/recipes/cases/node.json +21 -0
  13. package/dist/examples/recipes/cases/python-uv.json +21 -0
  14. package/dist/examples/recipes/cases/semantic.json +17 -0
  15. package/dist/examples/recipes/coding-change/check.js +16 -0
  16. package/dist/examples/recipes/coding-change/check.js.map +1 -0
  17. package/dist/examples/recipes/executable.js +20 -0
  18. package/dist/examples/recipes/executable.js.map +1 -0
  19. package/dist/examples/recipes/extension-artifacts.js +56 -0
  20. package/dist/examples/recipes/extension-artifacts.js.map +1 -0
  21. package/dist/examples/recipes/extension-methods.js +167 -0
  22. package/dist/examples/recipes/extension-methods.js.map +1 -0
  23. package/dist/examples/recipes/extension.js +28 -0
  24. package/dist/examples/recipes/extension.js.map +1 -0
  25. package/dist/examples/recipes/modules.js +9 -0
  26. package/dist/examples/recipes/modules.js.map +1 -0
  27. package/dist/examples/recipes/repository-skill/.agents/skills/startup-guide/SKILL.md +7 -0
  28. package/dist/examples/recipes/repository-skill/.claude/skills/startup-guide/SKILL.md +7 -0
  29. package/dist/examples/recipes/repository-skill/README.md +3 -0
  30. package/dist/examples/recipes/run-inputs.js +144 -0
  31. package/dist/examples/recipes/run-inputs.js.map +1 -0
  32. package/dist/examples/recipes/run-options.js +103 -0
  33. package/dist/examples/recipes/run-options.js.map +1 -0
  34. package/dist/examples/recipes/run.js +62 -0
  35. package/dist/examples/recipes/run.js.map +1 -0
  36. package/dist/examples/recipes/runtime/empty.json +1 -0
  37. package/dist/examples/recipes/runtime/goals.json +1 -0
  38. package/dist/examples/recipes/runtime/mise.json +6 -0
  39. package/dist/examples/recipes/runtime/path.json +1 -0
  40. package/dist/examples/recipes/runtime/plugins.json +4 -0
  41. package/dist/examples/recipes/runtime/python-uv.json +10 -0
  42. package/dist/examples/recipes/semantic-judge.js +27 -0
  43. package/dist/examples/recipes/semantic-judge.js.map +1 -0
  44. package/dist/examples/templates/coding/adapter.js +14 -0
  45. package/dist/examples/templates/coding/adapter.js.map +1 -0
  46. package/dist/examples/templates/coding/case.json +15 -0
  47. package/dist/examples/templates/repository-skill/.agents/skills/startup-guide/SKILL.md +6 -0
  48. package/dist/examples/templates/repository-skill/extension-data.js +61 -0
  49. package/dist/examples/templates/repository-skill/extension-data.js.map +1 -0
  50. package/dist/examples/templates/repository-skill/extension.js +29 -0
  51. package/dist/examples/templates/repository-skill/extension.js.map +1 -0
  52. package/dist/examples/templates/response/adapter.js +13 -0
  53. package/dist/examples/templates/response/adapter.js.map +1 -0
  54. package/dist/examples/templates/response/case.json +13 -0
  55. package/dist/src/advisory.js +86 -0
  56. package/dist/src/advisory.js.map +1 -0
  57. package/dist/src/candidate-artifacts.js +139 -0
  58. package/dist/src/candidate-artifacts.js.map +1 -0
  59. package/dist/src/candidate-codex-state.js +110 -0
  60. package/dist/src/candidate-codex-state.js.map +1 -0
  61. package/dist/src/case-validation.js +92 -0
  62. package/dist/src/case-validation.js.map +1 -0
  63. package/dist/src/cli/cancellation.js +21 -0
  64. package/dist/src/cli/cancellation.js.map +1 -0
  65. package/dist/src/cli/command.js +60 -0
  66. package/dist/src/cli/command.js.map +1 -0
  67. package/dist/src/cli/completion.js +14 -0
  68. package/dist/src/cli/completion.js.map +1 -0
  69. package/dist/src/cli/demo.js +45 -0
  70. package/dist/src/cli/demo.js.map +1 -0
  71. package/dist/src/cli/evaluation.js +40 -0
  72. package/dist/src/cli/evaluation.js.map +1 -0
  73. package/dist/src/cli/extension.js +54 -0
  74. package/dist/src/cli/extension.js.map +1 -0
  75. package/dist/src/cli/help.js +190 -0
  76. package/dist/src/cli/help.js.map +1 -0
  77. package/dist/src/cli/hosts.js +33 -0
  78. package/dist/src/cli/hosts.js.map +1 -0
  79. package/dist/src/cli/init-settings.js +29 -0
  80. package/dist/src/cli/init-settings.js.map +1 -0
  81. package/dist/src/cli/init.js +82 -0
  82. package/dist/src/cli/init.js.map +1 -0
  83. package/dist/src/cli/invocation.js +431 -0
  84. package/dist/src/cli/invocation.js.map +1 -0
  85. package/dist/src/cli/loading.js +110 -0
  86. package/dist/src/cli/loading.js.map +1 -0
  87. package/dist/src/cli/preparation.js +88 -0
  88. package/dist/src/cli/preparation.js.map +1 -0
  89. package/dist/src/cli/presentation.js +61 -0
  90. package/dist/src/cli/presentation.js.map +1 -0
  91. package/dist/src/cli/progress.js +5 -0
  92. package/dist/src/cli/progress.js.map +1 -0
  93. package/dist/src/cli/run-manifest.js +108 -0
  94. package/dist/src/cli/run-manifest.js.map +1 -0
  95. package/dist/src/cli/run-options.js +367 -0
  96. package/dist/src/cli/run-options.js.map +1 -0
  97. package/dist/src/cli/run-overrides.js +51 -0
  98. package/dist/src/cli/run-overrides.js.map +1 -0
  99. package/dist/src/cli/settings.js +127 -0
  100. package/dist/src/cli/settings.js.map +1 -0
  101. package/dist/src/cli/summary.js +28 -0
  102. package/dist/src/cli/summary.js.map +1 -0
  103. package/dist/src/cli.js +20 -0
  104. package/dist/src/cli.js.map +1 -0
  105. package/dist/src/contract-types.js +2 -0
  106. package/dist/src/contract-types.js.map +1 -0
  107. package/dist/src/engine.js +4 -0
  108. package/dist/src/engine.js.map +1 -0
  109. package/dist/src/evaluation/advisory.js +85 -0
  110. package/dist/src/evaluation/advisory.js.map +1 -0
  111. package/dist/src/evaluation/check-plan.js +292 -0
  112. package/dist/src/evaluation/check-plan.js.map +1 -0
  113. package/dist/src/evaluation/collection.js +61 -0
  114. package/dist/src/evaluation/collection.js.map +1 -0
  115. package/dist/src/evaluation/context.js +2 -0
  116. package/dist/src/evaluation/context.js.map +1 -0
  117. package/dist/src/evaluation/grading-host.js +28 -0
  118. package/dist/src/evaluation/grading-host.js.map +1 -0
  119. package/dist/src/evaluation/grading.js +154 -0
  120. package/dist/src/evaluation/grading.js.map +1 -0
  121. package/dist/src/evaluation/invocation-plan.js +312 -0
  122. package/dist/src/evaluation/invocation-plan.js.map +1 -0
  123. package/dist/src/evaluation/plan.js +376 -0
  124. package/dist/src/evaluation/plan.js.map +1 -0
  125. package/dist/src/evaluation/progress.js +14 -0
  126. package/dist/src/evaluation/progress.js.map +1 -0
  127. package/dist/src/evaluation/resources.js +159 -0
  128. package/dist/src/evaluation/resources.js.map +1 -0
  129. package/dist/src/evaluation/run.js +148 -0
  130. package/dist/src/evaluation/run.js.map +1 -0
  131. package/dist/src/evaluation/scheduler.js +27 -0
  132. package/dist/src/evaluation/scheduler.js.map +1 -0
  133. package/dist/src/evaluation/semantic.js +183 -0
  134. package/dist/src/evaluation/semantic.js.map +1 -0
  135. package/dist/src/evaluation/trial.js +593 -0
  136. package/dist/src/evaluation/trial.js.map +1 -0
  137. package/dist/src/evaluation/types.js +20 -0
  138. package/dist/src/evaluation/types.js.map +1 -0
  139. package/dist/src/evidence/host-results.js +67 -0
  140. package/dist/src/evidence/host-results.js.map +1 -0
  141. package/dist/src/evidence/retained-artifacts.js +17 -0
  142. package/dist/src/evidence/retained-artifacts.js.map +1 -0
  143. package/dist/src/evidence/trial-writer.js +131 -0
  144. package/dist/src/evidence/trial-writer.js.map +1 -0
  145. package/dist/src/evidence/usage.js +14 -0
  146. package/dist/src/evidence/usage.js.map +1 -0
  147. package/dist/src/executable.js +20 -0
  148. package/dist/src/executable.js.map +1 -0
  149. package/dist/src/extension-client.js +212 -0
  150. package/dist/src/extension-client.js.map +1 -0
  151. package/dist/src/extension-session.js +236 -0
  152. package/dist/src/extension-session.js.map +1 -0
  153. package/dist/src/fixtures/advisory.js +206 -0
  154. package/dist/src/fixtures/advisory.js.map +1 -0
  155. package/dist/src/fixtures/bin.js +41 -0
  156. package/dist/src/fixtures/bin.js.map +1 -0
  157. package/dist/src/fixtures/cleanup.js +43 -0
  158. package/dist/src/fixtures/cleanup.js.map +1 -0
  159. package/dist/src/fixtures/create.js +94 -0
  160. package/dist/src/fixtures/create.js.map +1 -0
  161. package/dist/src/fixtures/generated.js +181 -0
  162. package/dist/src/fixtures/generated.js.map +1 -0
  163. package/dist/src/fixtures/git-hooks.js +16 -0
  164. package/dist/src/fixtures/git-hooks.js.map +1 -0
  165. package/dist/src/fixtures/preparation.js +201 -0
  166. package/dist/src/fixtures/preparation.js.map +1 -0
  167. package/dist/src/fixtures/repository.js +255 -0
  168. package/dist/src/fixtures/repository.js.map +1 -0
  169. package/dist/src/fixtures/setup.js +175 -0
  170. package/dist/src/fixtures/setup.js.map +1 -0
  171. package/dist/src/fixtures/tools.js +57 -0
  172. package/dist/src/fixtures/tools.js.map +1 -0
  173. package/dist/src/fixtures/workspace-state.js +155 -0
  174. package/dist/src/fixtures/workspace-state.js.map +1 -0
  175. package/dist/src/generated/cli-result.cjs +2 -0
  176. package/dist/src/generated/extension.cjs +2 -0
  177. package/dist/src/generated/report.cjs +2 -0
  178. package/dist/src/generated/run-evidence.cjs +2 -0
  179. package/dist/src/generated/runtime.cjs +2 -0
  180. package/dist/src/git.js +72 -0
  181. package/dist/src/git.js.map +1 -0
  182. package/dist/src/graders/artifact.js +68 -0
  183. package/dist/src/graders/artifact.js.map +1 -0
  184. package/dist/src/graders/git-head.js +112 -0
  185. package/dist/src/graders/git-head.js.map +1 -0
  186. package/dist/src/graders/output.js +345 -0
  187. package/dist/src/graders/output.js.map +1 -0
  188. package/dist/src/graders/semantic.js +132 -0
  189. package/dist/src/graders/semantic.js.map +1 -0
  190. package/dist/src/graders/shell.js +321 -0
  191. package/dist/src/graders/shell.js.map +1 -0
  192. package/dist/src/host-diagnostic-redaction.js +52 -0
  193. package/dist/src/host-diagnostic-redaction.js.map +1 -0
  194. package/dist/src/host-diagnostics.js +248 -0
  195. package/dist/src/host-diagnostics.js.map +1 -0
  196. package/dist/src/hosts/claude-continuation.js +89 -0
  197. package/dist/src/hosts/claude-continuation.js.map +1 -0
  198. package/dist/src/hosts/claude-credential.js +121 -0
  199. package/dist/src/hosts/claude-credential.js.map +1 -0
  200. package/dist/src/hosts/claude-events.js +136 -0
  201. package/dist/src/hosts/claude-events.js.map +1 -0
  202. package/dist/src/hosts/claude-keychain.js +100 -0
  203. package/dist/src/hosts/claude-keychain.js.map +1 -0
  204. package/dist/src/hosts/claude-login-recovery.js +67 -0
  205. package/dist/src/hosts/claude-login-recovery.js.map +1 -0
  206. package/dist/src/hosts/claude-login-refresh.js +146 -0
  207. package/dist/src/hosts/claude-login-refresh.js.map +1 -0
  208. package/dist/src/hosts/claude-login-store.js +124 -0
  209. package/dist/src/hosts/claude-login-store.js.map +1 -0
  210. package/dist/src/hosts/claude-login.js +74 -0
  211. package/dist/src/hosts/claude-login.js.map +1 -0
  212. package/dist/src/hosts/claude-native-goal.js +138 -0
  213. package/dist/src/hosts/claude-native-goal.js.map +1 -0
  214. package/dist/src/hosts/claude-process.js +10 -0
  215. package/dist/src/hosts/claude-process.js.map +1 -0
  216. package/dist/src/hosts/claude-refresh-lock.js +76 -0
  217. package/dist/src/hosts/claude-refresh-lock.js.map +1 -0
  218. package/dist/src/hosts/claude-repository-invocation.js +229 -0
  219. package/dist/src/hosts/claude-repository-invocation.js.map +1 -0
  220. package/dist/src/hosts/claude-settings.js +156 -0
  221. package/dist/src/hosts/claude-settings.js.map +1 -0
  222. package/dist/src/hosts/claude-skill-activations.js +131 -0
  223. package/dist/src/hosts/claude-skill-activations.js.map +1 -0
  224. package/dist/src/hosts/claude-state.js +237 -0
  225. package/dist/src/hosts/claude-state.js.map +1 -0
  226. package/dist/src/hosts/claude-tool-calls.js +150 -0
  227. package/dist/src/hosts/claude-tool-calls.js.map +1 -0
  228. package/dist/src/hosts/claude.js +373 -0
  229. package/dist/src/hosts/claude.js.map +1 -0
  230. package/dist/src/hosts/codex-app-server.js +764 -0
  231. package/dist/src/hosts/codex-app-server.js.map +1 -0
  232. package/dist/src/hosts/codex-configuration.js +91 -0
  233. package/dist/src/hosts/codex-configuration.js.map +1 -0
  234. package/dist/src/hosts/codex-events.js +104 -0
  235. package/dist/src/hosts/codex-events.js.map +1 -0
  236. package/dist/src/hosts/codex-exec-controls.js +434 -0
  237. package/dist/src/hosts/codex-exec-controls.js.map +1 -0
  238. package/dist/src/hosts/codex-invocation.js +54 -0
  239. package/dist/src/hosts/codex-invocation.js.map +1 -0
  240. package/dist/src/hosts/codex-marketplace.js +185 -0
  241. package/dist/src/hosts/codex-marketplace.js.map +1 -0
  242. package/dist/src/hosts/codex-native-calls.js +516 -0
  243. package/dist/src/hosts/codex-native-calls.js.map +1 -0
  244. package/dist/src/hosts/codex-process.js +10 -0
  245. package/dist/src/hosts/codex-process.js.map +1 -0
  246. package/dist/src/hosts/codex-profile.js +206 -0
  247. package/dist/src/hosts/codex-profile.js.map +1 -0
  248. package/dist/src/hosts/codex-session-files.js +89 -0
  249. package/dist/src/hosts/codex-session-files.js.map +1 -0
  250. package/dist/src/hosts/codex-state.js +310 -0
  251. package/dist/src/hosts/codex-state.js.map +1 -0
  252. package/dist/src/hosts/codex.js +527 -0
  253. package/dist/src/hosts/codex.js.map +1 -0
  254. package/dist/src/hosts/isolation-common.js +43 -0
  255. package/dist/src/hosts/isolation-common.js.map +1 -0
  256. package/dist/src/hosts/isolation-roots.js +64 -0
  257. package/dist/src/hosts/isolation-roots.js.map +1 -0
  258. package/dist/src/hosts/isolation.js +12 -0
  259. package/dist/src/hosts/isolation.js.map +1 -0
  260. package/dist/src/hosts/linux-sandbox.js +127 -0
  261. package/dist/src/hosts/linux-sandbox.js.map +1 -0
  262. package/dist/src/hosts/mac-sandbox.js +137 -0
  263. package/dist/src/hosts/mac-sandbox.js.map +1 -0
  264. package/dist/src/hosts/native-controls.js +151 -0
  265. package/dist/src/hosts/native-controls.js.map +1 -0
  266. package/dist/src/hosts/native-request.js +33 -0
  267. package/dist/src/hosts/native-request.js.map +1 -0
  268. package/dist/src/hosts/process-lifecycle.js +167 -0
  269. package/dist/src/hosts/process-lifecycle.js.map +1 -0
  270. package/dist/src/hosts/protected-worktrees.js +81 -0
  271. package/dist/src/hosts/protected-worktrees.js.map +1 -0
  272. package/dist/src/hosts/skill-hook-catalog.js +100 -0
  273. package/dist/src/hosts/skill-hook-catalog.js.map +1 -0
  274. package/dist/src/hosts/skill-hook-handler.js +228 -0
  275. package/dist/src/hosts/skill-hook-handler.js.map +1 -0
  276. package/dist/src/hosts/skill-hooks.js +423 -0
  277. package/dist/src/hosts/skill-hooks.js.map +1 -0
  278. package/dist/src/hosts/workspace-fingerprint.js +72 -0
  279. package/dist/src/hosts/workspace-fingerprint.js.map +1 -0
  280. package/dist/src/identity.js +167 -0
  281. package/dist/src/identity.js.map +1 -0
  282. package/dist/src/instrumentation.js +83 -0
  283. package/dist/src/instrumentation.js.map +1 -0
  284. package/dist/src/native-transcript-state.js +85 -0
  285. package/dist/src/native-transcript-state.js.map +1 -0
  286. package/dist/src/native-transcript-view.js +65 -0
  287. package/dist/src/native-transcript-view.js.map +1 -0
  288. package/dist/src/native-transcripts.js +208 -0
  289. package/dist/src/native-transcripts.js.map +1 -0
  290. package/dist/src/paths.js +13 -0
  291. package/dist/src/paths.js.map +1 -0
  292. package/dist/src/process-lifecycle.js +101 -0
  293. package/dist/src/process-lifecycle.js.map +1 -0
  294. package/dist/src/provenance.js +263 -0
  295. package/dist/src/provenance.js.map +1 -0
  296. package/dist/src/prune.js +228 -0
  297. package/dist/src/prune.js.map +1 -0
  298. package/dist/src/report.js +276 -0
  299. package/dist/src/report.js.map +1 -0
  300. package/dist/src/resolved-case.js +29 -0
  301. package/dist/src/resolved-case.js.map +1 -0
  302. package/dist/src/results-lock.js +40 -0
  303. package/dist/src/results-lock.js.map +1 -0
  304. package/dist/src/results.js +127 -0
  305. package/dist/src/results.js.map +1 -0
  306. package/dist/src/run-owner.js +283 -0
  307. package/dist/src/run-owner.js.map +1 -0
  308. package/dist/src/runner-paths.js +11 -0
  309. package/dist/src/runner-paths.js.map +1 -0
  310. package/dist/src/runtime/config.js +323 -0
  311. package/dist/src/runtime/config.js.map +1 -0
  312. package/dist/src/runtime/discovery-apple.js +65 -0
  313. package/dist/src/runtime/discovery-apple.js.map +1 -0
  314. package/dist/src/runtime/discovery-providers.js +37 -0
  315. package/dist/src/runtime/discovery-providers.js.map +1 -0
  316. package/dist/src/runtime/discovery.js +40 -0
  317. package/dist/src/runtime/discovery.js.map +1 -0
  318. package/dist/src/runtime/hook-processes.js +81 -0
  319. package/dist/src/runtime/hook-processes.js.map +1 -0
  320. package/dist/src/runtime/hooks.js +304 -0
  321. package/dist/src/runtime/hooks.js.map +1 -0
  322. package/dist/src/runtime/paths.js +244 -0
  323. package/dist/src/runtime/paths.js.map +1 -0
  324. package/dist/src/runtime/query.js +76 -0
  325. package/dist/src/runtime/query.js.map +1 -0
  326. package/dist/src/runtime/seeds.js +98 -0
  327. package/dist/src/runtime/seeds.js.map +1 -0
  328. package/dist/src/runtime/shared-cache.js +81 -0
  329. package/dist/src/runtime/shared-cache.js.map +1 -0
  330. package/dist/src/runtime/state.js +106 -0
  331. package/dist/src/runtime/state.js.map +1 -0
  332. package/dist/src/runtime-process.js +148 -0
  333. package/dist/src/runtime-process.js.map +1 -0
  334. package/dist/src/schema-types.js +2 -0
  335. package/dist/src/schema-types.js.map +1 -0
  336. package/dist/src/schema.js +16 -0
  337. package/dist/src/schema.js.map +1 -0
  338. package/dist/src/shell.js +5 -0
  339. package/dist/src/shell.js.map +1 -0
  340. package/dist/src/sqlite-lock.js +18 -0
  341. package/dist/src/sqlite-lock.js.map +1 -0
  342. package/dist/src/storage.js +21 -0
  343. package/dist/src/storage.js.map +1 -0
  344. package/dist/src/transcript-retention.js +109 -0
  345. package/dist/src/transcript-retention.js.map +1 -0
  346. package/dist/src/value-guards.js +26 -0
  347. package/dist/src/value-guards.js.map +1 -0
  348. package/docs/architecture.md +5 -2
  349. package/docs/creating-cases.md +2 -3
  350. package/docs/development-cli.md +12 -7
  351. package/docs/documentation-quality.md +4 -3
  352. package/docs/evaluation-workflow.md +8 -8
  353. package/docs/getting-started.md +7 -6
  354. package/docs/guide-evaluation.md +1 -1
  355. package/docs/identity-v1.md +4 -1
  356. package/docs/installing.md +31 -13
  357. package/docs/licensing.md +2 -2
  358. package/docs/native-hosts.md +1 -1
  359. package/docs/recipes.md +41 -40
  360. package/docs/releases.md +20 -4
  361. package/docs/run-settings-v1.md +3 -3
  362. package/docs/specs/repository-guide.md +1 -1
  363. package/docs/troubleshooting.md +1 -1
  364. package/docs/typescript-quality.md +18 -1
  365. package/examples/recipes/executable.ts +19 -0
  366. package/examples/recipes/extension-artifacts.ts +1 -1
  367. package/examples/recipes/extension.ts +2 -1
  368. package/examples/recipes/modules.ts +9 -0
  369. package/examples/recipes/run-inputs.ts +14 -19
  370. package/examples/recipes/run-options.ts +9 -8
  371. package/examples/recipes/run.ts +21 -7
  372. package/examples/templates/repository-skill/extension-data.ts +1 -1
  373. package/examples/templates/repository-skill/extension.ts +2 -1
  374. package/package.json +14 -6
  375. package/src/cli/demo.ts +3 -2
  376. package/src/cli/help.ts +4 -3
  377. package/src/cli/init-settings.ts +5 -4
  378. package/src/cli/init.ts +9 -8
  379. package/src/cli/invocation.ts +2 -1
  380. package/src/cli/preparation.ts +2 -2
  381. package/src/cli.ts +1 -1
  382. package/src/executable.ts +19 -0
  383. package/src/extension-client.ts +6 -12
  384. package/src/fixtures/setup.ts +3 -2
  385. package/src/git.ts +2 -1
  386. package/src/graders/git-head.ts +3 -2
  387. package/src/graders/shell.ts +4 -3
  388. package/src/hosts/claude-keychain.ts +3 -2
  389. package/src/hosts/claude-login-refresh.ts +3 -2
  390. package/src/hosts/claude-refresh-lock.ts +2 -1
  391. package/src/hosts/isolation-roots.ts +3 -2
  392. package/src/hosts/process-lifecycle.ts +4 -6
  393. package/src/hosts/protected-worktrees.ts +2 -1
  394. package/src/hosts/skill-hook-handler.ts +1 -1
  395. package/src/hosts/skill-hooks.ts +10 -2
  396. package/src/provenance.ts +7 -6
  397. package/src/results-lock.ts +4 -4
  398. package/src/run-owner.ts +15 -9
  399. package/src/runner-paths.ts +21 -0
  400. package/src/runtime/hook-processes.ts +2 -1
  401. package/src/runtime/hooks.ts +9 -7
  402. package/src/runtime-process.ts +194 -0
  403. package/src/sqlite-lock.ts +25 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["report.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,yBAAyB;AAC5C,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,kBAAkB;AACtD,OAAO,EAAE,SAAS,EAAE,kBAAkB;AACtC,OAAO,EAAE,aAAa,EAAE,sBAAmB;AAC3C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,oBAAiB;AAC5E,OAAO,EAAE,oBAAoB,EAAE,2BAAwB;AACvD,OAAO,EAAE,yBAAyB,EAAE,kCAA+B;AASnE,SAAS,QAAQ,CAAC,MAAwC;IACxD,OAAO,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC;QAC5D,CAAC,CAAC,MAAM,CAAC,MAAM,CAAS,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,EAAE,CAAC,CAAC;QAC3D,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,SAAS,QAAQ,CAAC,MAAe;IAC/B,IACE,CAAC,MAAM,CAAC,MAAM;QACd,MAAM,CAAC,IAAI,CACT,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,WAAW;YACtC,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,WAAW;YACpC,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,cAAc,CACxC;QAED,OAAO,IAAI,CAAC;IACd,OAAO,CACL,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,MAAM;QAChE,MAAM,CAAC,MAAM,CACd,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACjE,eAAe,CAAC,MAAM,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,MAAiB;IAC3C,MAAM,IAAI,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAChE,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACzB,MAAM,QAAQ,GAAG,KAAK,CAAC;IACvB,IACE,QAAQ,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK;QAC/B,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,aAAa,CAAC,MAAM,CAAC;QAExD,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAiB;IAC7C,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,YAAY,CAAC;AAC7B,CAAC;AAED,SAAS,aAAa,CACpB,MAAc,EACd,MAAe,EACf,QAAyB;IAEzB,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IAC1E,IACE,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;QACjC,MAAM,CAAC,IAAI,CACT,CAAC,KAAK,EAAE,EAAE,CACR,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CACrE;QAED,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,SAAS,CAChB,IAAY,EACZ,MAAiB,EACjB,QAAc,EACd,QAAyB,EACzB,WAAkE;IAElE,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3E,MAAM,cAAc,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO;QACL,UAAU,EAAE,IAAI;QAChB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM;QACpC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM;QAChC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO;QAC3B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM;QAClC,YAAY,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QACvC,mBAAmB,EAAE,QAAQ,CAC3B,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,CACnD;QACD,GAAG,KAAK;QACR,GAAG,gBAAgB,CAAC,QAAQ,CAAC;QAC7B,cAAc;QACd,iBAAiB,EAAE;YACjB,QAAQ,EAAE,WAAW,CAAC,MAAM,CAC1B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAC1D,CAAC,MAAM;YACR,MAAM,EAAE,WAAW,CAAC,MAAM,CACxB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CACzD,CAAC,MAAM;SACT;QACD,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAChD,CAAC,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC7C,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC,CACJ;KACF,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAC7B,QAAyB;IAEzB,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,EAC1E,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;IACnB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,KAAK,SAAS;QAC5C,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;AACxE,CAAC;AACD,SAAS,aAAa,CAAC,QAA4B;IACjD,MAAM,QAAQ,GACZ,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACzE,OAAO;QACL,WAAW,EAAE,QAAQ;YACnB,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YAC5D,CAAC,CAAC,IAAI;QACR,YAAY,EAAE,QAAQ;YACpB,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YAC7D,CAAC,CAAC,IAAI;QACR,OAAO,EAAE,QAAQ;YACf,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACxD,CAAC,CAAC,IAAI;KACT,CAAC;AACJ,CAAC;AACD,SAAS,gBAAgB,CAAC,QAAyB;IACjD,IAAI,CAAC,QAAQ;QACX,OAAO;YACL,iBAAiB,EAAE,IAAI;YACvB,gBAAgB,EAAE,IAAI;YACtB,kBAAkB,EAAE,IAAI;YACxB,eAAe,EAAE,IAAI;YACrB,MAAM,EAAE,EAAE;SACX,CAAC;IACJ,OAAO;QACL,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW;QAC9C,gBAAgB,EAAE,QAAQ,CAAC,kBAAkB,CAAC,MAAM;QACpD,kBAAkB,EAAE,QAAQ,CAAC,SAAS,CAAC,SAAS;QAChD,eAAe,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM;QAC1C,MAAM,EAAE,QAAQ,CAAC,MAAM;KACxB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAe;IAChD,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM;QACvD,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAyB,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,WAAW,GAAG,MAAM,yBAAyB,CAAC,QAAQ,CAAC,CAAC;QAC9D,MAAM,CAAC,IAAI,CAAC;YACV,UAAU,EAAE,IAAI;YAChB,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM;YAClC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;YAC9B,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO;YACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;SAC/B,CAAC,CAAC;QACH,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,KAAK;YACjC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,MAAM,GAAG;QACb,MAAM,EAAE,iBAAiB;QACzB,MAAM;QACN,IAAI;QACJ,OAAO,EAAE;YACP,KAAK,EAAE,IAAI,CAAC,MAAM;YAClB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,MAAM;YAC1D,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,MAAM;YAC1D,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,MAAM;SACtE;KACF,CAAC;IACF,YAAY,CAAC,MAAM,CAAC,CAAC;IACrB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,IAAI,CAAC,KAAa;IACzB,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,QAAQ,CAAC,KAAoB,EAAE,MAAM,GAAG,CAAC;IAChD,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,OAAO,CAAC,KAAoB;IACnC,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,MAAgD;IAEhD,MAAM,KAAK,GAAG;QACZ,2BAA2B;QAC3B,EAAE;QACF,8HAA8H;QAC9H,EAAE;QACF,UAAU,MAAM,CAAC,OAAO,CAAC,KAAK,aAAa,MAAM,CAAC,OAAO,CAAC,MAAM,aAAa,MAAM,CAAC,OAAO,CAAC,MAAM,mBAAmB,MAAM,CAAC,OAAO,CAAC,WAAW,GAAG;QAClJ,EAAE;QACF,eAAe;QACf,EAAE;QACF,6DAA6D;QAC7D,yCAAyC;QACzC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAClB,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,QAAQ,MAAM,KAAK,CAAC,SAAS,MAAM,KAAK,CAAC,OAAO,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,SAAS,IAAI,CACnI;QACD,EAAE;QACF,kBAAkB;QAClB,EAAE;QACF,sIAAsI;QACtI,mEAAmE;QACnE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC;QACnC,EAAE;QACF,sBAAsB;QACtB,EAAE;QACF,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAChB,CAAC,GAAG,EAAE,EAAE,CACN,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,YAAY,IAAI,aAAa,GAAG,iBAAiB,CAAC,GAAG,CAAC,EAAE,CACzF;QACD,EAAE;KACH,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAC3C,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAC1E,CAAC;IACF,IAAI,QAAQ,CAAC,MAAM;QACjB,KAAK,CAAC,IAAI,CACR,oBAAoB,EACpB,EAAE,EACF,sDAAsD,EACtD,EAAE,EACF,qCAAqC,EACrC,4BAA4B,EAC5B,GAAG,QAAQ,CAAC,GAAG,CACb,CAAC,OAAO,EAAE,EAAE,CACV,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,KAAK,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,OAAO,CAAC,MAAM,IAAI,CAC7F,EACD,EAAE,CACH,CAAC;IACJ,KAAK,CAAC,IAAI,CACR,WAAW,EACX,EAAE,EACF,yCAAyC,EACzC,iCAAiC,EACjC,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAC7B,GAAG,CAAC,MAAM,CAAC,GAAG,CACZ,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CACjH,CACF,EACD,EAAE,CACH,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAc;IACvC,IAAI,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,EAAE,CAAC;IACtC,OAAO,yBAAyB,GAAG,CAAC,iBAAiB,CAAC,QAAQ,cAAc,GAAG,CAAC,iBAAiB,CAAC,MAAM,SAAS,CAAC;AACpH,CAAC;AAED,SAAS,YAAY,CAAC,IAAmB;IACvC,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AACnE,CAAC;AACD,SAAS,QAAQ,CAAC,IAAmB;IACnC,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3D,CAAC;AACD,SAAS,SAAS,CAAC,KAAkC;IACnD,OAAO,KAAK;QACV,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACtD,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AACD,SAAS,aAAa,CAAC,GAAc;IACnC,OAAO,GAAG,GAAG,CAAC,kBAAkB,IAAI,SAAS,MAAM,GAAG,CAAC,eAAe,IAAI,SAAS,EAAE,CAAC;AACxF,CAAC;AACD,SAAS,eAAe,CAAC,GAAc;IACrC,OAAO,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,SAAS,MAAM,GAAG,CAAC,OAAO,MAAM,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,aAAa,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC;AACpT,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAc;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CACnE,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAc;IACtC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;QACxC,IAAI,EAAE,IAAI;QACV,gBAAgB,EAAE,IAAI;QACtB,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE;YACP,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YACzB,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;YACjD,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YAC3B,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SACnC;KACF,CAAC,CAAC;IACH,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,KAAK,QAAQ;QACzD,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,MAA2C;IAE3C,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,oBAAoB,CAC3B,MAA2C;IAE3C,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,SAAS;QACtD,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,IAAI,MAAM,CAAC,cAAc,CAAC,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM;QACxD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,mBAAmB,CAC1B,MAA2C;IAE3C,OAAO,MAAM,CAAC,MAAM;QAClB,CAAC,CAAC;YACE,IAAI,CACF,MAAM,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,SAAS,CAAC,EAClE,aAAa,CACd;SACF;QACH,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;AACpC,CAAC;AACD,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC;AACzE,CAAC","sourcesContent":["import type {\n CliResultData,\n ReportData,\n RunEvidenceData,\n} from \"./schema-types\";\nimport { readFile } from \"node:fs/promises\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport { canonicalJson } from \"./identity\";\nimport { assertCliResult, assertReport, assertRunEvidence } from \"./schema\";\nimport { canonicalRuntimeRoot } from \"./runtime/paths\";\nimport { nativeTranscriptRetention } from \"./transcript-retention\";\n\ntype CliResult = CliResultData;\ntype Evidence = RunEvidenceData;\ntype Case = CliResult[\"cases\"][number];\ntype Trial = Case[\"trials\"][number];\n\nexport type ReportRow = ReportData[\"rows\"][number];\n\nfunction sumKnown(values: Array<number | null | undefined>): number | null {\n return values.length && values.every((value) => value != null)\n ? values.reduce<number>((total, value) => total + value, 0)\n : null;\n}\n\nfunction passRate(trials: Trial[]): number | null {\n if (\n !trials.length ||\n trials.some(\n (trial) =>\n trial.execution.status !== \"completed\" ||\n trial.grading.status !== \"completed\" ||\n trial.task.verdict === \"not_assessed\",\n )\n )\n return null;\n return (\n trials.filter((trial) => trial.task.verdict === \"passed\").length /\n trials.length\n );\n}\n\nasync function loadResult(path: string) {\n if (!isAbsolute(path))\n throw new Error(\"report result paths must be absolute\");\n const result: unknown = JSON.parse(await readFile(path, \"utf8\"));\n assertCliResult(result);\n return result;\n}\n\nasync function loadEvidence(result: CliResult): Promise<Evidence | null> {\n const path = retainedEvidencePath(result);\n if (path === null) return null;\n const value: unknown = JSON.parse(await readFile(path, \"utf8\"));\n assertRunEvidence(value);\n const evidence = value;\n if (\n evidence.runId !== result.runId ||\n canonicalJson(evidence.result) !== canonicalJson(result)\n )\n throw new Error(\"retained evidence differs from report result\");\n return evidence;\n}\n\nfunction retainedEvidencePath(result: CliResult): string | null {\n if (!result.evidencePath) {\n if (result.cases.length || result.exitCode === 0)\n throw new Error(\"completed result has no retained evidence\");\n return null;\n }\n if (!isAbsolute(result.evidencePath))\n throw new Error(\"evidence path must be absolute\");\n return result.evidencePath;\n}\n\nfunction trialEvidence(\n caseId: string,\n trials: Trial[],\n evidence: Evidence | null,\n) {\n if (!evidence) return [];\n const matching = evidence.trials.filter((item) => item.caseId === caseId);\n if (\n matching.length !== trials.length ||\n trials.some(\n (trial) =>\n matching.filter((item) => item.trial === trial.trial).length !== 1,\n )\n )\n throw new Error(\"retained trial evidence differs from report result\");\n return matching;\n}\n\nfunction reportRow(\n path: string,\n result: CliResult,\n selected: Case,\n evidence: Evidence | null,\n transcripts: Awaited<ReturnType<typeof nativeTranscriptRetention>>,\n): ReportRow {\n const retained = trialEvidence(selected.caseId, selected.trials, evidence);\n const candidateRoute = retainedCandidateRoute(evidence);\n const usage = retainedUsage(retained);\n return {\n resultFile: path,\n evidencePath: result.evidencePath,\n runId: result.runId,\n caseId: selected.caseId,\n execution: selected.execution.status,\n grading: selected.grading.status,\n task: selected.task.verdict,\n exitCode: result.exitCode,\n trialCount: selected.trials.length,\n taskPassRate: passRate(selected.trials),\n candidateDurationMs: sumKnown(\n retained.map((trial) => trial.candidateDurationMs),\n ),\n ...usage,\n ...retainedIdentity(evidence),\n candidateRoute,\n nativeTranscripts: {\n retained: transcripts.filter(\n (item) => item.caseId === selected.caseId && !item.pruned,\n ).length,\n pruned: transcripts.filter(\n (item) => item.caseId === selected.caseId && item.pruned,\n ).length,\n },\n domainOutcomes: selected.trials.flatMap((trial) =>\n (trial.domainOutcomes ?? []).map((outcome) => ({\n trial: trial.trial,\n id: outcome.id,\n status: outcome.status,\n })),\n ),\n };\n}\n\nfunction retainedCandidateRoute(\n evidence: Evidence | null,\n): ReportRow[\"candidateRoute\"] {\n if (!evidence) return null;\n const routes = evidence.routes.filter((route) => route.role === \"candidate\"),\n [route] = routes;\n if (routes.length !== 1 || route === undefined)\n throw new Error(\"retained candidate route is ambiguous\");\n return { host: route.host, model: route.model, effort: route.effort };\n}\nfunction retainedUsage(retained: Evidence[\"trials\"]) {\n const complete =\n retained.length > 0 && retained.every((trial) => trial.usage.complete);\n return {\n inputTokens: complete\n ? sumKnown(retained.map((trial) => trial.usage.inputTokens))\n : null,\n outputTokens: complete\n ? sumKnown(retained.map((trial) => trial.usage.outputTokens))\n : null,\n costUsd: complete\n ? sumKnown(retained.map((trial) => trial.usage.costUsd))\n : null,\n };\n}\nfunction retainedIdentity(evidence: Evidence | null) {\n if (!evidence)\n return {\n runnerBuildDigest: null,\n evaluationDigest: null,\n requestedCondition: null,\n actualCondition: null,\n routes: [],\n };\n return {\n runnerBuildDigest: evidence.runner.buildDigest,\n evaluationDigest: evidence.evaluationIdentity.digest,\n requestedCondition: evidence.condition.requested,\n actualCondition: evidence.condition.actual,\n routes: evidence.routes,\n };\n}\n\nexport async function createReport(paths: string[]) {\n if (!paths.length || new Set(paths).size !== paths.length)\n throw new Error(\"report needs distinct result files\");\n const rows: ReportRow[] = [];\n const inputs: ReportData[\"inputs\"] = [];\n for (const path of paths) {\n const result = await loadResult(path);\n const evidence = await loadEvidence(result);\n const transcripts = await nativeTranscriptRetention(evidence);\n inputs.push({\n resultFile: path,\n execution: result.execution.status,\n grading: result.grading.status,\n task: result.task.verdict,\n exitCode: result.exitCode,\n caseCount: result.cases.length,\n });\n for (const selected of result.cases)\n rows.push(reportRow(path, result, selected, evidence, transcripts));\n }\n const report = {\n format: \"sevro.report.v1\",\n inputs,\n rows,\n summary: {\n cases: rows.length,\n passed: rows.filter((row) => row.task === \"passed\").length,\n failed: rows.filter((row) => row.task === \"failed\").length,\n notAssessed: rows.filter((row) => row.task === \"not_assessed\").length,\n },\n };\n assertReport(report);\n return report;\n}\n\nfunction cell(value: string): string {\n return value.replaceAll(\"|\", \"\\\\|\").replaceAll(/[\\r\\n]/g, \" \");\n}\n\nfunction measured(value: number | null, digits = 0): string {\n return value === null ? \"unknown\" : value.toFixed(digits);\n}\n\nfunction seconds(value: number | null): string {\n return value === null ? \"unknown\" : `${(value / 1000).toFixed(2)}s`;\n}\n\nexport function renderReport(\n report: Awaited<ReturnType<typeof createReport>>,\n): string {\n const lines = [\n \"# Sevro evaluation report\",\n \"\",\n \"Task verdict, execution, and grading are separate. Unknown measurements are not zero. Rows do not claim matched comparisons.\",\n \"\",\n `Cases: ${report.summary.cases}; passed: ${report.summary.passed}; failed: ${report.summary.failed}; not assessed: ${report.summary.notAssessed}.`,\n \"\",\n \"## Input runs\",\n \"\",\n \"| Result file | Exit | Execution | Grading | Task | Cases |\",\n \"| --- | ---: | --- | --- | --- | ---: |\",\n ...report.inputs.map(\n (input) =>\n `| ${cell(input.resultFile)} | ${input.exitCode} | ${input.execution} | ${input.grading} | ${input.task} | ${input.caseCount} |`,\n ),\n \"\",\n \"## Case outcomes\",\n \"\",\n \"| Case | Task | Execution | Grading | Pass rate | Candidate time | Candidate tokens | Candidate cost | Condition | Candidate route |\",\n \"| --- | --- | --- | --- | ---: | ---: | ---: | ---: | --- | --- |\",\n ...report.rows.map(caseOutcomeLine),\n \"\",\n \"## Retained evidence\",\n \"\",\n ...report.rows.map(\n (row) =>\n `- ${cell(row.caseId)}: ${row.evidencePath ?? \"unavailable\"}${transcriptSummary(row)}`,\n ),\n \"\",\n ];\n const outcomes = report.rows.flatMap((row) =>\n row.domainOutcomes.map((outcome) => ({ caseId: row.caseId, ...outcome })),\n );\n if (outcomes.length)\n lines.push(\n \"## Domain outcomes\",\n \"\",\n \"Domain outcomes are independent of the task verdict.\",\n \"\",\n \"| Case | Trial | Outcome | Status |\",\n \"| --- | ---: | --- | --- |\",\n ...outcomes.map(\n (outcome) =>\n `| ${cell(outcome.caseId)} | ${outcome.trial} | ${cell(outcome.id)} | ${outcome.status} |`,\n ),\n \"\",\n );\n lines.push(\n \"## Routes\",\n \"\",\n \"| Case | Role | Host | Model | Effort |\",\n \"| --- | --- | --- | --- | --- |\",\n ...report.rows.flatMap((row) =>\n row.routes.map(\n (route) =>\n `| ${cell(row.caseId)} | ${route.role} | ${cell(route.host)} | ${cell(route.model)} | ${cell(route.effort)} |`,\n ),\n ),\n \"\",\n );\n return lines.join(\"\\n\");\n}\n\nfunction transcriptSummary(row: ReportRow): string {\n if (!row.nativeTranscripts) return \"\";\n return `; native transcripts: ${row.nativeTranscripts.retained} retained, ${row.nativeTranscripts.pruned} pruned`;\n}\n\nfunction passRateCell(rate: number | null): string {\n return rate === null ? \"unknown\" : `${(rate * 100).toFixed(0)}%`;\n}\nfunction costCell(cost: number | null): string {\n return cost === null ? \"unknown\" : `$${cost.toFixed(4)}`;\n}\nfunction routeCell(route: ReportRow[\"candidateRoute\"]): string {\n return route\n ? cell(`${route.host}/${route.model}@${route.effort}`)\n : \"unknown\";\n}\nfunction conditionCell(row: ReportRow): string {\n return `${row.requestedCondition ?? \"unknown\"} / ${row.actualCondition ?? \"unknown\"}`;\n}\nfunction caseOutcomeLine(row: ReportRow): string {\n return `| ${cell(row.caseId)} | ${row.task} | ${row.execution} | ${row.grading} | ${passRateCell(row.taskPassRate)} | ${seconds(row.candidateDurationMs)} | ${measured(row.inputTokens)} / ${measured(row.outputTokens)} | ${costCell(row.costUsd)} | ${conditionCell(row)} | ${routeCell(row.candidateRoute)} |`;\n}\n\nexport async function reportCommand(argv: string[]): Promise<number> {\n try {\n const values = reportInvocation(argv);\n const report = await createReport(await reportPaths(values));\n process.stdout.write(\n values.json ? `${JSON.stringify(report)}\\n` : renderReport(report),\n );\n return 0;\n } catch (error) {\n process.stderr.write(`${reportErrorMessage(error)}\\n`);\n return 64;\n }\n}\n\nfunction reportInvocation(argv: string[]) {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n strict: true,\n options: {\n json: { type: \"boolean\" },\n \"result-file\": { type: \"string\", multiple: true },\n latest: { type: \"boolean\" },\n \"results-root\": { type: \"string\" },\n },\n });\n if (positionals.length !== 1 || positionals[0] !== \"report\")\n throw new Error(\"expected the report command\");\n return values;\n}\n\nasync function reportPaths(\n values: ReturnType<typeof reportInvocation>,\n): Promise<string[]> {\n validateReportSource(values);\n const paths = selectedReportPaths(values);\n if (paths.some((path) => !path.trim()))\n throw new Error(\"--result-file must name a readable retained result file\");\n return Promise.all(paths.map((path) => canonicalRuntimeRoot(resolve(path))));\n}\n\nfunction validateReportSource(\n values: ReturnType<typeof reportInvocation>,\n): void {\n if (values.latest && values[\"result-file\"] !== undefined)\n throw new Error(\"--latest and --result-file are exclusive\");\n if (values[\"results-root\"] !== undefined && !values.latest)\n throw new Error(\"--results-root requires --latest\");\n}\n\nfunction selectedReportPaths(\n values: ReturnType<typeof reportInvocation>,\n): string[] {\n return values.latest\n ? [\n join(\n values[\"results-root\"] ?? join(process.cwd(), \".sevro\", \"results\"),\n \"latest.json\",\n ),\n ]\n : (values[\"result-file\"] ?? []);\n}\nfunction reportErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"invalid report input\";\n}\n"]}
@@ -0,0 +1,29 @@
1
+ function repositoryOverlay(fixture) {
2
+ return {
3
+ ...(fixture.files ? { files: fixture.files } : {}),
4
+ ...(fixture.staged ? { staged: fixture.staged } : {}),
5
+ ...(fixture.commitFiles ? { commitFiles: true } : {}),
6
+ };
7
+ }
8
+ function repositoryTools(fixture) {
9
+ return {
10
+ ...(fixture.hooks ? { hooks: fixture.hooks } : {}),
11
+ ...(fixture.bin ? { bin: fixture.bin } : {}),
12
+ };
13
+ }
14
+ /** Translate negotiated fixture declarations into the standalone case representation. */
15
+ export function resolvedFixture(fixture) {
16
+ switch (fixture.kind) {
17
+ case "inline":
18
+ return { files: fixture.files };
19
+ case "repository":
20
+ return {
21
+ sourceRef: fixture.sourceRef,
22
+ ...repositoryOverlay(fixture),
23
+ ...repositoryTools(fixture),
24
+ };
25
+ case "generated":
26
+ return fixture;
27
+ }
28
+ }
29
+ //# sourceMappingURL=resolved-case.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolved-case.js","sourceRoot":"","sources":["resolved-case.ts"],"names":[],"mappings":"AAGA,SAAS,iBAAiB,CAAC,OAA0B;IACnD,OAAO;QACL,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,OAA0B;IACjD,OAAO;QACL,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,eAAe,CAAC,OAAiC;IAC/D,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAClC,KAAK,YAAY;YACf,OAAO;gBACL,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,GAAG,iBAAiB,CAAC,OAAO,CAAC;gBAC7B,GAAG,eAAe,CAAC,OAAO,CAAC;aAC5B,CAAC;QACJ,KAAK,WAAW;YACd,OAAO,OAAO,CAAC;IACnB,CAAC;AACH,CAAC","sourcesContent":["import type { ExtensionCase } from \"./extension-session\";\nimport type { RepositoryFixture } from \"./fixtures/repository\";\n\nfunction repositoryOverlay(fixture: RepositoryFixture) {\n return {\n ...(fixture.files ? { files: fixture.files } : {}),\n ...(fixture.staged ? { staged: fixture.staged } : {}),\n ...(fixture.commitFiles ? { commitFiles: true } : {}),\n };\n}\n\nfunction repositoryTools(fixture: RepositoryFixture) {\n return {\n ...(fixture.hooks ? { hooks: fixture.hooks } : {}),\n ...(fixture.bin ? { bin: fixture.bin } : {}),\n };\n}\n\n/** Translate negotiated fixture declarations into the standalone case representation. */\nexport function resolvedFixture(fixture: ExtensionCase[\"fixture\"]) {\n switch (fixture.kind) {\n case \"inline\":\n return { files: fixture.files };\n case \"repository\":\n return {\n sourceRef: fixture.sourceRef,\n ...repositoryOverlay(fixture),\n ...repositoryTools(fixture),\n };\n case \"generated\":\n return fixture;\n }\n}\n"]}
@@ -0,0 +1,40 @@
1
+ import { openLockDatabase } from "./sqlite-lock.js";
2
+ import { join } from "node:path";
3
+ import { lstat } from "node:fs/promises";
4
+ export async function retainedFile(path) {
5
+ const info = await lstat(path).catch((cause) => {
6
+ if (cause.code === "ENOENT")
7
+ return null;
8
+ throw cause;
9
+ });
10
+ if (info && !info.isFile())
11
+ throw new Error(`retained storage must be a regular file: ${path}`);
12
+ return info;
13
+ }
14
+ /** Serialize result publication and pruning across CLI processes. Closing rolls back the lock transaction. */
15
+ export async function withResultsLock(root, action) {
16
+ const release = await acquireResultsLock(root);
17
+ try {
18
+ return await action();
19
+ }
20
+ finally {
21
+ release();
22
+ }
23
+ }
24
+ /** Hold a root lock while discovering and validating additional nested roots. */
25
+ export async function acquireResultsLock(root) {
26
+ await retainedFile(join(root, ".retention-lock.sqlite"));
27
+ const database = openLockDatabase(join(root, ".retention-lock.sqlite"));
28
+ try {
29
+ database.exec("PRAGMA busy_timeout = 5000");
30
+ database.exec("BEGIN IMMEDIATE");
31
+ return () => {
32
+ database.close();
33
+ };
34
+ }
35
+ catch (cause) {
36
+ database.close();
37
+ throw cause;
38
+ }
39
+ }
40
+ //# sourceMappingURL=results-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results-lock.js","sourceRoot":"","sources":["results-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,yBAAsB;AACjD,OAAO,EAAE,IAAI,EAAE,kBAAkB;AACjC,OAAO,EAAE,KAAK,EAAE,yBAAyB;AAEzC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACtD,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACpE,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IACH,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,EAAE,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8GAA8G;AAC9G,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,MAAwB;IAExB,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,EAAE,CAAC;IACxB,CAAC;YAAS,CAAC;QACT,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAY;IACnD,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC;IACxE,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC5C,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["import { openLockDatabase } from \"./sqlite-lock\";\nimport { join } from \"node:path\";\nimport { lstat } from \"node:fs/promises\";\n\nexport async function retainedFile(path: string) {\n const info = await lstat(path).catch((cause: unknown) => {\n if ((cause as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw cause;\n });\n if (info && !info.isFile())\n throw new Error(`retained storage must be a regular file: ${path}`);\n return info;\n}\n\n/** Serialize result publication and pruning across CLI processes. Closing rolls back the lock transaction. */\nexport async function withResultsLock<T>(\n root: string,\n action: () => Promise<T>,\n): Promise<T> {\n const release = await acquireResultsLock(root);\n try {\n return await action();\n } finally {\n release();\n }\n}\n\n/** Hold a root lock while discovering and validating additional nested roots. */\nexport async function acquireResultsLock(root: string): Promise<() => void> {\n await retainedFile(join(root, \".retention-lock.sqlite\"));\n const database = openLockDatabase(join(root, \".retention-lock.sqlite\"));\n try {\n database.exec(\"PRAGMA busy_timeout = 5000\");\n database.exec(\"BEGIN IMMEDIATE\");\n return () => {\n database.close();\n };\n } catch (cause) {\n database.close();\n throw cause;\n }\n}\n"]}
@@ -0,0 +1,127 @@
1
+ /** Reduce one trial without treating process completion as task success. */
2
+ export function assessTrial(input) {
3
+ const { declared, seen } = validateCheckResults(input);
4
+ const grading = trialGrading(input, declared.size, seen.size);
5
+ const task = trialVerdict(input, grading);
6
+ return {
7
+ execution: { status: input.execution },
8
+ grading: { status: grading },
9
+ task: { verdict: task },
10
+ };
11
+ }
12
+ function validateCheckResults(input) {
13
+ const declared = new Set(input.declaredChecks);
14
+ validateCheckDeclarations(input.declaredChecks, declared);
15
+ const seen = new Set();
16
+ for (const check of input.checks) {
17
+ if (!declared.has(check.id) || seen.has(check.id))
18
+ throw new Error(`unexpected or duplicate check result: ${check.id}`);
19
+ seen.add(check.id);
20
+ }
21
+ return { declared, seen };
22
+ }
23
+ function trialGrading(input, declared, seen) {
24
+ if (input.graderError)
25
+ return "error";
26
+ if (input.execution !== "completed")
27
+ return "not_requested";
28
+ if (evidenceUnavailable(input, declared, seen))
29
+ return "unavailable";
30
+ return declared === 0 ? "not_requested" : "completed";
31
+ }
32
+ function evidenceUnavailable(input, declared, seen) {
33
+ return (Boolean(input.requiredEvidenceUnavailable) ||
34
+ input.checks.some((check) => check.status === "unavailable") ||
35
+ seen !== declared);
36
+ }
37
+ function trialVerdict(input, grading) {
38
+ if (input.execution !== "completed")
39
+ return "not_assessed";
40
+ if (input.checks.some((check) => check.status === "failed"))
41
+ return "failed";
42
+ return grading === "completed" ? "passed" : "not_assessed";
43
+ }
44
+ /** Apply an explicitly selected policy only to a fully assessed trial. */
45
+ export function applyTaskVerdictPolicy(assessment, recommendation, selected) {
46
+ if (!selected)
47
+ return assessment;
48
+ if (recommendation === null ||
49
+ assessment.execution.status !== "completed" ||
50
+ assessment.grading.status !== "completed")
51
+ return { ...assessment, task: { verdict: "not_assessed" } };
52
+ return { ...assessment, task: { verdict: recommendation } };
53
+ }
54
+ /** Apply a case's pass threshold after every required trial has an assessment. */
55
+ export function summarizeAssessments(assessments, passThreshold = 1) {
56
+ validateSummaryInputs(assessments, passThreshold);
57
+ const execution = summaryExecution(assessments);
58
+ const grading = summaryGrading(assessments);
59
+ const task = summaryVerdict(assessments, passThreshold);
60
+ return {
61
+ execution: { status: execution },
62
+ grading: { status: grading },
63
+ task: { verdict: task },
64
+ };
65
+ }
66
+ function validateSummaryInputs(assessments, passThreshold) {
67
+ if (!assessments.length)
68
+ throw new Error("at least one assessment is required");
69
+ if (!Number.isFinite(passThreshold) ||
70
+ passThreshold <= 0 ||
71
+ passThreshold > 1)
72
+ throw new Error("pass threshold must be greater than zero and at most one");
73
+ }
74
+ function summaryExecution(assessments) {
75
+ const priority = ["failed", "cancelled", "not_run"];
76
+ return (priority.find((status) => assessments.some((item) => item.execution.status === status)) ?? "completed");
77
+ }
78
+ function summaryGrading(assessments) {
79
+ const priority = ["error", "unavailable", "completed"];
80
+ return (priority.find((status) => assessments.some((item) => item.grading.status === status)) ?? "not_requested");
81
+ }
82
+ function summaryVerdict(assessments, passThreshold) {
83
+ if (assessments.some((item) => item.task.verdict === "not_assessed"))
84
+ return "not_assessed";
85
+ const passed = assessments.filter((item) => item.task.verdict === "passed").length;
86
+ return passed / assessments.length >= passThreshold ? "passed" : "failed";
87
+ }
88
+ /** Combine case verdicts after each case has applied its own threshold. */
89
+ export function summarizeCases(cases) {
90
+ const summary = summarizeAssessments(cases);
91
+ if (cases.some((item) => item.task.verdict === "failed"))
92
+ return { ...summary, task: { verdict: "failed" } };
93
+ return summary;
94
+ }
95
+ /** Resolve the documented CLI exit category without discarding detailed states. */
96
+ export function exitCodeFor(assessment, context = {}) {
97
+ const interruption = interruptionExit(context);
98
+ if (interruption !== null)
99
+ return interruption;
100
+ if (executionFailed(assessment.execution.status, context))
101
+ return 2;
102
+ const gradingCodes = {
103
+ error: 3,
104
+ unavailable: 4,
105
+ };
106
+ return gradingCodes[assessment.grading.status] ?? taskExitCode(assessment);
107
+ }
108
+ function interruptionExit(context) {
109
+ if (context.signal === "SIGINT")
110
+ return 130;
111
+ if (context.signal === "SIGTERM")
112
+ return 143;
113
+ return context.internalFailure ? 70 : null;
114
+ }
115
+ function executionFailed(status, context) {
116
+ return (status === "failed" ||
117
+ status === "cancelled" ||
118
+ (status === "not_run" && !context.dryRun));
119
+ }
120
+ function taskExitCode(assessment) {
121
+ return assessment.task.verdict === "failed" ? 1 : 0;
122
+ }
123
+ function validateCheckDeclarations(ids, declared) {
124
+ if (declared.size !== ids.length || declared.has(""))
125
+ throw new Error("check declarations must have unique nonempty IDs");
126
+ }
127
+ //# sourceMappingURL=results.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results.js","sourceRoot":"","sources":["results.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Assessment,\n CheckOutcome,\n ExecutionStatus,\n GradingStatus,\n TaskVerdict,\n} from \"./contract-types\";\nexport type {\n Assessment,\n CheckOutcome,\n ExecutionStatus,\n GradingStatus,\n TaskVerdict,\n} from \"./contract-types\";\n\nexport interface TrialInput {\n execution: ExecutionStatus;\n declaredChecks: string[];\n checks: CheckOutcome[];\n graderError?: boolean;\n requiredEvidenceUnavailable?: boolean;\n}\n\n/** Reduce one trial without treating process completion as task success. */\nexport function assessTrial(input: TrialInput): Assessment {\n const { declared, seen } = validateCheckResults(input);\n const grading = trialGrading(input, declared.size, seen.size);\n const task = trialVerdict(input, grading);\n return {\n execution: { status: input.execution },\n grading: { status: grading },\n task: { verdict: task },\n };\n}\n\nfunction validateCheckResults(input: TrialInput) {\n const declared = new Set(input.declaredChecks);\n validateCheckDeclarations(input.declaredChecks, declared);\n const seen = new Set<string>();\n for (const check of input.checks) {\n if (!declared.has(check.id) || seen.has(check.id))\n throw new Error(`unexpected or duplicate check result: ${check.id}`);\n seen.add(check.id);\n }\n\n return { declared, seen };\n}\n\nfunction trialGrading(\n input: TrialInput,\n declared: number,\n seen: number,\n): GradingStatus {\n if (input.graderError) return \"error\";\n if (input.execution !== \"completed\") return \"not_requested\";\n if (evidenceUnavailable(input, declared, seen)) return \"unavailable\";\n return declared === 0 ? \"not_requested\" : \"completed\";\n}\n\nfunction evidenceUnavailable(\n input: TrialInput,\n declared: number,\n seen: number,\n): boolean {\n return (\n Boolean(input.requiredEvidenceUnavailable) ||\n input.checks.some((check) => check.status === \"unavailable\") ||\n seen !== declared\n );\n}\n\nfunction trialVerdict(input: TrialInput, grading: GradingStatus): TaskVerdict {\n if (input.execution !== \"completed\") return \"not_assessed\";\n if (input.checks.some((check) => check.status === \"failed\")) return \"failed\";\n return grading === \"completed\" ? \"passed\" : \"not_assessed\";\n}\n\n/** Apply an explicitly selected policy only to a fully assessed trial. */\nexport function applyTaskVerdictPolicy(\n assessment: Assessment,\n recommendation: TaskVerdict | null,\n selected: boolean,\n): Assessment {\n if (!selected) return assessment;\n if (\n recommendation === null ||\n assessment.execution.status !== \"completed\" ||\n assessment.grading.status !== \"completed\"\n )\n return { ...assessment, task: { verdict: \"not_assessed\" } };\n return { ...assessment, task: { verdict: recommendation } };\n}\n\n/** Apply a case's pass threshold after every required trial has an assessment. */\nexport function summarizeAssessments(\n assessments: Assessment[],\n passThreshold = 1,\n): Assessment {\n validateSummaryInputs(assessments, passThreshold);\n const execution = summaryExecution(assessments);\n const grading = summaryGrading(assessments);\n const task = summaryVerdict(assessments, passThreshold);\n return {\n execution: { status: execution },\n grading: { status: grading },\n task: { verdict: task },\n };\n}\n\nfunction validateSummaryInputs(\n assessments: Assessment[],\n passThreshold: number,\n): void {\n if (!assessments.length)\n throw new Error(\"at least one assessment is required\");\n if (\n !Number.isFinite(passThreshold) ||\n passThreshold <= 0 ||\n passThreshold > 1\n )\n throw new Error(\"pass threshold must be greater than zero and at most one\");\n}\n\nfunction summaryExecution(assessments: Assessment[]): ExecutionStatus {\n const priority: ExecutionStatus[] = [\"failed\", \"cancelled\", \"not_run\"];\n return (\n priority.find((status) =>\n assessments.some((item) => item.execution.status === status),\n ) ?? \"completed\"\n );\n}\n\nfunction summaryGrading(assessments: Assessment[]): GradingStatus {\n const priority: GradingStatus[] = [\"error\", \"unavailable\", \"completed\"];\n return (\n priority.find((status) =>\n assessments.some((item) => item.grading.status === status),\n ) ?? \"not_requested\"\n );\n}\n\nfunction summaryVerdict(\n assessments: Assessment[],\n passThreshold: number,\n): TaskVerdict {\n if (assessments.some((item) => item.task.verdict === \"not_assessed\"))\n return \"not_assessed\";\n const passed = assessments.filter(\n (item) => item.task.verdict === \"passed\",\n ).length;\n return passed / assessments.length >= passThreshold ? \"passed\" : \"failed\";\n}\n\n/** Combine case verdicts after each case has applied its own threshold. */\nexport function summarizeCases(cases: Assessment[]): Assessment {\n const summary = summarizeAssessments(cases);\n if (cases.some((item) => item.task.verdict === \"failed\"))\n return { ...summary, task: { verdict: \"failed\" } };\n return summary;\n}\n\nexport interface ExitContext {\n signal?: \"SIGINT\" | \"SIGTERM\";\n internalFailure?: boolean;\n dryRun?: boolean;\n}\n\n/** Resolve the documented CLI exit category without discarding detailed states. */\nexport function exitCodeFor(\n assessment: Assessment,\n context: ExitContext = {},\n): number {\n const interruption = interruptionExit(context);\n if (interruption !== null) return interruption;\n if (executionFailed(assessment.execution.status, context)) return 2;\n const gradingCodes: Partial<Record<GradingStatus, number>> = {\n error: 3,\n unavailable: 4,\n };\n return gradingCodes[assessment.grading.status] ?? taskExitCode(assessment);\n}\n\nfunction interruptionExit(context: ExitContext): number | null {\n if (context.signal === \"SIGINT\") return 130;\n if (context.signal === \"SIGTERM\") return 143;\n return context.internalFailure ? 70 : null;\n}\n\nfunction executionFailed(\n status: ExecutionStatus,\n context: ExitContext,\n): boolean {\n return (\n status === \"failed\" ||\n status === \"cancelled\" ||\n (status === \"not_run\" && !context.dryRun)\n );\n}\n\nfunction taskExitCode(assessment: Assessment): number {\n return assessment.task.verdict === \"failed\" ? 1 : 0;\n}\n\nfunction validateCheckDeclarations(ids: string[], declared: Set<string>): void {\n if (declared.size !== ids.length || declared.has(\"\"))\n throw new Error(\"check declarations must have unique nonempty IDs\");\n}\n"]}
@@ -0,0 +1,283 @@
1
+ import { spawnSync } from "./runtime-process.js";
2
+ import { isRecord } from "./value-guards.js";
3
+ import { openLockDatabase } from "./sqlite-lock.js";
4
+ import { randomUUID } from "node:crypto";
5
+ import { mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
6
+ import { hostname } from "node:os";
7
+ import { basename, dirname, join } from "node:path";
8
+ function errorCode(error) {
9
+ return isRecord(error) ? error.code : undefined;
10
+ }
11
+ function nonemptyText(value) {
12
+ return typeof value === "string" && value.length > 0;
13
+ }
14
+ function validClaimStatus(value) {
15
+ return (value === "active" ||
16
+ value === "complete" ||
17
+ value === "diagnostic" ||
18
+ value === "interrupted");
19
+ }
20
+ function validClaimIdentity(value) {
21
+ return (value.format === "sevro.run-owner.v1" &&
22
+ /^[a-f0-9]{64}$/.test(String(value.evaluationDigest)) &&
23
+ Boolean(value.attemptId) &&
24
+ validClaimStatus(value.status));
25
+ }
26
+ function validClaimPaths(value) {
27
+ return (nonemptyText(value.activeRunPath) &&
28
+ nonemptyText(value.evidenceDirectory) &&
29
+ nonemptyText(value.artifactPath));
30
+ }
31
+ function assertRetainedClaim(value, path) {
32
+ if (!isRecord(value) || !validClaimIdentity(value) || !validClaimPaths(value))
33
+ throw new Error(`unrecognized Sevro ownership record: ${path}`);
34
+ }
35
+ function atomicJson(path, value) {
36
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
37
+ const temporary = join(dirname(path), `.${basename(path)}.${randomUUID()}.tmp`);
38
+ try {
39
+ writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, {
40
+ flag: "wx",
41
+ mode: 0o600,
42
+ });
43
+ renameSync(temporary, path);
44
+ }
45
+ catch (error) {
46
+ try {
47
+ unlinkSync(temporary);
48
+ }
49
+ catch {
50
+ // The temporary file may not have been created.
51
+ }
52
+ throw error;
53
+ }
54
+ }
55
+ function withClaimLock(claimPath, action) {
56
+ const locks = join(dirname(dirname(claimPath)), "locks");
57
+ mkdirSync(locks, { recursive: true, mode: 0o700 });
58
+ const database = openLockDatabase(join(locks, `${basename(claimPath)}.sqlite`));
59
+ try {
60
+ database.exec("PRAGMA busy_timeout = 5000");
61
+ database.exec("CREATE TABLE IF NOT EXISTS mutex (id INTEGER PRIMARY KEY)");
62
+ database.exec("BEGIN IMMEDIATE");
63
+ const result = action();
64
+ database.exec("COMMIT");
65
+ return result;
66
+ }
67
+ finally {
68
+ database.close();
69
+ }
70
+ }
71
+ function readClaim(path) {
72
+ let bytes;
73
+ try {
74
+ bytes = readFileSync(path, "utf8");
75
+ }
76
+ catch (error) {
77
+ if (errorCode(error) === "ENOENT")
78
+ return null;
79
+ throw error;
80
+ }
81
+ const value = JSON.parse(bytes);
82
+ assertRetainedClaim(value, path);
83
+ return value;
84
+ }
85
+ function identityCommand(pid, windows) {
86
+ return windows
87
+ ? [
88
+ "powershell.exe",
89
+ "-NoProfile",
90
+ "-NonInteractive",
91
+ "-Command",
92
+ `(Get-Process -Id ${pid} -ErrorAction Stop).StartTime.ToUniversalTime().Ticks`,
93
+ ]
94
+ : ["/bin/ps", "-p", String(pid), "-o", "lstart="];
95
+ }
96
+ function identityEnvironment(windows) {
97
+ return windows
98
+ ? {
99
+ PATH: process.env.PATH ?? "",
100
+ SystemRoot: process.env.SystemRoot ?? "C:\\Windows",
101
+ }
102
+ : { PATH: "/usr/bin:/bin", LC_ALL: "C" };
103
+ }
104
+ function processStartTime(result) {
105
+ return result.stdout.toString().trim();
106
+ }
107
+ export function processIdentity(pid) {
108
+ const windows = process.platform === "win32";
109
+ const argv = identityCommand(pid, windows);
110
+ let result;
111
+ try {
112
+ result = spawnSync(argv, {
113
+ env: identityEnvironment(windows),
114
+ stdout: "pipe",
115
+ stderr: "ignore",
116
+ });
117
+ }
118
+ catch {
119
+ return null;
120
+ }
121
+ const startedAt = processStartTime(result);
122
+ return result.exitCode === 0 && startedAt
123
+ ? { pid, startedAt, host: hostname() }
124
+ : null;
125
+ }
126
+ function validProcessId(value) {
127
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
128
+ }
129
+ export function validProcessIdentity(value) {
130
+ return (isRecord(value) &&
131
+ value.host === hostname() &&
132
+ validProcessId(value.pid) &&
133
+ nonemptyText(value.startedAt));
134
+ }
135
+ function processLiveness(pid) {
136
+ try {
137
+ process.kill(pid, 0);
138
+ return "live";
139
+ }
140
+ catch (error) {
141
+ return errorCode(error) === "ESRCH" ? "dead" : "unknown";
142
+ }
143
+ }
144
+ export function ownerStatus(owner) {
145
+ if (!validProcessIdentity(owner))
146
+ return "unknown";
147
+ const liveness = processLiveness(owner.pid);
148
+ if (liveness !== "live")
149
+ return liveness;
150
+ const current = processIdentity(owner.pid);
151
+ if (!current)
152
+ return "unknown";
153
+ return current.startedAt === owner.startedAt ? "live" : "dead";
154
+ }
155
+ function activeRunFields(value) {
156
+ if (value == null)
157
+ return {};
158
+ // Preserve the existing object-spread representation of opaque active records.
159
+ const entries = Object.entries(value);
160
+ return Object.fromEntries(entries);
161
+ }
162
+ function preserveAbandoned(claim) {
163
+ const interrupted = {
164
+ ...claim,
165
+ status: "interrupted",
166
+ finalizedAt: new Date().toISOString(),
167
+ };
168
+ atomicJson(join(claim.evidenceDirectory, "run-owner.json"), interrupted);
169
+ let active;
170
+ try {
171
+ const parsed = JSON.parse(readFileSync(claim.activeRunPath, "utf8"));
172
+ active = activeRunFields(parsed);
173
+ }
174
+ catch (error) {
175
+ if (errorCode(error) !== "ENOENT")
176
+ throw error;
177
+ active = {
178
+ format: "sevro.active-run.v1",
179
+ runId: claim.attemptId,
180
+ artifactPath: claim.artifactPath,
181
+ evidenceDirectory: claim.evidenceDirectory,
182
+ completedTrials: [],
183
+ };
184
+ }
185
+ atomicJson(claim.activeRunPath, {
186
+ ...active,
187
+ status: "interrupted",
188
+ finalizedAt: interrupted.finalizedAt,
189
+ });
190
+ }
191
+ function validateClaimIdentityMatch(prior, evaluationDigest) {
192
+ if (prior && prior.evaluationDigest !== evaluationDigest)
193
+ throw new Error("Sevro ownership record has a different identity");
194
+ }
195
+ function retainPreviousOwner(prior, claimPath) {
196
+ if (prior === null || prior.status !== "active")
197
+ return;
198
+ const status = ownerStatus(prior.owner);
199
+ if (status === "live")
200
+ throw new Error(`equivalent Sevro run is active: ${claimPath}`);
201
+ if (status === "unknown")
202
+ throw new Error(`Sevro run ownership is unverifiable: ${claimPath}`);
203
+ preserveAbandoned(prior);
204
+ }
205
+ function validateCheckpointOwner(context) {
206
+ const current = readClaim(context.claimPath);
207
+ if (!current || current.attemptId !== context.claim.attemptId)
208
+ throw new Error("Sevro run ownership changed before checkpoint");
209
+ if (current.status !== "active")
210
+ throw new Error("Sevro run owner is already finalized");
211
+ if (ownerStatus(current.owner) !== "live")
212
+ throw new Error("Sevro run owner identity is no longer verifiable");
213
+ }
214
+ /** Claim one evaluation identity before candidate execution. */
215
+ export function startRunOwner(options) {
216
+ if (!/^[a-f0-9]{64}$/.test(options.evaluationDigest))
217
+ throw new Error("invalid evaluation identity for run ownership");
218
+ const claimPath = join(options.stateRoot, "owners", `${options.evaluationDigest}.json`);
219
+ return withClaimLock(claimPath, () => {
220
+ const prior = readClaim(claimPath);
221
+ validateClaimIdentityMatch(prior, options.evaluationDigest);
222
+ retainPreviousOwner(prior, claimPath);
223
+ const owner = processIdentity(process.pid);
224
+ if (!owner)
225
+ throw new Error("cannot verify Sevro runner process identity");
226
+ const claim = {
227
+ format: "sevro.run-owner.v1",
228
+ evaluationDigest: options.evaluationDigest,
229
+ attemptId: options.attemptId,
230
+ status: "active",
231
+ owner,
232
+ activeRunPath: options.activeRunPath,
233
+ evidenceDirectory: options.evidenceDirectory,
234
+ artifactPath: options.artifactPath,
235
+ startedAt: new Date().toISOString(),
236
+ };
237
+ const context = {
238
+ claimPath,
239
+ checkpointPath: options.checkpointPath,
240
+ claim,
241
+ };
242
+ checkpointRunOwner(context, [], "active", true);
243
+ return context;
244
+ });
245
+ }
246
+ /** Persist a checkpoint only while this attempt owns the identity. */
247
+ export function checkpointRunOwner(context, completedTrials, status, alreadyLocked = false) {
248
+ const write = () => {
249
+ if (!alreadyLocked)
250
+ validateCheckpointOwner(context);
251
+ const finalizedAt = status === "active" ? undefined : new Date().toISOString();
252
+ const updatedClaim = {
253
+ ...context.claim,
254
+ status,
255
+ ...(finalizedAt ? { finalizedAt } : {}),
256
+ };
257
+ atomicJson(context.checkpointPath, {
258
+ format: "sevro.run-checkpoint.v1",
259
+ runId: context.claim.attemptId,
260
+ completedTrials,
261
+ });
262
+ atomicJson(context.claim.activeRunPath, {
263
+ format: "sevro.active-run.v1",
264
+ runId: context.claim.attemptId,
265
+ evaluationDigest: context.claim.evaluationDigest,
266
+ attemptId: context.claim.attemptId,
267
+ status,
268
+ owner: context.claim.owner,
269
+ artifactPath: context.claim.artifactPath,
270
+ evidenceDirectory: context.claim.evidenceDirectory,
271
+ checkpointPath: context.checkpointPath,
272
+ completedTrials,
273
+ ...(finalizedAt ? { finalizedAt } : {}),
274
+ });
275
+ atomicJson(context.claimPath, updatedClaim);
276
+ context.claim = updatedClaim;
277
+ };
278
+ if (alreadyLocked)
279
+ write();
280
+ else
281
+ withClaimLock(context.claimPath, write);
282
+ }
283
+ //# sourceMappingURL=run-owner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-owner.js","sourceRoot":"","sources":["run-owner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,6BAA0B;AAC9C,OAAO,EAAE,QAAQ,EAAE,0BAAuB;AAC1C,OAAO,EAAE,gBAAgB,EAAE,yBAAsB;AACjD,OAAO,EAAE,UAAU,EAAE,oBAAoB;AACzC,OAAO,EACL,SAAS,EACT,YAAY,EACZ,UAAU,EACV,UAAU,EACV,aAAa,GACd,gBAAgB;AACjB,OAAO,EAAE,QAAQ,EAAE,gBAAgB;AACnC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB;AAkCpD,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC;AACD,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,CACL,KAAK,KAAK,QAAQ;QAClB,KAAK,KAAK,UAAU;QACpB,KAAK,KAAK,YAAY;QACtB,KAAK,KAAK,aAAa,CACxB,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,KAA8B;IACxD,OAAO,CACL,KAAK,CAAC,MAAM,KAAK,oBAAoB;QACrC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACrD,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;QACxB,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,CAC/B,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAA8B;IACrD,OAAO,CACL,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC;QACjC,YAAY,CAAC,KAAK,CAAC,iBAAiB,CAAC;QACrC,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CACjC,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAC1B,KAAc,EACd,IAAY;IAEZ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;QAC3E,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,EAAE,CAAC,CAAC;AACpE,CAAC;AAQD,SAAS,UAAU,CAAC,IAAY,EAAE,KAAc;IAC9C,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CACpB,OAAO,CAAC,IAAI,CAAC,EACb,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,UAAU,EAAE,MAAM,CACzC,CAAC;IACF,IAAI,CAAC;QACH,aAAa,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;YAC9D,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QACH,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC;YACH,UAAU,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAI,SAAiB,EAAE,MAAe;IAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACzD,SAAS,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,gBAAgB,CAC/B,IAAI,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAC7C,CAAC;IACF,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC5C,QAAQ,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;QAC3E,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,QAAQ,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC/C,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACzC,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,GAAW,EAAE,OAAgB;IACpD,OAAO,OAAO;QACZ,CAAC,CAAC;YACE,gBAAgB;YAChB,YAAY;YACZ,iBAAiB;YACjB,UAAU;YACV,oBAAoB,GAAG,uDAAuD;SAC/E;QACH,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAgB;IAC3C,OAAO,OAAO;QACZ,CAAC,CAAC;YACE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE;YAC5B,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,aAAa;SACpD;QACH,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;AAC7C,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAoC;IAC5D,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC7C,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,MAAoC,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE;YACvB,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC;YACjC,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC3C,OAAO,MAAM,CAAC,QAAQ,KAAK,CAAC,IAAI,SAAS;QACvC,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QACtC,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,OAAO,CACL,QAAQ,CAAC,KAAK,CAAC;QACf,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE;QACzB,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC;QACzB,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAC9B,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,GAAW;IAClC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,SAAS,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACnD,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,QAAQ,KAAK,MAAM;QAAE,OAAO,QAAQ,CAAC;IACzC,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,OAAO,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AACjE,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC7B,+EAA+E;IAC/E,MAAM,OAAO,GAAwB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3D,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAoB;IAC7C,MAAM,WAAW,GAAG;QAClB,GAAG,KAAK;QACR,MAAM,EAAE,aAAsB;QAC9B,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACtC,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,EAAE,WAAW,CAAC,CAAC;IACzE,IAAI,MAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAChC,YAAY,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,CAC1C,CAAC;QACF,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;QAC/C,MAAM,GAAG;YACP,MAAM,EAAE,qBAAqB;YAC7B,KAAK,EAAE,KAAK,CAAC,SAAS;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,eAAe,EAAE,EAAE;SACpB,CAAC;IACJ,CAAC;IACD,UAAU,CAAC,KAAK,CAAC,aAAa,EAAE;QAC9B,GAAG,MAAM;QACT,MAAM,EAAE,aAAa;QACrB,WAAW,EAAE,WAAW,CAAC,WAAW;KACrC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,0BAA0B,CACjC,KAA2B,EAC3B,gBAAwB;IAExB,IAAI,KAAK,IAAI,KAAK,CAAC,gBAAgB,KAAK,gBAAgB;QACtD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,mBAAmB,CAC1B,KAA2B,EAC3B,SAAiB;IAEjB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO;IACxD,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,MAAM,KAAK,MAAM;QACnB,MAAM,IAAI,KAAK,CAAC,mCAAmC,SAAS,EAAE,CAAC,CAAC;IAClE,IAAI,MAAM,KAAK,SAAS;QACtB,MAAM,IAAI,KAAK,CAAC,wCAAwC,SAAS,EAAE,CAAC,CAAC;IACvE,iBAAiB,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,uBAAuB,CAAC,OAAiB;IAChD,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,SAAS,KAAK,OAAO,CAAC,KAAK,CAAC,SAAS;QAC3D,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ;QAC7B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,IAAI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,MAAM;QACvC,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;AACxE,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,aAAa,CAAC,OAQ7B;IACC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,IAAI,CACpB,OAAO,CAAC,SAAS,EACjB,QAAQ,EACR,GAAG,OAAO,CAAC,gBAAgB,OAAO,CACnC,CAAC;IACF,OAAO,aAAa,CAAC,SAAS,EAAE,GAAG,EAAE;QACnC,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QACnC,0BAA0B,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC5D,mBAAmB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAC3E,MAAM,KAAK,GAAU;YACnB,MAAM,EAAE,oBAAoB;YAC5B,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,MAAM,EAAE,QAAQ;YAChB,KAAK;YACL,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;YAC5C,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QACF,MAAM,OAAO,GAAG;YACd,SAAS;YACT,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,KAAK;SACN,CAAC;QACF,kBAAkB,CAAC,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QAChD,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,kBAAkB,CAChC,OAAiB,EACjB,eAA0D,EAC1D,MAA4D,EAC5D,aAAa,GAAG,KAAK;IAErB,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC,aAAa;YAAE,uBAAuB,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,WAAW,GACf,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC7D,MAAM,YAAY,GAAG;YACnB,GAAG,OAAO,CAAC,KAAK;YAChB,MAAM;YACN,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxC,CAAC;QACF,UAAU,CAAC,OAAO,CAAC,cAAc,EAAE;YACjC,MAAM,EAAE,yBAAyB;YACjC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS;YAC9B,eAAe;SAChB,CAAC,CAAC;QACH,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE;YACtC,MAAM,EAAE,qBAAqB;YAC7B,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS;YAC9B,gBAAgB,EAAE,OAAO,CAAC,KAAK,CAAC,gBAAgB;YAChD,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS;YAClC,MAAM;YACN,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK;YAC1B,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,YAAY;YACxC,iBAAiB,EAAE,OAAO,CAAC,KAAK,CAAC,iBAAiB;YAClD,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,eAAe;YACf,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxC,CAAC,CAAC;QACH,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAC5C,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC;IAC/B,CAAC,CAAC;IACF,IAAI,aAAa;QAAE,KAAK,EAAE,CAAC;;QACtB,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;AAC/C,CAAC","sourcesContent":["import { spawnSync } from \"./runtime-process\";\nimport { isRecord } from \"./value-guards\";\nimport { openLockDatabase } from \"./sqlite-lock\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n mkdirSync,\n readFileSync,\n renameSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { basename, dirname, join } from \"node:path\";\n\nexport interface ProcessIdentity {\n pid: number;\n startedAt: string;\n host: string;\n}\n\ninterface Claim {\n format: \"sevro.run-owner.v1\";\n evaluationDigest: string;\n attemptId: string;\n status: \"active\" | \"complete\" | \"diagnostic\" | \"interrupted\";\n owner: ProcessIdentity;\n activeRunPath: string;\n evidenceDirectory: string;\n artifactPath: string;\n startedAt: string;\n finalizedAt?: string;\n}\n\ninterface RetainedClaim {\n format: \"sevro.run-owner.v1\";\n evaluationDigest: unknown;\n attemptId: unknown;\n status: Claim[\"status\"];\n owner?: unknown;\n activeRunPath: string;\n evidenceDirectory: string;\n artifactPath: string;\n startedAt?: unknown;\n finalizedAt?: unknown;\n}\n\nfunction errorCode(error: unknown): unknown {\n return isRecord(error) ? error.code : undefined;\n}\nfunction nonemptyText(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\nfunction validClaimStatus(value: unknown): value is Claim[\"status\"] {\n return (\n value === \"active\" ||\n value === \"complete\" ||\n value === \"diagnostic\" ||\n value === \"interrupted\"\n );\n}\n\nfunction validClaimIdentity(value: Record<string, unknown>): boolean {\n return (\n value.format === \"sevro.run-owner.v1\" &&\n /^[a-f0-9]{64}$/.test(String(value.evaluationDigest)) &&\n Boolean(value.attemptId) &&\n validClaimStatus(value.status)\n );\n}\n\nfunction validClaimPaths(value: Record<string, unknown>): boolean {\n return (\n nonemptyText(value.activeRunPath) &&\n nonemptyText(value.evidenceDirectory) &&\n nonemptyText(value.artifactPath)\n );\n}\n\nfunction assertRetainedClaim(\n value: unknown,\n path: string,\n): asserts value is RetainedClaim {\n if (!isRecord(value) || !validClaimIdentity(value) || !validClaimPaths(value))\n throw new Error(`unrecognized Sevro ownership record: ${path}`);\n}\n\nexport interface RunOwner {\n claimPath: string;\n checkpointPath: string;\n claim: Claim;\n}\n\nfunction atomicJson(path: string, value: unknown): void {\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n const temporary = join(\n dirname(path),\n `.${basename(path)}.${randomUUID()}.tmp`,\n );\n try {\n writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\\n`, {\n flag: \"wx\",\n mode: 0o600,\n });\n renameSync(temporary, path);\n } catch (error) {\n try {\n unlinkSync(temporary);\n } catch {\n // The temporary file may not have been created.\n }\n throw error;\n }\n}\n\nfunction withClaimLock<T>(claimPath: string, action: () => T): T {\n const locks = join(dirname(dirname(claimPath)), \"locks\");\n mkdirSync(locks, { recursive: true, mode: 0o700 });\n const database = openLockDatabase(\n join(locks, `${basename(claimPath)}.sqlite`),\n );\n try {\n database.exec(\"PRAGMA busy_timeout = 5000\");\n database.exec(\"CREATE TABLE IF NOT EXISTS mutex (id INTEGER PRIMARY KEY)\");\n database.exec(\"BEGIN IMMEDIATE\");\n const result = action();\n database.exec(\"COMMIT\");\n return result;\n } finally {\n database.close();\n }\n}\n\nfunction readClaim(path: string): RetainedClaim | null {\n let bytes: string;\n try {\n bytes = readFileSync(path, \"utf8\");\n } catch (error) {\n if (errorCode(error) === \"ENOENT\") return null;\n throw error;\n }\n const value: unknown = JSON.parse(bytes);\n assertRetainedClaim(value, path);\n return value;\n}\n\nfunction identityCommand(pid: number, windows: boolean): string[] {\n return windows\n ? [\n \"powershell.exe\",\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-Command\",\n `(Get-Process -Id ${pid} -ErrorAction Stop).StartTime.ToUniversalTime().Ticks`,\n ]\n : [\"/bin/ps\", \"-p\", String(pid), \"-o\", \"lstart=\"];\n}\n\nfunction identityEnvironment(windows: boolean) {\n return windows\n ? {\n PATH: process.env.PATH ?? \"\",\n SystemRoot: process.env.SystemRoot ?? \"C:\\\\Windows\",\n }\n : { PATH: \"/usr/bin:/bin\", LC_ALL: \"C\" };\n}\n\nfunction processStartTime(result: ReturnType<typeof spawnSync>): string {\n return result.stdout.toString().trim();\n}\n\nexport function processIdentity(pid: number): ProcessIdentity | null {\n const windows = process.platform === \"win32\";\n const argv = identityCommand(pid, windows);\n let result: ReturnType<typeof spawnSync>;\n try {\n result = spawnSync(argv, {\n env: identityEnvironment(windows),\n stdout: \"pipe\",\n stderr: \"ignore\",\n });\n } catch {\n return null;\n }\n const startedAt = processStartTime(result);\n return result.exitCode === 0 && startedAt\n ? { pid, startedAt, host: hostname() }\n : null;\n}\n\nfunction validProcessId(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value > 0;\n}\n\nexport function validProcessIdentity(value: unknown): value is ProcessIdentity {\n return (\n isRecord(value) &&\n value.host === hostname() &&\n validProcessId(value.pid) &&\n nonemptyText(value.startedAt)\n );\n}\n\nfunction processLiveness(pid: number): \"live\" | \"dead\" | \"unknown\" {\n try {\n process.kill(pid, 0);\n return \"live\";\n } catch (error) {\n return errorCode(error) === \"ESRCH\" ? \"dead\" : \"unknown\";\n }\n}\n\nexport function ownerStatus(owner: unknown): \"live\" | \"dead\" | \"unknown\" {\n if (!validProcessIdentity(owner)) return \"unknown\";\n const liveness = processLiveness(owner.pid);\n if (liveness !== \"live\") return liveness;\n const current = processIdentity(owner.pid);\n if (!current) return \"unknown\";\n return current.startedAt === owner.startedAt ? \"live\" : \"dead\";\n}\n\nfunction activeRunFields(value: unknown): Record<string, unknown> {\n if (value == null) return {};\n // Preserve the existing object-spread representation of opaque active records.\n const entries: [string, unknown][] = Object.entries(value);\n return Object.fromEntries(entries);\n}\n\nfunction preserveAbandoned(claim: RetainedClaim): void {\n const interrupted = {\n ...claim,\n status: \"interrupted\" as const,\n finalizedAt: new Date().toISOString(),\n };\n atomicJson(join(claim.evidenceDirectory, \"run-owner.json\"), interrupted);\n let active: Record<string, unknown>;\n try {\n const parsed: unknown = JSON.parse(\n readFileSync(claim.activeRunPath, \"utf8\"),\n );\n active = activeRunFields(parsed);\n } catch (error) {\n if (errorCode(error) !== \"ENOENT\") throw error;\n active = {\n format: \"sevro.active-run.v1\",\n runId: claim.attemptId,\n artifactPath: claim.artifactPath,\n evidenceDirectory: claim.evidenceDirectory,\n completedTrials: [],\n };\n }\n atomicJson(claim.activeRunPath, {\n ...active,\n status: \"interrupted\",\n finalizedAt: interrupted.finalizedAt,\n });\n}\n\nfunction validateClaimIdentityMatch(\n prior: RetainedClaim | null,\n evaluationDigest: string,\n): void {\n if (prior && prior.evaluationDigest !== evaluationDigest)\n throw new Error(\"Sevro ownership record has a different identity\");\n}\n\nfunction retainPreviousOwner(\n prior: RetainedClaim | null,\n claimPath: string,\n): void {\n if (prior === null || prior.status !== \"active\") return;\n const status = ownerStatus(prior.owner);\n if (status === \"live\")\n throw new Error(`equivalent Sevro run is active: ${claimPath}`);\n if (status === \"unknown\")\n throw new Error(`Sevro run ownership is unverifiable: ${claimPath}`);\n preserveAbandoned(prior);\n}\n\nfunction validateCheckpointOwner(context: RunOwner): void {\n const current = readClaim(context.claimPath);\n if (!current || current.attemptId !== context.claim.attemptId)\n throw new Error(\"Sevro run ownership changed before checkpoint\");\n if (current.status !== \"active\")\n throw new Error(\"Sevro run owner is already finalized\");\n if (ownerStatus(current.owner) !== \"live\")\n throw new Error(\"Sevro run owner identity is no longer verifiable\");\n}\n\n/** Claim one evaluation identity before candidate execution. */\nexport function startRunOwner(options: {\n stateRoot: string;\n evaluationDigest: string;\n attemptId: string;\n activeRunPath: string;\n checkpointPath: string;\n evidenceDirectory: string;\n artifactPath: string;\n}): RunOwner {\n if (!/^[a-f0-9]{64}$/.test(options.evaluationDigest))\n throw new Error(\"invalid evaluation identity for run ownership\");\n const claimPath = join(\n options.stateRoot,\n \"owners\",\n `${options.evaluationDigest}.json`,\n );\n return withClaimLock(claimPath, () => {\n const prior = readClaim(claimPath);\n validateClaimIdentityMatch(prior, options.evaluationDigest);\n retainPreviousOwner(prior, claimPath);\n const owner = processIdentity(process.pid);\n if (!owner) throw new Error(\"cannot verify Sevro runner process identity\");\n const claim: Claim = {\n format: \"sevro.run-owner.v1\",\n evaluationDigest: options.evaluationDigest,\n attemptId: options.attemptId,\n status: \"active\",\n owner,\n activeRunPath: options.activeRunPath,\n evidenceDirectory: options.evidenceDirectory,\n artifactPath: options.artifactPath,\n startedAt: new Date().toISOString(),\n };\n const context = {\n claimPath,\n checkpointPath: options.checkpointPath,\n claim,\n };\n checkpointRunOwner(context, [], \"active\", true);\n return context;\n });\n}\n\n/** Persist a checkpoint only while this attempt owns the identity. */\nexport function checkpointRunOwner(\n context: RunOwner,\n completedTrials: { trial: number; artifactPath: string }[],\n status: \"active\" | \"complete\" | \"diagnostic\" | \"interrupted\",\n alreadyLocked = false,\n): void {\n const write = () => {\n if (!alreadyLocked) validateCheckpointOwner(context);\n const finalizedAt =\n status === \"active\" ? undefined : new Date().toISOString();\n const updatedClaim = {\n ...context.claim,\n status,\n ...(finalizedAt ? { finalizedAt } : {}),\n };\n atomicJson(context.checkpointPath, {\n format: \"sevro.run-checkpoint.v1\",\n runId: context.claim.attemptId,\n completedTrials,\n });\n atomicJson(context.claim.activeRunPath, {\n format: \"sevro.active-run.v1\",\n runId: context.claim.attemptId,\n evaluationDigest: context.claim.evaluationDigest,\n attemptId: context.claim.attemptId,\n status,\n owner: context.claim.owner,\n artifactPath: context.claim.artifactPath,\n evidenceDirectory: context.claim.evidenceDirectory,\n checkpointPath: context.checkpointPath,\n completedTrials,\n ...(finalizedAt ? { finalizedAt } : {}),\n });\n atomicJson(context.claimPath, updatedClaim);\n context.claim = updatedClaim;\n };\n if (alreadyLocked) write();\n else withClaimLock(context.claimPath, write);\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { resolve, join } from "node:path";
2
+ export const sourceRuntime = import.meta.filename.endsWith(".ts");
3
+ export const runnerRoot = resolve(import.meta.dirname, sourceRuntime ? ".." : "../..");
4
+ export function examplePath(...parts) {
5
+ const path = join(runnerRoot, ...(sourceRuntime ? [] : ["dist"]), "examples", ...parts);
6
+ return runtimeModule(path);
7
+ }
8
+ export function runtimeModule(path) {
9
+ return sourceRuntime ? path : path.replace(/\.ts$/, ".js");
10
+ }
11
+ //# sourceMappingURL=runner-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-paths.js","sourceRoot":"","sources":["runner-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB;AAE1C,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAC/B,MAAM,CAAC,IAAI,CAAC,OAAO,EACnB,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAC/B,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,GAAG,KAAe;IAC5C,MAAM,IAAI,GAAG,IAAI,CACf,UAAU,EACV,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAClC,UAAU,EACV,GAAG,KAAK,CACT,CAAC;IACF,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC7D,CAAC","sourcesContent":["import { resolve, join } from \"node:path\";\n\nexport const sourceRuntime = import.meta.filename.endsWith(\".ts\");\nexport const runnerRoot = resolve(\n import.meta.dirname,\n sourceRuntime ? \"..\" : \"../..\",\n);\n\nexport function examplePath(...parts: string[]): string {\n const path = join(\n runnerRoot,\n ...(sourceRuntime ? [] : [\"dist\"]),\n \"examples\",\n ...parts,\n );\n return runtimeModule(path);\n}\n\nexport function runtimeModule(path: string): string {\n return sourceRuntime ? path : path.replace(/\\.ts$/, \".js\");\n}\n"]}