@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
@@ -1,4 +1,5 @@
1
- import { runtimeSeedSources } from "../runtime-config";
1
+ import { spawn, type Subprocess } from "../runtime-process";
2
+ import { runtimeLocalHttpEnabled, runtimeSeedSources } from "../runtime/config";
2
3
  import {
3
4
  candidateArtifactEnvironment,
4
5
  type CandidateArtifactRoots,
@@ -6,9 +7,15 @@ import {
6
7
  import { mkdir, stat } from "node:fs/promises";
7
8
  import { delimiter, join } from "node:path";
8
9
  import { prepareIsolatedCommand } from "../hosts/isolation";
9
- import type { RuntimePolicy } from "../runtime-config";
10
- import { prepareRuntimeState } from "../runtime-state";
10
+ import type { RuntimePolicy } from "../runtime/config";
11
+ import { prepareRuntimeState } from "../runtime/state";
12
+ import { sharedCacheDenyRoots } from "../runtime/shared-cache";
11
13
  import { hashJson } from "../identity";
14
+ import {
15
+ captureBoundedText,
16
+ ProcessDeadline,
17
+ terminateOwnedProcessGroup,
18
+ } from "../process-lifecycle";
12
19
 
13
20
  const DEFAULT_TIMEOUT_MS = 30_000;
14
21
  const MAX_TIMEOUT_MS = 120_000;
@@ -239,32 +246,12 @@ function forbiddenPatternFailure(
239
246
  async function boundedOutput(
240
247
  stream: ReadableStream<Uint8Array>,
241
248
  ): Promise<string> {
242
- const chunks: Uint8Array[] = [];
243
- let size = 0;
244
- for await (const chunk of stream) {
245
- size += chunk.byteLength;
246
- if (size > MAX_OUTPUT_BYTES) throw new Error("shell stdout exceeds 1 MiB");
247
- chunks.push(chunk);
248
- }
249
- return new TextDecoder("utf-8", { fatal: true }).decode(
250
- Buffer.concat(chunks),
251
- );
252
- }
253
-
254
- function stopProcess(proc: Bun.Subprocess): void {
255
- if (process.platform !== "win32") {
256
- try {
257
- process.kill(-proc.pid, "SIGKILL");
258
- return;
259
- } catch {
260
- // The group may already be gone.
261
- }
262
- }
263
- try {
264
- proc.kill("SIGKILL");
265
- } catch {
266
- // The process already exited.
267
- }
249
+ return captureBoundedText(stream, {
250
+ limit: MAX_OUTPUT_BYTES,
251
+ overflow: "reject",
252
+ exceeded: () => new Error("shell stdout exceeds 1 MiB"),
253
+ cancelOnError: true,
254
+ });
268
255
  }
269
256
 
270
257
  interface ShellRunOptions {
@@ -294,7 +281,11 @@ async function shellRuntime(options: ShellRunOptions) {
294
281
  privateRuntimeRoot: runtime.root,
295
282
  };
296
283
  }
297
- const root = join(options.workspace, ".git", "sevro-runtime"),
284
+ const root = join(
285
+ options.privateStateRoot,
286
+ "runtime",
287
+ hashJson(options.workspace),
288
+ ),
298
289
  home = join(root, "check-home"),
299
290
  temp = join(root, "check-tmp");
300
291
  await Promise.all([
@@ -305,9 +296,10 @@ async function shellRuntime(options: ShellRunOptions) {
305
296
  root,
306
297
  home,
307
298
  temp,
308
- uvCache: join(root, "uv-cache"),
299
+ uvCache: join(options.workspace, ".git", "sevro-runtime", "uv-cache"),
309
300
  environment: {} as Record<string, string>,
310
- privateRuntimeRoot: undefined,
301
+ privateRuntimeRoot: root,
302
+ writableCacheRoots: [],
311
303
  };
312
304
  }
313
305
  type ShellRuntime = Awaited<ReturnType<typeof shellRuntime>>;
@@ -359,7 +351,7 @@ async function requireShellRuntimeCache(
359
351
  }
360
352
  function shellStdout(
361
353
  check: PreparedShellCheck,
362
- output: Bun.Subprocess["stdout"],
354
+ output: Subprocess["stdout"],
363
355
  ): ReadableStream<Uint8Array> | null {
364
356
  if (!check.captureStdout) return null;
365
357
  if (!(output instanceof ReadableStream))
@@ -367,36 +359,45 @@ function shellStdout(
367
359
  return output;
368
360
  }
369
361
  class ShellExecution {
370
- private proc?: Bun.Subprocess;
371
- private timer?: ReturnType<typeof setTimeout>;
372
- private cancel?: () => void;
362
+ private proc?: Subprocess;
363
+ private readonly deadline: ProcessDeadline;
373
364
  constructor(
374
365
  private check: PreparedShellCheck,
375
366
  private options: ShellRunOptions,
376
367
  private isolation: Isolation,
377
368
  private runtime: ShellRuntime,
378
- ) {}
369
+ ) {
370
+ this.deadline = new ProcessDeadline({
371
+ timeoutMs: check.timeoutMs,
372
+ signal: options.signal,
373
+ interruption: (reason) =>
374
+ new Error(
375
+ reason === "timeout"
376
+ ? "shell check timed out"
377
+ : "shell check cancelled",
378
+ ),
379
+ });
380
+ }
379
381
  async run(): Promise<ShellCheckResult> {
380
382
  try {
381
383
  const running = this.spawn();
382
384
  const stream = shellStdout(this.check, running.stdout);
383
- const timeout = this.deadline();
384
- const aborted = this.cancellation();
385
- const completed = Promise.all([
386
- running.exited,
387
- stream ? boundedOutput(stream) : Promise.resolve(null),
388
- ]).then(([exitCode, stdout]) => ({ exitCode, stdout }));
389
- return await Promise.race([completed, timeout, aborted]);
385
+ return await this.deadline.wait(() =>
386
+ Promise.all([
387
+ running.exited,
388
+ stream ? boundedOutput(stream) : Promise.resolve(null),
389
+ ]).then(([exitCode, stdout]) => ({ exitCode, stdout })),
390
+ );
390
391
  } catch (error) {
391
392
  await this.stop();
392
393
  throw error;
393
394
  } finally {
394
- this.releaseListeners();
395
+ this.deadline.dispose();
395
396
  await this.isolation.release();
396
397
  }
397
398
  }
398
399
  private spawn() {
399
- this.proc = Bun.spawn(this.isolation.argv, {
400
+ this.proc = spawn(this.isolation.argv, {
400
401
  cwd: this.options.workspace,
401
402
  env: shellEnvironment(this.options, this.runtime),
402
403
  detached: true,
@@ -406,35 +407,12 @@ class ShellExecution {
406
407
  });
407
408
  return this.proc;
408
409
  }
409
- private deadline(): Promise<never> {
410
- return new Promise((_resolve, reject) => {
411
- this.timer = setTimeout(() => {
412
- reject(new Error("shell check timed out"));
413
- }, this.check.timeoutMs);
414
- });
415
- }
416
- private cancellation(): Promise<never> {
417
- return new Promise((_resolve, reject) => {
418
- const signal = this.options.signal;
419
- if (!signal) return;
420
- this.cancel = () => {
421
- reject(new Error("shell check cancelled"));
422
- };
423
- if (signal.aborted) this.cancel();
424
- else signal.addEventListener("abort", this.cancel, { once: true });
425
- });
426
- }
427
410
  private async stop(): Promise<void> {
428
411
  const proc = this.proc;
429
412
  if (!proc) return;
430
- stopProcess(proc);
413
+ terminateOwnedProcessGroup(proc);
431
414
  await proc.exited;
432
415
  }
433
- private releaseListeners(): void {
434
- if (this.timer) clearTimeout(this.timer);
435
- if (this.cancel)
436
- this.options.signal?.removeEventListener("abort", this.cancel);
437
- }
438
416
  }
439
417
 
440
418
  /** Run a check without inherited credentials or retaining raw process output. */
@@ -451,17 +429,22 @@ export async function runShellCheck(
451
429
  protectedRootsCanonical: options.protectedRootsCanonical,
452
430
  privateStateRoot: options.privateStateRoot,
453
431
  denyNetwork: true,
432
+ localHttp: runtimeLocalHttpEnabled(options.runtimePolicy, "checks"),
454
433
  readOnlyRoots: options.runtimePolicy?.readOnlyRoots,
455
434
  candidateArtifactRoots: options.candidateArtifactRoots,
456
435
  transcriptReadRoots: options.candidateTranscriptRoot
457
436
  ? [options.candidateTranscriptRoot]
458
437
  : [],
459
438
  writableRuntimeRoot: runtime.privateRuntimeRoot,
439
+ writableCacheRoots: runtime.writableCacheRoots,
460
440
  });
461
441
  await requireShellRuntimeCache(options, runtime);
462
442
  return new ShellExecution(check, options, isolated, runtime).run();
463
443
  }
464
444
 
465
445
  function shellSeedSources(options: ShellRunOptions): string[] {
466
- return runtimeSeedSources(options.runtimePolicy);
446
+ return [
447
+ ...runtimeSeedSources(options.runtimePolicy),
448
+ ...sharedCacheDenyRoots(options.runtimePolicy, "checks"),
449
+ ];
467
450
  }
@@ -0,0 +1,52 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import { isRecord } from "./value-guards";
3
+
4
+ function credentialStrings(value: unknown): string[] {
5
+ const pending: unknown[] = [value];
6
+ const secrets: string[] = [];
7
+ for (let visited = 0; visited < 256; visited++) {
8
+ const item = pending.pop();
9
+ if (typeof item === "string") {
10
+ if (item.length >= 8) secrets.push(item);
11
+ } else if (isRecord(item)) pending.push(...Object.values(item));
12
+ }
13
+ return secrets;
14
+ }
15
+
16
+ /** Read credentials only for scrubbing; failures belong to the actual host preparation. */
17
+ export async function diagnosticSecrets(path: string): Promise<string[]> {
18
+ try {
19
+ if ((await stat(path)).size > 1024 * 1024) return [];
20
+ const text = await readFile(path, "utf8");
21
+ try {
22
+ const value: unknown = JSON.parse(text);
23
+ return credentialStrings(value);
24
+ } catch {
25
+ return text.trim() ? [text.trim()] : [];
26
+ }
27
+ } catch {
28
+ return [];
29
+ }
30
+ }
31
+
32
+ export function redactDiagnosticText(text: string, secrets: string[]): string {
33
+ for (const secret of secrets) {
34
+ text = text.replaceAll(secret, "[redacted]");
35
+ text = redactCredentialSuffix(text, secret);
36
+ }
37
+ return text
38
+ .replace(/(authorization\s*:\s*)[^\r\n]+/gi, "$1[redacted]")
39
+ .replace(/\bBearer\s+\S+/gi, "Bearer [redacted]")
40
+ .replace(/\bsk-[A-Za-z0-9_-]+/g, "[redacted]")
41
+ .replace(
42
+ /((?:api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[=:]\s*)\S+/gi,
43
+ "$1[redacted]",
44
+ );
45
+ }
46
+
47
+ function redactCredentialSuffix(text: string, secret: string): string {
48
+ const start = text.lastIndexOf(secret.slice(0, Math.min(8, secret.length)));
49
+ if (start >= 0 && secret.startsWith(text.slice(start)))
50
+ return text.slice(0, start) + "[redacted]";
51
+ return text;
52
+ }
@@ -0,0 +1,331 @@
1
+ import type { HostResult } from "./evaluation/types";
2
+ import type { RuntimeRole } from "./runtime/state";
3
+ import {
4
+ diagnosticSecrets,
5
+ redactDiagnosticText,
6
+ } from "./host-diagnostic-redaction";
7
+
8
+ const MAX_TEXT_BYTES = 64 * 1024;
9
+ interface ProcessDiagnostic {
10
+ code: number | null;
11
+ out: string;
12
+ stderr: Uint8Array;
13
+ stderrTruncated: boolean;
14
+ signal: string | null;
15
+ durationMs: number;
16
+ stdoutTruncated?: boolean;
17
+ reason: "exit" | "timeout" | "cancelled" | "error" | "spawn";
18
+ }
19
+
20
+ export type ProcessFailureReason = ProcessDiagnostic["reason"];
21
+
22
+ export class HostDiagnosticPersistenceError extends Error {
23
+ constructor(persistenceCause: unknown, hostCause: unknown) {
24
+ super("host diagnostic persistence failed", {
25
+ cause: new AggregateError(
26
+ [hostCause, persistenceCause],
27
+ "host and persistence failures",
28
+ ),
29
+ });
30
+ }
31
+ }
32
+
33
+ export function rethrowDiagnosticPersistenceError(cause: unknown): void {
34
+ if (cause instanceof HostDiagnosticPersistenceError) throw cause;
35
+ }
36
+
37
+ /** Drain observers capture only a prefix; completion records actual native termination. */
38
+ export class HostProcessDiagnostics {
39
+ readonly stdout = new DiagnosticStream();
40
+ readonly stderr = new DiagnosticStream();
41
+ private started = performance.now();
42
+ constructor(private diagnostics: HostDiagnostics) {}
43
+ recordUnstarted(): void {
44
+ if (!this.diagnostics.enabled) return;
45
+ this.diagnostics.process({
46
+ code: null,
47
+ signal: null,
48
+ durationMs: performance.now() - this.started,
49
+ out: "",
50
+ stderr: new Uint8Array(),
51
+ stderrTruncated: false,
52
+ reason: "spawn",
53
+ });
54
+ }
55
+ async record(
56
+ process: { exited: Promise<number | null>; signalCode?: string | null },
57
+ reason: ProcessFailureReason = "exit",
58
+ ): Promise<void> {
59
+ if (!this.diagnostics.enabled) return;
60
+ this.diagnostics.process({
61
+ code: await process.exited,
62
+ signal: process.signalCode ?? null,
63
+ durationMs: performance.now() - this.started,
64
+ out: this.stdout.bytes().toString("utf8"),
65
+ stdoutTruncated: this.stdout.truncated,
66
+ stderr: this.stderr.bytes(),
67
+ stderrTruncated: this.stderr.truncated,
68
+ reason,
69
+ });
70
+ }
71
+ }
72
+
73
+ function boundedText(bytes: Uint8Array, secrets: string[]) {
74
+ const redacted = Buffer.from(
75
+ redactDiagnosticText(
76
+ Buffer.from(bytes.subarray(0, MAX_TEXT_BYTES)).toString("utf8"),
77
+ secrets,
78
+ ),
79
+ );
80
+ return {
81
+ text: new TextDecoder().decode(redacted.subarray(0, MAX_TEXT_BYTES), {
82
+ stream: true,
83
+ }),
84
+ truncated:
85
+ bytes.byteLength > MAX_TEXT_BYTES || redacted.byteLength > MAX_TEXT_BYTES,
86
+ };
87
+ }
88
+
89
+ /** Keep a byte-bounded prefix while the owning transport continues draining. */
90
+ export class DiagnosticStream {
91
+ private chunks: Uint8Array[] = [];
92
+ private size = 0;
93
+ truncated = false;
94
+ add(bytes: Uint8Array): void {
95
+ const retained = bytes.subarray(0, Math.max(0, MAX_TEXT_BYTES - this.size));
96
+ if (retained.byteLength) this.chunks.push(Buffer.from(retained));
97
+ this.size += retained.byteLength;
98
+ this.truncated ||= retained.byteLength !== bytes.byteLength;
99
+ }
100
+ bytes(): Buffer {
101
+ return Buffer.concat(this.chunks);
102
+ }
103
+ }
104
+
105
+ function errorCode(cause: Error): { code?: string | number } {
106
+ if (!("code" in cause)) return {};
107
+ const code: unknown = cause.code;
108
+ return typeof code === "string" || typeof code === "number" ? { code } : {};
109
+ }
110
+
111
+ function errorEvidence(
112
+ cause: unknown,
113
+ secrets: string[],
114
+ ): Record<string, unknown> {
115
+ return errorChain(cause, secrets, new Set());
116
+ }
117
+
118
+ function errorChain(
119
+ cause: unknown,
120
+ secrets: string[],
121
+ seen: Set<Error>,
122
+ ): Record<string, unknown> {
123
+ if (!(cause instanceof Error))
124
+ return {
125
+ name: "NonError",
126
+ message: redactDiagnosticText(String(cause).slice(0, 8192), secrets),
127
+ };
128
+ if (seen.has(cause) || seen.size === 8) return { truncated: true };
129
+ seen.add(cause);
130
+ return {
131
+ ...errorDetails(cause, secrets),
132
+ ...(cause.cause === undefined
133
+ ? {}
134
+ : { cause: errorChain(cause.cause, secrets, seen) }),
135
+ };
136
+ }
137
+
138
+ function errorDetails(cause: Error, secrets: string[]) {
139
+ return {
140
+ name: redactDiagnosticText(cause.name.slice(0, 200), secrets),
141
+ message: redactDiagnosticText(cause.message.slice(0, 8192), secrets),
142
+ stack: redactDiagnosticText(cause.stack?.slice(0, 8192) ?? "", secrets),
143
+ ...errorCode(cause),
144
+ };
145
+ }
146
+
147
+ /** A cleanup exception must not replace an already captured host/persistence failure. */
148
+ export async function cleanupNativeState(
149
+ diagnostics: HostDiagnostics,
150
+ cleanup: () => Promise<void>,
151
+ ): Promise<void> {
152
+ beginNativeCleanup(diagnostics);
153
+ try {
154
+ await cleanup();
155
+ } catch (cause) {
156
+ if (!diagnostics.failureCaptured) throw cause;
157
+ console.warn(
158
+ "native state cleanup failed; original host failure preserved",
159
+ );
160
+ }
161
+ }
162
+
163
+ function beginNativeCleanup(diagnostics: HostDiagnostics): void {
164
+ if (!diagnostics.failureCaptured) diagnostics.stage = "cleanup";
165
+ }
166
+
167
+ export function diagnosticConfiguration(enabled: boolean | undefined) {
168
+ return enabled ? { "sevro.host.retain-diagnostics": true } : {};
169
+ }
170
+
171
+ export function createHostDiagnostics(
172
+ host: "codex" | "claude",
173
+ enabled: boolean | undefined,
174
+ request: {
175
+ runtimeRole?: RuntimeRole;
176
+ retainHostDiagnostics?: (bytes: Uint8Array) => Promise<void>;
177
+ },
178
+ ): HostDiagnostics {
179
+ return enabled
180
+ ? new RetainedHostDiagnostics(
181
+ host,
182
+ request.runtimeRole,
183
+ request.retainHostDiagnostics,
184
+ )
185
+ : new DisabledHostDiagnostics();
186
+ }
187
+
188
+ export async function diagnoseHostRequest(
189
+ diagnostics: HostDiagnostics,
190
+ execute: () => Promise<HostResult>,
191
+ ): Promise<HostResult> {
192
+ try {
193
+ return await execute();
194
+ } catch (cause) {
195
+ if (cause instanceof HostDiagnosticPersistenceError) throw cause;
196
+ if (!diagnostics.enabled) throw cause;
197
+ const result: HostResult = {
198
+ finalMessage: null,
199
+ complete: false,
200
+ executionFailed: true,
201
+ actualCondition: "passive",
202
+ };
203
+ await diagnostics.retain(result, cause);
204
+ return result;
205
+ }
206
+ }
207
+
208
+ export interface HostDiagnostics {
209
+ readonly enabled: boolean;
210
+ stage: string;
211
+ failure: unknown;
212
+ readonly failureCaptured: boolean;
213
+ readCredentials(path: string | undefined): Promise<void>;
214
+ registerCredentials(
215
+ environment: Record<string, string>,
216
+ names: readonly string[],
217
+ ): void;
218
+ process(result: ProcessDiagnostic): void;
219
+ retain(result: HostResult, cause: unknown): Promise<void>;
220
+ retainFailure(result: HostResult, message: string): Promise<void>;
221
+ }
222
+
223
+ class DisabledHostDiagnostics implements HostDiagnostics {
224
+ readonly enabled = false;
225
+ stage = "preparation";
226
+ failure: unknown;
227
+ readonly failureCaptured = false;
228
+
229
+ readCredentials(): Promise<void> {
230
+ return Promise.resolve();
231
+ }
232
+
233
+ registerCredentials(): void {}
234
+
235
+ process(): void {}
236
+
237
+ retain(): Promise<void> {
238
+ return Promise.resolve();
239
+ }
240
+
241
+ retainFailure(): Promise<void> {
242
+ return Promise.resolve();
243
+ }
244
+ }
245
+
246
+ /** Private failure evidence, independent of native sessions and transcript access. */
247
+ class RetainedHostDiagnostics implements HostDiagnostics {
248
+ readonly enabled = true;
249
+ stage = "preparation";
250
+ failure: unknown;
251
+ failureCaptured = false;
252
+ private processes: Record<string, unknown>[] = [];
253
+ private processesDropped = 0;
254
+ private secrets: string[] = [];
255
+ constructor(
256
+ private host: "codex" | "claude",
257
+ private role: RuntimeRole = "candidate",
258
+ private persist?: (bytes: Uint8Array) => Promise<void>,
259
+ ) {}
260
+
261
+ async readCredentials(path: string | undefined): Promise<void> {
262
+ if (path) this.secrets.push(...(await diagnosticSecrets(path)));
263
+ }
264
+
265
+ registerCredentials(
266
+ environment: Record<string, string>,
267
+ names: readonly string[],
268
+ ): void {
269
+ for (const name of names) {
270
+ const value = environment[name];
271
+ if (value) this.secrets.push(value);
272
+ }
273
+ }
274
+
275
+ process(result: ProcessDiagnostic): void {
276
+ const stdout = boundedText(Buffer.from(result.out), this.secrets);
277
+ const stderr = boundedText(result.stderr, this.secrets);
278
+ this.addProcess({
279
+ stage: this.stage,
280
+ code: result.code,
281
+ signal: result.signal,
282
+ durationMs: result.durationMs,
283
+ reason: result.reason,
284
+ stdout: stdout.text,
285
+ stdoutTruncated: stdout.truncated || result.stdoutTruncated === true,
286
+ stderr: stderr.text,
287
+ stderrTruncated: stderr.truncated || result.stderrTruncated,
288
+ });
289
+ }
290
+
291
+ private addProcess(receipt: Record<string, unknown>): void {
292
+ this.processes.push(receipt);
293
+ while (
294
+ this.processes.length > 32 ||
295
+ Buffer.byteLength(JSON.stringify(this.processes)) > 2 * 1024 * 1024
296
+ ) {
297
+ this.processes.shift();
298
+ this.processesDropped++;
299
+ }
300
+ }
301
+
302
+ async retainFailure(result: HostResult, message: string): Promise<void> {
303
+ if (result.executionFailed)
304
+ await this.retain(result, this.failure ?? new Error(message));
305
+ }
306
+
307
+ async retain(result: HostResult, cause: unknown): Promise<void> {
308
+ this.failureCaptured = true;
309
+ const bytes = Buffer.from(
310
+ JSON.stringify({
311
+ format: "sevro.host-diagnostics.v1",
312
+ host: this.host,
313
+ role: this.role,
314
+ stage: this.stage,
315
+ error: errorEvidence(cause, this.secrets),
316
+ processes: this.processes,
317
+ processesDropped: this.processesDropped,
318
+ }),
319
+ );
320
+ if (this.persist) {
321
+ try {
322
+ await this.persist(bytes);
323
+ } catch (persistenceCause) {
324
+ throw new HostDiagnosticPersistenceError(persistenceCause, cause);
325
+ }
326
+ return;
327
+ }
328
+ result.artifacts ??= [];
329
+ result.artifacts.push({ id: "sevro.host.diagnostics", bytes });
330
+ }
331
+ }