@bjoernrochel/sevro 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (403) hide show
  1. package/CONTRIBUTING.md +34 -4
  2. package/README.md +7 -6
  3. package/dist/examples/basic/graded.json +13 -0
  4. package/dist/examples/basic/host.js +9 -0
  5. package/dist/examples/basic/host.js.map +1 -0
  6. package/dist/examples/basic/prompt-only.json +7 -0
  7. package/dist/examples/recipes/candidate.js +23 -0
  8. package/dist/examples/recipes/candidate.js.map +1 -0
  9. package/dist/examples/recipes/cases/coding-change.json +21 -0
  10. package/dist/examples/recipes/cases/host-tools.json +21 -0
  11. package/dist/examples/recipes/cases/mise.json +21 -0
  12. package/dist/examples/recipes/cases/node.json +21 -0
  13. package/dist/examples/recipes/cases/python-uv.json +21 -0
  14. package/dist/examples/recipes/cases/semantic.json +17 -0
  15. package/dist/examples/recipes/coding-change/check.js +16 -0
  16. package/dist/examples/recipes/coding-change/check.js.map +1 -0
  17. package/dist/examples/recipes/executable.js +20 -0
  18. package/dist/examples/recipes/executable.js.map +1 -0
  19. package/dist/examples/recipes/extension-artifacts.js +56 -0
  20. package/dist/examples/recipes/extension-artifacts.js.map +1 -0
  21. package/dist/examples/recipes/extension-methods.js +167 -0
  22. package/dist/examples/recipes/extension-methods.js.map +1 -0
  23. package/dist/examples/recipes/extension.js +28 -0
  24. package/dist/examples/recipes/extension.js.map +1 -0
  25. package/dist/examples/recipes/modules.js +9 -0
  26. package/dist/examples/recipes/modules.js.map +1 -0
  27. package/dist/examples/recipes/repository-skill/.agents/skills/startup-guide/SKILL.md +7 -0
  28. package/dist/examples/recipes/repository-skill/.claude/skills/startup-guide/SKILL.md +7 -0
  29. package/dist/examples/recipes/repository-skill/README.md +3 -0
  30. package/dist/examples/recipes/run-inputs.js +144 -0
  31. package/dist/examples/recipes/run-inputs.js.map +1 -0
  32. package/dist/examples/recipes/run-options.js +103 -0
  33. package/dist/examples/recipes/run-options.js.map +1 -0
  34. package/dist/examples/recipes/run.js +62 -0
  35. package/dist/examples/recipes/run.js.map +1 -0
  36. package/dist/examples/recipes/runtime/empty.json +1 -0
  37. package/dist/examples/recipes/runtime/goals.json +1 -0
  38. package/dist/examples/recipes/runtime/mise.json +6 -0
  39. package/dist/examples/recipes/runtime/path.json +1 -0
  40. package/dist/examples/recipes/runtime/plugins.json +4 -0
  41. package/dist/examples/recipes/runtime/python-uv.json +10 -0
  42. package/dist/examples/recipes/semantic-judge.js +27 -0
  43. package/dist/examples/recipes/semantic-judge.js.map +1 -0
  44. package/dist/examples/templates/coding/adapter.js +14 -0
  45. package/dist/examples/templates/coding/adapter.js.map +1 -0
  46. package/dist/examples/templates/coding/case.json +15 -0
  47. package/dist/examples/templates/repository-skill/.agents/skills/startup-guide/SKILL.md +6 -0
  48. package/dist/examples/templates/repository-skill/extension-data.js +61 -0
  49. package/dist/examples/templates/repository-skill/extension-data.js.map +1 -0
  50. package/dist/examples/templates/repository-skill/extension.js +29 -0
  51. package/dist/examples/templates/repository-skill/extension.js.map +1 -0
  52. package/dist/examples/templates/response/adapter.js +13 -0
  53. package/dist/examples/templates/response/adapter.js.map +1 -0
  54. package/dist/examples/templates/response/case.json +13 -0
  55. package/dist/src/advisory.js +86 -0
  56. package/dist/src/advisory.js.map +1 -0
  57. package/dist/src/candidate-artifacts.js +139 -0
  58. package/dist/src/candidate-artifacts.js.map +1 -0
  59. package/dist/src/candidate-codex-state.js +110 -0
  60. package/dist/src/candidate-codex-state.js.map +1 -0
  61. package/dist/src/case-validation.js +92 -0
  62. package/dist/src/case-validation.js.map +1 -0
  63. package/dist/src/cli/cancellation.js +21 -0
  64. package/dist/src/cli/cancellation.js.map +1 -0
  65. package/dist/src/cli/command.js +60 -0
  66. package/dist/src/cli/command.js.map +1 -0
  67. package/dist/src/cli/completion.js +14 -0
  68. package/dist/src/cli/completion.js.map +1 -0
  69. package/dist/src/cli/demo.js +45 -0
  70. package/dist/src/cli/demo.js.map +1 -0
  71. package/dist/src/cli/evaluation.js +40 -0
  72. package/dist/src/cli/evaluation.js.map +1 -0
  73. package/dist/src/cli/extension.js +54 -0
  74. package/dist/src/cli/extension.js.map +1 -0
  75. package/dist/src/cli/help.js +190 -0
  76. package/dist/src/cli/help.js.map +1 -0
  77. package/dist/src/cli/hosts.js +33 -0
  78. package/dist/src/cli/hosts.js.map +1 -0
  79. package/dist/src/cli/init-settings.js +29 -0
  80. package/dist/src/cli/init-settings.js.map +1 -0
  81. package/dist/src/cli/init.js +82 -0
  82. package/dist/src/cli/init.js.map +1 -0
  83. package/dist/src/cli/invocation.js +431 -0
  84. package/dist/src/cli/invocation.js.map +1 -0
  85. package/dist/src/cli/loading.js +110 -0
  86. package/dist/src/cli/loading.js.map +1 -0
  87. package/dist/src/cli/preparation.js +88 -0
  88. package/dist/src/cli/preparation.js.map +1 -0
  89. package/dist/src/cli/presentation.js +61 -0
  90. package/dist/src/cli/presentation.js.map +1 -0
  91. package/dist/src/cli/progress.js +5 -0
  92. package/dist/src/cli/progress.js.map +1 -0
  93. package/dist/src/cli/run-manifest.js +108 -0
  94. package/dist/src/cli/run-manifest.js.map +1 -0
  95. package/dist/src/cli/run-options.js +367 -0
  96. package/dist/src/cli/run-options.js.map +1 -0
  97. package/dist/src/cli/run-overrides.js +51 -0
  98. package/dist/src/cli/run-overrides.js.map +1 -0
  99. package/dist/src/cli/settings.js +127 -0
  100. package/dist/src/cli/settings.js.map +1 -0
  101. package/dist/src/cli/summary.js +28 -0
  102. package/dist/src/cli/summary.js.map +1 -0
  103. package/dist/src/cli.js +20 -0
  104. package/dist/src/cli.js.map +1 -0
  105. package/dist/src/contract-types.js +2 -0
  106. package/dist/src/contract-types.js.map +1 -0
  107. package/dist/src/engine.js +4 -0
  108. package/dist/src/engine.js.map +1 -0
  109. package/dist/src/evaluation/advisory.js +85 -0
  110. package/dist/src/evaluation/advisory.js.map +1 -0
  111. package/dist/src/evaluation/check-plan.js +292 -0
  112. package/dist/src/evaluation/check-plan.js.map +1 -0
  113. package/dist/src/evaluation/collection.js +61 -0
  114. package/dist/src/evaluation/collection.js.map +1 -0
  115. package/dist/src/evaluation/context.js +2 -0
  116. package/dist/src/evaluation/context.js.map +1 -0
  117. package/dist/src/evaluation/grading-host.js +28 -0
  118. package/dist/src/evaluation/grading-host.js.map +1 -0
  119. package/dist/src/evaluation/grading.js +154 -0
  120. package/dist/src/evaluation/grading.js.map +1 -0
  121. package/dist/src/evaluation/invocation-plan.js +312 -0
  122. package/dist/src/evaluation/invocation-plan.js.map +1 -0
  123. package/dist/src/evaluation/plan.js +376 -0
  124. package/dist/src/evaluation/plan.js.map +1 -0
  125. package/dist/src/evaluation/progress.js +14 -0
  126. package/dist/src/evaluation/progress.js.map +1 -0
  127. package/dist/src/evaluation/resources.js +159 -0
  128. package/dist/src/evaluation/resources.js.map +1 -0
  129. package/dist/src/evaluation/run.js +148 -0
  130. package/dist/src/evaluation/run.js.map +1 -0
  131. package/dist/src/evaluation/scheduler.js +27 -0
  132. package/dist/src/evaluation/scheduler.js.map +1 -0
  133. package/dist/src/evaluation/semantic.js +183 -0
  134. package/dist/src/evaluation/semantic.js.map +1 -0
  135. package/dist/src/evaluation/trial.js +593 -0
  136. package/dist/src/evaluation/trial.js.map +1 -0
  137. package/dist/src/evaluation/types.js +20 -0
  138. package/dist/src/evaluation/types.js.map +1 -0
  139. package/dist/src/evidence/host-results.js +67 -0
  140. package/dist/src/evidence/host-results.js.map +1 -0
  141. package/dist/src/evidence/retained-artifacts.js +17 -0
  142. package/dist/src/evidence/retained-artifacts.js.map +1 -0
  143. package/dist/src/evidence/trial-writer.js +131 -0
  144. package/dist/src/evidence/trial-writer.js.map +1 -0
  145. package/dist/src/evidence/usage.js +14 -0
  146. package/dist/src/evidence/usage.js.map +1 -0
  147. package/dist/src/executable.js +20 -0
  148. package/dist/src/executable.js.map +1 -0
  149. package/dist/src/extension-client.js +212 -0
  150. package/dist/src/extension-client.js.map +1 -0
  151. package/dist/src/extension-session.js +236 -0
  152. package/dist/src/extension-session.js.map +1 -0
  153. package/dist/src/fixtures/advisory.js +206 -0
  154. package/dist/src/fixtures/advisory.js.map +1 -0
  155. package/dist/src/fixtures/bin.js +41 -0
  156. package/dist/src/fixtures/bin.js.map +1 -0
  157. package/dist/src/fixtures/cleanup.js +43 -0
  158. package/dist/src/fixtures/cleanup.js.map +1 -0
  159. package/dist/src/fixtures/create.js +94 -0
  160. package/dist/src/fixtures/create.js.map +1 -0
  161. package/dist/src/fixtures/generated.js +181 -0
  162. package/dist/src/fixtures/generated.js.map +1 -0
  163. package/dist/src/fixtures/git-hooks.js +16 -0
  164. package/dist/src/fixtures/git-hooks.js.map +1 -0
  165. package/dist/src/fixtures/preparation.js +201 -0
  166. package/dist/src/fixtures/preparation.js.map +1 -0
  167. package/dist/src/fixtures/repository.js +255 -0
  168. package/dist/src/fixtures/repository.js.map +1 -0
  169. package/dist/src/fixtures/setup.js +175 -0
  170. package/dist/src/fixtures/setup.js.map +1 -0
  171. package/dist/src/fixtures/tools.js +57 -0
  172. package/dist/src/fixtures/tools.js.map +1 -0
  173. package/dist/src/fixtures/workspace-state.js +155 -0
  174. package/dist/src/fixtures/workspace-state.js.map +1 -0
  175. package/dist/src/generated/cli-result.cjs +2 -0
  176. package/dist/src/generated/extension.cjs +2 -0
  177. package/dist/src/generated/report.cjs +2 -0
  178. package/dist/src/generated/run-evidence.cjs +2 -0
  179. package/dist/src/generated/runtime.cjs +2 -0
  180. package/dist/src/git.js +72 -0
  181. package/dist/src/git.js.map +1 -0
  182. package/dist/src/graders/artifact.js +68 -0
  183. package/dist/src/graders/artifact.js.map +1 -0
  184. package/dist/src/graders/git-head.js +112 -0
  185. package/dist/src/graders/git-head.js.map +1 -0
  186. package/dist/src/graders/output.js +345 -0
  187. package/dist/src/graders/output.js.map +1 -0
  188. package/dist/src/graders/semantic.js +132 -0
  189. package/dist/src/graders/semantic.js.map +1 -0
  190. package/dist/src/graders/shell.js +321 -0
  191. package/dist/src/graders/shell.js.map +1 -0
  192. package/dist/src/host-diagnostic-redaction.js +52 -0
  193. package/dist/src/host-diagnostic-redaction.js.map +1 -0
  194. package/dist/src/host-diagnostics.js +248 -0
  195. package/dist/src/host-diagnostics.js.map +1 -0
  196. package/dist/src/hosts/claude-continuation.js +89 -0
  197. package/dist/src/hosts/claude-continuation.js.map +1 -0
  198. package/dist/src/hosts/claude-credential.js +121 -0
  199. package/dist/src/hosts/claude-credential.js.map +1 -0
  200. package/dist/src/hosts/claude-events.js +136 -0
  201. package/dist/src/hosts/claude-events.js.map +1 -0
  202. package/dist/src/hosts/claude-keychain.js +100 -0
  203. package/dist/src/hosts/claude-keychain.js.map +1 -0
  204. package/dist/src/hosts/claude-login-recovery.js +67 -0
  205. package/dist/src/hosts/claude-login-recovery.js.map +1 -0
  206. package/dist/src/hosts/claude-login-refresh.js +146 -0
  207. package/dist/src/hosts/claude-login-refresh.js.map +1 -0
  208. package/dist/src/hosts/claude-login-store.js +124 -0
  209. package/dist/src/hosts/claude-login-store.js.map +1 -0
  210. package/dist/src/hosts/claude-login.js +74 -0
  211. package/dist/src/hosts/claude-login.js.map +1 -0
  212. package/dist/src/hosts/claude-native-goal.js +138 -0
  213. package/dist/src/hosts/claude-native-goal.js.map +1 -0
  214. package/dist/src/hosts/claude-process.js +10 -0
  215. package/dist/src/hosts/claude-process.js.map +1 -0
  216. package/dist/src/hosts/claude-refresh-lock.js +76 -0
  217. package/dist/src/hosts/claude-refresh-lock.js.map +1 -0
  218. package/dist/src/hosts/claude-repository-invocation.js +229 -0
  219. package/dist/src/hosts/claude-repository-invocation.js.map +1 -0
  220. package/dist/src/hosts/claude-settings.js +156 -0
  221. package/dist/src/hosts/claude-settings.js.map +1 -0
  222. package/dist/src/hosts/claude-skill-activations.js +131 -0
  223. package/dist/src/hosts/claude-skill-activations.js.map +1 -0
  224. package/dist/src/hosts/claude-state.js +237 -0
  225. package/dist/src/hosts/claude-state.js.map +1 -0
  226. package/dist/src/hosts/claude-tool-calls.js +150 -0
  227. package/dist/src/hosts/claude-tool-calls.js.map +1 -0
  228. package/dist/src/hosts/claude.js +373 -0
  229. package/dist/src/hosts/claude.js.map +1 -0
  230. package/dist/src/hosts/codex-app-server.js +764 -0
  231. package/dist/src/hosts/codex-app-server.js.map +1 -0
  232. package/dist/src/hosts/codex-configuration.js +91 -0
  233. package/dist/src/hosts/codex-configuration.js.map +1 -0
  234. package/dist/src/hosts/codex-events.js +104 -0
  235. package/dist/src/hosts/codex-events.js.map +1 -0
  236. package/dist/src/hosts/codex-exec-controls.js +434 -0
  237. package/dist/src/hosts/codex-exec-controls.js.map +1 -0
  238. package/dist/src/hosts/codex-invocation.js +54 -0
  239. package/dist/src/hosts/codex-invocation.js.map +1 -0
  240. package/dist/src/hosts/codex-marketplace.js +185 -0
  241. package/dist/src/hosts/codex-marketplace.js.map +1 -0
  242. package/dist/src/hosts/codex-native-calls.js +516 -0
  243. package/dist/src/hosts/codex-native-calls.js.map +1 -0
  244. package/dist/src/hosts/codex-process.js +10 -0
  245. package/dist/src/hosts/codex-process.js.map +1 -0
  246. package/dist/src/hosts/codex-profile.js +206 -0
  247. package/dist/src/hosts/codex-profile.js.map +1 -0
  248. package/dist/src/hosts/codex-session-files.js +89 -0
  249. package/dist/src/hosts/codex-session-files.js.map +1 -0
  250. package/dist/src/hosts/codex-state.js +310 -0
  251. package/dist/src/hosts/codex-state.js.map +1 -0
  252. package/dist/src/hosts/codex.js +527 -0
  253. package/dist/src/hosts/codex.js.map +1 -0
  254. package/dist/src/hosts/isolation-common.js +43 -0
  255. package/dist/src/hosts/isolation-common.js.map +1 -0
  256. package/dist/src/hosts/isolation-roots.js +64 -0
  257. package/dist/src/hosts/isolation-roots.js.map +1 -0
  258. package/dist/src/hosts/isolation.js +12 -0
  259. package/dist/src/hosts/isolation.js.map +1 -0
  260. package/dist/src/hosts/linux-sandbox.js +127 -0
  261. package/dist/src/hosts/linux-sandbox.js.map +1 -0
  262. package/dist/src/hosts/mac-sandbox.js +137 -0
  263. package/dist/src/hosts/mac-sandbox.js.map +1 -0
  264. package/dist/src/hosts/native-controls.js +151 -0
  265. package/dist/src/hosts/native-controls.js.map +1 -0
  266. package/dist/src/hosts/native-request.js +33 -0
  267. package/dist/src/hosts/native-request.js.map +1 -0
  268. package/dist/src/hosts/process-lifecycle.js +167 -0
  269. package/dist/src/hosts/process-lifecycle.js.map +1 -0
  270. package/dist/src/hosts/protected-worktrees.js +81 -0
  271. package/dist/src/hosts/protected-worktrees.js.map +1 -0
  272. package/dist/src/hosts/skill-hook-catalog.js +100 -0
  273. package/dist/src/hosts/skill-hook-catalog.js.map +1 -0
  274. package/dist/src/hosts/skill-hook-handler.js +228 -0
  275. package/dist/src/hosts/skill-hook-handler.js.map +1 -0
  276. package/dist/src/hosts/skill-hooks.js +423 -0
  277. package/dist/src/hosts/skill-hooks.js.map +1 -0
  278. package/dist/src/hosts/workspace-fingerprint.js +72 -0
  279. package/dist/src/hosts/workspace-fingerprint.js.map +1 -0
  280. package/dist/src/identity.js +167 -0
  281. package/dist/src/identity.js.map +1 -0
  282. package/dist/src/instrumentation.js +83 -0
  283. package/dist/src/instrumentation.js.map +1 -0
  284. package/dist/src/native-transcript-state.js +85 -0
  285. package/dist/src/native-transcript-state.js.map +1 -0
  286. package/dist/src/native-transcript-view.js +65 -0
  287. package/dist/src/native-transcript-view.js.map +1 -0
  288. package/dist/src/native-transcripts.js +208 -0
  289. package/dist/src/native-transcripts.js.map +1 -0
  290. package/dist/src/paths.js +13 -0
  291. package/dist/src/paths.js.map +1 -0
  292. package/dist/src/process-lifecycle.js +101 -0
  293. package/dist/src/process-lifecycle.js.map +1 -0
  294. package/dist/src/provenance.js +263 -0
  295. package/dist/src/provenance.js.map +1 -0
  296. package/dist/src/prune.js +228 -0
  297. package/dist/src/prune.js.map +1 -0
  298. package/dist/src/report.js +276 -0
  299. package/dist/src/report.js.map +1 -0
  300. package/dist/src/resolved-case.js +29 -0
  301. package/dist/src/resolved-case.js.map +1 -0
  302. package/dist/src/results-lock.js +40 -0
  303. package/dist/src/results-lock.js.map +1 -0
  304. package/dist/src/results.js +127 -0
  305. package/dist/src/results.js.map +1 -0
  306. package/dist/src/run-owner.js +283 -0
  307. package/dist/src/run-owner.js.map +1 -0
  308. package/dist/src/runner-paths.js +11 -0
  309. package/dist/src/runner-paths.js.map +1 -0
  310. package/dist/src/runtime/config.js +323 -0
  311. package/dist/src/runtime/config.js.map +1 -0
  312. package/dist/src/runtime/discovery-apple.js +65 -0
  313. package/dist/src/runtime/discovery-apple.js.map +1 -0
  314. package/dist/src/runtime/discovery-providers.js +37 -0
  315. package/dist/src/runtime/discovery-providers.js.map +1 -0
  316. package/dist/src/runtime/discovery.js +40 -0
  317. package/dist/src/runtime/discovery.js.map +1 -0
  318. package/dist/src/runtime/hook-processes.js +81 -0
  319. package/dist/src/runtime/hook-processes.js.map +1 -0
  320. package/dist/src/runtime/hooks.js +304 -0
  321. package/dist/src/runtime/hooks.js.map +1 -0
  322. package/dist/src/runtime/paths.js +244 -0
  323. package/dist/src/runtime/paths.js.map +1 -0
  324. package/dist/src/runtime/query.js +76 -0
  325. package/dist/src/runtime/query.js.map +1 -0
  326. package/dist/src/runtime/seeds.js +98 -0
  327. package/dist/src/runtime/seeds.js.map +1 -0
  328. package/dist/src/runtime/shared-cache.js +81 -0
  329. package/dist/src/runtime/shared-cache.js.map +1 -0
  330. package/dist/src/runtime/state.js +106 -0
  331. package/dist/src/runtime/state.js.map +1 -0
  332. package/dist/src/runtime-process.js +148 -0
  333. package/dist/src/runtime-process.js.map +1 -0
  334. package/dist/src/schema-types.js +2 -0
  335. package/dist/src/schema-types.js.map +1 -0
  336. package/dist/src/schema.js +16 -0
  337. package/dist/src/schema.js.map +1 -0
  338. package/dist/src/shell.js +5 -0
  339. package/dist/src/shell.js.map +1 -0
  340. package/dist/src/sqlite-lock.js +18 -0
  341. package/dist/src/sqlite-lock.js.map +1 -0
  342. package/dist/src/storage.js +21 -0
  343. package/dist/src/storage.js.map +1 -0
  344. package/dist/src/transcript-retention.js +109 -0
  345. package/dist/src/transcript-retention.js.map +1 -0
  346. package/dist/src/value-guards.js +26 -0
  347. package/dist/src/value-guards.js.map +1 -0
  348. package/docs/architecture.md +5 -2
  349. package/docs/creating-cases.md +2 -3
  350. package/docs/development-cli.md +12 -7
  351. package/docs/documentation-quality.md +4 -3
  352. package/docs/evaluation-workflow.md +8 -8
  353. package/docs/getting-started.md +7 -6
  354. package/docs/guide-evaluation.md +1 -1
  355. package/docs/identity-v1.md +4 -1
  356. package/docs/installing.md +31 -13
  357. package/docs/licensing.md +2 -2
  358. package/docs/native-hosts.md +1 -1
  359. package/docs/recipes.md +41 -40
  360. package/docs/releases.md +20 -4
  361. package/docs/run-settings-v1.md +3 -3
  362. package/docs/specs/repository-guide.md +1 -1
  363. package/docs/troubleshooting.md +1 -1
  364. package/docs/typescript-quality.md +18 -1
  365. package/examples/recipes/executable.ts +19 -0
  366. package/examples/recipes/extension-artifacts.ts +1 -1
  367. package/examples/recipes/extension.ts +2 -1
  368. package/examples/recipes/modules.ts +9 -0
  369. package/examples/recipes/run-inputs.ts +14 -19
  370. package/examples/recipes/run-options.ts +9 -8
  371. package/examples/recipes/run.ts +21 -7
  372. package/examples/templates/repository-skill/extension-data.ts +1 -1
  373. package/examples/templates/repository-skill/extension.ts +2 -1
  374. package/package.json +14 -6
  375. package/src/cli/demo.ts +3 -2
  376. package/src/cli/help.ts +4 -3
  377. package/src/cli/init-settings.ts +5 -4
  378. package/src/cli/init.ts +9 -8
  379. package/src/cli/invocation.ts +2 -1
  380. package/src/cli/preparation.ts +2 -2
  381. package/src/cli.ts +1 -1
  382. package/src/executable.ts +19 -0
  383. package/src/extension-client.ts +6 -12
  384. package/src/fixtures/setup.ts +3 -2
  385. package/src/git.ts +2 -1
  386. package/src/graders/git-head.ts +3 -2
  387. package/src/graders/shell.ts +4 -3
  388. package/src/hosts/claude-keychain.ts +3 -2
  389. package/src/hosts/claude-login-refresh.ts +3 -2
  390. package/src/hosts/claude-refresh-lock.ts +2 -1
  391. package/src/hosts/isolation-roots.ts +3 -2
  392. package/src/hosts/process-lifecycle.ts +4 -6
  393. package/src/hosts/protected-worktrees.ts +2 -1
  394. package/src/hosts/skill-hook-handler.ts +1 -1
  395. package/src/hosts/skill-hooks.ts +10 -2
  396. package/src/provenance.ts +7 -6
  397. package/src/results-lock.ts +4 -4
  398. package/src/run-owner.ts +15 -9
  399. package/src/runner-paths.ts +21 -0
  400. package/src/runtime/hook-processes.ts +2 -1
  401. package/src/runtime/hooks.ts +9 -7
  402. package/src/runtime-process.ts +194 -0
  403. package/src/sqlite-lock.ts +25 -0
@@ -0,0 +1,764 @@
1
+ import { redactDiagnosticText } from "../host-diagnostic-redaction.js";
2
+ import { isRecord, requireRecord } from "../value-guards.js";
3
+ import { spawn } from "node:child_process";
4
+ import { createInterface } from "node:readline";
5
+ import { HostProcessDiagnostics, } from "../host-diagnostics.js";
6
+ function record(value) {
7
+ return requireRecord(value, "Malformed app-server object");
8
+ }
9
+ function identifier(value) {
10
+ if (typeof value !== "string" || !value)
11
+ throw new Error("Missing app-server identifier");
12
+ return value;
13
+ }
14
+ function protocolMessage(line) {
15
+ try {
16
+ return record(JSON.parse(line));
17
+ }
18
+ catch {
19
+ throw new Error("Malformed app-server JSON message");
20
+ }
21
+ }
22
+ function publicErrorMessage(value) {
23
+ if (typeof value !== "string")
24
+ return { message: null };
25
+ const redacted = redactDiagnosticText(value.slice(0, 20000), []);
26
+ return {
27
+ message: redacted.slice(0, 2000),
28
+ ...(value.length > 20000 || redacted.length > 2000
29
+ ? { messageTruncated: true }
30
+ : {}),
31
+ };
32
+ }
33
+ function errorClassification(value) {
34
+ const tag = (s) => typeof s === "string" && /^[A-Za-z][A-Za-z0-9]{0,79}$/.test(s);
35
+ if (tag(value))
36
+ return { code: value };
37
+ if (!isRecord(value))
38
+ return { code: null };
39
+ return classifiedErrorEntry(value, tag);
40
+ }
41
+ function classifiedErrorEntry(value, tag) {
42
+ const entries = Object.entries(value);
43
+ const [entry] = entries;
44
+ if (entries.length !== 1 || entry === undefined || !tag(entry[0]))
45
+ return { code: null };
46
+ const [code, details] = entry;
47
+ return { code, ...errorHttpStatus(details) };
48
+ }
49
+ function validHttpStatus(value) {
50
+ return (typeof value === "number" &&
51
+ Number.isInteger(value) &&
52
+ value >= 0 &&
53
+ value <= 65535);
54
+ }
55
+ function errorHttpStatus(details) {
56
+ const status = details && typeof details === "object"
57
+ ? details.httpStatusCode
58
+ : undefined;
59
+ return {
60
+ ...(validHttpStatus(status) ? { httpStatusCode: status } : {}),
61
+ };
62
+ }
63
+ /** JSON-RPC transport only: no goal mutation, retries or synthesized user turns. */
64
+ class AppServerRpc {
65
+ process;
66
+ exited;
67
+ queue = [];
68
+ nextId = 1;
69
+ pending = new Map();
70
+ wake;
71
+ failure;
72
+ closing = false;
73
+ receivedBytes = 0;
74
+ reads;
75
+ errors;
76
+ stderr = "";
77
+ capture;
78
+ constructor(argv, cwd, env, diagnostics) {
79
+ this.capture = new HostProcessDiagnostics(diagnostics);
80
+ this.process = spawn(identifier(argv[0]), argv.slice(1), {
81
+ detached: process.platform !== "win32",
82
+ cwd,
83
+ env,
84
+ stdio: "pipe",
85
+ });
86
+ this.exited = new Promise((resolve) => {
87
+ this.process.once("exit", resolve);
88
+ this.process.once("error", (error) => {
89
+ if (this.process.pid === undefined)
90
+ this.capture.recordUnstarted();
91
+ this.fail(error);
92
+ resolve(null);
93
+ });
94
+ });
95
+ this.process.stdout.on("data", (chunk) => {
96
+ this.capture.stdout.add(chunk);
97
+ });
98
+ this.reads = this.readLines().catch((error) => {
99
+ this.fail(error);
100
+ });
101
+ this.process.stdin.on("error", (error) => {
102
+ this.fail(error);
103
+ });
104
+ this.errors = new Promise((resolve) => {
105
+ this.process.stderr.on("data", (chunk) => {
106
+ this.capture.stderr.add(chunk);
107
+ this.stderr = (this.stderr + String(chunk)).slice(-16000);
108
+ });
109
+ this.process.stderr.on("end", resolve);
110
+ this.process.stderr.on("close", resolve);
111
+ this.process.stderr.on("error", (error) => {
112
+ this.fail(error);
113
+ resolve();
114
+ });
115
+ });
116
+ void this.exited.then((code) => {
117
+ if (!this.closing)
118
+ this.fail(new Error(`App-server exited before settlement (${code})`));
119
+ });
120
+ }
121
+ fail(error) {
122
+ this.failure ??= error instanceof Error ? error : new Error(String(error));
123
+ for (const pending of this.pending.values())
124
+ pending.reject(this.failure);
125
+ this.pending.clear();
126
+ this.wake?.();
127
+ }
128
+ assertHealthy() {
129
+ if (this.failure)
130
+ throw this.failure;
131
+ }
132
+ send(value) {
133
+ this.process.stdin.write(JSON.stringify(value) + "\n");
134
+ }
135
+ readLines() {
136
+ return new Promise((resolve) => {
137
+ const lines = createInterface({ input: this.process.stdout });
138
+ this.process.stdout.on("close", () => {
139
+ lines.close();
140
+ });
141
+ lines.on("line", (line) => {
142
+ try {
143
+ this.receivedBytes += Buffer.byteLength(line);
144
+ if (this.receivedBytes > 8 * 1024 * 1024)
145
+ throw new Error("App-server stream exceeds limit");
146
+ if (!line.trim())
147
+ return;
148
+ this.receive(protocolMessage(line));
149
+ }
150
+ catch (error) {
151
+ this.fail(error);
152
+ }
153
+ });
154
+ lines.on("close", () => {
155
+ if (!this.closing)
156
+ this.fail(new Error("App-server stdout closed before settlement"));
157
+ resolve();
158
+ });
159
+ });
160
+ }
161
+ receive(message) {
162
+ this.refuseServerRequest(message);
163
+ if (typeof message.id === "number")
164
+ this.receiveResponse(message, message.id);
165
+ else if (typeof message.method === "string")
166
+ this.receiveNotification(message.method, message.params);
167
+ else
168
+ throw new Error("Malformed app-server message");
169
+ }
170
+ refuseServerRequest(message) {
171
+ if (typeof message.method !== "string" || message.id === undefined)
172
+ return;
173
+ this.send({
174
+ id: message.id,
175
+ error: {
176
+ code: -32601,
177
+ message: "Unattended eval cannot answer this server request",
178
+ },
179
+ });
180
+ throw new Error(`Unsupported app-server request: ${message.method}`);
181
+ }
182
+ receiveResponse(message, id) {
183
+ const pending = this.pending.get(id);
184
+ if (!pending)
185
+ throw new Error("Unmatched app-server response");
186
+ // Validate before removing the waiter so malformed responses reject it.
187
+ const value = record(message.error ?? message.result);
188
+ this.pending.delete(id);
189
+ if (message.error)
190
+ pending.reject(new Error(`App-server RPC failed (${String(value.code)})`));
191
+ else
192
+ pending.resolve(value);
193
+ }
194
+ receiveNotification(method, value) {
195
+ // Drop reasoning, account metadata, deltas and private raw events at ingress.
196
+ if (![
197
+ "turn/started",
198
+ "turn/completed",
199
+ "thread/goal/updated",
200
+ "thread/goal/cleared",
201
+ "thread/tokenUsage/updated",
202
+ "item/completed",
203
+ "error",
204
+ ].includes(method))
205
+ return;
206
+ const params = record(value);
207
+ if (!allowedNotificationItem(method, params))
208
+ return;
209
+ if (this.queue.length >= 1024)
210
+ throw new Error("App-server notification queue exceeds limit");
211
+ this.queue.push({ method, params });
212
+ this.wake?.();
213
+ }
214
+ /** The session's configured time bound is the only deadline, including startup. */
215
+ async call(method, params) {
216
+ if (this.failure)
217
+ throw this.failure;
218
+ const id = this.nextId++;
219
+ return new Promise((resolve, reject) => {
220
+ this.pending.set(id, { resolve, reject, method });
221
+ try {
222
+ this.send({ id, method, params });
223
+ }
224
+ catch (error) {
225
+ this.fail(error);
226
+ }
227
+ });
228
+ }
229
+ pendingMethods() {
230
+ return Array.from(this.pending.values(), (pending) => pending.method);
231
+ }
232
+ async initialize() {
233
+ await this.call("initialize", {
234
+ clientInfo: { name: "sevro_eval", version: "0.1.0" },
235
+ capabilities: { experimentalApi: false },
236
+ });
237
+ this.send({ method: "initialized", params: {} });
238
+ }
239
+ async next() {
240
+ while (!this.failure && !this.queue.length)
241
+ await new Promise((resolve) => {
242
+ this.wake = resolve;
243
+ });
244
+ this.wake = undefined;
245
+ if (this.failure)
246
+ throw this.failure;
247
+ const notification = this.queue.shift();
248
+ if (!notification)
249
+ throw new Error("Missing app-server notification");
250
+ return notification;
251
+ }
252
+ async close() {
253
+ this.closing = true;
254
+ this.process.stdin.end();
255
+ let shutdownError;
256
+ const terminate = (signal) => {
257
+ try {
258
+ if (this.process.pid)
259
+ process.kill(-this.process.pid, signal);
260
+ }
261
+ catch (error) {
262
+ if (error.code !== "ESRCH")
263
+ shutdownError ??= error;
264
+ }
265
+ };
266
+ const term = setTimeout(() => {
267
+ terminate("SIGTERM");
268
+ }, 5000);
269
+ const kill = setTimeout(() => {
270
+ terminate("SIGKILL");
271
+ }, 6000);
272
+ try {
273
+ await this.exited;
274
+ await this.reads;
275
+ await this.errors;
276
+ }
277
+ finally {
278
+ clearTimeout(term);
279
+ clearTimeout(kill);
280
+ }
281
+ if (shutdownError !== undefined)
282
+ throw shutdownError;
283
+ }
284
+ }
285
+ function allowedNotificationItem(method, params) {
286
+ return (method !== "item/completed" ||
287
+ ["commandExecution", "collabAgentToolCall"].includes(String(record(params.item).type)));
288
+ }
289
+ /** Convert only public tool items used by the existing bounded evidence readers. */
290
+ function toolEvent(value) {
291
+ const item = record(value);
292
+ if (item.type === "commandExecution")
293
+ return {
294
+ type: "item.completed",
295
+ item: {
296
+ id: item.id,
297
+ type: "command_execution",
298
+ command: item.command,
299
+ status: item.status === "completed" ? "completed" : item.status,
300
+ exit_code: item.exitCode,
301
+ aggregated_output: item.aggregatedOutput,
302
+ },
303
+ };
304
+ if (item.type === "collabAgentToolCall")
305
+ return {
306
+ type: "item.completed",
307
+ item: {
308
+ id: item.id,
309
+ type: "collab_tool_call",
310
+ tool: typeof item.tool === "string"
311
+ ? item.tool.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
312
+ : item.tool,
313
+ status: item.status,
314
+ sender_thread_id: item.senderThreadId,
315
+ receiver_thread_ids: item.receiverThreadIds,
316
+ prompt: item.prompt,
317
+ model: item.model,
318
+ reasoning_effort: item.reasoningEffort,
319
+ },
320
+ };
321
+ return undefined;
322
+ }
323
+ /** Require the exact terminal turn, not a previous checkpoint or child response. */
324
+ export function appServerFinal(thread, turnId) {
325
+ const items = completedAppServerTurn(thread, turnId).items;
326
+ if (!Array.isArray(items))
327
+ throw new Error("Completed app-server turn has no items");
328
+ const finals = items
329
+ .map(record)
330
+ .filter((item) => item.type === "agentMessage" &&
331
+ item.phase === "final_answer" &&
332
+ typeof item.text === "string");
333
+ if (!finals.length)
334
+ throw new Error("Completed app-server turn has no final response");
335
+ return finals.map((item) => item.text).join("\n\n");
336
+ }
337
+ function completedAppServerTurn(thread, turnId) {
338
+ const turns = record(thread).turns;
339
+ if (!Array.isArray(turns))
340
+ throw new Error("App-server thread has no retained turns");
341
+ const matches = turns.map(record).filter((turn) => turn.id === turnId);
342
+ const [turn] = matches;
343
+ if (matches.length !== 1 || turn === undefined || turn.status !== "completed")
344
+ throw new Error("Missing completed app-server turn");
345
+ return turn;
346
+ }
347
+ const GOAL_STATUSES = [
348
+ "active",
349
+ "paused",
350
+ "blocked",
351
+ "usageLimited",
352
+ "budgetLimited",
353
+ "complete",
354
+ ];
355
+ export function appServerGoalStatus(value, threadId) {
356
+ if (value === null)
357
+ return null;
358
+ const goal = record(value);
359
+ requireGoalIdentity(goal, threadId);
360
+ requireGoalObjective(goal.objective);
361
+ return String(goal.status);
362
+ }
363
+ function requireGoalIdentity(goal, threadId) {
364
+ if (goal.threadId !== threadId ||
365
+ typeof goal.status !== "string" ||
366
+ !GOAL_STATUSES.includes(goal.status))
367
+ throw new Error("Invalid native goal readback");
368
+ }
369
+ function requireGoalObjective(objective) {
370
+ if (typeof objective !== "string" ||
371
+ !objective.length ||
372
+ Array.from(objective).length > 4000)
373
+ throw new Error("Invalid native goal readback");
374
+ }
375
+ /** Observe one original host thread. Capability coordination stays in its skill. */
376
+ class AppServerSession {
377
+ rpc;
378
+ options;
379
+ evidence = {
380
+ type: "sevro.codex.app-server",
381
+ clientTurns: 0,
382
+ turns: [],
383
+ goals: [],
384
+ };
385
+ out = [];
386
+ finalMessage = null;
387
+ threadId = "";
388
+ goalSeen = false;
389
+ emittedItems = new Set();
390
+ followUp;
391
+ constructor(rpc, options) {
392
+ this.rpc = rpc;
393
+ this.options = options;
394
+ this.followUp = options.request.control?.followUpPrompt;
395
+ }
396
+ emit(event) {
397
+ this.out.push(JSON.stringify(event));
398
+ }
399
+ async start() {
400
+ const { request } = this.options;
401
+ await this.rpc.initialize();
402
+ const started = await this.rpc.call("thread/start", {
403
+ cwd: request.repoDir,
404
+ model: request.model,
405
+ modelProvider: "openai",
406
+ config: {
407
+ model_reasoning_effort: request.effort,
408
+ default_permissions: this.options.permissionProfile,
409
+ ...(this.options.vettedHooks
410
+ ? { bypass_hook_trust: true, features: { hooks: true } }
411
+ : {}),
412
+ },
413
+ approvalPolicy: "never",
414
+ allowProviderModelFallback: false,
415
+ ephemeral: false,
416
+ });
417
+ this.threadId = identifier(record(started.thread).id);
418
+ this.evidence.threadId = this.threadId;
419
+ this.evidence.model = String(started.model);
420
+ this.evidence.effort = String(started.reasoningEffort);
421
+ if (started.model !== request.model ||
422
+ started.reasoningEffort !== request.effort ||
423
+ started.modelProvider !== "openai")
424
+ throw new Error("App-server effective root route mismatch");
425
+ this.emit({ type: "thread.started", thread_id: this.threadId });
426
+ await this.startUserTurn(request.prompt);
427
+ }
428
+ async startUserTurn(prompt) {
429
+ const { request } = this.options;
430
+ const response = await this.rpc.call("turn/start", {
431
+ threadId: this.threadId,
432
+ model: request.model,
433
+ effort: request.effort,
434
+ input: [{ type: "text", text: prompt, text_elements: [] }],
435
+ });
436
+ identifier(record(response.turn).id);
437
+ this.evidence.clientTurns++;
438
+ }
439
+ emitItem(value) {
440
+ const item = record(value);
441
+ const key = identifier(item.id);
442
+ const event = toolEvent(item);
443
+ if (event && !this.emittedItems.has(key)) {
444
+ this.emittedItems.add(key);
445
+ this.emit(event);
446
+ }
447
+ }
448
+ observeGoal(params, source = "notification") {
449
+ const status = requiredGoalStatus(params.goal, this.threadId);
450
+ this.goalSeen = true;
451
+ const observation = {
452
+ status,
453
+ characters: Array.from(String(record(params.goal).objective)).length,
454
+ turnId: typeof params.turnId === "string" ? params.turnId : null,
455
+ at: new Date().toISOString(),
456
+ source,
457
+ };
458
+ const previous = this.evidence.goals.at(-1);
459
+ if (!sameGoalObservation(previous, observation))
460
+ this.evidence.goals.push(observation);
461
+ }
462
+ observeTurn(value, status) {
463
+ const turn = record(value);
464
+ const id = identifier(turn.id);
465
+ this.evidence.turns.push({
466
+ id,
467
+ status: status ?? String(turn.status),
468
+ at: new Date().toISOString(),
469
+ });
470
+ return id;
471
+ }
472
+ observeError(source, turnId, willRetry, value) {
473
+ const errors = (this.evidence.errors ??= []);
474
+ if (errors.length === 32) {
475
+ errors.shift();
476
+ this.evidence.errorsDropped = (this.evidence.errorsDropped ?? 0) + 1;
477
+ }
478
+ errors.push(errorReceipt(source, this.threadId, turnId, willRetry, value));
479
+ }
480
+ async onNotification({ method, params, }) {
481
+ if (params.threadId !== this.threadId)
482
+ return false;
483
+ switch (method) {
484
+ case "error":
485
+ this.observeError("error", params.turnId, params.willRetry, params.error);
486
+ if (params.willRetry !== true)
487
+ throw new Error("App-server reported a fatal turn error");
488
+ break;
489
+ case "item/completed":
490
+ this.emitItem(params.item);
491
+ break;
492
+ case "thread/goal/updated":
493
+ this.observeGoal(params);
494
+ break;
495
+ case "thread/goal/cleared":
496
+ throw new Error("Participant cleared the observed native goal");
497
+ case "turn/started":
498
+ this.observeTurn(params.turn, "started");
499
+ this.emit({ type: "turn.started" });
500
+ break;
501
+ case "turn/completed":
502
+ return this.onCompletedTurn(record(params.turn));
503
+ }
504
+ return false;
505
+ }
506
+ async onCompletedTurn(turn) {
507
+ const turnId = this.observeTurn(turn);
508
+ this.requireCompletedTurn(turn, turnId);
509
+ const status = await this.completedGoal(turnId);
510
+ this.emit({ type: "turn.completed" });
511
+ if (this.followUp !== undefined)
512
+ return this.deliverFeedback(turnId, status, this.followUp);
513
+ return status !== "active" && (await this.captureFinal(turnId));
514
+ }
515
+ requireCompletedTurn(turn, turnId) {
516
+ if (turn.status === "completed")
517
+ return;
518
+ this.observeError("turn/completed", turnId, null, turn.error);
519
+ throw new Error(`App-server turn ${String(turn.status)}`);
520
+ }
521
+ async completedGoal(turnId) {
522
+ const goal = await this.rpc.call("thread/goal/get", {
523
+ threadId: this.threadId,
524
+ });
525
+ const status = appServerGoalStatus(goal.goal, this.threadId);
526
+ this.evidence.goalStatus = status;
527
+ if (this.goalSeen && status === null)
528
+ throw new Error("Observed native goal disappeared");
529
+ if (status !== null)
530
+ this.observeGoal({ goal: goal.goal, turnId }, "readback");
531
+ return status;
532
+ }
533
+ async deliverFeedback(turnId, status, prompt) {
534
+ // User input does not require a terminal goal. Preserve the completed
535
+ // response and actual boundary before delivering the declared follow-up.
536
+ if (!(await this.captureFinal(turnId, true)))
537
+ return false;
538
+ const boundary = protocolMessage(await this.options.followUpBoundary(this.threadId, {
539
+ nativeGoalObserved: this.goalSeen,
540
+ nativeGoalStatus: status,
541
+ }));
542
+ if (!this.responseBoundaryReady(turnId))
543
+ return false;
544
+ this.emit({
545
+ ...boundary,
546
+ native_goal_observed: this.goalSeen,
547
+ native_goal_status: status,
548
+ });
549
+ this.followUp = undefined;
550
+ await this.startUserTurn(prompt);
551
+ return false;
552
+ }
553
+ async captureFinal(turnId, forFeedback = false) {
554
+ const snapshot = await this.rpc.call("thread/read", {
555
+ threadId: this.threadId,
556
+ includeTurns: true,
557
+ });
558
+ const { thread, turns } = retainedThread(snapshot, this.threadId);
559
+ const latest = record(turns.at(-1));
560
+ // A later native turn can start while readback is pending. Wait for it.
561
+ if (!latestTurnReady(latest, turnId))
562
+ return false;
563
+ const final = appServerFinal(thread, turnId);
564
+ for (const value of turns)
565
+ this.backfillItems(record(value));
566
+ this.finalMessage = final;
567
+ this.evidence.finalTurnId = turnId;
568
+ this.emit({
569
+ type: "item.completed",
570
+ item: { type: "agent_message", text: final },
571
+ });
572
+ if (forFeedback)
573
+ return this.responseBoundaryReady(turnId);
574
+ this.assertSettled();
575
+ return true;
576
+ }
577
+ /** Continuation may race feedback capture; errors still stop delivery. */
578
+ responseBoundaryReady(turnId) {
579
+ this.rpc.assertHealthy();
580
+ let ready = true;
581
+ for (const event of this.rpc.queue) {
582
+ const { params } = event;
583
+ if (params.threadId !== this.threadId)
584
+ continue;
585
+ this.validateResponseEvent(event);
586
+ if (laterRootTurn(event, turnId))
587
+ ready = false;
588
+ }
589
+ return ready;
590
+ }
591
+ validateResponseEvent(event) {
592
+ if (event.method === "error" || event.method === "thread/goal/cleared")
593
+ this.checkPendingSettlement(event);
594
+ if (event.method === "thread/goal/updated")
595
+ appServerGoalStatus(event.params.goal, this.threadId);
596
+ }
597
+ /** Readback and file I/O can race with a terminal protocol event. */
598
+ assertSettled() {
599
+ this.rpc.assertHealthy();
600
+ for (const event of this.rpc.queue) {
601
+ if (event.params.threadId !== this.threadId)
602
+ continue;
603
+ this.checkPendingSettlement(event);
604
+ }
605
+ }
606
+ checkPendingSettlement({ method, params }) {
607
+ this.requireNonfatalPendingError(method, params);
608
+ if (method === "thread/goal/cleared")
609
+ throw new Error("Native goal cleared during settlement");
610
+ this.requireSettledGoal(method, params);
611
+ if (laterRootTurn({ method, params }, this.evidence.finalTurnId))
612
+ throw new Error("Another root turn appeared during settlement");
613
+ }
614
+ requireNonfatalPendingError(method, params) {
615
+ if (method === "error" && params.willRetry !== true) {
616
+ this.observeError("error", params.turnId, params.willRetry, params.error);
617
+ throw new Error("App-server reported a fatal error during settlement");
618
+ }
619
+ }
620
+ requireSettledGoal(method, params) {
621
+ if (method === "thread/goal/updated" &&
622
+ appServerGoalStatus(params.goal, this.threadId) === "active")
623
+ throw new Error("Native goal became active during settlement");
624
+ }
625
+ backfillItems(turn) {
626
+ if (Array.isArray(turn.items))
627
+ for (const item of turn.items)
628
+ this.emitItem(item);
629
+ }
630
+ async run() {
631
+ await this.start();
632
+ while (!(await this.onNotification(await this.rpc.next()))) {
633
+ /* Native host owns continuation. */
634
+ }
635
+ }
636
+ }
637
+ function requiredGoalStatus(value, threadId) {
638
+ const status = appServerGoalStatus(value, threadId);
639
+ if (status === null)
640
+ throw new Error("Malformed app-server object");
641
+ return status;
642
+ }
643
+ function sameGoalObservation(previous, observation) {
644
+ return (previous?.status === observation.status &&
645
+ previous.turnId === observation.turnId &&
646
+ previous.source === observation.source);
647
+ }
648
+ function errorReceipt(source, threadId, turnId, willRetry, value) {
649
+ const error = isRecord(value) ? value : {};
650
+ return {
651
+ source,
652
+ threadId,
653
+ turnId: typeof turnId === "string" ? turnId.slice(0, 200) : null,
654
+ willRetry: typeof willRetry === "boolean" ? willRetry : null,
655
+ ...publicErrorMessage(error.message),
656
+ ...errorClassification(error.codexErrorInfo),
657
+ };
658
+ }
659
+ function retainedThread(snapshot, threadId) {
660
+ const thread = record(snapshot.thread);
661
+ if (thread.id !== threadId)
662
+ throw new Error("App-server returned another thread");
663
+ const turns = thread.turns;
664
+ if (!Array.isArray(turns))
665
+ throw new Error("Missing app-server history");
666
+ return { thread, turns: turns };
667
+ }
668
+ function latestTurnReady(latest, turnId) {
669
+ if (latest.id === turnId)
670
+ return true;
671
+ if (latest.status === "inProgress" || latest.status === "completed")
672
+ return false;
673
+ throw new Error("Later app-server turn did not complete");
674
+ }
675
+ function laterRootTurn(event, turnId) {
676
+ return (["turn/started", "turn/completed"].includes(event.method) &&
677
+ record(event.params.turn).id !== turnId);
678
+ }
679
+ function requireAppServerRun(request, bound) {
680
+ if (request.signal?.aborted)
681
+ throw new Error("Codex run cancelled");
682
+ if (!Number.isFinite(bound) || bound <= 0)
683
+ throw new Error("Invalid app-server time bound");
684
+ }
685
+ function sessionFailure(session, error) {
686
+ session.options.diagnostics.failure = error;
687
+ session.evidence.failure =
688
+ error instanceof Error ? error.message : String(error);
689
+ session.emit({ type: "turn.failed" });
690
+ }
691
+ /** Name an unanswered request so a stalled startup stays distinguishable. */
692
+ function timeBoundFailure(pending) {
693
+ const reached = "App-server evaluation time bound reached";
694
+ return pending.length ? `${reached} awaiting ${pending.join(", ")}` : reached;
695
+ }
696
+ async function completeSession(session, rpc, request, bound) {
697
+ const cancel = () => {
698
+ rpc.fail(new Error("Codex run cancelled"));
699
+ };
700
+ request.signal?.addEventListener("abort", cancel, { once: true });
701
+ const deadline = setTimeout(() => {
702
+ rpc.fail(new Error(timeBoundFailure(rpc.pendingMethods())));
703
+ }, bound);
704
+ let code = 0;
705
+ try {
706
+ await session.run();
707
+ session.assertSettled();
708
+ }
709
+ catch (error) {
710
+ sessionFailure(session, error);
711
+ code = 1;
712
+ }
713
+ finally {
714
+ clearTimeout(deadline);
715
+ request.signal?.removeEventListener("abort", cancel);
716
+ }
717
+ return closeSession(session, rpc, code);
718
+ }
719
+ async function closeSession(session, rpc, code) {
720
+ try {
721
+ await rpc.close();
722
+ return code;
723
+ }
724
+ catch (error) {
725
+ if (code === 0)
726
+ sessionFailure(session, error);
727
+ return 1;
728
+ }
729
+ }
730
+ function settlementCode(session, code) {
731
+ if (code !== 0)
732
+ return code;
733
+ try {
734
+ session.assertSettled();
735
+ return 0;
736
+ }
737
+ catch (error) {
738
+ sessionFailure(session, error);
739
+ return 1;
740
+ }
741
+ }
742
+ export async function runCodexAppServer(options) {
743
+ const { request, argv, env } = options;
744
+ const bound = request.control?.appServerTimeoutMs ?? 3600000;
745
+ requireAppServerRun(request, bound);
746
+ const rpc = new AppServerRpc(argv, request.repoDir, env, options.diagnostics);
747
+ const session = new AppServerSession(rpc, options);
748
+ const code = await completeSession(session, rpc, request, bound);
749
+ // Flush stdout before accepting success, including trailing data and terminal errors.
750
+ const finalCode = settlementCode(session, code);
751
+ if (rpc.process.pid !== undefined)
752
+ await rpc.capture.record({ exited: rpc.exited, signalCode: rpc.process.signalCode }, finalCode === 0 ? "exit" : "error");
753
+ return {
754
+ out: session.out.join("\n"),
755
+ err: rpc.stderr,
756
+ code: finalCode,
757
+ finalMessage: completedMessage(session, finalCode),
758
+ evidence: session.evidence,
759
+ };
760
+ }
761
+ function completedMessage(session, code) {
762
+ return code === 0 ? session.finalMessage : null;
763
+ }
764
+ //# sourceMappingURL=codex-app-server.js.map