@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,323 @@
1
+ import { lstat, readFile, realpath } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { declaredRuntimeRoots, optionalRuntimeRoots, runtimePathDirectories, runtimeInheritedPath, requireRuntimeReadRoots, } from "./paths.js";
4
+ import validate from "../generated/runtime.cjs";
5
+ import { requireArtifactDirectories, } from "../candidate-artifacts.js";
6
+ import { runtimeSeedDigest } from "./seeds.js";
7
+ import { resolveSharedCaches, requireSharedCachePolicy, } from "./shared-cache.js";
8
+ import { discoverRuntimeSupport, } from "./discovery.js";
9
+ /** Canonical roles; schemas:generate projects this list into the runtime schema. */
10
+ export const RUNTIME_ROLES = [
11
+ "candidate",
12
+ "checks",
13
+ "hooks",
14
+ "semantic",
15
+ "advisory",
16
+ ];
17
+ export function runtimeLocalHttpEnabled(policy, role) {
18
+ const network = policy?.network;
19
+ return network?.localHttp === true && ["candidate", "checks"].includes(role);
20
+ }
21
+ export function runtimeNativeGoalEnabled(policy) {
22
+ const hooks = policy?.hooks;
23
+ return hooks?.nativeGoal === true;
24
+ }
25
+ const validatedPolicies = new WeakSet();
26
+ export function runtimePolicySnapshot(policy) {
27
+ if (!policy)
28
+ return undefined;
29
+ const snapshot = structuredClone(policy);
30
+ if (!validatedPolicies.has(policy))
31
+ requireRuntimePolicy(snapshot);
32
+ Object.freeze(snapshot.network);
33
+ freezeArtifactDirectories(snapshot);
34
+ Object.freeze(snapshot.environment);
35
+ Object.freeze(snapshot.readOnlyRoots);
36
+ freezeDiscovery(snapshot);
37
+ freezeRuntimeCaches(snapshot);
38
+ Object.freeze(snapshot.seedReadDenyRoots);
39
+ const hooks = snapshot.hooks;
40
+ if (hooks) {
41
+ Object.freeze(hooks.plugins);
42
+ Object.freeze(hooks);
43
+ }
44
+ Object.freeze(snapshot);
45
+ validatedPolicies.add(snapshot);
46
+ return snapshot;
47
+ }
48
+ /** Loaded snapshots are already validated; mutable direct API inputs still need validation. */
49
+ export function requireRuntimePolicy(policy) {
50
+ if (validatedPolicies.has(policy))
51
+ return;
52
+ snapshotEnvironment([], policy.environment);
53
+ requireRuntimeCaches(policy.seeds ?? [], policy.sharedCacheDirectories ?? []);
54
+ requireSharedCachePolicy(policy);
55
+ requireArtifactDirectories(policy.artifactDirectories ?? []);
56
+ }
57
+ function requireRuntimeCaches(seeds, caches) {
58
+ requireRuntimeSeedTargets([...seeds, ...caches]);
59
+ for (const seed of seeds)
60
+ if (seed.roles !== undefined)
61
+ requireRuntimeRoles(seed.roles, "seed");
62
+ for (const cache of caches)
63
+ requireRuntimeRoles(cache.roles, "shared cache");
64
+ }
65
+ function freezeRuntimeCaches(snapshot) {
66
+ for (const seed of [
67
+ ...(snapshot.seeds ?? []),
68
+ ...(snapshot.sharedCacheDirectories ?? []),
69
+ ]) {
70
+ Object.freeze(seed.roles);
71
+ Object.freeze(seed);
72
+ }
73
+ Object.freeze(snapshot.seeds);
74
+ Object.freeze(snapshot.sharedCacheDirectories);
75
+ }
76
+ function freezeDiscovery(snapshot) {
77
+ for (const source of snapshot.discovery ?? []) {
78
+ Object.freeze(source.readOnlyRoots);
79
+ Object.freeze(source);
80
+ }
81
+ Object.freeze(snapshot.discovery);
82
+ Object.freeze(snapshot.skippedOptionalReadOnlyRoots);
83
+ }
84
+ function freezeArtifactDirectories(snapshot) {
85
+ const directories = snapshot.artifactDirectories ?? [];
86
+ for (const directory of directories)
87
+ Object.freeze(directory);
88
+ Object.freeze(snapshot.artifactDirectories);
89
+ }
90
+ function assertRuntimeConfiguration(value) {
91
+ if (!validate(value)) {
92
+ // Ajv always populates errors when validation fails.
93
+ const issue = validate.errors[0];
94
+ throw new Error(`runtime configuration schema ${runtimeSchemaPath(issue)}: ${issue.message}`);
95
+ }
96
+ }
97
+ function runtimeSchemaPath(issue) {
98
+ const params = issue.params;
99
+ const property = params.additionalProperty ?? params.missingProperty;
100
+ const suffix = typeof property === "string"
101
+ ? "/" + property.replaceAll("~", "~0").replaceAll("/", "~1")
102
+ : "";
103
+ return safeFilesystemPath(issue.instancePath + suffix || "/");
104
+ }
105
+ const RESERVED_ENVIRONMENT = /^(HOME|TMPDIR|TMPPREFIX|TMP|TEMP|CODEX_HOME|CODEX_THREAD_ID|CLAUDE_CONFIG_DIR|CLAUDE_EFFORT|BASH_ENV|ENV|ZDOTDIR|NODE_OPTIONS|BUN_OPTIONS|UV_OFFLINE|GIT_CONFIG.*|LD_.*|DYLD_.*|CLAUDE_CODE_.*|SEVRO_CODEX_.*|SEVRO_NATIVE_.*|SEVRO_CANDIDATE_.*)$/i;
106
+ function requireEnvironmentName(name) {
107
+ if (!/^[A-Za-z_][A-Za-z0-9_]{0,127}$/.test(name))
108
+ throw new Error("invalid runtime environment variable name");
109
+ if (RESERVED_ENVIRONMENT.test(name) ||
110
+ /KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|AUTH/i.test(name))
111
+ throw new Error(`runtime environment variable is protected: ${name}`);
112
+ }
113
+ function snapshotEnvironment(names, values) {
114
+ const inherited = Object.fromEntries(names.map((name) => {
115
+ requireEnvironmentName(name);
116
+ const value = process.env[name];
117
+ if (value === undefined)
118
+ throw new Error(`runtime environment variable is missing: ${name}`);
119
+ return [name, value];
120
+ }));
121
+ const environment = { ...inherited, ...values };
122
+ for (const [name, value] of Object.entries(environment)) {
123
+ requireEnvironmentName(name);
124
+ if (value.includes("\0") || Buffer.byteLength(value) > 8192)
125
+ throw new Error("runtime environment value is invalid or oversized");
126
+ }
127
+ return environment;
128
+ }
129
+ function requireRuntimeSeedTargets(seeds) {
130
+ const targets = seeds.map((seed) => seed.target);
131
+ if (targets.some((target) => !/^[a-z][a-z0-9-]{0,63}$/.test(target) ||
132
+ ["home", "tmp"].includes(target)))
133
+ throw new Error("runtime seed target is invalid or reserved");
134
+ if (new Set(targets).size !== targets.length)
135
+ throw new Error("runtime seed targets overlap");
136
+ }
137
+ /** Read the operator's repository configuration before any candidate starts. */
138
+ export async function loadRuntimeConfiguration(projectRoot, explicitFile, protectedRoots = []) {
139
+ const path = await selectedRuntimeFile(projectRoot, explicitFile);
140
+ if (path === undefined)
141
+ return undefined;
142
+ try {
143
+ const canonical = await realpath(path);
144
+ const source = await readFile(canonical, "utf8");
145
+ if (Buffer.byteLength(source) > 65536)
146
+ throw new Error("runtime configuration exceeds 64 KiB");
147
+ return runtimePolicySnapshot(await resolveRuntimeConfiguration(parseRuntimeConfiguration(source), dirname(canonical), protectedRoots));
148
+ }
149
+ catch (cause) {
150
+ throw new Error(`${runtimeConfigurationDiagnostic(cause)} at ${safeFilesystemPath(path)}`, { cause });
151
+ }
152
+ }
153
+ function parseRuntimeConfiguration(source) {
154
+ try {
155
+ return JSON.parse(source);
156
+ }
157
+ catch (cause) {
158
+ throw new Error("runtime configuration $: invalid JSON; check the JSON syntax", { cause });
159
+ }
160
+ }
161
+ function runtimeConfigurationDiagnostic(cause) {
162
+ if (cause instanceof Error &&
163
+ /^(runtime |declared runtime |selected Apple )/.test(cause.message))
164
+ return `invalid runtime configuration: ${cause.message}`;
165
+ const filesystem = runtimeFilesystemDiagnostic(cause);
166
+ if (filesystem)
167
+ return filesystem;
168
+ return "invalid runtime configuration";
169
+ }
170
+ function runtimeFilesystemDiagnostic(cause) {
171
+ if (!(cause instanceof Error))
172
+ return undefined;
173
+ const error = cause;
174
+ if (!validFilesystemCode(error.code) ||
175
+ !validFilesystemOperation(error.syscall) ||
176
+ typeof error.path !== "string")
177
+ return undefined;
178
+ const path = safeFilesystemPath(error.path);
179
+ return `invalid runtime configuration: filesystem ${error.syscall} failed (${error.code}) at ${path}`;
180
+ }
181
+ function validFilesystemCode(code) {
182
+ return code !== undefined && /^E[A-Z0-9]+$/.test(code);
183
+ }
184
+ function validFilesystemOperation(operation) {
185
+ return operation !== undefined && /^[A-Za-z][A-Za-z0-9_]*$/.test(operation);
186
+ }
187
+ function safeFilesystemPath(path) {
188
+ return Array.from(path.slice(0, 256), (character) => {
189
+ const code = character.charCodeAt(0);
190
+ return code < 0x20 || code === 0x7f ? "?" : character;
191
+ }).join("");
192
+ }
193
+ async function selectedRuntimeFile(projectRoot, explicitFile) {
194
+ const path = explicitFile ?? join(projectRoot, "sevro.json");
195
+ const info = await selectedRuntimeStat(path, Boolean(explicitFile));
196
+ if (!info)
197
+ return undefined;
198
+ if (!info.isFile() || info.size > 65536)
199
+ throw new Error("invalid runtime configuration: expected a regular file up to 64 KiB");
200
+ return path;
201
+ }
202
+ async function selectedRuntimeStat(path, explicit) {
203
+ try {
204
+ return await lstat(path);
205
+ }
206
+ catch (cause) {
207
+ if (!explicit && cause.code === "ENOENT")
208
+ return undefined;
209
+ throw new Error(runtimeFilesystemDiagnostic(cause) ?? "invalid runtime configuration", { cause });
210
+ }
211
+ }
212
+ async function resolvedSeeds(seeds, environment, base) {
213
+ return Promise.all(seeds.map(async (seed) => {
214
+ const roots = await declaredRuntimeRoots([seed.source], environment, base);
215
+ requireRuntimeReadRoots(roots, []);
216
+ const [source] = roots;
217
+ if (!source)
218
+ throw new Error("runtime seed source is missing");
219
+ return {
220
+ source,
221
+ target: seed.target,
222
+ ...(seed.roles ? { roles: seed.roles } : {}),
223
+ sha256: await runtimeSeedDigest(source),
224
+ };
225
+ }));
226
+ }
227
+ async function resolveRuntimeConfiguration(value, base, protectedRoots) {
228
+ assertRuntimeConfiguration(value);
229
+ const environment = await resolvedRuntimeEnvironment(value);
230
+ const optional = await optionalRuntimeRoots(value.filesystem?.optionalReadOnlyRoots ?? [], environment, base, protectedRoots);
231
+ const pathRoots = await runtimePathDirectories(environment.PATH);
232
+ requireRuntimeReadRoots(pathRoots, protectedRoots);
233
+ requireRuntimeReadRoots(optional.roots, protectedRoots);
234
+ const discovery = await discoverRuntimeSupport(environment, protectedRoots);
235
+ const readOnlyRoots = [
236
+ ...optional.roots,
237
+ ...discovery.sources.flatMap((source) => source.readOnlyRoots),
238
+ ...pathRoots.filter((root) => !discovery.excludedPrefixes.includes(root)),
239
+ ...(await declaredRuntimeRoots(configurationReadRoots(value), environment, base)),
240
+ ];
241
+ requireRuntimeReadRoots(readOnlyRoots, protectedRoots);
242
+ return {
243
+ format: value.format,
244
+ ...selectedRuntimeCapabilities(value),
245
+ ...artifactConfiguration(value.runtime),
246
+ environment,
247
+ readOnlyRoots: [...new Set(readOnlyRoots)].sort(),
248
+ discovery: discovery.sources,
249
+ skippedOptionalReadOnlyRoots: optional.skipped,
250
+ ...(await resolvedRuntimeCaches(value, environment, base, [
251
+ ...protectedRoots,
252
+ ...readOnlyRoots,
253
+ ])),
254
+ hooks: resolvedHooks(value.hooks),
255
+ };
256
+ }
257
+ async function resolvedRuntimeCaches(value, environment, base, protectedRoots) {
258
+ const seeds = await resolvedSeeds(configurationSeeds(value), environment, base);
259
+ const caches = await resolveSharedCaches(value.runtime?.sharedCacheDirectories ?? [], environment, base, [...protectedRoots, ...seeds.map((seed) => seed.source)]);
260
+ return {
261
+ seeds,
262
+ ...(caches.length ? { sharedCacheDirectories: caches } : {}),
263
+ };
264
+ }
265
+ function selectedRuntimeCapabilities(value) {
266
+ return {
267
+ ...(value.network === undefined ? {} : { network: value.network }),
268
+ ...(value.codexState === undefined ? {} : { codexState: value.codexState }),
269
+ ...(value.nativeTranscripts === undefined
270
+ ? {}
271
+ : { nativeTranscripts: value.nativeTranscripts }),
272
+ };
273
+ }
274
+ async function resolvedRuntimeEnvironment(value) {
275
+ const { inherit, set } = configurationEnvironment(value);
276
+ const environment = snapshotEnvironment(inherit, set);
277
+ for (const [name, value] of Object.entries(environment)) {
278
+ if (name === "PATH" && inherit.includes(name) && !Object.hasOwn(set, name))
279
+ environment[name] = await runtimeInheritedPath(value);
280
+ }
281
+ return environment;
282
+ }
283
+ function configurationEnvironment(value) {
284
+ const environment = value.environment;
285
+ return { inherit: environment?.inherit ?? [], set: environment?.set ?? {} };
286
+ }
287
+ function artifactConfiguration(runtime) {
288
+ const directories = runtime?.artifactDirectories;
289
+ if (directories === undefined)
290
+ return {};
291
+ return { artifactDirectories: directories };
292
+ }
293
+ function configurationReadRoots(value) {
294
+ return value.filesystem?.readOnlyRoots ?? [];
295
+ }
296
+ function configurationSeeds(value) {
297
+ return value.runtime?.seedDirectories ?? [];
298
+ }
299
+ function resolvedHooks(hooks) {
300
+ return {
301
+ nativeGoal: hooks?.nativeGoal ?? false,
302
+ plugins: hooks?.plugins ?? [],
303
+ };
304
+ }
305
+ function requireRuntimeRoles(roles, kind) {
306
+ if (!validRoleArray(roles) ||
307
+ new Set(roles).size !== roles.length ||
308
+ roles.some((role) => !RUNTIME_ROLES.includes(role)))
309
+ throw new Error(`runtime ${kind} roles are invalid`);
310
+ }
311
+ export function runtimeRoleSeeds(policy, role) {
312
+ return (policy.seeds ?? []).filter((seed) => seed.roles?.includes(role) ?? role !== "checks");
313
+ }
314
+ function validRoleArray(roles) {
315
+ return Array.isArray(roles) && roles.length > 0;
316
+ }
317
+ export function runtimeSeedSources(policy) {
318
+ return [
319
+ ...(policy?.seedReadDenyRoots ?? []),
320
+ ...(policy?.seeds ?? []).map((seed) => seed.source),
321
+ ];
322
+ }
323
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["config.ts"],"names":[],"mappings":"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","sourcesContent":["import { lstat, readFile, realpath } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport type { ErrorObject } from \"ajv\";\nimport {\n declaredRuntimeRoots,\n optionalRuntimeRoots,\n runtimePathDirectories,\n runtimeInheritedPath,\n requireRuntimeReadRoots,\n} from \"./paths\";\nimport validate from \"../generated/runtime.cjs\";\nimport {\n requireArtifactDirectories,\n type RuntimeArtifactDirectory,\n} from \"../candidate-artifacts\";\nimport { runtimeSeedDigest } from \"./seeds\";\nimport {\n resolveSharedCaches,\n requireSharedCachePolicy,\n type SharedCacheDirectory,\n} from \"./shared-cache\";\nimport {\n discoverRuntimeSupport,\n type RuntimeDiscoverySource,\n} from \"./discovery\";\n\n/** Canonical roles; schemas:generate projects this list into the runtime schema. */\nexport const RUNTIME_ROLES = [\n \"candidate\",\n \"checks\",\n \"hooks\",\n \"semantic\",\n \"advisory\",\n] as const;\nexport type RuntimeRole = (typeof RUNTIME_ROLES)[number];\nexport interface RuntimeSeed {\n source: string;\n target: string;\n roles?: RuntimeRole[];\n}\nexport interface RuntimeConfiguration {\n format: \"sevro.runtime.v1\";\n codexState?: boolean;\n network?: { localHttp?: boolean };\n nativeTranscripts?: boolean;\n environment?: { inherit?: string[]; set?: Record<string, string> };\n filesystem?: { readOnlyRoots?: string[]; optionalReadOnlyRoots?: string[] };\n runtime?: {\n seedDirectories?: RuntimeSeed[];\n sharedCacheDirectories?: SharedCacheDirectory[];\n artifactDirectories?: RuntimeArtifactDirectory[];\n };\n hooks?: { nativeGoal?: boolean; plugins?: string[] };\n}\n\nexport interface RuntimePolicy {\n format: \"sevro.runtime.v1\";\n codexState?: boolean;\n network?: { localHttp?: boolean };\n artifactDirectories?: RuntimeArtifactDirectory[];\n nativeTranscripts?: boolean;\n environment: Record<string, string>;\n readOnlyRoots: string[];\n discovery?: RuntimeDiscoverySource[];\n skippedOptionalReadOnlyRoots?: string[];\n /** Original source denials retained when a derived role policy omits seeds. */\n seedReadDenyRoots?: string[];\n seeds?: (RuntimeSeed & { sha256: string })[];\n sharedCacheDirectories?: SharedCacheDirectory[];\n hooks?: { nativeGoal?: boolean; plugins?: string[] };\n}\n\nexport function runtimeLocalHttpEnabled(\n policy: RuntimePolicy | undefined,\n role: RuntimeRole,\n): boolean {\n const network = policy?.network;\n return network?.localHttp === true && [\"candidate\", \"checks\"].includes(role);\n}\n\nexport function runtimeNativeGoalEnabled(\n policy: RuntimePolicy | undefined,\n): boolean {\n const hooks = policy?.hooks;\n return hooks?.nativeGoal === true;\n}\n\nconst validatedPolicies = new WeakSet<RuntimePolicy>();\n\nexport function runtimePolicySnapshot(policy: RuntimePolicy): RuntimePolicy;\nexport function runtimePolicySnapshot(\n policy: RuntimePolicy | undefined,\n): RuntimePolicy | undefined;\nexport function runtimePolicySnapshot(\n policy: RuntimePolicy | undefined,\n): RuntimePolicy | undefined {\n if (!policy) return undefined;\n const snapshot = structuredClone(policy);\n if (!validatedPolicies.has(policy)) requireRuntimePolicy(snapshot);\n Object.freeze(snapshot.network);\n freezeArtifactDirectories(snapshot);\n Object.freeze(snapshot.environment);\n Object.freeze(snapshot.readOnlyRoots);\n freezeDiscovery(snapshot);\n freezeRuntimeCaches(snapshot);\n Object.freeze(snapshot.seedReadDenyRoots);\n const hooks = snapshot.hooks;\n if (hooks) {\n Object.freeze(hooks.plugins);\n Object.freeze(hooks);\n }\n Object.freeze(snapshot);\n validatedPolicies.add(snapshot);\n return snapshot;\n}\n\n/** Loaded snapshots are already validated; mutable direct API inputs still need validation. */\nexport function requireRuntimePolicy(policy: RuntimePolicy): void {\n if (validatedPolicies.has(policy)) return;\n snapshotEnvironment([], policy.environment);\n requireRuntimeCaches(policy.seeds ?? [], policy.sharedCacheDirectories ?? []);\n requireSharedCachePolicy(policy);\n requireArtifactDirectories(policy.artifactDirectories ?? []);\n}\n\nfunction requireRuntimeCaches(\n seeds: RuntimeSeed[],\n caches: SharedCacheDirectory[],\n): void {\n requireRuntimeSeedTargets([...seeds, ...caches]);\n for (const seed of seeds)\n if (seed.roles !== undefined) requireRuntimeRoles(seed.roles, \"seed\");\n for (const cache of caches) requireRuntimeRoles(cache.roles, \"shared cache\");\n}\n\nfunction freezeRuntimeCaches(snapshot: RuntimePolicy): void {\n for (const seed of [\n ...(snapshot.seeds ?? []),\n ...(snapshot.sharedCacheDirectories ?? []),\n ]) {\n Object.freeze(seed.roles);\n Object.freeze(seed);\n }\n Object.freeze(snapshot.seeds);\n Object.freeze(snapshot.sharedCacheDirectories);\n}\n\nfunction freezeDiscovery(snapshot: RuntimePolicy): void {\n for (const source of snapshot.discovery ?? []) {\n Object.freeze(source.readOnlyRoots);\n Object.freeze(source);\n }\n Object.freeze(snapshot.discovery);\n Object.freeze(snapshot.skippedOptionalReadOnlyRoots);\n}\n\nfunction freezeArtifactDirectories(snapshot: RuntimePolicy): void {\n const directories = snapshot.artifactDirectories ?? [];\n for (const directory of directories) Object.freeze(directory);\n Object.freeze(snapshot.artifactDirectories);\n}\n\nfunction assertRuntimeConfiguration(\n value: unknown,\n): asserts value is RuntimeConfiguration {\n if (!validate(value)) {\n // Ajv always populates errors when validation fails.\n const issue = (validate.errors as [ErrorObject, ...ErrorObject[]])[0];\n throw new Error(\n `runtime configuration schema ${runtimeSchemaPath(issue)}: ${issue.message}`,\n );\n }\n}\n\nfunction runtimeSchemaPath(issue: ErrorObject): string {\n const params = issue.params as Record<string, unknown>;\n const property = params.additionalProperty ?? params.missingProperty;\n const suffix =\n typeof property === \"string\"\n ? \"/\" + property.replaceAll(\"~\", \"~0\").replaceAll(\"/\", \"~1\")\n : \"\";\n return safeFilesystemPath(issue.instancePath + suffix || \"/\");\n}\n\nconst RESERVED_ENVIRONMENT =\n /^(HOME|TMPDIR|TMPPREFIX|TMP|TEMP|CODEX_HOME|CODEX_THREAD_ID|CLAUDE_CONFIG_DIR|CLAUDE_EFFORT|BASH_ENV|ENV|ZDOTDIR|NODE_OPTIONS|BUN_OPTIONS|UV_OFFLINE|GIT_CONFIG.*|LD_.*|DYLD_.*|CLAUDE_CODE_.*|SEVRO_CODEX_.*|SEVRO_NATIVE_.*|SEVRO_CANDIDATE_.*)$/i;\n\nfunction requireEnvironmentName(name: string): void {\n if (!/^[A-Za-z_][A-Za-z0-9_]{0,127}$/.test(name))\n throw new Error(\"invalid runtime environment variable name\");\n if (\n RESERVED_ENVIRONMENT.test(name) ||\n /KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|AUTH/i.test(name)\n )\n throw new Error(`runtime environment variable is protected: ${name}`);\n}\n\nfunction snapshotEnvironment(\n names: string[],\n values: Record<string, string>,\n): Record<string, string> {\n const inherited = Object.fromEntries(\n names.map((name) => {\n requireEnvironmentName(name);\n const value = process.env[name];\n if (value === undefined)\n throw new Error(`runtime environment variable is missing: ${name}`);\n return [name, value];\n }),\n );\n const environment = { ...inherited, ...values };\n for (const [name, value] of Object.entries(environment)) {\n requireEnvironmentName(name);\n if (value.includes(\"\\0\") || Buffer.byteLength(value) > 8192)\n throw new Error(\"runtime environment value is invalid or oversized\");\n }\n return environment;\n}\n\nfunction requireRuntimeSeedTargets(seeds: RuntimeSeed[]): void {\n const targets = seeds.map((seed) => seed.target);\n if (\n targets.some(\n (target) =>\n !/^[a-z][a-z0-9-]{0,63}$/.test(target) ||\n [\"home\", \"tmp\"].includes(target),\n )\n )\n throw new Error(\"runtime seed target is invalid or reserved\");\n if (new Set(targets).size !== targets.length)\n throw new Error(\"runtime seed targets overlap\");\n}\n\n/** Read the operator's repository configuration before any candidate starts. */\nexport async function loadRuntimeConfiguration(\n projectRoot: string,\n explicitFile?: string,\n protectedRoots: string[] = [],\n): Promise<RuntimePolicy | undefined> {\n const path = await selectedRuntimeFile(projectRoot, explicitFile);\n if (path === undefined) return undefined;\n try {\n const canonical = await realpath(path);\n const source = await readFile(canonical, \"utf8\");\n if (Buffer.byteLength(source) > 65536)\n throw new Error(\"runtime configuration exceeds 64 KiB\");\n return runtimePolicySnapshot(\n await resolveRuntimeConfiguration(\n parseRuntimeConfiguration(source),\n dirname(canonical),\n protectedRoots,\n ),\n );\n } catch (cause) {\n throw new Error(\n `${runtimeConfigurationDiagnostic(cause)} at ${safeFilesystemPath(path)}`,\n { cause },\n );\n }\n}\n\nfunction parseRuntimeConfiguration(source: string): unknown {\n try {\n return JSON.parse(source);\n } catch (cause) {\n throw new Error(\n \"runtime configuration $: invalid JSON; check the JSON syntax\",\n { cause },\n );\n }\n}\n\nfunction runtimeConfigurationDiagnostic(cause: unknown): string {\n if (\n cause instanceof Error &&\n /^(runtime |declared runtime |selected Apple )/.test(cause.message)\n )\n return `invalid runtime configuration: ${cause.message}`;\n const filesystem = runtimeFilesystemDiagnostic(cause);\n if (filesystem) return filesystem;\n return \"invalid runtime configuration\";\n}\n\nfunction runtimeFilesystemDiagnostic(cause: unknown): string | undefined {\n if (!(cause instanceof Error)) return undefined;\n const error = cause as NodeJS.ErrnoException;\n if (\n !validFilesystemCode(error.code) ||\n !validFilesystemOperation(error.syscall) ||\n typeof error.path !== \"string\"\n )\n return undefined;\n const path = safeFilesystemPath(error.path);\n return `invalid runtime configuration: filesystem ${error.syscall} failed (${error.code}) at ${path}`;\n}\n\nfunction validFilesystemCode(code: string | undefined): boolean {\n return code !== undefined && /^E[A-Z0-9]+$/.test(code);\n}\n\nfunction validFilesystemOperation(operation: string | undefined): boolean {\n return operation !== undefined && /^[A-Za-z][A-Za-z0-9_]*$/.test(operation);\n}\n\nfunction safeFilesystemPath(path: string): string {\n return Array.from(path.slice(0, 256), (character) => {\n const code = character.charCodeAt(0);\n return code < 0x20 || code === 0x7f ? \"?\" : character;\n }).join(\"\");\n}\n\nasync function selectedRuntimeFile(\n projectRoot: string,\n explicitFile?: string,\n): Promise<string | undefined> {\n const path = explicitFile ?? join(projectRoot, \"sevro.json\");\n const info = await selectedRuntimeStat(path, Boolean(explicitFile));\n if (!info) return undefined;\n if (!info.isFile() || info.size > 65536)\n throw new Error(\n \"invalid runtime configuration: expected a regular file up to 64 KiB\",\n );\n return path;\n}\n\nasync function selectedRuntimeStat(path: string, explicit: boolean) {\n try {\n return await lstat(path);\n } catch (cause) {\n if (!explicit && (cause as NodeJS.ErrnoException).code === \"ENOENT\")\n return undefined;\n throw new Error(\n runtimeFilesystemDiagnostic(cause) ?? \"invalid runtime configuration\",\n { cause },\n );\n }\n}\n\nasync function resolvedSeeds(\n seeds: RuntimeSeed[],\n environment: Record<string, string>,\n base: string,\n) {\n return Promise.all(\n seeds.map(async (seed) => {\n const roots = await declaredRuntimeRoots(\n [seed.source],\n environment,\n base,\n );\n requireRuntimeReadRoots(roots, []);\n const [source] = roots;\n if (!source) throw new Error(\"runtime seed source is missing\");\n return {\n source,\n target: seed.target,\n ...(seed.roles ? { roles: seed.roles } : {}),\n sha256: await runtimeSeedDigest(source),\n };\n }),\n );\n}\n\nasync function resolveRuntimeConfiguration(\n value: unknown,\n base: string,\n protectedRoots: string[],\n): Promise<RuntimePolicy> {\n assertRuntimeConfiguration(value);\n const environment = await resolvedRuntimeEnvironment(value);\n const optional = await optionalRuntimeRoots(\n value.filesystem?.optionalReadOnlyRoots ?? [],\n environment,\n base,\n protectedRoots,\n );\n const pathRoots = await runtimePathDirectories(environment.PATH);\n requireRuntimeReadRoots(pathRoots, protectedRoots);\n requireRuntimeReadRoots(optional.roots, protectedRoots);\n const discovery = await discoverRuntimeSupport(environment, protectedRoots);\n const readOnlyRoots = [\n ...optional.roots,\n ...discovery.sources.flatMap((source) => source.readOnlyRoots),\n ...pathRoots.filter((root) => !discovery.excludedPrefixes.includes(root)),\n ...(await declaredRuntimeRoots(\n configurationReadRoots(value),\n environment,\n base,\n )),\n ];\n requireRuntimeReadRoots(readOnlyRoots, protectedRoots);\n return {\n format: value.format,\n ...selectedRuntimeCapabilities(value),\n ...artifactConfiguration(value.runtime),\n environment,\n readOnlyRoots: [...new Set(readOnlyRoots)].sort(),\n discovery: discovery.sources,\n skippedOptionalReadOnlyRoots: optional.skipped,\n ...(await resolvedRuntimeCaches(value, environment, base, [\n ...protectedRoots,\n ...readOnlyRoots,\n ])),\n hooks: resolvedHooks(value.hooks),\n };\n}\n\nasync function resolvedRuntimeCaches(\n value: RuntimeConfiguration,\n environment: Record<string, string>,\n base: string,\n protectedRoots: string[],\n) {\n const seeds = await resolvedSeeds(\n configurationSeeds(value),\n environment,\n base,\n );\n const caches = await resolveSharedCaches(\n value.runtime?.sharedCacheDirectories ?? [],\n environment,\n base,\n [...protectedRoots, ...seeds.map((seed) => seed.source)],\n );\n return {\n seeds,\n ...(caches.length ? { sharedCacheDirectories: caches } : {}),\n };\n}\n\nfunction selectedRuntimeCapabilities(value: RuntimeConfiguration) {\n return {\n ...(value.network === undefined ? {} : { network: value.network }),\n ...(value.codexState === undefined ? {} : { codexState: value.codexState }),\n ...(value.nativeTranscripts === undefined\n ? {}\n : { nativeTranscripts: value.nativeTranscripts }),\n };\n}\n\nasync function resolvedRuntimeEnvironment(value: RuntimeConfiguration) {\n const { inherit, set } = configurationEnvironment(value);\n const environment = snapshotEnvironment(inherit, set);\n for (const [name, value] of Object.entries(environment)) {\n if (name === \"PATH\" && inherit.includes(name) && !Object.hasOwn(set, name))\n environment[name] = await runtimeInheritedPath(value);\n }\n return environment;\n}\n\nfunction configurationEnvironment(value: RuntimeConfiguration) {\n const environment = value.environment;\n return { inherit: environment?.inherit ?? [], set: environment?.set ?? {} };\n}\n\nfunction artifactConfiguration(runtime: RuntimeConfiguration[\"runtime\"]) {\n const directories = runtime?.artifactDirectories;\n if (directories === undefined) return {};\n return { artifactDirectories: directories };\n}\nfunction configurationReadRoots(value: RuntimeConfiguration): string[] {\n return value.filesystem?.readOnlyRoots ?? [];\n}\nfunction configurationSeeds(value: RuntimeConfiguration) {\n return value.runtime?.seedDirectories ?? [];\n}\n\nfunction resolvedHooks(hooks: RuntimeConfiguration[\"hooks\"]) {\n return {\n nativeGoal: hooks?.nativeGoal ?? false,\n plugins: hooks?.plugins ?? [],\n };\n}\n\nfunction requireRuntimeRoles(roles: RuntimeRole[], kind: string): void {\n if (\n !validRoleArray(roles) ||\n new Set(roles).size !== roles.length ||\n roles.some((role) => !RUNTIME_ROLES.includes(role))\n )\n throw new Error(`runtime ${kind} roles are invalid`);\n}\n\nexport function runtimeRoleSeeds(policy: RuntimePolicy, role: RuntimeRole) {\n return (policy.seeds ?? []).filter(\n (seed) => seed.roles?.includes(role) ?? role !== \"checks\",\n );\n}\n\nfunction validRoleArray(roles: unknown): roles is RuntimeRole[] {\n return Array.isArray(roles) && roles.length > 0;\n}\n\nexport function runtimeSeedSources(\n policy: RuntimePolicy | undefined,\n): string[] {\n return [\n ...(policy?.seedReadDenyRoots ?? []),\n ...(policy?.seeds ?? []).map((seed) => seed.source),\n ];\n}\n"]}
@@ -0,0 +1,65 @@
1
+ import { realpath } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { RuntimeMetadataQueryError } from "./query.js";
4
+ import { optionalRuntimeRoots, requireRuntimeReadRoots } from "./paths.js";
5
+ import { providerExecutable, query, requireProvider, } from "./discovery-providers.js";
6
+ export async function discoverApple(path, environment, sources, protectedRoots) {
7
+ const executable = await providerExecutable("xcode-select", path);
8
+ if (!executable)
9
+ return;
10
+ if (!(await selectedAppleShim(executable, path)))
11
+ return;
12
+ await requireProvider(executable, protectedRoots);
13
+ const directory = await selectedAppleDirectory(executable, environment);
14
+ if (directory === undefined)
15
+ return;
16
+ const support = await selectedDeveloperRoots(directory, protectedRoots);
17
+ requireRuntimeReadRoots(support.roots, []);
18
+ sources.push({
19
+ provider: "apple-developer",
20
+ executable,
21
+ readOnlyRoots: support.roots,
22
+ });
23
+ }
24
+ async function selectedDeveloperRoots(directory, protectedRoots) {
25
+ const support = await optionalRuntimeRoots([directory], {}, "/", protectedRoots);
26
+ if (support.skipped.length)
27
+ throw new Error("selected Apple developer directory is missing");
28
+ return support;
29
+ }
30
+ async function selectedAppleShim(provider, path) {
31
+ const providerDirectory = dirname(await realpath(provider));
32
+ for (const name of [
33
+ "git",
34
+ "python3",
35
+ "clang",
36
+ "clang++",
37
+ "cc",
38
+ "c++",
39
+ "xcrun",
40
+ "xcodebuild",
41
+ "swift",
42
+ "make",
43
+ "ar",
44
+ "ranlib",
45
+ ]) {
46
+ const executable = await providerExecutable(name, path);
47
+ if (executable && dirname(await realpath(executable)) === providerDirectory)
48
+ return true;
49
+ }
50
+ return false;
51
+ }
52
+ async function selectedAppleDirectory(executable, environment) {
53
+ try {
54
+ return await query(executable, "--print-path", environment);
55
+ }
56
+ catch (cause) {
57
+ const failure = cause.cause;
58
+ if (environment.DEVELOPER_DIR === undefined &&
59
+ failure instanceof RuntimeMetadataQueryError &&
60
+ failure.noActiveDeveloper)
61
+ return undefined;
62
+ throw cause;
63
+ }
64
+ }
65
+ //# sourceMappingURL=discovery-apple.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery-apple.js","sourceRoot":"","sources":["discovery-apple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,yBAAyB;AAC5C,OAAO,EAAE,OAAO,EAAE,kBAAkB;AACpC,OAAO,EAAE,yBAAyB,EAAE,mBAAgB;AACpD,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,mBAAgB;AACxE,OAAO,EACL,kBAAkB,EAClB,KAAK,EACL,eAAe,GAEhB,iCAA8B;AAE/B,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAY,EACZ,WAAmC,EACnC,OAAiC,EACjC,cAAwB;IAExB,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IAClE,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,IAAI,CAAC,CAAC,MAAM,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO;IACzD,MAAM,eAAe,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,MAAM,sBAAsB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACxE,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO;IACpC,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACxE,uBAAuB,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC;QACX,QAAQ,EAAE,iBAAiB;QAC3B,UAAU;QACV,aAAa,EAAE,OAAO,CAAC,KAAK;KAC7B,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,SAAiB,EACjB,cAAwB;IAExB,MAAM,OAAO,GAAG,MAAM,oBAAoB,CACxC,CAAC,SAAS,CAAC,EACX,EAAE,EACF,GAAG,EACH,cAAc,CACf,CAAC;IACF,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM;QACxB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,QAAgB,EAChB,IAAY;IAEZ,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5D,KAAK,MAAM,IAAI,IAAI;QACjB,KAAK;QACL,SAAS;QACT,OAAO;QACP,SAAS;QACT,IAAI;QACJ,KAAK;QACL,OAAO;QACP,YAAY;QACZ,OAAO;QACP,MAAM;QACN,IAAI;QACJ,QAAQ;KACT,EAAE,CAAC;QACF,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACxD,IAAI,UAAU,IAAI,OAAO,CAAC,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,iBAAiB;YACzE,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,UAAkB,EAClB,WAAmC;IAEnC,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,UAAU,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAI,KAAe,CAAC,KAAK,CAAC;QACvC,IACE,WAAW,CAAC,aAAa,KAAK,SAAS;YACvC,OAAO,YAAY,yBAAyB;YAC5C,OAAO,CAAC,iBAAiB;YAEzB,OAAO,SAAS,CAAC;QACnB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["import { realpath } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { RuntimeMetadataQueryError } from \"./query\";\nimport { optionalRuntimeRoots, requireRuntimeReadRoots } from \"./paths\";\nimport {\n providerExecutable,\n query,\n requireProvider,\n type RuntimeDiscoverySource,\n} from \"./discovery-providers\";\n\nexport async function discoverApple(\n path: string,\n environment: Record<string, string>,\n sources: RuntimeDiscoverySource[],\n protectedRoots: string[],\n) {\n const executable = await providerExecutable(\"xcode-select\", path);\n if (!executable) return;\n if (!(await selectedAppleShim(executable, path))) return;\n await requireProvider(executable, protectedRoots);\n const directory = await selectedAppleDirectory(executable, environment);\n if (directory === undefined) return;\n const support = await selectedDeveloperRoots(directory, protectedRoots);\n requireRuntimeReadRoots(support.roots, []);\n sources.push({\n provider: \"apple-developer\",\n executable,\n readOnlyRoots: support.roots,\n });\n}\n\nasync function selectedDeveloperRoots(\n directory: string,\n protectedRoots: string[],\n) {\n const support = await optionalRuntimeRoots(\n [directory],\n {},\n \"/\",\n protectedRoots,\n );\n if (support.skipped.length)\n throw new Error(\"selected Apple developer directory is missing\");\n return support;\n}\n\nasync function selectedAppleShim(\n provider: string,\n path: string,\n): Promise<boolean> {\n const providerDirectory = dirname(await realpath(provider));\n for (const name of [\n \"git\",\n \"python3\",\n \"clang\",\n \"clang++\",\n \"cc\",\n \"c++\",\n \"xcrun\",\n \"xcodebuild\",\n \"swift\",\n \"make\",\n \"ar\",\n \"ranlib\",\n ]) {\n const executable = await providerExecutable(name, path);\n if (executable && dirname(await realpath(executable)) === providerDirectory)\n return true;\n }\n return false;\n}\n\nasync function selectedAppleDirectory(\n executable: string,\n environment: Record<string, string>,\n) {\n try {\n return await query(executable, \"--print-path\", environment);\n } catch (cause) {\n const failure = (cause as Error).cause;\n if (\n environment.DEVELOPER_DIR === undefined &&\n failure instanceof RuntimeMetadataQueryError &&\n failure.noActiveDeveloper\n )\n return undefined;\n throw cause;\n }\n}\n"]}
@@ -0,0 +1,37 @@
1
+ import { access, realpath } from "node:fs/promises";
2
+ import { constants } from "node:fs";
3
+ import { delimiter, isAbsolute, join } from "node:path";
4
+ import { runtimeMetadataQuery } from "./query.js";
5
+ import { requireRuntimeReadRoots } from "./paths.js";
6
+ import { containsControl } from "../value-guards.js";
7
+ export async function providerExecutable(name, path) {
8
+ for (const entry of path.split(delimiter)) {
9
+ const executable = join(entry, name);
10
+ try {
11
+ await access(executable, constants.X_OK);
12
+ return executable;
13
+ }
14
+ catch (cause) {
15
+ const code = cause.code;
16
+ if (code !== "ENOENT" && code !== "EACCES")
17
+ throw cause;
18
+ }
19
+ }
20
+ return undefined;
21
+ }
22
+ export async function query(executable, argument, environment) {
23
+ try {
24
+ const value = (await runtimeMetadataQuery(executable, argument, environment)).trim();
25
+ if (!isAbsolute(value) || containsControl(value))
26
+ throw new Error("expected one absolute metadata path");
27
+ return value;
28
+ }
29
+ catch (cause) {
30
+ const reason = cause instanceof Error ? cause.message : "query unavailable";
31
+ throw new Error(`runtime discovery query failed: ${executable} ${argument}: ${reason} (3 second / 8 KiB bound)`, { cause });
32
+ }
33
+ }
34
+ export async function requireProvider(executable, protectedRoots) {
35
+ requireRuntimeReadRoots([executable, await realpath(executable)], protectedRoots);
36
+ }
37
+ //# sourceMappingURL=discovery-providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery-providers.js","sourceRoot":"","sources":["discovery-providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,yBAAyB;AACpD,OAAO,EAAE,SAAS,EAAE,gBAAgB;AACpC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,kBAAkB;AACxD,OAAO,EAAE,oBAAoB,EAAE,mBAAgB;AAC/C,OAAO,EAAE,uBAAuB,EAAE,mBAAgB;AAClD,OAAO,EAAE,eAAe,EAAE,2BAAwB;AAQlD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAY,EAAE,IAAY;IACjE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;YACzC,OAAO,UAAU,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;YACnD,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,UAAkB,EAClB,QAAgB,EAChB,WAAmC;IAEnC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,CACZ,MAAM,oBAAoB,CAAC,UAAU,EAAE,QAAQ,EAAE,WAAW,CAAC,CAC9D,CAAC,IAAI,EAAE,CAAC;QACT,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,eAAe,CAAC,KAAK,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;QAC5E,MAAM,IAAI,KAAK,CACb,mCAAmC,UAAU,IAAI,QAAQ,KAAK,MAAM,2BAA2B,EAC/F,EAAE,KAAK,EAAE,CACV,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,cAAwB;IAExB,uBAAuB,CACrB,CAAC,UAAU,EAAE,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC,EACxC,cAAc,CACf,CAAC;AACJ,CAAC","sourcesContent":["import { access, realpath } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { delimiter, isAbsolute, join } from \"node:path\";\nimport { runtimeMetadataQuery } from \"./query\";\nimport { requireRuntimeReadRoots } from \"./paths\";\nimport { containsControl } from \"../value-guards\";\n\nexport interface RuntimeDiscoverySource {\n provider: \"homebrew\" | \"apple-developer\";\n executable: string;\n readOnlyRoots: string[];\n}\n\nexport async function providerExecutable(name: string, path: string) {\n for (const entry of path.split(delimiter)) {\n const executable = join(entry, name);\n try {\n await access(executable, constants.X_OK);\n return executable;\n } catch (cause) {\n const code = (cause as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\" && code !== \"EACCES\") throw cause;\n }\n }\n return undefined;\n}\n\nexport async function query(\n executable: string,\n argument: string,\n environment: Record<string, string>,\n) {\n try {\n const value = (\n await runtimeMetadataQuery(executable, argument, environment)\n ).trim();\n if (!isAbsolute(value) || containsControl(value))\n throw new Error(\"expected one absolute metadata path\");\n return value;\n } catch (cause) {\n const reason = cause instanceof Error ? cause.message : \"query unavailable\";\n throw new Error(\n `runtime discovery query failed: ${executable} ${argument}: ${reason} (3 second / 8 KiB bound)`,\n { cause },\n );\n }\n}\n\nexport async function requireProvider(\n executable: string,\n protectedRoots: string[],\n) {\n requireRuntimeReadRoots(\n [executable, await realpath(executable)],\n protectedRoots,\n );\n}\n"]}
@@ -0,0 +1,40 @@
1
+ import { realpath } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { insideRuntimeRoot, optionalRuntimeRoots, requireRuntimeReadRoots, } from "./paths.js";
4
+ import { providerExecutable, query, requireProvider, } from "./discovery-providers.js";
5
+ async function homebrew(executable, environment, protectedRoots) {
6
+ const prefix = await query(executable, "--prefix", environment);
7
+ const canonicalPrefix = await realpath(prefix);
8
+ requireRuntimeReadRoots([prefix, canonicalPrefix], []);
9
+ const cellar = await query(executable, "--cellar", environment);
10
+ const support = await optionalRuntimeRoots([cellar, join(prefix, "opt"), join(prefix, "etc")], {}, "/", protectedRoots);
11
+ requireRuntimeReadRoots(support.roots, []);
12
+ if (support.roots.some((root) => [prefix, canonicalPrefix].some((installation) => insideRuntimeRoot(root, installation))))
13
+ throw new Error("runtime Homebrew metadata grants whole installation prefix");
14
+ return { prefix, roots: support.roots };
15
+ }
16
+ /** Query only providers selected by the operator's declared PATH. */
17
+ export async function discoverRuntimeSupport(environment, protectedRoots) {
18
+ const path = environment.PATH;
19
+ const sources = [];
20
+ const excludedPrefixes = [];
21
+ if (path === undefined)
22
+ return { sources, excludedPrefixes };
23
+ const brew = await providerExecutable("brew", path);
24
+ if (brew) {
25
+ await requireProvider(brew, protectedRoots);
26
+ const support = await homebrew(brew, environment, protectedRoots);
27
+ excludedPrefixes.push(support.prefix, await realpath(support.prefix));
28
+ sources.push({
29
+ provider: "homebrew",
30
+ executable: brew,
31
+ readOnlyRoots: support.roots,
32
+ });
33
+ }
34
+ if (process.platform === "darwin") {
35
+ const { discoverApple } = await import("./discovery-apple.js");
36
+ await discoverApple(path, environment, sources, protectedRoots);
37
+ }
38
+ return { sources, excludedPrefixes };
39
+ }
40
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,yBAAyB;AAC5C,OAAO,EAAE,IAAI,EAAE,kBAAkB;AACjC,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,GACxB,mBAAgB;AACjB,OAAO,EACL,kBAAkB,EAClB,KAAK,EACL,eAAe,GAEhB,iCAA8B;AAG/B,KAAK,UAAU,QAAQ,CACrB,UAAkB,EAClB,WAAmC,EACnC,cAAwB;IAExB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAChE,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/C,uBAAuB,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,MAAM,oBAAoB,CACxC,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,EAClD,EAAE,EACF,GAAG,EACH,cAAc,CACf,CAAC;IACF,uBAAuB,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3C,IACE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAC1B,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CAC9C,iBAAiB,CAAC,IAAI,EAAE,YAAY,CAAC,CACtC,CACF;QAED,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAC;IACJ,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;AAC1C,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,WAAmC,EACnC,cAAwB;IAExB,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC;IAC9B,MAAM,OAAO,GAA6B,EAAE,CAAC;IAC7C,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC7D,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACpD,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,eAAe,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;QAClE,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC;YACX,QAAQ,EAAE,UAAU;YACpB,UAAU,EAAE,IAAI;YAChB,aAAa,EAAE,OAAO,CAAC,KAAK;SAC7B,CAAC,CAAC;IACL,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,wBAAqB,CAAC;QAC5D,MAAM,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;AACvC,CAAC","sourcesContent":["import { realpath } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n insideRuntimeRoot,\n optionalRuntimeRoots,\n requireRuntimeReadRoots,\n} from \"./paths\";\nimport {\n providerExecutable,\n query,\n requireProvider,\n type RuntimeDiscoverySource,\n} from \"./discovery-providers\";\nexport type { RuntimeDiscoverySource } from \"./discovery-providers\";\n\nasync function homebrew(\n executable: string,\n environment: Record<string, string>,\n protectedRoots: string[],\n) {\n const prefix = await query(executable, \"--prefix\", environment);\n const canonicalPrefix = await realpath(prefix);\n requireRuntimeReadRoots([prefix, canonicalPrefix], []);\n const cellar = await query(executable, \"--cellar\", environment);\n const support = await optionalRuntimeRoots(\n [cellar, join(prefix, \"opt\"), join(prefix, \"etc\")],\n {},\n \"/\",\n protectedRoots,\n );\n requireRuntimeReadRoots(support.roots, []);\n if (\n support.roots.some((root) =>\n [prefix, canonicalPrefix].some((installation) =>\n insideRuntimeRoot(root, installation),\n ),\n )\n )\n throw new Error(\n \"runtime Homebrew metadata grants whole installation prefix\",\n );\n return { prefix, roots: support.roots };\n}\n\n/** Query only providers selected by the operator's declared PATH. */\nexport async function discoverRuntimeSupport(\n environment: Record<string, string>,\n protectedRoots: string[],\n) {\n const path = environment.PATH;\n const sources: RuntimeDiscoverySource[] = [];\n const excludedPrefixes: string[] = [];\n if (path === undefined) return { sources, excludedPrefixes };\n const brew = await providerExecutable(\"brew\", path);\n if (brew) {\n await requireProvider(brew, protectedRoots);\n const support = await homebrew(brew, environment, protectedRoots);\n excludedPrefixes.push(support.prefix, await realpath(support.prefix));\n sources.push({\n provider: \"homebrew\",\n executable: brew,\n readOnlyRoots: support.roots,\n });\n }\n if (process.platform === \"darwin\") {\n const { discoverApple } = await import(\"./discovery-apple\");\n await discoverApple(path, environment, sources, protectedRoots);\n }\n return { sources, excludedPrefixes };\n}\n"]}
@@ -0,0 +1,81 @@
1
+ import { spawn } from "../runtime-process.js";
2
+ import { readFile, readdir, writeFile } from "node:fs/promises";
3
+ import { basename, dirname, join } from "node:path";
4
+ import { isRecord } from "../value-guards.js";
5
+ export async function hookExecutions(receipts) {
6
+ return Promise.all((await readdir(receipts))
7
+ .filter((name) => name.startsWith("call."))
8
+ .map(async (name) => {
9
+ try {
10
+ const value = JSON.parse(await readFile(join(receipts, name), "utf8"));
11
+ return isRecord(value) ? value : { status: "unknown" };
12
+ }
13
+ catch {
14
+ return { status: "unknown" };
15
+ }
16
+ }));
17
+ }
18
+ async function processOutput(argv) {
19
+ const child = spawn(argv, { stdout: "pipe", stderr: "ignore" });
20
+ const output = await new Response(child.stdout).text();
21
+ await child.exited;
22
+ if (Buffer.byteLength(output) > 1024 * 1024)
23
+ throw new Error("hook process ownership exceeds size limit");
24
+ return output;
25
+ }
26
+ function ownedWrapper(execution, receipts) {
27
+ return (validProcessId(execution.pid) &&
28
+ typeof execution.wrapper === "string" &&
29
+ dirname(execution.wrapper) === dirname(receipts) &&
30
+ /^hook-[0-9]+\.sh$/.test(basename(execution.wrapper)));
31
+ }
32
+ function validProcessId(pid) {
33
+ return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 1;
34
+ }
35
+ function processChildren(table, root) {
36
+ const pairs = table
37
+ .trim()
38
+ .split("\n")
39
+ .map((line) => line.trim().split(/\s+/).map(Number));
40
+ const pending = [root], children = [];
41
+ while (pending.length) {
42
+ const parent = pending.pop();
43
+ const found = pairs
44
+ .filter((pair) => pair[1] === parent)
45
+ .map((pair) => pair[0])
46
+ .filter((pid) => pid !== undefined);
47
+ pending.push(...found);
48
+ children.push(...found);
49
+ }
50
+ return children;
51
+ }
52
+ function stopProcess(pid) {
53
+ try {
54
+ process.kill(pid, "SIGKILL");
55
+ }
56
+ catch {
57
+ /* The owned process may already have exited. */
58
+ }
59
+ }
60
+ /** Stop only processes still bound to a runner-owned private hook wrapper. */
61
+ export async function releaseHookProcesses(receipts) {
62
+ await writeFile(join(receipts, "stopped"), "stopped\n", { mode: 0o600 });
63
+ for (const execution of await hookExecutions(receipts)) {
64
+ if (!ownedWrapper(execution, receipts))
65
+ continue;
66
+ const command = await processOutput([
67
+ "/bin/ps",
68
+ "-p",
69
+ String(execution.pid),
70
+ "-o",
71
+ "command=",
72
+ ]);
73
+ if (!command.includes(execution.wrapper))
74
+ continue;
75
+ const children = processChildren(await processOutput(["/bin/ps", "-axo", "pid=,ppid="]), execution.pid);
76
+ children.reverse().forEach(stopProcess);
77
+ await new Promise((resolve) => setTimeout(resolve, 50));
78
+ stopProcess(execution.pid);
79
+ }
80
+ }
81
+ //# sourceMappingURL=hook-processes.js.map