@bjoernrochel/sevro 0.1.0-rc.8 → 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 (582) hide show
  1. package/CONTRIBUTING.md +52 -6
  2. package/README.md +12 -7
  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/README.md +19 -15
  349. package/docs/architecture.md +141 -17
  350. package/docs/assets/README.md +5 -4
  351. package/docs/builtin-graders-v1.md +9 -2
  352. package/docs/codex-host.md +155 -57
  353. package/docs/contracts.md +2 -1
  354. package/docs/creating-cases.md +10 -4
  355. package/docs/development-cli.md +197 -24
  356. package/docs/documentation-quality.md +16 -5
  357. package/docs/evaluation-workflow.md +110 -0
  358. package/docs/extension-protocol-v1.md +26 -3
  359. package/docs/getting-started.md +29 -7
  360. package/docs/guide-evaluation.md +34 -2
  361. package/docs/identity-v1.md +29 -3
  362. package/docs/installing.md +35 -17
  363. package/docs/licensing.md +2 -2
  364. package/docs/native-controls.md +76 -5
  365. package/docs/native-hosts.md +197 -8
  366. package/docs/reading-results.md +102 -0
  367. package/docs/recipes.md +490 -0
  368. package/docs/releases.md +48 -13
  369. package/docs/report-v1.md +29 -1
  370. package/docs/results-v1.md +122 -4
  371. package/docs/run-settings-v1.md +147 -0
  372. package/docs/runtime-v1.md +255 -22
  373. package/docs/specs/repository-guide.md +1 -1
  374. package/docs/troubleshooting.md +12 -12
  375. package/docs/typescript-quality.md +106 -26
  376. package/examples/recipes/candidate.ts +26 -0
  377. package/examples/recipes/cases/coding-change.json +21 -0
  378. package/examples/recipes/cases/host-tools.json +21 -0
  379. package/examples/recipes/cases/mise.json +21 -0
  380. package/examples/recipes/cases/node.json +21 -0
  381. package/examples/recipes/cases/python-uv.json +21 -0
  382. package/examples/recipes/cases/semantic.json +17 -0
  383. package/examples/recipes/coding-change/check.ts +23 -0
  384. package/examples/recipes/executable.ts +19 -0
  385. package/examples/recipes/extension-artifacts.ts +65 -0
  386. package/examples/recipes/extension-methods.ts +174 -0
  387. package/examples/recipes/extension.ts +38 -0
  388. package/examples/recipes/modules.ts +9 -0
  389. package/examples/recipes/repository-skill/.agents/skills/startup-guide/SKILL.md +7 -0
  390. package/examples/recipes/repository-skill/.claude/skills/startup-guide/SKILL.md +7 -0
  391. package/examples/recipes/repository-skill/README.md +3 -0
  392. package/examples/recipes/run-inputs.ts +183 -0
  393. package/examples/recipes/run-options.ts +132 -0
  394. package/examples/recipes/run.ts +77 -0
  395. package/examples/recipes/runtime/empty.json +1 -0
  396. package/examples/recipes/runtime/goals.json +1 -0
  397. package/examples/recipes/runtime/mise.json +6 -0
  398. package/examples/recipes/runtime/path.json +1 -0
  399. package/examples/recipes/runtime/plugins.json +4 -0
  400. package/examples/recipes/runtime/python-uv.json +10 -0
  401. package/examples/recipes/semantic-judge.ts +29 -0
  402. package/examples/templates/coding/adapter.ts +17 -0
  403. package/examples/templates/coding/case.json +15 -0
  404. package/examples/templates/repository-skill/.agents/skills/startup-guide/SKILL.md +6 -0
  405. package/examples/templates/repository-skill/extension-data.ts +64 -0
  406. package/examples/templates/repository-skill/extension.ts +32 -0
  407. package/examples/templates/response/adapter.ts +12 -0
  408. package/examples/templates/response/case.json +13 -0
  409. package/package.json +23 -9
  410. package/schemas/report-v1.schema.json +9 -0
  411. package/schemas/run-evidence-v1.schema.json +2 -1
  412. package/schemas/runtime-v1.schema.json +43 -7
  413. package/src/advisory.ts +2 -2
  414. package/src/candidate-artifacts.ts +42 -11
  415. package/src/candidate-codex-state.ts +185 -0
  416. package/src/case-validation.ts +73 -50
  417. package/src/cli/cancellation.ts +20 -0
  418. package/src/cli/command.ts +87 -0
  419. package/src/cli/completion.ts +15 -0
  420. package/src/cli/demo.ts +61 -0
  421. package/src/cli/evaluation.ts +55 -0
  422. package/src/cli/extension.ts +79 -0
  423. package/src/cli/help.ts +199 -0
  424. package/src/cli/hosts.ts +55 -0
  425. package/src/cli/init-settings.ts +31 -0
  426. package/src/cli/init.ts +112 -0
  427. package/src/{cli-invocation.ts → cli/invocation.ts} +215 -218
  428. package/src/cli/loading.ts +151 -0
  429. package/src/cli/preparation.ts +154 -0
  430. package/src/cli/presentation.ts +93 -0
  431. package/src/cli/progress.ts +6 -0
  432. package/src/cli/run-manifest.ts +128 -0
  433. package/src/cli/run-options.ts +403 -0
  434. package/src/cli/run-overrides.ts +69 -0
  435. package/src/cli/settings.ts +154 -0
  436. package/src/cli/summary.ts +43 -0
  437. package/src/cli.ts +14 -592
  438. package/src/contract-types.ts +94 -0
  439. package/src/engine.ts +9 -5
  440. package/src/evaluation/advisory.ts +150 -0
  441. package/src/{evaluation-check-plan.ts → evaluation/check-plan.ts} +103 -67
  442. package/src/evaluation/collection.ts +88 -0
  443. package/src/evaluation/context.ts +10 -0
  444. package/src/{evaluation-grading-host.ts → evaluation/grading-host.ts} +5 -5
  445. package/src/evaluation/grading.ts +235 -0
  446. package/src/{evaluation-invocation-plan.ts → evaluation/invocation-plan.ts} +147 -58
  447. package/src/{evaluation-plan.ts → evaluation/plan.ts} +208 -141
  448. package/src/evaluation/progress.ts +19 -0
  449. package/src/evaluation/resources.ts +241 -0
  450. package/src/evaluation/run.ts +206 -0
  451. package/src/{evaluation-semantic.ts → evaluation/semantic.ts} +77 -87
  452. package/src/evaluation/trial.ts +800 -0
  453. package/src/{evaluation-types.ts → evaluation/types.ts} +79 -29
  454. package/src/evidence/host-results.ts +85 -0
  455. package/src/evidence/retained-artifacts.ts +18 -0
  456. package/src/evidence/trial-writer.ts +203 -0
  457. package/src/evidence/usage.ts +17 -0
  458. package/src/executable.ts +19 -0
  459. package/src/extension-client.ts +40 -108
  460. package/src/extension-session.ts +24 -48
  461. package/src/{advisory-fixture.ts → fixtures/advisory.ts} +12 -72
  462. package/src/{fixture-bin.ts → fixtures/bin.ts} +1 -1
  463. package/src/{fixture-cleanup.ts → fixtures/cleanup.ts} +13 -7
  464. package/src/fixtures/create.ts +183 -0
  465. package/src/{generated-fixture.ts → fixtures/generated.ts} +10 -53
  466. package/src/{git-hooks.ts → fixtures/git-hooks.ts} +1 -1
  467. package/src/{preparation.ts → fixtures/preparation.ts} +6 -16
  468. package/src/{repository-fixture.ts → fixtures/repository.ts} +30 -64
  469. package/src/{fixture-setup.ts → fixtures/setup.ts} +36 -53
  470. package/src/{fixture-tools.ts → fixtures/tools.ts} +1 -1
  471. package/src/{workspace-state.ts → fixtures/workspace-state.ts} +5 -5
  472. package/src/generated/cli-result.d.cts +2 -1
  473. package/src/generated/extension.d.cts +2 -1
  474. package/src/generated/report.cjs +1 -1
  475. package/src/generated/report.d.cts +2 -1
  476. package/src/generated/run-evidence.cjs +1 -1
  477. package/src/generated/run-evidence.d.cts +2 -1
  478. package/src/generated/runtime.cjs +1 -1
  479. package/src/generated/runtime.d.cts +2 -1
  480. package/src/git.ts +94 -0
  481. package/src/graders/git-head.ts +31 -85
  482. package/src/graders/shell.ts +54 -71
  483. package/src/host-diagnostic-redaction.ts +52 -0
  484. package/src/host-diagnostics.ts +331 -0
  485. package/src/hosts/claude-continuation.ts +57 -40
  486. package/src/hosts/claude-credential.ts +160 -63
  487. package/src/hosts/claude-events.ts +34 -18
  488. package/src/hosts/claude-keychain.ts +79 -21
  489. package/src/hosts/claude-login-recovery.ts +85 -0
  490. package/src/hosts/claude-login-refresh.ts +179 -0
  491. package/src/hosts/claude-login-store.ts +162 -0
  492. package/src/hosts/claude-login.ts +107 -0
  493. package/src/hosts/claude-native-goal.ts +15 -12
  494. package/src/hosts/claude-process.ts +10 -50
  495. package/src/hosts/claude-refresh-lock.ts +82 -0
  496. package/src/hosts/claude-repository-invocation.ts +9 -34
  497. package/src/hosts/claude-settings.ts +46 -9
  498. package/src/hosts/claude-skill-activations.ts +169 -0
  499. package/src/hosts/claude-state.ts +28 -15
  500. package/src/hosts/claude-tool-calls.ts +13 -10
  501. package/src/hosts/claude.ts +121 -81
  502. package/src/hosts/codex-app-server.ts +78 -52
  503. package/src/hosts/codex-configuration.ts +5 -10
  504. package/src/hosts/codex-exec-controls.ts +516 -0
  505. package/src/hosts/codex-marketplace.ts +12 -10
  506. package/src/hosts/codex-native-calls.ts +15 -122
  507. package/src/hosts/codex-process.ts +10 -183
  508. package/src/hosts/codex-profile.ts +36 -21
  509. package/src/hosts/codex-session-files.ts +1 -9
  510. package/src/hosts/codex-state.ts +134 -18
  511. package/src/hosts/codex.ts +210 -183
  512. package/src/hosts/isolation-common.ts +8 -11
  513. package/src/hosts/isolation-roots.ts +5 -4
  514. package/src/hosts/linux-sandbox.ts +15 -2
  515. package/src/hosts/mac-sandbox.ts +87 -18
  516. package/src/hosts/native-controls.ts +72 -22
  517. package/src/hosts/native-request.ts +55 -0
  518. package/src/hosts/process-lifecycle.ts +215 -49
  519. package/src/hosts/protected-worktrees.ts +3 -2
  520. package/src/hosts/skill-hook-catalog.ts +131 -0
  521. package/src/hosts/skill-hook-handler.ts +374 -0
  522. package/src/hosts/skill-hooks.ts +585 -0
  523. package/src/instrumentation.ts +7 -8
  524. package/src/native-transcript-state.ts +22 -3
  525. package/src/native-transcript-view.ts +52 -13
  526. package/src/native-transcripts.ts +26 -11
  527. package/src/paths.ts +22 -0
  528. package/src/process-lifecycle.ts +150 -0
  529. package/src/provenance.ts +34 -13
  530. package/src/prune.ts +300 -0
  531. package/src/report.ts +63 -36
  532. package/src/resolved-case.ts +1 -1
  533. package/src/results-lock.ts +42 -0
  534. package/src/results.ts +14 -18
  535. package/src/run-owner.ts +15 -9
  536. package/src/runner-paths.ts +21 -0
  537. package/src/{runtime-config.ts → runtime/config.ts} +160 -46
  538. package/src/{runtime-discovery-apple.ts → runtime/discovery-apple.ts} +3 -3
  539. package/src/{runtime-discovery-providers.ts → runtime/discovery-providers.ts} +3 -9
  540. package/src/{runtime-discovery.ts → runtime/discovery.ts} +4 -4
  541. package/src/{runtime-hook-processes.ts → runtime/hook-processes.ts} +3 -2
  542. package/src/{runtime-hooks.ts → runtime/hooks.ts} +40 -28
  543. package/src/{runtime-paths.ts → runtime/paths.ts} +5 -19
  544. package/src/{runtime-query.ts → runtime/query.ts} +5 -5
  545. package/src/{runtime-seeds.ts → runtime/seeds.ts} +3 -3
  546. package/src/runtime/shared-cache.ts +130 -0
  547. package/src/{runtime-state.ts → runtime/state.ts} +28 -11
  548. package/src/runtime-process.ts +194 -0
  549. package/src/schema-types.ts +73 -161
  550. package/src/shell.ts +4 -0
  551. package/src/sqlite-lock.ts +25 -0
  552. package/src/transcript-retention.ts +146 -0
  553. package/src/value-guards.ts +22 -0
  554. package/docs/assets/sevro-logo.png +0 -0
  555. package/docs/assets/sevro-symbol.svg +0 -1
  556. package/docs/assets/sevro-wordmark.svg +0 -1
  557. package/docs/cache-ownership-validation.md +0 -49
  558. package/docs/claude-continuation-validation.md +0 -47
  559. package/docs/concurrency-validation.md +0 -86
  560. package/docs/configuration-root-validation.md +0 -70
  561. package/docs/engine-slice.md +0 -114
  562. package/docs/evidence/runtime-startup-30/README.md +0 -185
  563. package/docs/evidence/runtime-startup-30/after.json +0 -319
  564. package/docs/evidence/runtime-startup-30/baseline-timeout.jsonl +0 -2
  565. package/docs/evidence/runtime-startup-30/before.json +0 -403
  566. package/docs/evidence/runtime-startup-30/consumer-smoke.json +0 -63
  567. package/docs/evidence/runtime-startup-30/full-policy-diagnostic.jsonl +0 -3
  568. package/docs/evidence/runtime-startup-30/minimal-policy-diagnostic.jsonl +0 -3
  569. package/docs/evidence/runtime-startup-30/plugin-template-assessment.json +0 -20
  570. package/docs/evidence/runtime-startup-30/seedless-timeout.jsonl +0 -2
  571. package/docs/evidence.md +0 -17
  572. package/docs/fixture-cleanup-validation.md +0 -73
  573. package/docs/guide-verification.json +0 -239
  574. package/src/evaluation-context.ts +0 -259
  575. package/src/evaluation-fixture.ts +0 -302
  576. package/src/evaluation-run.ts +0 -200
  577. package/src/evaluation-trial.ts +0 -1016
  578. package/src/hosts/claude-nested-skills.ts +0 -272
  579. package/src/hosts/codex-command-output.ts +0 -510
  580. package/src/hosts/codex-executor-command.ts +0 -291
  581. package/src/hosts/codex-skill-reads.ts +0 -783
  582. /package/src/{trial-scheduler.ts → evaluation/scheduler.ts} +0 -0
@@ -0,0 +1,13 @@
1
+ {
2
+ "id": "response-check",
3
+ "prompt": "Return exactly ready.",
4
+ "fixture": { "files": { "README.md": "Response-check fixture.\n" } },
5
+ "checks": [
6
+ {
7
+ "id": "ready",
8
+ "grader": "sevro.regex",
9
+ "configuration": { "pattern": "^ready$" }
10
+ }
11
+ ],
12
+ "requiredEvidence": []
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bjoernrochel/sevro",
3
- "version": "0.1.0-rc.8",
3
+ "version": "1.1.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "A standalone evaluation runner for agentic coding capabilities",
6
6
  "type": "module",
@@ -19,13 +19,21 @@
19
19
  "README.md",
20
20
  "CONTRIBUTING.md",
21
21
  "LICENSE",
22
- "docs/",
22
+ "docs/*.md",
23
+ "!docs/*-validation.md",
24
+ "!docs/engine-slice.md",
25
+ "!docs/evidence.md",
26
+ "!docs/usability-study.md",
27
+ "docs/assets/README.md",
28
+ "docs/licenses/",
29
+ "docs/specs/",
23
30
  "examples/",
24
31
  "schemas/",
25
- "src/"
32
+ "src/",
33
+ "dist/"
26
34
  ],
27
35
  "bin": {
28
- "sevro": "./src/cli.ts"
36
+ "sevro": "./dist/src/cli.js"
29
37
  },
30
38
  "scripts": {
31
39
  "check:typescript": "bun scripts/check-typescript.ts",
@@ -42,14 +50,18 @@
42
50
  "test:docs-examples": "bun scripts/verify-doc-examples.ts",
43
51
  "guide:sync": "bun scripts/sync-guide.ts",
44
52
  "eval:guide": "bun scripts/eval-guide.ts",
45
- "release:prepare": "bun scripts/prepare-release.ts",
53
+ "release:prepare": "bun run build && bun scripts/prepare-release.ts",
46
54
  "typecheck": "tsc --noEmit",
47
- "format:check": "prettier --check README.md CONTRIBUTING.md AGENTS.md CLAUDE.md 'docs/**/*.md' '.agents/**/*.md' '.agents/**/*.json' '.claude/**/*.md' 'scripts/**/*.md' examples/**/*.json examples/**/*.ts schemas/*.json src/**/*.ts scripts/**/*.ts scripts/**/*.cjs tests/**/*.ts eslint.config.mjs package.json tsconfig.json typescript-sources.json .github/workflows/*.yml"
55
+ "format:check": "prettier --check README.md CONTRIBUTING.md AGENTS.md CLAUDE.md 'docs/**/*.md' '.agents/**/*.md' '.agents/**/*.json' '.claude/**/*.md' 'scripts/**/*.md' 'scripts/**/*.json' 'examples/**/*.json' 'examples/**/*.ts' 'schemas/*.json' 'src/**/*.ts' 'scripts/**/*.ts' 'scripts/**/*.cjs' 'tests/**/*.ts' eslint.config.mjs package.json tsconfig.json '.github/workflows/*.yml'",
56
+ "build": "bun scripts/build.ts",
57
+ "prepack": "bun run build",
58
+ "test:runtime-node": "bun scripts/verify-node-runtime.ts"
48
59
  },
49
60
  "dependencies": {
50
61
  "ajv": "8.20.0",
51
62
  "smol-toml": "1.8.0",
52
- "typescript": "5.9.3"
63
+ "typescript": "5.9.3",
64
+ "yaml": "2.9.1"
53
65
  },
54
66
  "devDependencies": {
55
67
  "@babel/core": "8.0.6",
@@ -68,11 +80,13 @@
68
80
  "istanbul-lib-coverage": "3.2.2",
69
81
  "istanbul-lib-instrument": "6.0.3",
70
82
  "istanbul-lib-report": "3.0.1",
71
- "istanbul-lib-source-maps": "5.0.6",
72
83
  "istanbul-reports": "3.2.0",
73
84
  "markdown-it": "14.2.0",
74
- "prettier": "^3.9.9",
85
+ "prettier": "3.9.9",
75
86
  "shell-quote": "1.12.0",
76
87
  "typescript-eslint": "8.71.1"
88
+ },
89
+ "engines": {
90
+ "node": ">=24.13.0"
77
91
  }
78
92
  }
@@ -110,6 +110,15 @@
110
110
  "domainOutcomes"
111
111
  ],
112
112
  "properties": {
113
+ "nativeTranscripts": {
114
+ "type": "object",
115
+ "required": ["retained", "pruned"],
116
+ "properties": {
117
+ "retained": { "type": "integer", "minimum": 0 },
118
+ "pruned": { "type": "integer", "minimum": 0 }
119
+ },
120
+ "additionalProperties": false
121
+ },
113
122
  "resultFile": { "$ref": "#/$defs/path" },
114
123
  "evidencePath": { "type": ["string", "null"] },
115
124
  "runId": { "type": ["string", "null"] },
@@ -80,7 +80,8 @@
80
80
  "required": ["digest", "redacted"],
81
81
  "properties": {
82
82
  "digest": { "$ref": "#/$defs/digest" },
83
- "redacted": { "type": "object" }
83
+ "redacted": { "type": "object" },
84
+ "resolved": { "type": "object" }
84
85
  },
85
86
  "additionalProperties": false
86
87
  },
@@ -5,7 +5,23 @@
5
5
  "type": "object",
6
6
  "additionalProperties": false,
7
7
  "required": ["format"],
8
+ "$defs": {
9
+ "runtimeRole": {
10
+ "$comment": "Generated from RUNTIME_ROLES by bun run schemas:generate.",
11
+ "enum": ["candidate", "checks", "hooks", "semantic", "advisory"]
12
+ }
13
+ },
8
14
  "properties": {
15
+ "codexState": {
16
+ "type": "boolean"
17
+ },
18
+ "network": {
19
+ "type": "object",
20
+ "additionalProperties": false,
21
+ "properties": {
22
+ "localHttp": { "type": "boolean" }
23
+ }
24
+ },
9
25
  "nativeTranscripts": {
10
26
  "type": "boolean"
11
27
  },
@@ -52,6 +68,32 @@
52
68
  }
53
69
  }
54
70
  },
71
+ "sharedCacheDirectories": {
72
+ "type": "array",
73
+ "maxItems": 16,
74
+ "items": {
75
+ "type": "object",
76
+ "additionalProperties": false,
77
+ "required": ["source", "target", "roles"],
78
+ "properties": {
79
+ "source": { "type": "string", "minLength": 1, "maxLength": 4096 },
80
+ "target": {
81
+ "type": "string",
82
+ "pattern": "^[a-z][a-z0-9-]{0,63}$",
83
+ "not": { "enum": ["home", "tmp"] }
84
+ },
85
+ "roles": {
86
+ "type": "array",
87
+ "minItems": 1,
88
+ "maxItems": 5,
89
+ "uniqueItems": true,
90
+ "items": {
91
+ "$ref": "#/$defs/runtimeRole"
92
+ }
93
+ }
94
+ }
95
+ }
96
+ },
55
97
  "seedDirectories": {
56
98
  "type": "array",
57
99
  "maxItems": 16,
@@ -78,13 +120,7 @@
78
120
  "maxItems": 5,
79
121
  "uniqueItems": true,
80
122
  "items": {
81
- "enum": [
82
- "candidate",
83
- "checks",
84
- "hooks",
85
- "semantic",
86
- "advisory"
87
- ]
123
+ "$ref": "#/$defs/runtimeRole"
88
124
  }
89
125
  }
90
126
  }
package/src/advisory.ts CHANGED
@@ -7,14 +7,14 @@ const DIMENSIONS = [
7
7
  "scopeDiscipline",
8
8
  ] as const;
9
9
 
10
- export interface AdvisoryAssessment {
10
+ export type AdvisoryAssessment = {
11
11
  verdict: "pass" | "fail";
12
12
  overallScore: number;
13
13
  dimensions: Record<(typeof DIMENSIONS)[number], number>;
14
14
  strengths: string[];
15
15
  weaknesses: string[];
16
16
  summary: string;
17
- }
17
+ };
18
18
 
19
19
  function object(value: unknown): Record<string, unknown> {
20
20
  if (!value || typeof value !== "object" || Array.isArray(value))
@@ -1,11 +1,20 @@
1
1
  import { lstat, readdir, realpath, rm } from "node:fs/promises";
2
+ import { containsControl } from "./value-guards";
2
3
  import { join, relative, sep } from "node:path";
4
+ import {
5
+ allocateCodexStateLease,
6
+ candidateCodexArtifactBinding,
7
+ candidateCodexArtifactRoots,
8
+ codexStateEnabled,
9
+ releaseCandidateCodexState,
10
+ requireUnreservedArtifactName,
11
+ } from "./candidate-codex-state";
3
12
  import {
4
13
  allocateNativeState,
5
14
  nativeStatePath,
6
15
  } from "./native-transcript-state";
7
- import type { RuntimePolicy, RuntimeRole } from "./runtime-config";
8
- import { clearFixtureContents } from "./fixture-cleanup";
16
+ import type { RuntimePolicy, RuntimeRole } from "./runtime/config";
17
+ import { clearFixtureContents } from "./fixtures/cleanup";
9
18
 
10
19
  export interface RuntimeArtifactDirectory {
11
20
  name: string;
@@ -35,6 +44,7 @@ export function requireArtifactDirectories(
35
44
  function requireArtifactDirectory(directory: RuntimeArtifactDirectory): void {
36
45
  if (!/^[a-z][a-z0-9_]{0,63}$/.test(directory.name))
37
46
  throw new Error("runtime artifact directory name is invalid");
47
+ requireUnreservedArtifactName(directory.name);
38
48
  const path = directory.path;
39
49
  if (!validArtifactPath(path))
40
50
  throw new Error("runtime artifact directory path is invalid");
@@ -47,24 +57,33 @@ function requireArtifactDirectory(directory: RuntimeArtifactDirectory): void {
47
57
  function validArtifactPath(path: string): boolean {
48
58
  if (typeof path !== "string" || path.length > 4096 || path.includes("\\"))
49
59
  return false;
50
- return !Array.from(path).some(
51
- (character) =>
52
- character.charCodeAt(0) < 0x20 || character.charCodeAt(0) === 0x7f,
53
- );
60
+ return !containsControl(path);
54
61
  }
55
62
 
56
63
  /** Allocate before host execution so exceptions cannot lose cleanup ownership. */
57
64
  export async function allocateCandidateRuntime(
58
65
  policy: RuntimePolicy | undefined,
66
+ retainHome = false,
59
67
  ): Promise<string | undefined> {
60
68
  const directories = policy?.artifactDirectories ?? [];
61
- if (!directories.length) return undefined;
69
+ const codexState = codexStateEnabled(policy);
70
+ if (!candidateRuntimeRequired(directories, codexState, retainHome))
71
+ return undefined;
62
72
  requireArtifactDirectories(directories);
63
73
  const root = await allocateNativeState("candidate-runtime-");
64
74
  leases.set(root, directories);
75
+ allocateCodexStateLease(root, codexState);
65
76
  return root;
66
77
  }
67
78
 
79
+ function candidateRuntimeRequired(
80
+ directories: RuntimeArtifactDirectory[],
81
+ codexState: boolean,
82
+ retainHome: boolean,
83
+ ): boolean {
84
+ return directories.length > 0 || codexState || retainHome;
85
+ }
86
+
68
87
  export async function requireCandidateRuntime(
69
88
  root: string | undefined,
70
89
  role?: RuntimeRole,
@@ -91,6 +110,7 @@ export async function candidateArtifactRoots(
91
110
  const roots = Object.fromEntries(
92
111
  directories.map(({ name, path }) => [name, join(root, "home", path)]),
93
112
  );
113
+ Object.assign(roots, candidateCodexArtifactRoots(root));
94
114
  await requireCandidateArtifactRoots(roots);
95
115
  return roots;
96
116
  }
@@ -100,19 +120,29 @@ export async function requireCandidateArtifactRoots(
100
120
  roots: CandidateArtifactRoots | undefined,
101
121
  ): Promise<void> {
102
122
  for (const [name, path] of Object.entries(roots ?? {})) {
103
- const { root, directory } = artifactRootBinding(name, path);
104
- await requireArtifactAncestors(root, directory.path);
123
+ const binding = artifactRootBinding(name, path);
124
+ await requireArtifactAncestors(binding.root, binding.directoryPath);
125
+ if (binding.file && !(await lstat(path)).isFile())
126
+ throw new Error(
127
+ "candidate Codex configuration must remain a regular file",
128
+ );
105
129
  await requireArtifactTree(path);
106
130
  }
107
131
  }
108
132
 
109
133
  function artifactRootBinding(name: string, path: string) {
134
+ const codex = candidateCodexArtifactBinding(name, path);
135
+ if (codex) return codex;
136
+ return homeArtifactBinding(name, path);
137
+ }
138
+
139
+ function homeArtifactBinding(name: string, path: string) {
110
140
  const parts = relative(nativeStatePath(), path).split(sep);
111
141
  const root = join(nativeStatePath(), parts[0] ?? "");
112
142
  const directory = leases.get(root)?.find((item) => item.name === name);
113
143
  if (!directory || path !== join(root, "home", directory.path))
114
144
  throw new Error("candidate artifact grant is not bound to an active trial");
115
- return { root, directory };
145
+ return { root, directoryPath: join("home", directory.path), file: false };
116
146
  }
117
147
 
118
148
  async function requireArtifactAncestors(
@@ -120,7 +150,7 @@ async function requireArtifactAncestors(
120
150
  path: string,
121
151
  ): Promise<void> {
122
152
  let current = root;
123
- for (const part of ["", "home", ...path.split("/")]) {
153
+ for (const part of ["", ...path.split(sep)]) {
124
154
  current = join(current, part);
125
155
  const info = await lstat(current);
126
156
  if (!info.isDirectory() || (await realpath(current)) !== current)
@@ -169,6 +199,7 @@ export async function releaseCandidateRuntime(
169
199
  root: string | undefined,
170
200
  ): Promise<void> {
171
201
  if (root === undefined) return;
202
+ await releaseCandidateCodexState(root);
172
203
  await clearFixtureContents(root);
173
204
  await rm(root, { recursive: true, force: true });
174
205
  leases.delete(root);
@@ -0,0 +1,185 @@
1
+ import { lstat, realpath, rm } from "node:fs/promises";
2
+ import { basename, dirname, join, relative } from "node:path";
3
+ import { userInfo } from "node:os";
4
+ import { nativeStatePath } from "./native-transcript-state";
5
+ import { clearFixtureContents } from "./fixtures/cleanup";
6
+ import type { RuntimePolicy } from "./runtime/config";
7
+
8
+ interface CodexPaths {
9
+ codexHome: string;
10
+ parentHome: string;
11
+ commandHome: string;
12
+ }
13
+ interface ArtifactBinding {
14
+ root: string;
15
+ path: string;
16
+ directoryPath: string;
17
+ file?: boolean;
18
+ }
19
+ interface CodexLease {
20
+ state?: { stateRoot: string; artifacts: Record<string, ArtifactBinding> };
21
+ }
22
+ const leases = new Map<string, CodexLease>();
23
+ const ARTIFACT_NAMES = [
24
+ "codex_config",
25
+ "codex_skills",
26
+ "agent_skills",
27
+ "command_agent_skills",
28
+ "command_codex_skills",
29
+ ];
30
+
31
+ export function codexStateEnabled(policy: RuntimePolicy | undefined): boolean {
32
+ return policy?.codexState === true;
33
+ }
34
+
35
+ export function requireUnreservedArtifactName(name: string): void {
36
+ if (ARTIFACT_NAMES.includes(name))
37
+ throw new Error(
38
+ "runtime artifact directory name is reserved for Codex state",
39
+ );
40
+ }
41
+
42
+ export function allocateCodexStateLease(root: string, enabled: boolean): void {
43
+ if (enabled) leases.set(root, {});
44
+ }
45
+
46
+ /** Bind the actual host state to one trial before execution; never substitute a grader home. */
47
+ export async function retainCandidateCodexState(
48
+ runtimeRoot: string | undefined,
49
+ stateRoot: string,
50
+ paths: CodexPaths,
51
+ ): Promise<void> {
52
+ if (runtimeRoot === undefined) return;
53
+ const lease = leases.get(runtimeRoot);
54
+ if (!lease) return;
55
+ if (lease.state)
56
+ throw new Error(
57
+ "candidate Codex state is already bound to a native request",
58
+ );
59
+ requireCodexLayout(stateRoot, runtimeRoot, paths);
60
+ await requirePrivateState(stateRoot);
61
+ await requirePrivateState(paths.codexHome);
62
+ lease.state = {
63
+ stateRoot,
64
+ artifacts: codexArtifacts(stateRoot, runtimeRoot, paths),
65
+ };
66
+ }
67
+
68
+ function requireCodexLayout(
69
+ stateRoot: string,
70
+ runtimeRoot: string,
71
+ paths: CodexPaths,
72
+ ): void {
73
+ if (
74
+ dirname(stateRoot) !== nativeStatePath() ||
75
+ !basename(stateRoot).startsWith("codex-")
76
+ )
77
+ throw new Error("candidate Codex state must be a native request directory");
78
+ requireCodexHomes(stateRoot, runtimeRoot, paths);
79
+ }
80
+
81
+ function requireCodexHomes(
82
+ stateRoot: string,
83
+ runtimeRoot: string,
84
+ paths: CodexPaths,
85
+ ): void {
86
+ if (
87
+ paths.codexHome !== join(stateRoot, "codex-home") ||
88
+ paths.parentHome !== join(stateRoot, "home") ||
89
+ paths.commandHome !== join(runtimeRoot, "home")
90
+ )
91
+ throw new Error("candidate Codex homes must belong to the current trial");
92
+ }
93
+
94
+ async function requirePrivateState(root: string): Promise<void> {
95
+ const info = await lstat(root);
96
+ if (
97
+ !info.isDirectory() ||
98
+ info.uid !== userInfo().uid ||
99
+ (info.mode & 0o077) !== 0 ||
100
+ (await realpath(root)) !== root
101
+ )
102
+ throw new Error(
103
+ "candidate Codex state must be owned, private and canonical",
104
+ );
105
+ }
106
+
107
+ function binding(root: string, path: string, file = false): ArtifactBinding {
108
+ return {
109
+ root,
110
+ path,
111
+ directoryPath: relative(root, file ? dirname(path) : path),
112
+ file,
113
+ };
114
+ }
115
+
116
+ function codexArtifacts(
117
+ stateRoot: string,
118
+ runtimeRoot: string,
119
+ paths: CodexPaths,
120
+ ): Record<string, ArtifactBinding> {
121
+ return {
122
+ codex_config: binding(
123
+ stateRoot,
124
+ join(paths.codexHome, "config.toml"),
125
+ true,
126
+ ),
127
+ codex_skills: binding(stateRoot, join(paths.codexHome, "skills")),
128
+ agent_skills: binding(
129
+ stateRoot,
130
+ join(paths.parentHome, ".agents", "skills"),
131
+ ),
132
+ command_agent_skills: binding(
133
+ runtimeRoot,
134
+ join(paths.commandHome, ".agents", "skills"),
135
+ ),
136
+ command_codex_skills: binding(
137
+ runtimeRoot,
138
+ join(paths.commandHome, ".codex", "skills"),
139
+ ),
140
+ };
141
+ }
142
+
143
+ export function candidateCodexArtifactRoots(
144
+ root: string,
145
+ ): Record<string, string> {
146
+ const lease = leases.get(root);
147
+ if (!lease) return {};
148
+ if (!lease.state) throw new Error("candidate Codex state is unavailable");
149
+ return Object.fromEntries(
150
+ Object.entries(lease.state.artifacts).map(([name, item]) => [
151
+ name,
152
+ item.path,
153
+ ]),
154
+ );
155
+ }
156
+
157
+ export function candidateCodexArtifactBinding(
158
+ name: string,
159
+ path: string,
160
+ ): ArtifactBinding | undefined {
161
+ for (const lease of leases.values()) {
162
+ const artifact = lease.state?.artifacts[name];
163
+ if (artifact?.path === path) return artifact;
164
+ }
165
+ return undefined;
166
+ }
167
+
168
+ export function candidateCodexStateRetained(
169
+ runtimeRoot: string | undefined,
170
+ stateRoot: string,
171
+ ): boolean {
172
+ return (
173
+ runtimeRoot !== undefined &&
174
+ leases.get(runtimeRoot)?.state?.stateRoot === stateRoot
175
+ );
176
+ }
177
+
178
+ export async function releaseCandidateCodexState(root: string): Promise<void> {
179
+ const state = leases.get(root)?.state;
180
+ if (state) {
181
+ await clearFixtureContents(state.stateRoot);
182
+ await rm(state.stateRoot, { recursive: true, force: true });
183
+ }
184
+ leases.delete(root);
185
+ }
@@ -1,27 +1,19 @@
1
1
  import { type ResolvedCase } from "./engine";
2
- import { prepareGeneratedFixture } from "./generated-fixture";
3
- import { prepareRepositoryFixture } from "./repository-fixture";
4
- import {
5
- isOptionalNonblankString,
6
- isRecord,
7
- isStringArray,
8
- } from "./value-guards";
2
+ import { prepareGeneratedFixture } from "./fixtures/generated";
3
+ import { prepareRepositoryFixture } from "./fixtures/repository";
4
+ import { isOptionalNonblankString, isRecord } from "./value-guards";
9
5
 
10
- function validGeneratedFixture(value: Record<string, unknown>): boolean {
6
+ function fixtureDeclarationIssue(
7
+ value: Record<string, unknown>,
8
+ ): string | undefined {
11
9
  try {
12
- prepareGeneratedFixture(value);
13
- return true;
14
- } catch {
15
- return false;
16
- }
17
- }
18
-
19
- function validRepositoryFixture(value: Record<string, unknown>): boolean {
20
- try {
21
- prepareRepositoryFixture({ kind: "repository", ...value });
22
- return true;
23
- } catch {
24
- return false;
10
+ if (value.kind === "generated") prepareGeneratedFixture(value);
11
+ else prepareRepositoryFixture({ kind: "repository", ...value });
12
+ return undefined;
13
+ } catch (error) {
14
+ const detail =
15
+ error instanceof Error ? error.message : "invalid declaration";
16
+ return `fixture: ${detail}; correct the fixture declaration`;
25
17
  }
26
18
  }
27
19
 
@@ -34,49 +26,80 @@ export function validInlineFixture(value: Record<string, unknown>): boolean {
34
26
  );
35
27
  }
36
28
 
37
- function fixtureFields(value: Record<string, unknown>): boolean {
38
- if (Object.hasOwn(value, "sourceRef")) return validRepositoryFixture(value);
39
- return validInlineFixture(value);
29
+ function inlineFixtureIssue(
30
+ value: Record<string, unknown>,
31
+ ): string | undefined {
32
+ if (!Object.hasOwn(value, "files") || !isRecord(value.files))
33
+ return "fixture.files: expected an object mapping file paths to string contents";
34
+ const entry = Object.entries(value.files).find(
35
+ ([, content]) => typeof content !== "string",
36
+ );
37
+ return entry
38
+ ? `fixture.files[${JSON.stringify(entry[0])}]: expected string contents`
39
+ : undefined;
40
40
  }
41
41
 
42
- function validFixture(value: unknown): boolean {
43
- if (!isRecord(value)) return false;
44
- if (value.kind === "generated") return validGeneratedFixture(value);
45
- if (value.kind !== undefined) return false;
46
- return fixtureFields(value);
42
+ function fixtureIssue(value: unknown): string | undefined {
43
+ if (!isRecord(value)) return "fixture: expected an object";
44
+ if (value.kind === "generated") return fixtureDeclarationIssue(value);
45
+ if (value.kind !== undefined)
46
+ return "fixture.kind: omit for inline/repository fixtures, or use generated";
47
+ if (Object.hasOwn(value, "sourceRef")) return fixtureDeclarationIssue(value);
48
+ return inlineFixtureIssue(value);
47
49
  }
48
50
 
49
51
  function nonemptyString(value: unknown): value is string {
50
52
  return typeof value === "string" && value.length > 0;
51
53
  }
52
54
 
53
- function validCaseDetails(value: Record<string, unknown>): boolean {
54
- return (
55
- nonemptyString(value.id) &&
56
- nonemptyString(value.prompt) &&
57
- isOptionalNonblankString(value.followUpPrompt) &&
58
- validFixture(value.fixture)
59
- );
55
+ function caseDetailsIssue(value: Record<string, unknown>): string | undefined {
56
+ for (const field of ["id", "prompt"])
57
+ if (!nonemptyString(value[field]))
58
+ return `${field}: expected a nonempty string`;
59
+ if (!isOptionalNonblankString(value.followUpPrompt))
60
+ return "followUpPrompt: omit or supply a nonblank string";
61
+ return fixtureIssue(value.fixture);
60
62
  }
61
63
 
62
- function validCheck(value: unknown): boolean {
63
- return (
64
- isRecord(value) &&
65
- typeof value.id === "string" &&
66
- typeof value.grader === "string" &&
67
- isRecord(value.configuration)
68
- );
64
+ function checkIssue(value: unknown, location: string): string | undefined {
65
+ if (!isRecord(value)) return `${location}: expected an object`;
66
+ for (const field of ["id", "grader"])
67
+ if (typeof value[field] !== "string")
68
+ return `${location}.${field}: expected a string`;
69
+ if (!isRecord(value.configuration))
70
+ return `${location}.configuration: expected an object`;
71
+ return undefined;
69
72
  }
70
73
 
71
- function validChecks(value: unknown): boolean {
72
- return Array.isArray(value) && value.every(validCheck);
74
+ function checksIssue(value: unknown): string | undefined {
75
+ if (!Array.isArray(value))
76
+ return "checks: expected an array of check objects";
77
+ for (const [index, check] of value.entries()) {
78
+ const issue = checkIssue(check, `checks[${index}]`);
79
+ if (issue) return issue;
80
+ }
81
+ return undefined;
73
82
  }
74
83
 
75
- export function isResolvedCase(value: unknown): value is ResolvedCase {
84
+ function requiredEvidenceIssue(value: unknown): string | undefined {
85
+ if (!Array.isArray(value))
86
+ return "requiredEvidence: expected an array of strings";
87
+ const index = value.findIndex((entry: unknown) => typeof entry !== "string");
88
+ return index < 0
89
+ ? undefined
90
+ : `requiredEvidence[${index}]: expected a string`;
91
+ }
92
+
93
+ /** Explain the first invalid field using the same checks as the case type guard. */
94
+ export function resolvedCaseIssue(value: unknown): string | undefined {
95
+ if (!isRecord(value)) return "case: expected an object";
76
96
  return (
77
- isRecord(value) &&
78
- validCaseDetails(value) &&
79
- validChecks(value.checks) &&
80
- isStringArray(value.requiredEvidence)
97
+ caseDetailsIssue(value) ??
98
+ checksIssue(value.checks) ??
99
+ requiredEvidenceIssue(value.requiredEvidence)
81
100
  );
82
101
  }
102
+
103
+ export function isResolvedCase(value: unknown): value is ResolvedCase {
104
+ return resolvedCaseIssue(value) === undefined;
105
+ }