@prismatic-io/lux 0.0.1

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 (636) hide show
  1. package/LICENSE +21 -0
  2. package/lib/answerers/claude-code/index.d.ts +17 -0
  3. package/lib/answerers/claude-code/index.d.ts.map +1 -0
  4. package/lib/answerers/claude-code/index.js +280 -0
  5. package/lib/answerers/claude-code/index.js.map +1 -0
  6. package/lib/answerers/persona/index.d.ts +40 -0
  7. package/lib/answerers/persona/index.d.ts.map +1 -0
  8. package/lib/answerers/persona/index.js +265 -0
  9. package/lib/answerers/persona/index.js.map +1 -0
  10. package/lib/answerers/scripted/index.d.ts +8 -0
  11. package/lib/answerers/scripted/index.d.ts.map +1 -0
  12. package/lib/answerers/scripted/index.js +163 -0
  13. package/lib/answerers/scripted/index.js.map +1 -0
  14. package/lib/answerers/shared.d.ts +13 -0
  15. package/lib/answerers/shared.d.ts.map +1 -0
  16. package/lib/answerers/shared.js +17 -0
  17. package/lib/answerers/shared.js.map +1 -0
  18. package/lib/answerers/terminal/index.d.ts +9 -0
  19. package/lib/answerers/terminal/index.d.ts.map +1 -0
  20. package/lib/answerers/terminal/index.js +97 -0
  21. package/lib/answerers/terminal/index.js.map +1 -0
  22. package/lib/assertions/core/command-exits-zero.d.ts +21 -0
  23. package/lib/assertions/core/command-exits-zero.d.ts.map +1 -0
  24. package/lib/assertions/core/command-exits-zero.js +87 -0
  25. package/lib/assertions/core/command-exits-zero.js.map +1 -0
  26. package/lib/assertions/core/event-checks.d.ts +57 -0
  27. package/lib/assertions/core/event-checks.d.ts.map +1 -0
  28. package/lib/assertions/core/event-checks.js +123 -0
  29. package/lib/assertions/core/event-checks.js.map +1 -0
  30. package/lib/assertions/core/file-checks.d.ts +103 -0
  31. package/lib/assertions/core/file-checks.d.ts.map +1 -0
  32. package/lib/assertions/core/file-checks.js +288 -0
  33. package/lib/assertions/core/file-checks.js.map +1 -0
  34. package/lib/assertions/core/helpers.d.ts +66 -0
  35. package/lib/assertions/core/helpers.d.ts.map +1 -0
  36. package/lib/assertions/core/helpers.js +170 -0
  37. package/lib/assertions/core/helpers.js.map +1 -0
  38. package/lib/assertions/core/index.d.ts +15 -0
  39. package/lib/assertions/core/index.d.ts.map +1 -0
  40. package/lib/assertions/core/index.js +56 -0
  41. package/lib/assertions/core/index.js.map +1 -0
  42. package/lib/assertions/core/json-pointer-equals.d.ts +19 -0
  43. package/lib/assertions/core/json-pointer-equals.d.ts.map +1 -0
  44. package/lib/assertions/core/json-pointer-equals.js +71 -0
  45. package/lib/assertions/core/json-pointer-equals.js.map +1 -0
  46. package/lib/assertions/core/output-checks.d.ts +46 -0
  47. package/lib/assertions/core/output-checks.d.ts.map +1 -0
  48. package/lib/assertions/core/output-checks.js +121 -0
  49. package/lib/assertions/core/output-checks.js.map +1 -0
  50. package/lib/assertions/core/predicate.d.ts +14 -0
  51. package/lib/assertions/core/predicate.d.ts.map +1 -0
  52. package/lib/assertions/core/predicate.js +55 -0
  53. package/lib/assertions/core/predicate.js.map +1 -0
  54. package/lib/assertions/core/resource-checks.d.ts +71 -0
  55. package/lib/assertions/core/resource-checks.d.ts.map +1 -0
  56. package/lib/assertions/core/resource-checks.js +159 -0
  57. package/lib/assertions/core/resource-checks.js.map +1 -0
  58. package/lib/assertions/core/safe-regex.d.ts +23 -0
  59. package/lib/assertions/core/safe-regex.d.ts.map +1 -0
  60. package/lib/assertions/core/safe-regex.js +102 -0
  61. package/lib/assertions/core/safe-regex.js.map +1 -0
  62. package/lib/assertions/core/tool-called-with.d.ts +21 -0
  63. package/lib/assertions/core/tool-called-with.d.ts.map +1 -0
  64. package/lib/assertions/core/tool-called-with.js +69 -0
  65. package/lib/assertions/core/tool-called-with.js.map +1 -0
  66. package/lib/assertions/core/tool-calls.d.ts +22 -0
  67. package/lib/assertions/core/tool-calls.d.ts.map +1 -0
  68. package/lib/assertions/core/tool-calls.js +17 -0
  69. package/lib/assertions/core/tool-calls.js.map +1 -0
  70. package/lib/assertions/core/tool-invocation.d.ts +36 -0
  71. package/lib/assertions/core/tool-invocation.d.ts.map +1 -0
  72. package/lib/assertions/core/tool-invocation.js +170 -0
  73. package/lib/assertions/core/tool-invocation.js.map +1 -0
  74. package/lib/assertions/core/tool-result-checks.d.ts +59 -0
  75. package/lib/assertions/core/tool-result-checks.d.ts.map +1 -0
  76. package/lib/assertions/core/tool-result-checks.js +193 -0
  77. package/lib/assertions/core/tool-result-checks.js.map +1 -0
  78. package/lib/assertions/mcp/discovery-checks.d.ts +36 -0
  79. package/lib/assertions/mcp/discovery-checks.d.ts.map +1 -0
  80. package/lib/assertions/mcp/discovery-checks.js +122 -0
  81. package/lib/assertions/mcp/discovery-checks.js.map +1 -0
  82. package/lib/assertions/mcp/index.d.ts +10 -0
  83. package/lib/assertions/mcp/index.d.ts.map +1 -0
  84. package/lib/assertions/mcp/index.js +25 -0
  85. package/lib/assertions/mcp/index.js.map +1 -0
  86. package/lib/assertions/rubric/index.d.ts +104 -0
  87. package/lib/assertions/rubric/index.d.ts.map +1 -0
  88. package/lib/assertions/rubric/index.js +191 -0
  89. package/lib/assertions/rubric/index.js.map +1 -0
  90. package/lib/assertions/rubric/internal.d.ts +14 -0
  91. package/lib/assertions/rubric/internal.d.ts.map +1 -0
  92. package/lib/assertions/rubric/internal.js +335 -0
  93. package/lib/assertions/rubric/internal.js.map +1 -0
  94. package/lib/authoring.d.ts +3 -0
  95. package/lib/authoring.d.ts.map +1 -0
  96. package/lib/authoring.js +3 -0
  97. package/lib/authoring.js.map +1 -0
  98. package/lib/cli/bin.d.ts +3 -0
  99. package/lib/cli/bin.d.ts.map +1 -0
  100. package/lib/cli/bin.js +15 -0
  101. package/lib/cli/bin.js.map +1 -0
  102. package/lib/cli/command-runtime.d.ts +5 -0
  103. package/lib/cli/command-runtime.d.ts.map +1 -0
  104. package/lib/cli/command-runtime.js +30 -0
  105. package/lib/cli/command-runtime.js.map +1 -0
  106. package/lib/cli/init.d.ts +21 -0
  107. package/lib/cli/init.d.ts.map +1 -0
  108. package/lib/cli/init.js +340 -0
  109. package/lib/cli/init.js.map +1 -0
  110. package/lib/cli/program.d.ts +22 -0
  111. package/lib/cli/program.d.ts.map +1 -0
  112. package/lib/cli/program.js +757 -0
  113. package/lib/cli/program.js.map +1 -0
  114. package/lib/cli/render/format.d.ts +14 -0
  115. package/lib/cli/render/format.d.ts.map +1 -0
  116. package/lib/cli/render/format.js +71 -0
  117. package/lib/cli/render/format.js.map +1 -0
  118. package/lib/cli/render/reporter.d.ts +73 -0
  119. package/lib/cli/render/reporter.d.ts.map +1 -0
  120. package/lib/cli/render/reporter.js +519 -0
  121. package/lib/cli/render/reporter.js.map +1 -0
  122. package/lib/cli/render/tty.d.ts +77 -0
  123. package/lib/cli/render/tty.d.ts.map +1 -0
  124. package/lib/cli/render/tty.js +283 -0
  125. package/lib/cli/render/tty.js.map +1 -0
  126. package/lib/cli/run-options.d.ts +27 -0
  127. package/lib/cli/run-options.d.ts.map +1 -0
  128. package/lib/cli/run-options.js +58 -0
  129. package/lib/cli/run-options.js.map +1 -0
  130. package/lib/cli/skills.d.ts +38 -0
  131. package/lib/cli/skills.d.ts.map +1 -0
  132. package/lib/cli/skills.js +84 -0
  133. package/lib/cli/skills.js.map +1 -0
  134. package/lib/core/annotation.d.ts +56 -0
  135. package/lib/core/annotation.d.ts.map +1 -0
  136. package/lib/core/annotation.js +92 -0
  137. package/lib/core/annotation.js.map +1 -0
  138. package/lib/core/answerer.d.ts +68 -0
  139. package/lib/core/answerer.d.ts.map +1 -0
  140. package/lib/core/answerer.js +17 -0
  141. package/lib/core/answerer.js.map +1 -0
  142. package/lib/core/artifact-evidence.d.ts +50 -0
  143. package/lib/core/artifact-evidence.d.ts.map +1 -0
  144. package/lib/core/artifact-evidence.js +185 -0
  145. package/lib/core/artifact-evidence.js.map +1 -0
  146. package/lib/core/artifact-snapshot.d.ts +37 -0
  147. package/lib/core/artifact-snapshot.d.ts.map +1 -0
  148. package/lib/core/artifact-snapshot.js +339 -0
  149. package/lib/core/artifact-snapshot.js.map +1 -0
  150. package/lib/core/assertion.d.ts +129 -0
  151. package/lib/core/assertion.d.ts.map +1 -0
  152. package/lib/core/assertion.js +75 -0
  153. package/lib/core/assertion.js.map +1 -0
  154. package/lib/core/case.d.ts +79 -0
  155. package/lib/core/case.d.ts.map +1 -0
  156. package/lib/core/case.js +90 -0
  157. package/lib/core/case.js.map +1 -0
  158. package/lib/core/conversation-turn.d.ts +23 -0
  159. package/lib/core/conversation-turn.d.ts.map +1 -0
  160. package/lib/core/conversation-turn.js +31 -0
  161. package/lib/core/conversation-turn.js.map +1 -0
  162. package/lib/core/driver.d.ts +64 -0
  163. package/lib/core/driver.d.ts.map +1 -0
  164. package/lib/core/driver.js +18 -0
  165. package/lib/core/driver.js.map +1 -0
  166. package/lib/core/emitter.d.ts +20 -0
  167. package/lib/core/emitter.d.ts.map +1 -0
  168. package/lib/core/emitter.js +34 -0
  169. package/lib/core/emitter.js.map +1 -0
  170. package/lib/core/events.d.ts +202 -0
  171. package/lib/core/events.d.ts.map +1 -0
  172. package/lib/core/events.js +107 -0
  173. package/lib/core/events.js.map +1 -0
  174. package/lib/core/exec.d.ts +82 -0
  175. package/lib/core/exec.d.ts.map +1 -0
  176. package/lib/core/exec.js +168 -0
  177. package/lib/core/exec.js.map +1 -0
  178. package/lib/core/experiment.d.ts +285 -0
  179. package/lib/core/experiment.d.ts.map +1 -0
  180. package/lib/core/experiment.js +389 -0
  181. package/lib/core/experiment.js.map +1 -0
  182. package/lib/core/glob.d.ts +3 -0
  183. package/lib/core/glob.d.ts.map +1 -0
  184. package/lib/core/glob.js +32 -0
  185. package/lib/core/glob.js.map +1 -0
  186. package/lib/core/hash.d.ts +8 -0
  187. package/lib/core/hash.d.ts.map +1 -0
  188. package/lib/core/hash.js +214 -0
  189. package/lib/core/hash.js.map +1 -0
  190. package/lib/core/index.d.ts +29 -0
  191. package/lib/core/index.d.ts.map +1 -0
  192. package/lib/core/index.js +29 -0
  193. package/lib/core/index.js.map +1 -0
  194. package/lib/core/lifecycle-fixtures.d.ts +20 -0
  195. package/lib/core/lifecycle-fixtures.d.ts.map +1 -0
  196. package/lib/core/lifecycle-fixtures.js +109 -0
  197. package/lib/core/lifecycle-fixtures.js.map +1 -0
  198. package/lib/core/lifecycle-hooks.d.ts +52 -0
  199. package/lib/core/lifecycle-hooks.d.ts.map +1 -0
  200. package/lib/core/lifecycle-hooks.js +42 -0
  201. package/lib/core/lifecycle-hooks.js.map +1 -0
  202. package/lib/core/mcp-events.d.ts +44 -0
  203. package/lib/core/mcp-events.d.ts.map +1 -0
  204. package/lib/core/mcp-events.js +23 -0
  205. package/lib/core/mcp-events.js.map +1 -0
  206. package/lib/core/model-cli.d.ts +57 -0
  207. package/lib/core/model-cli.d.ts.map +1 -0
  208. package/lib/core/model-cli.js +237 -0
  209. package/lib/core/model-cli.js.map +1 -0
  210. package/lib/core/observer.d.ts +31 -0
  211. package/lib/core/observer.d.ts.map +1 -0
  212. package/lib/core/observer.js +25 -0
  213. package/lib/core/observer.js.map +1 -0
  214. package/lib/core/platform-process.d.ts +33 -0
  215. package/lib/core/platform-process.d.ts.map +1 -0
  216. package/lib/core/platform-process.js +214 -0
  217. package/lib/core/platform-process.js.map +1 -0
  218. package/lib/core/registry.d.ts +22 -0
  219. package/lib/core/registry.d.ts.map +1 -0
  220. package/lib/core/registry.js +45 -0
  221. package/lib/core/registry.js.map +1 -0
  222. package/lib/core/rubric.d.ts +18 -0
  223. package/lib/core/rubric.d.ts.map +1 -0
  224. package/lib/core/rubric.js +49 -0
  225. package/lib/core/rubric.js.map +1 -0
  226. package/lib/core/run.d.ts +419 -0
  227. package/lib/core/run.d.ts.map +1 -0
  228. package/lib/core/run.js +126 -0
  229. package/lib/core/run.js.map +1 -0
  230. package/lib/core/statistics.d.ts +39 -0
  231. package/lib/core/statistics.d.ts.map +1 -0
  232. package/lib/core/statistics.js +163 -0
  233. package/lib/core/statistics.js.map +1 -0
  234. package/lib/core/subject.d.ts +4 -0
  235. package/lib/core/subject.d.ts.map +1 -0
  236. package/lib/core/subject.js +46 -0
  237. package/lib/core/subject.js.map +1 -0
  238. package/lib/core/tool-events.d.ts +69 -0
  239. package/lib/core/tool-events.d.ts.map +1 -0
  240. package/lib/core/tool-events.js +242 -0
  241. package/lib/core/tool-events.js.map +1 -0
  242. package/lib/core/usage.d.ts +78 -0
  243. package/lib/core/usage.d.ts.map +1 -0
  244. package/lib/core/usage.js +104 -0
  245. package/lib/core/usage.js.map +1 -0
  246. package/lib/core/wire.d.ts +83 -0
  247. package/lib/core/wire.d.ts.map +1 -0
  248. package/lib/core/wire.js +101 -0
  249. package/lib/core/wire.js.map +1 -0
  250. package/lib/core/zod.d.ts +10 -0
  251. package/lib/core/zod.d.ts.map +1 -0
  252. package/lib/core/zod.js +18 -0
  253. package/lib/core/zod.js.map +1 -0
  254. package/lib/drivers/claude-code/index.d.ts +55 -0
  255. package/lib/drivers/claude-code/index.d.ts.map +1 -0
  256. package/lib/drivers/claude-code/index.js +779 -0
  257. package/lib/drivers/claude-code/index.js.map +1 -0
  258. package/lib/drivers/claude-code/parse-events.d.ts +46 -0
  259. package/lib/drivers/claude-code/parse-events.d.ts.map +1 -0
  260. package/lib/drivers/claude-code/parse-events.js +387 -0
  261. package/lib/drivers/claude-code/parse-events.js.map +1 -0
  262. package/lib/drivers/codex/app-events.d.ts +16 -0
  263. package/lib/drivers/codex/app-events.d.ts.map +1 -0
  264. package/lib/drivers/codex/app-events.js +184 -0
  265. package/lib/drivers/codex/app-events.js.map +1 -0
  266. package/lib/drivers/codex/config.d.ts +55 -0
  267. package/lib/drivers/codex/config.d.ts.map +1 -0
  268. package/lib/drivers/codex/config.js +125 -0
  269. package/lib/drivers/codex/config.js.map +1 -0
  270. package/lib/drivers/codex/index.d.ts +8 -0
  271. package/lib/drivers/codex/index.d.ts.map +1 -0
  272. package/lib/drivers/codex/index.js +904 -0
  273. package/lib/drivers/codex/index.js.map +1 -0
  274. package/lib/drivers/mcp/index.d.ts +52 -0
  275. package/lib/drivers/mcp/index.d.ts.map +1 -0
  276. package/lib/drivers/mcp/index.js +282 -0
  277. package/lib/drivers/mcp/index.js.map +1 -0
  278. package/lib/drivers/mcp/transport.d.ts +50 -0
  279. package/lib/drivers/mcp/transport.d.ts.map +1 -0
  280. package/lib/drivers/mcp/transport.js +190 -0
  281. package/lib/drivers/mcp/transport.js.map +1 -0
  282. package/lib/drivers/shared/artifacts.d.ts +4 -0
  283. package/lib/drivers/shared/artifacts.d.ts.map +1 -0
  284. package/lib/drivers/shared/artifacts.js +81 -0
  285. package/lib/drivers/shared/artifacts.js.map +1 -0
  286. package/lib/drivers/shared/secure-copy.d.ts +2 -0
  287. package/lib/drivers/shared/secure-copy.d.ts.map +1 -0
  288. package/lib/drivers/shared/secure-copy.js +35 -0
  289. package/lib/drivers/shared/secure-copy.js.map +1 -0
  290. package/lib/drivers/subprocess/index.d.ts +24 -0
  291. package/lib/drivers/subprocess/index.d.ts.map +1 -0
  292. package/lib/drivers/subprocess/index.js +451 -0
  293. package/lib/drivers/subprocess/index.js.map +1 -0
  294. package/lib/index.d.ts +40 -0
  295. package/lib/index.d.ts.map +1 -0
  296. package/lib/index.js +48 -0
  297. package/lib/index.js.map +1 -0
  298. package/lib/optimization/reflective.d.ts +27 -0
  299. package/lib/optimization/reflective.d.ts.map +1 -0
  300. package/lib/optimization/reflective.js +257 -0
  301. package/lib/optimization/reflective.js.map +1 -0
  302. package/lib/orchestrator/annotation-loader.d.ts +65 -0
  303. package/lib/orchestrator/annotation-loader.d.ts.map +1 -0
  304. package/lib/orchestrator/annotation-loader.js +73 -0
  305. package/lib/orchestrator/annotation-loader.js.map +1 -0
  306. package/lib/orchestrator/annotation-store.d.ts +3 -0
  307. package/lib/orchestrator/annotation-store.d.ts.map +1 -0
  308. package/lib/orchestrator/annotation-store.js +100 -0
  309. package/lib/orchestrator/annotation-store.js.map +1 -0
  310. package/lib/orchestrator/authored-dependencies.d.ts +3 -0
  311. package/lib/orchestrator/authored-dependencies.d.ts.map +1 -0
  312. package/lib/orchestrator/authored-dependencies.js +146 -0
  313. package/lib/orchestrator/authored-dependencies.js.map +1 -0
  314. package/lib/orchestrator/campaign-lifecycle.d.ts +105 -0
  315. package/lib/orchestrator/campaign-lifecycle.d.ts.map +1 -0
  316. package/lib/orchestrator/campaign-lifecycle.js +141 -0
  317. package/lib/orchestrator/campaign-lifecycle.js.map +1 -0
  318. package/lib/orchestrator/candidate-integrity.d.ts +4 -0
  319. package/lib/orchestrator/candidate-integrity.d.ts.map +1 -0
  320. package/lib/orchestrator/candidate-integrity.js +14 -0
  321. package/lib/orchestrator/candidate-integrity.js.map +1 -0
  322. package/lib/orchestrator/candidates.d.ts +13 -0
  323. package/lib/orchestrator/candidates.d.ts.map +1 -0
  324. package/lib/orchestrator/candidates.js +577 -0
  325. package/lib/orchestrator/candidates.js.map +1 -0
  326. package/lib/orchestrator/compare.d.ts +80 -0
  327. package/lib/orchestrator/compare.d.ts.map +1 -0
  328. package/lib/orchestrator/compare.js +270 -0
  329. package/lib/orchestrator/compare.js.map +1 -0
  330. package/lib/orchestrator/comparison-identity.d.ts +10 -0
  331. package/lib/orchestrator/comparison-identity.d.ts.map +1 -0
  332. package/lib/orchestrator/comparison-identity.js +39 -0
  333. package/lib/orchestrator/comparison-identity.js.map +1 -0
  334. package/lib/orchestrator/config.d.ts +121 -0
  335. package/lib/orchestrator/config.d.ts.map +1 -0
  336. package/lib/orchestrator/config.js +176 -0
  337. package/lib/orchestrator/config.js.map +1 -0
  338. package/lib/orchestrator/content-bound-json.d.ts +5 -0
  339. package/lib/orchestrator/content-bound-json.d.ts.map +1 -0
  340. package/lib/orchestrator/content-bound-json.js +59 -0
  341. package/lib/orchestrator/content-bound-json.js.map +1 -0
  342. package/lib/orchestrator/discover.d.ts +45 -0
  343. package/lib/orchestrator/discover.d.ts.map +1 -0
  344. package/lib/orchestrator/discover.js +98 -0
  345. package/lib/orchestrator/discover.js.map +1 -0
  346. package/lib/orchestrator/doctor.d.ts +141 -0
  347. package/lib/orchestrator/doctor.d.ts.map +1 -0
  348. package/lib/orchestrator/doctor.js +525 -0
  349. package/lib/orchestrator/doctor.js.map +1 -0
  350. package/lib/orchestrator/driver-session.d.ts +177 -0
  351. package/lib/orchestrator/driver-session.d.ts.map +1 -0
  352. package/lib/orchestrator/driver-session.js +396 -0
  353. package/lib/orchestrator/driver-session.js.map +1 -0
  354. package/lib/orchestrator/evaluator-identity.d.ts +7 -0
  355. package/lib/orchestrator/evaluator-identity.d.ts.map +1 -0
  356. package/lib/orchestrator/evaluator-identity.js +42 -0
  357. package/lib/orchestrator/evaluator-identity.js.map +1 -0
  358. package/lib/orchestrator/experiment-budget.d.ts +11 -0
  359. package/lib/orchestrator/experiment-budget.d.ts.map +1 -0
  360. package/lib/orchestrator/experiment-budget.js +51 -0
  361. package/lib/orchestrator/experiment-budget.js.map +1 -0
  362. package/lib/orchestrator/experiment-context.d.ts +43 -0
  363. package/lib/orchestrator/experiment-context.d.ts.map +1 -0
  364. package/lib/orchestrator/experiment-context.js +9 -0
  365. package/lib/orchestrator/experiment-context.js.map +1 -0
  366. package/lib/orchestrator/experiment-contracts.d.ts +290 -0
  367. package/lib/orchestrator/experiment-contracts.d.ts.map +1 -0
  368. package/lib/orchestrator/experiment-contracts.js +38 -0
  369. package/lib/orchestrator/experiment-contracts.js.map +1 -0
  370. package/lib/orchestrator/experiment-corpus.d.ts +21 -0
  371. package/lib/orchestrator/experiment-corpus.d.ts.map +1 -0
  372. package/lib/orchestrator/experiment-corpus.js +276 -0
  373. package/lib/orchestrator/experiment-corpus.js.map +1 -0
  374. package/lib/orchestrator/experiment-evaluation.d.ts +44 -0
  375. package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -0
  376. package/lib/orchestrator/experiment-evaluation.js +542 -0
  377. package/lib/orchestrator/experiment-evaluation.js.map +1 -0
  378. package/lib/orchestrator/experiment-finish.d.ts +6 -0
  379. package/lib/orchestrator/experiment-finish.d.ts.map +1 -0
  380. package/lib/orchestrator/experiment-finish.js +19 -0
  381. package/lib/orchestrator/experiment-finish.js.map +1 -0
  382. package/lib/orchestrator/experiment-identity.d.ts +6 -0
  383. package/lib/orchestrator/experiment-identity.d.ts.map +1 -0
  384. package/lib/orchestrator/experiment-identity.js +257 -0
  385. package/lib/orchestrator/experiment-identity.js.map +1 -0
  386. package/lib/orchestrator/experiment-loader.d.ts +175 -0
  387. package/lib/orchestrator/experiment-loader.d.ts.map +1 -0
  388. package/lib/orchestrator/experiment-loader.js +77 -0
  389. package/lib/orchestrator/experiment-loader.js.map +1 -0
  390. package/lib/orchestrator/experiment-report.d.ts +450 -0
  391. package/lib/orchestrator/experiment-report.d.ts.map +1 -0
  392. package/lib/orchestrator/experiment-report.js +570 -0
  393. package/lib/orchestrator/experiment-report.js.map +1 -0
  394. package/lib/orchestrator/experiment-runs.d.ts +379 -0
  395. package/lib/orchestrator/experiment-runs.d.ts.map +1 -0
  396. package/lib/orchestrator/experiment-runs.js +796 -0
  397. package/lib/orchestrator/experiment-runs.js.map +1 -0
  398. package/lib/orchestrator/experiment-runtime-identity.d.ts +41 -0
  399. package/lib/orchestrator/experiment-runtime-identity.d.ts.map +1 -0
  400. package/lib/orchestrator/experiment-runtime-identity.js +411 -0
  401. package/lib/orchestrator/experiment-runtime-identity.js.map +1 -0
  402. package/lib/orchestrator/experiment-selection.d.ts +25 -0
  403. package/lib/orchestrator/experiment-selection.d.ts.map +1 -0
  404. package/lib/orchestrator/experiment-selection.js +286 -0
  405. package/lib/orchestrator/experiment-selection.js.map +1 -0
  406. package/lib/orchestrator/experiment.d.ts +11 -0
  407. package/lib/orchestrator/experiment.d.ts.map +1 -0
  408. package/lib/orchestrator/experiment.js +639 -0
  409. package/lib/orchestrator/experiment.js.map +1 -0
  410. package/lib/orchestrator/fixture-identity.d.ts +7 -0
  411. package/lib/orchestrator/fixture-identity.d.ts.map +1 -0
  412. package/lib/orchestrator/fixture-identity.js +55 -0
  413. package/lib/orchestrator/fixture-identity.js.map +1 -0
  414. package/lib/orchestrator/fs-read.d.ts +19 -0
  415. package/lib/orchestrator/fs-read.d.ts.map +1 -0
  416. package/lib/orchestrator/fs-read.js +113 -0
  417. package/lib/orchestrator/fs-read.js.map +1 -0
  418. package/lib/orchestrator/grader-experiment.d.ts +190 -0
  419. package/lib/orchestrator/grader-experiment.d.ts.map +1 -0
  420. package/lib/orchestrator/grader-experiment.js +579 -0
  421. package/lib/orchestrator/grader-experiment.js.map +1 -0
  422. package/lib/orchestrator/grading.d.ts +31 -0
  423. package/lib/orchestrator/grading.d.ts.map +1 -0
  424. package/lib/orchestrator/grading.js +186 -0
  425. package/lib/orchestrator/grading.js.map +1 -0
  426. package/lib/orchestrator/index.d.ts +22 -0
  427. package/lib/orchestrator/index.d.ts.map +1 -0
  428. package/lib/orchestrator/index.js +30 -0
  429. package/lib/orchestrator/index.js.map +1 -0
  430. package/lib/orchestrator/lifecycle-hook-execution.d.ts +4 -0
  431. package/lib/orchestrator/lifecycle-hook-execution.d.ts.map +1 -0
  432. package/lib/orchestrator/lifecycle-hook-execution.js +67 -0
  433. package/lib/orchestrator/lifecycle-hook-execution.js.map +1 -0
  434. package/lib/orchestrator/list-runs.d.ts +33 -0
  435. package/lib/orchestrator/list-runs.d.ts.map +1 -0
  436. package/lib/orchestrator/list-runs.js +308 -0
  437. package/lib/orchestrator/list-runs.js.map +1 -0
  438. package/lib/orchestrator/loader.d.ts +3 -0
  439. package/lib/orchestrator/loader.d.ts.map +1 -0
  440. package/lib/orchestrator/loader.js +17 -0
  441. package/lib/orchestrator/loader.js.map +1 -0
  442. package/lib/orchestrator/optimization-lifecycle.d.ts +12 -0
  443. package/lib/orchestrator/optimization-lifecycle.d.ts.map +1 -0
  444. package/lib/orchestrator/optimization-lifecycle.js +92 -0
  445. package/lib/orchestrator/optimization-lifecycle.js.map +1 -0
  446. package/lib/orchestrator/orchestrator.d.ts +144 -0
  447. package/lib/orchestrator/orchestrator.d.ts.map +1 -0
  448. package/lib/orchestrator/orchestrator.js +632 -0
  449. package/lib/orchestrator/orchestrator.js.map +1 -0
  450. package/lib/orchestrator/owned-lock.d.ts +17 -0
  451. package/lib/orchestrator/owned-lock.d.ts.map +1 -0
  452. package/lib/orchestrator/owned-lock.js +149 -0
  453. package/lib/orchestrator/owned-lock.js.map +1 -0
  454. package/lib/orchestrator/package-version.d.ts +2 -0
  455. package/lib/orchestrator/package-version.d.ts.map +1 -0
  456. package/lib/orchestrator/package-version.js +4 -0
  457. package/lib/orchestrator/package-version.js.map +1 -0
  458. package/lib/orchestrator/provenance.d.ts +5 -0
  459. package/lib/orchestrator/provenance.d.ts.map +1 -0
  460. package/lib/orchestrator/provenance.js +137 -0
  461. package/lib/orchestrator/provenance.js.map +1 -0
  462. package/lib/orchestrator/regrade.d.ts +80 -0
  463. package/lib/orchestrator/regrade.d.ts.map +1 -0
  464. package/lib/orchestrator/regrade.js +433 -0
  465. package/lib/orchestrator/regrade.js.map +1 -0
  466. package/lib/orchestrator/rubric-loader.d.ts +7 -0
  467. package/lib/orchestrator/rubric-loader.d.ts.map +1 -0
  468. package/lib/orchestrator/rubric-loader.js +65 -0
  469. package/lib/orchestrator/rubric-loader.js.map +1 -0
  470. package/lib/orchestrator/run-dir.d.ts +40 -0
  471. package/lib/orchestrator/run-dir.d.ts.map +1 -0
  472. package/lib/orchestrator/run-dir.js +161 -0
  473. package/lib/orchestrator/run-dir.js.map +1 -0
  474. package/lib/orchestrator/run-execution.d.ts +30 -0
  475. package/lib/orchestrator/run-execution.d.ts.map +1 -0
  476. package/lib/orchestrator/run-execution.js +531 -0
  477. package/lib/orchestrator/run-execution.js.map +1 -0
  478. package/lib/orchestrator/run-lifecycle.d.ts +115 -0
  479. package/lib/orchestrator/run-lifecycle.d.ts.map +1 -0
  480. package/lib/orchestrator/run-lifecycle.js +136 -0
  481. package/lib/orchestrator/run-lifecycle.js.map +1 -0
  482. package/lib/orchestrator/suite-compare.d.ts +76 -0
  483. package/lib/orchestrator/suite-compare.d.ts.map +1 -0
  484. package/lib/orchestrator/suite-compare.js +159 -0
  485. package/lib/orchestrator/suite-compare.js.map +1 -0
  486. package/lib/orchestrator/suite-lifecycle.d.ts +157 -0
  487. package/lib/orchestrator/suite-lifecycle.d.ts.map +1 -0
  488. package/lib/orchestrator/suite-lifecycle.js +253 -0
  489. package/lib/orchestrator/suite-lifecycle.js.map +1 -0
  490. package/lib/orchestrator/suite-runs.d.ts +91 -0
  491. package/lib/orchestrator/suite-runs.d.ts.map +1 -0
  492. package/lib/orchestrator/suite-runs.js +157 -0
  493. package/lib/orchestrator/suite-runs.js.map +1 -0
  494. package/lib/orchestrator/suite-summary.d.ts +109 -0
  495. package/lib/orchestrator/suite-summary.d.ts.map +1 -0
  496. package/lib/orchestrator/suite-summary.js +213 -0
  497. package/lib/orchestrator/suite-summary.js.map +1 -0
  498. package/lib/orchestrator/trace-limits.d.ts +20 -0
  499. package/lib/orchestrator/trace-limits.d.ts.map +1 -0
  500. package/lib/orchestrator/trace-limits.js +28 -0
  501. package/lib/orchestrator/trace-limits.js.map +1 -0
  502. package/lib/orchestrator/validate-plugin-config.d.ts +10 -0
  503. package/lib/orchestrator/validate-plugin-config.d.ts.map +1 -0
  504. package/lib/orchestrator/validate-plugin-config.js +26 -0
  505. package/lib/orchestrator/validate-plugin-config.js.map +1 -0
  506. package/package.json +84 -0
  507. package/skills/lux/SKILL.md +85 -0
  508. package/skills/lux/references/cli.md +102 -0
  509. package/skills/lux/references/eval-authoring.md +105 -0
  510. package/skills/lux-answerer/SKILL.md +169 -0
  511. package/src/answerers/claude-code/index.ts +342 -0
  512. package/src/answerers/persona/index.ts +327 -0
  513. package/src/answerers/scripted/index.ts +186 -0
  514. package/src/answerers/shared.ts +23 -0
  515. package/src/answerers/terminal/index.ts +117 -0
  516. package/src/assertions/core/command-exits-zero.ts +94 -0
  517. package/src/assertions/core/event-checks.ts +138 -0
  518. package/src/assertions/core/file-checks.ts +336 -0
  519. package/src/assertions/core/helpers.ts +203 -0
  520. package/src/assertions/core/index.ts +80 -0
  521. package/src/assertions/core/json-pointer-equals.ts +84 -0
  522. package/src/assertions/core/output-checks.ts +134 -0
  523. package/src/assertions/core/predicate.ts +67 -0
  524. package/src/assertions/core/resource-checks.ts +180 -0
  525. package/src/assertions/core/safe-regex.ts +196 -0
  526. package/src/assertions/core/tool-called-with.ts +68 -0
  527. package/src/assertions/core/tool-calls.ts +28 -0
  528. package/src/assertions/core/tool-invocation.ts +198 -0
  529. package/src/assertions/core/tool-result-checks.ts +211 -0
  530. package/src/assertions/mcp/discovery-checks.ts +139 -0
  531. package/src/assertions/mcp/index.ts +37 -0
  532. package/src/assertions/rubric/index.ts +258 -0
  533. package/src/assertions/rubric/internal.ts +367 -0
  534. package/src/authoring.ts +2 -0
  535. package/src/cli/bin.ts +14 -0
  536. package/src/cli/command-runtime.ts +34 -0
  537. package/src/cli/init.ts +410 -0
  538. package/src/cli/program.ts +992 -0
  539. package/src/cli/render/format.ts +69 -0
  540. package/src/cli/render/reporter.ts +643 -0
  541. package/src/cli/render/tty.ts +314 -0
  542. package/src/cli/run-options.ts +82 -0
  543. package/src/cli/skills.ts +129 -0
  544. package/src/core/annotation.ts +104 -0
  545. package/src/core/answerer.ts +75 -0
  546. package/src/core/artifact-evidence.ts +249 -0
  547. package/src/core/artifact-snapshot.ts +429 -0
  548. package/src/core/assertion.ts +156 -0
  549. package/src/core/case.ts +103 -0
  550. package/src/core/conversation-turn.ts +47 -0
  551. package/src/core/driver.ts +75 -0
  552. package/src/core/emitter.ts +38 -0
  553. package/src/core/events.ts +135 -0
  554. package/src/core/exec.ts +263 -0
  555. package/src/core/experiment.ts +467 -0
  556. package/src/core/glob.ts +31 -0
  557. package/src/core/hash.ts +237 -0
  558. package/src/core/index.ts +28 -0
  559. package/src/core/lifecycle-fixtures.ts +145 -0
  560. package/src/core/lifecycle-hooks.ts +101 -0
  561. package/src/core/mcp-events.ts +57 -0
  562. package/src/core/model-cli.ts +271 -0
  563. package/src/core/observer.ts +50 -0
  564. package/src/core/platform-process.ts +284 -0
  565. package/src/core/registry.ts +57 -0
  566. package/src/core/rubric.ts +52 -0
  567. package/src/core/run.ts +144 -0
  568. package/src/core/statistics.ts +194 -0
  569. package/src/core/subject.ts +50 -0
  570. package/src/core/tool-events.ts +292 -0
  571. package/src/core/usage.ts +123 -0
  572. package/src/core/wire.ts +135 -0
  573. package/src/core/zod.ts +20 -0
  574. package/src/drivers/claude-code/index.ts +866 -0
  575. package/src/drivers/claude-code/parse-events.ts +464 -0
  576. package/src/drivers/codex/app-events.ts +218 -0
  577. package/src/drivers/codex/config.ts +128 -0
  578. package/src/drivers/codex/index.ts +995 -0
  579. package/src/drivers/mcp/index.ts +351 -0
  580. package/src/drivers/mcp/transport.ts +222 -0
  581. package/src/drivers/shared/artifacts.ts +86 -0
  582. package/src/drivers/shared/secure-copy.ts +40 -0
  583. package/src/drivers/subprocess/index.ts +490 -0
  584. package/src/index.ts +594 -0
  585. package/src/optimization/reflective.ts +319 -0
  586. package/src/orchestrator/annotation-loader.ts +97 -0
  587. package/src/orchestrator/annotation-store.ts +112 -0
  588. package/src/orchestrator/authored-dependencies.ts +193 -0
  589. package/src/orchestrator/campaign-lifecycle.ts +181 -0
  590. package/src/orchestrator/candidate-integrity.ts +18 -0
  591. package/src/orchestrator/candidates.ts +683 -0
  592. package/src/orchestrator/compare.ts +358 -0
  593. package/src/orchestrator/comparison-identity.ts +45 -0
  594. package/src/orchestrator/config.ts +205 -0
  595. package/src/orchestrator/content-bound-json.ts +71 -0
  596. package/src/orchestrator/discover.ts +132 -0
  597. package/src/orchestrator/doctor.ts +781 -0
  598. package/src/orchestrator/driver-session.ts +507 -0
  599. package/src/orchestrator/evaluator-identity.ts +45 -0
  600. package/src/orchestrator/experiment-budget.ts +61 -0
  601. package/src/orchestrator/experiment-context.ts +41 -0
  602. package/src/orchestrator/experiment-contracts.ts +43 -0
  603. package/src/orchestrator/experiment-corpus.ts +416 -0
  604. package/src/orchestrator/experiment-evaluation.ts +749 -0
  605. package/src/orchestrator/experiment-finish.ts +33 -0
  606. package/src/orchestrator/experiment-identity.ts +356 -0
  607. package/src/orchestrator/experiment-loader.ts +105 -0
  608. package/src/orchestrator/experiment-report.ts +788 -0
  609. package/src/orchestrator/experiment-runs.ts +960 -0
  610. package/src/orchestrator/experiment-runtime-identity.ts +465 -0
  611. package/src/orchestrator/experiment-selection.ts +467 -0
  612. package/src/orchestrator/experiment.ts +991 -0
  613. package/src/orchestrator/fixture-identity.ts +67 -0
  614. package/src/orchestrator/fs-read.ts +126 -0
  615. package/src/orchestrator/grader-experiment.ts +856 -0
  616. package/src/orchestrator/grading.ts +260 -0
  617. package/src/orchestrator/index.ts +186 -0
  618. package/src/orchestrator/lifecycle-hook-execution.ts +90 -0
  619. package/src/orchestrator/list-runs.ts +384 -0
  620. package/src/orchestrator/loader.ts +19 -0
  621. package/src/orchestrator/optimization-lifecycle.ts +126 -0
  622. package/src/orchestrator/orchestrator.ts +919 -0
  623. package/src/orchestrator/owned-lock.ts +147 -0
  624. package/src/orchestrator/package-version.ts +5 -0
  625. package/src/orchestrator/provenance.ts +140 -0
  626. package/src/orchestrator/regrade.ts +580 -0
  627. package/src/orchestrator/rubric-loader.ts +74 -0
  628. package/src/orchestrator/run-dir.ts +209 -0
  629. package/src/orchestrator/run-execution.ts +694 -0
  630. package/src/orchestrator/run-lifecycle.ts +174 -0
  631. package/src/orchestrator/suite-compare.ts +195 -0
  632. package/src/orchestrator/suite-lifecycle.ts +335 -0
  633. package/src/orchestrator/suite-runs.ts +202 -0
  634. package/src/orchestrator/suite-summary.ts +276 -0
  635. package/src/orchestrator/trace-limits.ts +65 -0
  636. package/src/orchestrator/validate-plugin-config.ts +34 -0
@@ -0,0 +1,490 @@
1
+ import type { ChildProcessWithoutNullStreams } from "node:child_process";
2
+ import { createInterface } from "node:readline";
3
+ import { fileURLToPath } from "node:url";
4
+ import { z } from "zod";
5
+ import {
6
+ type AgentDriver,
7
+ type Answer,
8
+ type Artifact,
9
+ DoneSchema,
10
+ type DriverEventMap,
11
+ type DriverPlugin,
12
+ ErrorEventSchema,
13
+ type FormatAnswerFn,
14
+ formatWireAnswer,
15
+ InterruptSchema,
16
+ type ManagedProcess,
17
+ type ParsedDriverEvent,
18
+ type ParseEventFn,
19
+ ProgressSchema,
20
+ parseWireEvent,
21
+ type ReadyState,
22
+ ReadyStateSchema,
23
+ type StartContext,
24
+ spawnManagedProcess,
25
+ TypedEmitter,
26
+ } from "../../core/index.js";
27
+ import { walkArtifacts } from "../shared/artifacts.js";
28
+
29
+ export const SubprocessDriverConfigSchema = z
30
+ .object({
31
+ command: z.string(),
32
+ args: z.array(z.string()).optional(),
33
+ cwd: z.string().optional(),
34
+ env: z.record(z.string(), z.string()).optional(),
35
+ /** Inherit the host environment. Experiment mode always forces this off. */
36
+ inheritEnv: z.boolean().optional(),
37
+ protocol: z.enum(["lux-jsonl", "custom"]).default("lux-jsonl"),
38
+ idleTimeoutMs: z.number().positive().default(120_000),
39
+ maxInterrupts: z.number().positive().default(20),
40
+ /**
41
+ * Maximum files inventoried from LUX_ARTIFACTS_DIR. Keep the conservative
42
+ * default unless the child deliberately emits bounded full snapshots.
43
+ */
44
+ maxArtifactFiles: z.number().int().positive().max(250_000).optional(),
45
+ /**
46
+ * Cap on a single stdout line's bytes — readline buffers a newline-less
47
+ * stream without bound, so a misbehaving agent could OOM the host.
48
+ */
49
+ maxLineBytes: z.number().positive().optional(),
50
+ /**
51
+ * For "custom" protocols: parse a stdout line into a Lux driver event,
52
+ * or null to ignore it. Required for "custom", rejected for "lux-jsonl".
53
+ */
54
+ parseEvent: z.custom<ParseEventFn>((v) => typeof v === "function").optional(),
55
+ /**
56
+ * For "custom" protocols: serialize a Lux Answer into a stdin line.
57
+ * Defaults to the lux-jsonl format.
58
+ */
59
+ formatAnswer: z.custom<FormatAnswerFn>((v) => typeof v === "function").optional(),
60
+ /**
61
+ * For "custom" protocols: serialize the initial prompt into a stdin line
62
+ * written once at startup, for agents that read the opening turn from
63
+ * stdin rather than the LUX_PROMPT env var or argv.
64
+ */
65
+ formatPrompt: z.custom<(text: string) => string>((v) => typeof v === "function").optional(),
66
+ /** Close stdin after the opening prompt for one-shot CLIs that wait for EOF. */
67
+ closeStdinAfterPrompt: z.boolean().optional(),
68
+ })
69
+ .strict()
70
+ .refine((cfg) => cfg.protocol !== "custom" || cfg.parseEvent !== undefined, {
71
+ path: ["parseEvent"],
72
+ message: 'protocol "custom" requires a parseEvent function',
73
+ })
74
+ .refine((cfg) => cfg.protocol !== "lux-jsonl" || cfg.parseEvent === undefined, {
75
+ path: ["parseEvent"],
76
+ message: 'parseEvent is only used with protocol "custom"',
77
+ });
78
+
79
+ export type SubprocessDriverConfig = z.infer<typeof SubprocessDriverConfigSchema>;
80
+
81
+ const KILL_GRACE_MS = 5_000;
82
+ const DEFAULT_MAX_LINE_BYTES = 10_000_000;
83
+ const MAX_STDERR_TAIL_CHARS = 8_192;
84
+ const DEFAULT_MAX_ARTIFACT_FILES = 500;
85
+ const ARTIFACT_SNAPSHOT_MODULE = fileURLToPath(
86
+ new URL("../../core/artifact-snapshot.js", import.meta.url),
87
+ );
88
+ // Grace for a still-open stdout to flush buffered lines after the child's
89
+ // exit before the read end is force-destroyed.
90
+ const EXIT_FLUSH_GRACE_MS = 1_000;
91
+
92
+ const ParsedDriverEventSchema = z.discriminatedUnion("tag", [
93
+ z.object({ tag: z.literal("ready"), ready: ReadyStateSchema }),
94
+ z.object({ tag: z.literal("interrupt"), interrupt: InterruptSchema }),
95
+ z.object({ tag: z.literal("progress"), progress: ProgressSchema }),
96
+ z.object({ tag: z.literal("done"), done: DoneSchema }),
97
+ z.object({ tag: z.literal("error"), error: ErrorEventSchema }),
98
+ ]);
99
+
100
+ class SubprocessDriverImpl implements AgentDriver {
101
+ private readonly emitter = new TypedEmitter<DriverEventMap>();
102
+ private child: ChildProcessWithoutNullStreams | null = null;
103
+ private managed: ManagedProcess | null = null;
104
+ private readyResolved: ((ready: ReadyState) => void) | null = null;
105
+ private readyRejected: ((err: Error) => void) | null = null;
106
+ private idleTimer: NodeJS.Timeout | null = null;
107
+ private exitFlushTimer: NodeJS.Timeout | null = null;
108
+ private interruptsSeen = 0;
109
+ private pendingAnswers = 0;
110
+ private exited = false;
111
+ private stdoutDone = false;
112
+ private pipeHeldPastExit = false;
113
+ private terminalSent = false;
114
+ private exitDescription = "";
115
+ private exitSettled: Promise<void> = Promise.resolve();
116
+ // Chains events so handlers are awaited in emission order (see AgentDriver);
117
+ // readline delivers buffered lines synchronously.
118
+ private dispatchChain: Promise<void> = Promise.resolve();
119
+ private readonly parse: ParseEventFn;
120
+ private readonly format: FormatAnswerFn;
121
+ private readonly maxLineBytes: number;
122
+ private readonly config: SubprocessDriverConfig;
123
+ private artifactsDir: string | null = null;
124
+
125
+ constructor(config: SubprocessDriverConfig) {
126
+ this.config = config;
127
+ this.parse = config.parseEvent ?? parseWireEvent;
128
+ this.format = config.formatAnswer ?? formatWireAnswer;
129
+ this.maxLineBytes = config.maxLineBytes ?? DEFAULT_MAX_LINE_BYTES;
130
+ }
131
+
132
+ on<K extends keyof DriverEventMap>(event: K, handler: (e: DriverEventMap[K]) => void): void {
133
+ this.emitter.on(event, handler);
134
+ }
135
+
136
+ off<K extends keyof DriverEventMap>(event: K, handler: (e: DriverEventMap[K]) => void): void {
137
+ this.emitter.off(event, handler);
138
+ }
139
+
140
+ async start(ctx: StartContext): Promise<ReadyState> {
141
+ this.artifactsDir = ctx.artifactsDir;
142
+ const managed = spawnManagedProcess(this.config.command, this.config.args ?? [], {
143
+ cwd: this.config.cwd ?? ctx.runDir,
144
+ env: {
145
+ ...(this.config.inheritEnv === false ? {} : process.env),
146
+ ...this.config.env,
147
+ ...(ctx.caseId ? { LUX_CASE_ID: ctx.caseId } : {}),
148
+ LUX_RUN_DIR: ctx.runDir,
149
+ LUX_ARTIFACTS_DIR: ctx.artifactsDir,
150
+ LUX_PROMPT: ctx.prompt,
151
+ LUX_ARTIFACT_SNAPSHOT_MODULE: ARTIFACT_SNAPSHOT_MODULE,
152
+ },
153
+ killGraceMs: KILL_GRACE_MS,
154
+ });
155
+ const { child } = managed;
156
+ this.managed = managed;
157
+ this.child = child;
158
+ this.exitSettled = managed.exited.then(() => {});
159
+ // The child error handler below turns spawn failures into driver events.
160
+ void managed.spawned.catch(() => {});
161
+ this.bumpIdleTimer();
162
+
163
+ // A child that exits before draining stdin turns the next write into an
164
+ // EPIPE 'error' event that would crash the whole process.
165
+ child.stdin.on("error", () => {});
166
+
167
+ // setEncoding keeps a multibyte character straddling a pipe-chunk
168
+ // boundary from being mangled.
169
+ child.stderr.setEncoding("utf8");
170
+ let stderrTail = "";
171
+ child.stderr.on("data", (chunk: string) => {
172
+ const lines = (stderrTail + chunk).split("\n");
173
+ // Cap the retained partial line so unterminated stderr can't grow
174
+ // without bound.
175
+ stderrTail = (lines.pop() ?? "").slice(0, MAX_STDERR_TAIL_CHARS);
176
+ for (const line of lines) process.stderr.write(`[subprocess] ${line}\n`);
177
+ });
178
+ child.stderr.on("close", () => {
179
+ if (stderrTail) process.stderr.write(`[subprocess] ${stderrTail}\n`);
180
+ stderrTail = "";
181
+ });
182
+
183
+ // Tracks the unterminated tail: an over-cap partial line must die before
184
+ // readline's unbounded buffering OOMs the host. Complete lines are
185
+ // capped in handleLine.
186
+ let lineBytes = 0;
187
+ child.stdout.on("data", (chunk: Buffer) => {
188
+ const lastNewline = chunk.lastIndexOf(0x0a);
189
+ lineBytes = lastNewline === -1 ? lineBytes + chunk.length : chunk.length - lastNewline - 1;
190
+ if (lineBytes > this.maxLineBytes) this.failLineCap();
191
+ });
192
+
193
+ const stdoutLines = createInterface({ input: child.stdout });
194
+ stdoutLines.on("line", (line) => this.handleLine(line));
195
+ // readline 'close' fires only after every buffered line delivers, so a
196
+ // done line racing the child's exit wins over the synthetic exit error.
197
+ stdoutLines.on("close", () => {
198
+ this.stdoutDone = true;
199
+ this.emitExitErrorIfSilent();
200
+ });
201
+
202
+ if (this.config.formatPrompt) {
203
+ child.stdin.write(this.config.formatPrompt(ctx.prompt));
204
+ if (this.config.closeStdinAfterPrompt) child.stdin.end();
205
+ }
206
+
207
+ // Removed once the child is gone, or a suite sharing one AbortSignal
208
+ // would retain every exited driver for its life.
209
+ const onAbort = (): void => this.terminate();
210
+
211
+ // A missing/unexecutable binary emits `error`, not a throw; unhandled,
212
+ // it crashes the whole `lux run` instead of failing one case.
213
+ child.on("error", (err) => {
214
+ ctx.abortSignal.removeEventListener("abort", onAbort);
215
+ this.exited = true;
216
+ this.clearIdleTimer();
217
+ this.fail({
218
+ exitReason: "error",
219
+ reason: `failed to spawn '${this.config.command}': ${err.message}`,
220
+ });
221
+ });
222
+
223
+ child.on("exit", (code, signal) => {
224
+ ctx.abortSignal.removeEventListener("abort", onAbort);
225
+ this.exited = true;
226
+ this.clearIdleTimer();
227
+ this.exitDescription = `code=${code}, signal=${signal}`;
228
+ if (this.readyRejected) {
229
+ this.fail({
230
+ exitReason: "error",
231
+ reason: `subprocess exited before ready (${this.exitDescription})`,
232
+ });
233
+ return;
234
+ }
235
+ this.emitExitErrorIfSilent();
236
+ // readline's close never fires while a grandchild holds our stdout,
237
+ // which would hang the run: let buffered lines flush, then close the
238
+ // interface ourselves (destroying the stream alone never ends readline).
239
+ if (!this.stdoutDone) {
240
+ this.exitFlushTimer = setTimeout(() => {
241
+ if (this.stdoutDone) return;
242
+ this.pipeHeldPastExit = true;
243
+ stdoutLines.close();
244
+ child.stdout.destroy();
245
+ child.stderr.destroy();
246
+ }, EXIT_FLUSH_GRACE_MS);
247
+ }
248
+ });
249
+
250
+ return new Promise<ReadyState>((resolveStart, reject) => {
251
+ this.readyResolved = resolveStart;
252
+ this.readyRejected = reject;
253
+ // An already-aborted signal never fires "abort"; terminate directly.
254
+ if (ctx.abortSignal.aborted) this.terminate();
255
+ else ctx.abortSignal.addEventListener("abort", onAbort, { once: true });
256
+ });
257
+ }
258
+
259
+ /**
260
+ * Route a fatal condition to whoever is waiting: reject a pending start(),
261
+ * otherwise emit a terminal error event — never both, never twice.
262
+ */
263
+ private fail(error: DriverEventMap["error"]): void {
264
+ if (this.terminalSent) return;
265
+ this.terminalSent = true;
266
+ this.clearIdleTimer();
267
+ if (this.readyRejected) {
268
+ this.readyRejected(new Error(error.reason));
269
+ this.readyRejected = null;
270
+ this.readyResolved = null;
271
+ return;
272
+ }
273
+ this.emitInOrder("error", error);
274
+ }
275
+
276
+ /**
277
+ * All emits ride one promise chain so every handler is awaited before the
278
+ * next event dispatches (the AgentDriver ordering contract). A throwing
279
+ * handler becomes the terminal error and kills the child.
280
+ */
281
+ private emitInOrder<K extends keyof DriverEventMap>(event: K, payload: DriverEventMap[K]): void {
282
+ this.dispatchChain = this.dispatchChain
283
+ .then(() => this.emitter.emit(event, payload))
284
+ .catch((err: unknown) => {
285
+ this.fail({
286
+ exitReason: "error",
287
+ reason: `${String(event)} handler failed: ${err instanceof Error ? err.message : String(err)}`,
288
+ });
289
+ this.terminate();
290
+ });
291
+ }
292
+
293
+ // A child that exits without emitting done/error would hang the run
294
+ // forever. Requires both 'exit' and stdout close so no trailing line is
295
+ // still in flight.
296
+ private emitExitErrorIfSilent(): void {
297
+ if (!this.exited || !this.stdoutDone) return;
298
+ this.fail({
299
+ exitReason: "error",
300
+ reason: `subprocess exited before done (${this.exitDescription})`,
301
+ });
302
+ }
303
+
304
+ /** Request graceful shutdown; the shared supervisor owns escalation. */
305
+ private terminate(): void {
306
+ if (this.exited) void this.managed?.forceTerminate();
307
+ else void this.managed?.terminate();
308
+ }
309
+
310
+ private failLineCap(): void {
311
+ this.fail({
312
+ exitReason: "error",
313
+ reason: `stdout line exceeded ${this.maxLineBytes} bytes`,
314
+ });
315
+ this.terminate();
316
+ }
317
+
318
+ private handleLine(line: string): void {
319
+ // Post-terminal chatter must not re-arm the idle timer on a dead run.
320
+ if (this.terminalSent) return;
321
+ if (!line.trim()) return;
322
+ if (Buffer.byteLength(line) > this.maxLineBytes) {
323
+ this.failLineCap();
324
+ return;
325
+ }
326
+ // parseEvent is user-supplied: a throw inside readline's synchronous
327
+ // 'line' handler would take down the whole lux process, not just this case.
328
+ let parsed: ReturnType<ParseEventFn>;
329
+ try {
330
+ parsed = this.parse(line);
331
+ } catch (err) {
332
+ this.fail({
333
+ exitReason: "error",
334
+ reason: `parseEvent threw: ${err instanceof Error ? err.message : String(err)}`,
335
+ });
336
+ this.terminate();
337
+ return;
338
+ }
339
+ if (!parsed) return;
340
+ // A single line may carry multiple events (e.g. text + tool_use blocks).
341
+ const events = (Array.isArray(parsed) ? parsed : [parsed]).flatMap((event) => {
342
+ const validated = ParsedDriverEventSchema.safeParse(event);
343
+ return validated.success ? [validated.data] : [];
344
+ });
345
+ if (events.length === 0) return;
346
+ // Only protocol activity demonstrates that the agent is alive. Logs and
347
+ // malformed JSON must not keep a wedged agent running indefinitely.
348
+ if (this.pendingAnswers === 0) this.bumpIdleTimer();
349
+ for (const event of events) {
350
+ this.dispatchEvent(event);
351
+ }
352
+ }
353
+
354
+ private dispatchEvent(parsed: ParsedDriverEvent): void {
355
+ // Everything past the first done/error is dropped, even from a
356
+ // malformed agent that keeps emitting.
357
+ if (this.terminalSent) return;
358
+ // A terminal event or interrupt before ready is a protocol violation:
359
+ // a terminal here would strand the pending start(), and a pre-ready
360
+ // interrupt would pause the idle clock's never-became-ready rescue.
361
+ // Progress stays allowed — boot-time telemetry is harmless.
362
+ if (this.readyRejected && parsed.tag === "error") {
363
+ this.fail(parsed.error);
364
+ return;
365
+ }
366
+ if (this.readyRejected && parsed.tag !== "ready" && parsed.tag !== "progress") {
367
+ this.fail({
368
+ exitReason: "error",
369
+ reason: `agent emitted ${parsed.tag} before ready`,
370
+ });
371
+ return;
372
+ }
373
+ switch (parsed.tag) {
374
+ case "ready":
375
+ if (this.readyResolved) {
376
+ this.readyResolved(parsed.ready);
377
+ this.readyResolved = null;
378
+ this.readyRejected = null;
379
+ }
380
+ return;
381
+ case "error":
382
+ this.terminalSent = true;
383
+ this.clearIdleTimer();
384
+ this.emitInOrder("error", parsed.error);
385
+ return;
386
+ case "done":
387
+ this.terminalSent = true;
388
+ this.clearIdleTimer();
389
+ this.emitInOrder("done", parsed.done);
390
+ return;
391
+ case "interrupt":
392
+ this.interruptsSeen++;
393
+ if (this.interruptsSeen > this.config.maxInterrupts) {
394
+ this.fail({
395
+ exitReason: "max-interactions",
396
+ reason: `exceeded maxInterrupts (${this.config.maxInterrupts})`,
397
+ });
398
+ return;
399
+ }
400
+ // The answerer's round-trip is the user's time, not the agent's:
401
+ // the idle clock stops here and restarts in respond(); the
402
+ // answerer's own wait budget still bounds the window.
403
+ this.pendingAnswers++;
404
+ this.clearIdleTimer();
405
+ this.emitInOrder("interrupt", parsed.interrupt);
406
+ return;
407
+ case "progress":
408
+ this.emitInOrder("progress", parsed.progress);
409
+ return;
410
+ }
411
+ }
412
+
413
+ async respond(answer: Answer): Promise<void> {
414
+ if (!this.child || this.exited) {
415
+ throw new Error("cannot respond: subprocess is not running");
416
+ }
417
+ this.pendingAnswers = Math.max(0, this.pendingAnswers - 1);
418
+ if (this.pendingAnswers === 0) this.bumpIdleTimer();
419
+ const line = this.format(answer);
420
+ await new Promise<void>((res, rej) => {
421
+ this.child?.stdin.write(line, (err) => (err ? rej(err) : res()));
422
+ });
423
+ }
424
+
425
+ async collect(): Promise<Artifact[]> {
426
+ await this.quiesce();
427
+ return this.artifactsDir
428
+ ? walkArtifacts(this.artifactsDir, this.config.maxArtifactFiles ?? DEFAULT_MAX_ARTIFACT_FILES)
429
+ : [];
430
+ }
431
+
432
+ async quiesce(): Promise<void> {
433
+ this.clearIdleTimer();
434
+ this.clearExitFlushTimer();
435
+ if (this.child && !this.exited) {
436
+ this.child.stdin.end();
437
+ this.terminate();
438
+ } else if (this.child && (this.pipeHeldPastExit || !this.stdoutDone)) {
439
+ // The child is gone but something it spawned still holds our stdout:
440
+ // reap group survivors and drop the pipe so it can't outlive the suite.
441
+ await this.managed?.forceTerminate();
442
+ this.child.stdout.destroy();
443
+ this.child.stderr.destroy();
444
+ }
445
+ await this.exitSettled;
446
+ }
447
+
448
+ async close(): Promise<void> {
449
+ await this.quiesce();
450
+ this.emitter.removeAllListeners();
451
+ }
452
+
453
+ private bumpIdleTimer(): void {
454
+ this.clearIdleTimer();
455
+ this.idleTimer = setTimeout(() => {
456
+ const reason = `no event for ${this.config.idleTimeoutMs}ms`;
457
+ // Idle before ready means start() is still pending; reject it (and kill
458
+ // the child) or the orchestrator waits forever.
459
+ const preReady = this.readyRejected !== null;
460
+ this.fail(
461
+ preReady
462
+ ? { exitReason: "error", reason: `subprocess never became ready: ${reason}` }
463
+ : { exitReason: "idle-timeout", reason },
464
+ );
465
+ // Kill immediately: the run is lost and the child would keep doing
466
+ // billable work until close().
467
+ this.terminate();
468
+ }, this.config.idleTimeoutMs);
469
+ }
470
+
471
+ private clearIdleTimer(): void {
472
+ if (this.idleTimer) {
473
+ clearTimeout(this.idleTimer);
474
+ this.idleTimer = null;
475
+ }
476
+ }
477
+
478
+ private clearExitFlushTimer(): void {
479
+ if (this.exitFlushTimer) {
480
+ clearTimeout(this.exitFlushTimer);
481
+ this.exitFlushTimer = null;
482
+ }
483
+ }
484
+ }
485
+
486
+ export const subprocessDriver: DriverPlugin<SubprocessDriverConfig> = {
487
+ name: "subprocess",
488
+ configSchema: SubprocessDriverConfigSchema,
489
+ create: (config) => new SubprocessDriverImpl(config),
490
+ };