@prismatic-io/lux 0.0.2-preview.3 → 0.0.2-preview.32

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 (727) hide show
  1. package/lib/answerers/claude-code/index.d.ts +15 -3
  2. package/lib/answerers/claude-code/index.d.ts.map +1 -1
  3. package/lib/answerers/claude-code/index.js +6 -5
  4. package/lib/answerers/claude-code/index.js.map +1 -1
  5. package/lib/answerers/persona/index.d.ts +44 -5
  6. package/lib/answerers/persona/index.d.ts.map +1 -1
  7. package/lib/answerers/persona/index.js +60 -34
  8. package/lib/answerers/persona/index.js.map +1 -1
  9. package/lib/answerers/terminal/index.d.ts +9 -3
  10. package/lib/answerers/terminal/index.d.ts.map +1 -1
  11. package/lib/answerers/terminal/index.js +7 -5
  12. package/lib/answerers/terminal/index.js.map +1 -1
  13. package/lib/assertions/authoring.d.ts +2 -2
  14. package/lib/assertions/authoring.d.ts.map +1 -1
  15. package/lib/assertions/authoring.js.map +1 -1
  16. package/lib/assertions/core/command-exits-zero.d.ts +4 -1
  17. package/lib/assertions/core/command-exits-zero.d.ts.map +1 -1
  18. package/lib/assertions/core/command-exits-zero.js +50 -7
  19. package/lib/assertions/core/command-exits-zero.js.map +1 -1
  20. package/lib/assertions/core/event-checks.d.ts +3 -0
  21. package/lib/assertions/core/event-checks.d.ts.map +1 -1
  22. package/lib/assertions/core/event-checks.js +49 -3
  23. package/lib/assertions/core/event-checks.js.map +1 -1
  24. package/lib/assertions/core/file-checks.d.ts +6 -0
  25. package/lib/assertions/core/file-checks.d.ts.map +1 -1
  26. package/lib/assertions/core/helpers.d.ts +2 -7
  27. package/lib/assertions/core/helpers.d.ts.map +1 -1
  28. package/lib/assertions/core/helpers.js +2 -6
  29. package/lib/assertions/core/helpers.js.map +1 -1
  30. package/lib/assertions/core/index.d.ts.map +1 -1
  31. package/lib/assertions/core/index.js +2 -1
  32. package/lib/assertions/core/index.js.map +1 -1
  33. package/lib/assertions/core/json-pointer-equals.d.ts +1 -0
  34. package/lib/assertions/core/json-pointer-equals.d.ts.map +1 -1
  35. package/lib/assertions/core/output-checks.d.ts +3 -0
  36. package/lib/assertions/core/output-checks.d.ts.map +1 -1
  37. package/lib/assertions/core/predicate.d.ts +1 -0
  38. package/lib/assertions/core/predicate.d.ts.map +1 -1
  39. package/lib/assertions/core/resource-checks.d.ts +25 -0
  40. package/lib/assertions/core/resource-checks.d.ts.map +1 -1
  41. package/lib/assertions/core/resource-checks.js +35 -5
  42. package/lib/assertions/core/resource-checks.js.map +1 -1
  43. package/lib/assertions/rubric/index.d.ts +28 -3
  44. package/lib/assertions/rubric/index.d.ts.map +1 -1
  45. package/lib/assertions/rubric/index.js +59 -13
  46. package/lib/assertions/rubric/index.js.map +1 -1
  47. package/lib/assertions/rubric/internal.d.ts +30 -5
  48. package/lib/assertions/rubric/internal.d.ts.map +1 -1
  49. package/lib/assertions/rubric/internal.js +181 -28
  50. package/lib/assertions/rubric/internal.js.map +1 -1
  51. package/lib/authoring.d.ts +36 -2
  52. package/lib/authoring.d.ts.map +1 -1
  53. package/lib/authoring.js +36 -1
  54. package/lib/authoring.js.map +1 -1
  55. package/lib/cli/bin.js +2 -13
  56. package/lib/cli/bin.js.map +1 -1
  57. package/lib/cli/command-runtime.d.ts +3 -3
  58. package/lib/cli/command-runtime.d.ts.map +1 -1
  59. package/lib/cli/command-runtime.js +17 -6
  60. package/lib/cli/command-runtime.js.map +1 -1
  61. package/lib/cli/doctor.d.ts +55 -0
  62. package/lib/cli/doctor.d.ts.map +1 -0
  63. package/lib/cli/doctor.js +14 -0
  64. package/lib/cli/doctor.js.map +1 -0
  65. package/lib/cli/harness-plan.d.ts +26 -0
  66. package/lib/cli/harness-plan.d.ts.map +1 -0
  67. package/lib/cli/harness-plan.js +75 -0
  68. package/lib/cli/harness-plan.js.map +1 -0
  69. package/lib/cli/init-templates.d.ts +11 -0
  70. package/lib/cli/init-templates.d.ts.map +1 -0
  71. package/lib/cli/init-templates.js +215 -0
  72. package/lib/cli/init-templates.js.map +1 -0
  73. package/lib/cli/init.d.ts +10 -0
  74. package/lib/cli/init.d.ts.map +1 -1
  75. package/lib/cli/init.js +34 -173
  76. package/lib/cli/init.js.map +1 -1
  77. package/lib/cli/output-schemas.d.ts +1408 -0
  78. package/lib/cli/output-schemas.d.ts.map +1 -0
  79. package/lib/cli/output-schemas.js +91 -0
  80. package/lib/cli/output-schemas.js.map +1 -0
  81. package/lib/cli/program.d.ts +140 -12
  82. package/lib/cli/program.d.ts.map +1 -1
  83. package/lib/cli/program.js +779 -646
  84. package/lib/cli/program.js.map +1 -1
  85. package/lib/cli/render/reporter.d.ts.map +1 -1
  86. package/lib/cli/render/reporter.js +48 -8
  87. package/lib/cli/render/reporter.js.map +1 -1
  88. package/lib/cli/run-options.d.ts +20 -4
  89. package/lib/cli/run-options.d.ts.map +1 -1
  90. package/lib/cli/run-options.js +100 -19
  91. package/lib/cli/run-options.js.map +1 -1
  92. package/lib/cli/view.d.ts +15 -0
  93. package/lib/cli/view.d.ts.map +1 -0
  94. package/lib/cli/view.js +168 -0
  95. package/lib/cli/view.js.map +1 -0
  96. package/lib/container/driver.d.ts +27 -0
  97. package/lib/container/driver.d.ts.map +1 -0
  98. package/lib/container/driver.js +197 -0
  99. package/lib/container/driver.js.map +1 -0
  100. package/lib/container/protocol.d.ts +12 -0
  101. package/lib/container/protocol.d.ts.map +1 -0
  102. package/lib/container/protocol.js +38 -0
  103. package/lib/container/protocol.js.map +1 -0
  104. package/lib/container/resources.d.ts +12 -0
  105. package/lib/container/resources.d.ts.map +1 -0
  106. package/lib/container/resources.js +133 -0
  107. package/lib/container/resources.js.map +1 -0
  108. package/lib/container/worker.d.ts +2 -0
  109. package/lib/container/worker.d.ts.map +1 -0
  110. package/lib/container/worker.js +85 -0
  111. package/lib/container/worker.js.map +1 -0
  112. package/lib/core/action-events.d.ts +29 -0
  113. package/lib/core/action-events.d.ts.map +1 -0
  114. package/lib/core/action-events.js +51 -0
  115. package/lib/core/action-events.js.map +1 -0
  116. package/lib/core/agent-activity.d.ts +49 -0
  117. package/lib/core/agent-activity.d.ts.map +1 -0
  118. package/lib/core/agent-activity.js +206 -0
  119. package/lib/core/agent-activity.js.map +1 -0
  120. package/lib/core/agent-environment.d.ts +5 -0
  121. package/lib/core/agent-environment.d.ts.map +1 -0
  122. package/lib/core/agent-environment.js +47 -0
  123. package/lib/core/agent-environment.js.map +1 -0
  124. package/lib/core/agent-events.d.ts +26 -0
  125. package/lib/core/agent-events.d.ts.map +1 -0
  126. package/lib/core/agent-events.js +13 -0
  127. package/lib/core/agent-events.js.map +1 -0
  128. package/lib/core/annotation.d.ts +6 -2
  129. package/lib/core/annotation.d.ts.map +1 -1
  130. package/lib/core/annotation.js +2 -1
  131. package/lib/core/annotation.js.map +1 -1
  132. package/lib/core/answerer.d.ts +12 -0
  133. package/lib/core/answerer.d.ts.map +1 -1
  134. package/lib/core/answerer.js +2 -0
  135. package/lib/core/answerer.js.map +1 -1
  136. package/lib/core/artifact-evidence.d.ts +8 -0
  137. package/lib/core/artifact-evidence.d.ts.map +1 -1
  138. package/lib/core/artifact-evidence.js +36 -4
  139. package/lib/core/artifact-evidence.js.map +1 -1
  140. package/lib/core/assertion.d.ts +20 -2
  141. package/lib/core/assertion.d.ts.map +1 -1
  142. package/lib/core/assertion.js +19 -1
  143. package/lib/core/assertion.js.map +1 -1
  144. package/lib/core/case.d.ts +111 -3
  145. package/lib/core/case.d.ts.map +1 -1
  146. package/lib/core/case.js +17 -2
  147. package/lib/core/case.js.map +1 -1
  148. package/lib/core/command-verification.d.ts +10 -0
  149. package/lib/core/command-verification.d.ts.map +1 -0
  150. package/lib/core/command-verification.js +66 -0
  151. package/lib/core/command-verification.js.map +1 -0
  152. package/lib/core/driver-execution.d.ts +83 -0
  153. package/lib/core/driver-execution.d.ts.map +1 -0
  154. package/lib/core/driver-execution.js +72 -0
  155. package/lib/core/driver-execution.js.map +1 -0
  156. package/lib/core/driver-metrics.d.ts +98 -0
  157. package/lib/core/driver-metrics.d.ts.map +1 -0
  158. package/lib/core/driver-metrics.js +36 -0
  159. package/lib/core/driver-metrics.js.map +1 -0
  160. package/lib/core/driver.d.ts +64 -0
  161. package/lib/core/driver.d.ts.map +1 -1
  162. package/lib/core/driver.js +28 -0
  163. package/lib/core/driver.js.map +1 -1
  164. package/lib/core/duration.d.ts +5 -0
  165. package/lib/core/duration.d.ts.map +1 -0
  166. package/lib/core/duration.js +49 -0
  167. package/lib/core/duration.js.map +1 -0
  168. package/lib/core/environment.d.ts +18 -0
  169. package/lib/core/environment.d.ts.map +1 -0
  170. package/lib/core/environment.js +21 -0
  171. package/lib/core/environment.js.map +1 -0
  172. package/lib/core/evaluation-clusters.d.ts +17 -0
  173. package/lib/core/evaluation-clusters.d.ts.map +1 -0
  174. package/lib/core/evaluation-clusters.js +23 -0
  175. package/lib/core/evaluation-clusters.js.map +1 -0
  176. package/lib/core/events.d.ts +36 -0
  177. package/lib/core/events.d.ts.map +1 -1
  178. package/lib/core/events.js +12 -2
  179. package/lib/core/events.js.map +1 -1
  180. package/lib/core/experiment.d.ts +32 -2
  181. package/lib/core/experiment.d.ts.map +1 -1
  182. package/lib/core/experiment.js +35 -18
  183. package/lib/core/experiment.js.map +1 -1
  184. package/lib/core/file-tree.d.ts +7 -0
  185. package/lib/core/file-tree.d.ts.map +1 -0
  186. package/lib/core/file-tree.js +35 -0
  187. package/lib/core/file-tree.js.map +1 -0
  188. package/lib/core/global-id.d.ts +6 -0
  189. package/lib/core/global-id.d.ts.map +1 -0
  190. package/lib/core/global-id.js +17 -0
  191. package/lib/core/global-id.js.map +1 -0
  192. package/lib/core/harness-catalog.d.ts +35 -0
  193. package/lib/core/harness-catalog.d.ts.map +1 -0
  194. package/lib/core/harness-catalog.js +45 -0
  195. package/lib/core/harness-catalog.js.map +1 -0
  196. package/lib/core/harness-catalogs/antigravity.d.ts +11 -0
  197. package/lib/core/harness-catalogs/antigravity.d.ts.map +1 -0
  198. package/lib/core/harness-catalogs/antigravity.js +23 -0
  199. package/lib/core/harness-catalogs/antigravity.js.map +1 -0
  200. package/lib/core/harness-catalogs/claude-code.d.ts +12 -0
  201. package/lib/core/harness-catalogs/claude-code.d.ts.map +1 -0
  202. package/lib/core/harness-catalogs/claude-code.js +24 -0
  203. package/lib/core/harness-catalogs/claude-code.js.map +1 -0
  204. package/lib/core/harness-catalogs/codex.d.ts +11 -0
  205. package/lib/core/harness-catalogs/codex.d.ts.map +1 -0
  206. package/lib/core/harness-catalogs/codex.js +26 -0
  207. package/lib/core/harness-catalogs/codex.js.map +1 -0
  208. package/lib/core/harness-catalogs/copilot.d.ts +29 -0
  209. package/lib/core/harness-catalogs/copilot.d.ts.map +1 -0
  210. package/lib/core/harness-catalogs/copilot.js +45 -0
  211. package/lib/core/harness-catalogs/copilot.js.map +1 -0
  212. package/lib/core/harness-catalogs/cursor.d.ts +2 -0
  213. package/lib/core/harness-catalogs/cursor.d.ts.map +1 -0
  214. package/lib/core/harness-catalogs/cursor.js +13 -0
  215. package/lib/core/harness-catalogs/cursor.js.map +1 -0
  216. package/lib/core/harness-catalogs/grok-build.d.ts +7 -0
  217. package/lib/core/harness-catalogs/grok-build.d.ts.map +1 -0
  218. package/lib/core/harness-catalogs/grok-build.js +18 -0
  219. package/lib/core/harness-catalogs/grok-build.js.map +1 -0
  220. package/lib/core/harness-catalogs/index.d.ts +73 -0
  221. package/lib/core/harness-catalogs/index.d.ts.map +1 -0
  222. package/lib/core/harness-catalogs/index.js +17 -0
  223. package/lib/core/harness-catalogs/index.js.map +1 -0
  224. package/lib/core/harness-matrix.d.ts +154 -0
  225. package/lib/core/harness-matrix.d.ts.map +1 -0
  226. package/lib/core/harness-matrix.js +204 -0
  227. package/lib/core/harness-matrix.js.map +1 -0
  228. package/lib/core/index.d.ts +12 -0
  229. package/lib/core/index.d.ts.map +1 -1
  230. package/lib/core/index.js +12 -0
  231. package/lib/core/index.js.map +1 -1
  232. package/lib/core/lifecycle-fixtures.d.ts.map +1 -1
  233. package/lib/core/lifecycle-fixtures.js +4 -2
  234. package/lib/core/lifecycle-fixtures.js.map +1 -1
  235. package/lib/core/model-cli.d.ts +9 -11
  236. package/lib/core/model-cli.d.ts.map +1 -1
  237. package/lib/core/model-cli.js +31 -19
  238. package/lib/core/model-cli.js.map +1 -1
  239. package/lib/core/platform-process.d.ts +6 -1
  240. package/lib/core/platform-process.d.ts.map +1 -1
  241. package/lib/core/platform-process.js +49 -11
  242. package/lib/core/platform-process.js.map +1 -1
  243. package/lib/core/rubric.d.ts +1 -0
  244. package/lib/core/rubric.d.ts.map +1 -1
  245. package/lib/core/run.d.ts +293 -1
  246. package/lib/core/run.d.ts.map +1 -1
  247. package/lib/core/run.js +27 -0
  248. package/lib/core/run.js.map +1 -1
  249. package/lib/core/secure-copy.d.ts.map +1 -0
  250. package/lib/core/secure-copy.js.map +1 -0
  251. package/lib/core/usage.d.ts +5 -0
  252. package/lib/core/usage.d.ts.map +1 -1
  253. package/lib/core/usage.js +3 -0
  254. package/lib/core/usage.js.map +1 -1
  255. package/lib/core/wire.d.ts +12 -0
  256. package/lib/core/wire.d.ts.map +1 -1
  257. package/lib/core/wire.js +5 -1
  258. package/lib/core/wire.js.map +1 -1
  259. package/lib/drivers/antigravity/artifacts.d.ts +2 -0
  260. package/lib/drivers/antigravity/artifacts.d.ts.map +1 -0
  261. package/lib/drivers/antigravity/artifacts.js +33 -0
  262. package/lib/drivers/antigravity/artifacts.js.map +1 -0
  263. package/lib/drivers/antigravity/config.d.ts +88 -0
  264. package/lib/drivers/antigravity/config.d.ts.map +1 -0
  265. package/lib/drivers/antigravity/config.js +87 -0
  266. package/lib/drivers/antigravity/config.js.map +1 -0
  267. package/lib/drivers/antigravity/events.d.ts +4 -0
  268. package/lib/drivers/antigravity/events.d.ts.map +1 -0
  269. package/lib/drivers/antigravity/events.js +241 -0
  270. package/lib/drivers/antigravity/events.js.map +1 -0
  271. package/lib/drivers/antigravity/index.d.ts +114 -0
  272. package/lib/drivers/antigravity/index.d.ts.map +1 -0
  273. package/lib/drivers/antigravity/index.js +113 -0
  274. package/lib/drivers/antigravity/index.js.map +1 -0
  275. package/lib/drivers/antigravity/runtime.d.ts +7 -0
  276. package/lib/drivers/antigravity/runtime.d.ts.map +1 -0
  277. package/lib/drivers/antigravity/runtime.js +83 -0
  278. package/lib/drivers/antigravity/runtime.js.map +1 -0
  279. package/lib/drivers/claude-code/deferred-process.d.ts +17 -0
  280. package/lib/drivers/claude-code/deferred-process.d.ts.map +1 -0
  281. package/lib/drivers/claude-code/deferred-process.js +108 -0
  282. package/lib/drivers/claude-code/deferred-process.js.map +1 -0
  283. package/lib/drivers/claude-code/index.d.ts +180 -10
  284. package/lib/drivers/claude-code/index.d.ts.map +1 -1
  285. package/lib/drivers/claude-code/index.js +186 -252
  286. package/lib/drivers/claude-code/index.js.map +1 -1
  287. package/lib/drivers/claude-code/isolation.d.ts +8 -0
  288. package/lib/drivers/claude-code/isolation.d.ts.map +1 -0
  289. package/lib/drivers/claude-code/isolation.js +199 -0
  290. package/lib/drivers/claude-code/isolation.js.map +1 -0
  291. package/lib/drivers/claude-code/parse-events.d.ts.map +1 -1
  292. package/lib/drivers/claude-code/parse-events.js +73 -8
  293. package/lib/drivers/claude-code/parse-events.js.map +1 -1
  294. package/lib/drivers/codex/app-events.d.ts +9 -2
  295. package/lib/drivers/codex/app-events.d.ts.map +1 -1
  296. package/lib/drivers/codex/app-events.js +104 -12
  297. package/lib/drivers/codex/app-events.js.map +1 -1
  298. package/lib/drivers/codex/config.d.ts +66 -5
  299. package/lib/drivers/codex/config.d.ts.map +1 -1
  300. package/lib/drivers/codex/config.js +39 -8
  301. package/lib/drivers/codex/config.js.map +1 -1
  302. package/lib/drivers/codex/exec-events.d.ts +4 -0
  303. package/lib/drivers/codex/exec-events.d.ts.map +1 -0
  304. package/lib/drivers/codex/exec-events.js +230 -0
  305. package/lib/drivers/codex/exec-events.js.map +1 -0
  306. package/lib/drivers/codex/index.d.ts +138 -4
  307. package/lib/drivers/codex/index.d.ts.map +1 -1
  308. package/lib/drivers/codex/index.js +112 -276
  309. package/lib/drivers/codex/index.js.map +1 -1
  310. package/lib/drivers/copilot/config.d.ts +84 -0
  311. package/lib/drivers/copilot/config.d.ts.map +1 -0
  312. package/lib/drivers/copilot/config.js +57 -0
  313. package/lib/drivers/copilot/config.js.map +1 -0
  314. package/lib/drivers/copilot/index.d.ts +107 -0
  315. package/lib/drivers/copilot/index.d.ts.map +1 -0
  316. package/lib/drivers/copilot/index.js +268 -0
  317. package/lib/drivers/copilot/index.js.map +1 -0
  318. package/lib/drivers/cursor/config.d.ts +28 -0
  319. package/lib/drivers/cursor/config.d.ts.map +1 -0
  320. package/lib/drivers/cursor/config.js +28 -0
  321. package/lib/drivers/cursor/config.js.map +1 -0
  322. package/lib/drivers/cursor/index.d.ts +44 -0
  323. package/lib/drivers/cursor/index.d.ts.map +1 -0
  324. package/lib/drivers/cursor/index.js +286 -0
  325. package/lib/drivers/cursor/index.js.map +1 -0
  326. package/lib/drivers/cursor/interaction.d.ts +6 -0
  327. package/lib/drivers/cursor/interaction.d.ts.map +1 -0
  328. package/lib/drivers/cursor/interaction.js +55 -0
  329. package/lib/drivers/cursor/interaction.js.map +1 -0
  330. package/lib/drivers/grok-build/config.d.ts +68 -0
  331. package/lib/drivers/grok-build/config.d.ts.map +1 -0
  332. package/lib/drivers/grok-build/config.js +40 -0
  333. package/lib/drivers/grok-build/config.js.map +1 -0
  334. package/lib/drivers/grok-build/index.d.ts +87 -0
  335. package/lib/drivers/grok-build/index.d.ts.map +1 -0
  336. package/lib/drivers/grok-build/index.js +293 -0
  337. package/lib/drivers/grok-build/index.js.map +1 -0
  338. package/lib/drivers/mcp/index.d.ts +37 -4
  339. package/lib/drivers/mcp/index.d.ts.map +1 -1
  340. package/lib/drivers/mcp/index.js +25 -11
  341. package/lib/drivers/mcp/index.js.map +1 -1
  342. package/lib/drivers/shared/acp-events.d.ts +15 -0
  343. package/lib/drivers/shared/acp-events.d.ts.map +1 -0
  344. package/lib/drivers/shared/acp-events.js +83 -0
  345. package/lib/drivers/shared/acp-events.js.map +1 -0
  346. package/lib/drivers/shared/acp-interaction.d.ts +7 -0
  347. package/lib/drivers/shared/acp-interaction.d.ts.map +1 -0
  348. package/lib/drivers/shared/acp-interaction.js +20 -0
  349. package/lib/drivers/shared/acp-interaction.js.map +1 -0
  350. package/lib/drivers/shared/acp-session.d.ts +4 -0
  351. package/lib/drivers/shared/acp-session.d.ts.map +1 -0
  352. package/lib/drivers/shared/acp-session.js +23 -0
  353. package/lib/drivers/shared/acp-session.js.map +1 -0
  354. package/lib/drivers/shared/acp-transport.d.ts +40 -0
  355. package/lib/drivers/shared/acp-transport.d.ts.map +1 -0
  356. package/lib/drivers/shared/acp-transport.js +152 -0
  357. package/lib/drivers/shared/acp-transport.js.map +1 -0
  358. package/lib/drivers/shared/artifacts.d.ts.map +1 -1
  359. package/lib/drivers/shared/artifacts.js +3 -2
  360. package/lib/drivers/shared/artifacts.js.map +1 -1
  361. package/lib/drivers/shared/experiment-behavior.d.ts +13 -0
  362. package/lib/drivers/shared/experiment-behavior.d.ts.map +1 -0
  363. package/lib/drivers/shared/experiment-behavior.js +197 -0
  364. package/lib/drivers/shared/experiment-behavior.js.map +1 -0
  365. package/lib/drivers/shared/experiment-policy.d.ts +4 -0
  366. package/lib/drivers/shared/experiment-policy.d.ts.map +1 -0
  367. package/lib/drivers/shared/experiment-policy.js +143 -0
  368. package/lib/drivers/shared/experiment-policy.js.map +1 -0
  369. package/lib/drivers/subprocess/index.d.ts +39 -4
  370. package/lib/drivers/subprocess/index.d.ts.map +1 -1
  371. package/lib/drivers/subprocess/index.js +56 -12
  372. package/lib/drivers/subprocess/index.js.map +1 -1
  373. package/lib/index.d.ts +22 -8
  374. package/lib/index.d.ts.map +1 -1
  375. package/lib/index.js +20 -6
  376. package/lib/index.js.map +1 -1
  377. package/lib/optimization/reflective.d.ts +3 -1
  378. package/lib/optimization/reflective.d.ts.map +1 -1
  379. package/lib/optimization/reflective.js +3 -2
  380. package/lib/optimization/reflective.js.map +1 -1
  381. package/lib/orchestrator/annotation-loader.d.ts +6 -2
  382. package/lib/orchestrator/annotation-loader.d.ts.map +1 -1
  383. package/lib/orchestrator/annotation-loader.js +8 -0
  384. package/lib/orchestrator/annotation-loader.js.map +1 -1
  385. package/lib/orchestrator/annotation-store.d.ts.map +1 -1
  386. package/lib/orchestrator/annotation-store.js +16 -2
  387. package/lib/orchestrator/annotation-store.js.map +1 -1
  388. package/lib/orchestrator/artifact-origin.d.ts +3 -0
  389. package/lib/orchestrator/artifact-origin.d.ts.map +1 -0
  390. package/lib/orchestrator/artifact-origin.js +40 -0
  391. package/lib/orchestrator/artifact-origin.js.map +1 -0
  392. package/lib/orchestrator/campaign-lifecycle.d.ts +1 -0
  393. package/lib/orchestrator/campaign-lifecycle.d.ts.map +1 -1
  394. package/lib/orchestrator/campaign-lifecycle.js +4 -1
  395. package/lib/orchestrator/campaign-lifecycle.js.map +1 -1
  396. package/lib/orchestrator/candidates.d.ts.map +1 -1
  397. package/lib/orchestrator/candidates.js +3 -2
  398. package/lib/orchestrator/candidates.js.map +1 -1
  399. package/lib/orchestrator/compare.d.ts +19 -3
  400. package/lib/orchestrator/compare.d.ts.map +1 -1
  401. package/lib/orchestrator/compare.js +32 -6
  402. package/lib/orchestrator/compare.js.map +1 -1
  403. package/lib/orchestrator/comparison-identity.d.ts.map +1 -1
  404. package/lib/orchestrator/comparison-identity.js +2 -0
  405. package/lib/orchestrator/comparison-identity.js.map +1 -1
  406. package/lib/orchestrator/config.d.ts +179 -1
  407. package/lib/orchestrator/config.d.ts.map +1 -1
  408. package/lib/orchestrator/config.js +18 -4
  409. package/lib/orchestrator/config.js.map +1 -1
  410. package/lib/orchestrator/discover.d.ts +1 -0
  411. package/lib/orchestrator/discover.d.ts.map +1 -1
  412. package/lib/orchestrator/discover.js +7 -1
  413. package/lib/orchestrator/discover.js.map +1 -1
  414. package/lib/orchestrator/doctor.d.ts +1 -0
  415. package/lib/orchestrator/doctor.d.ts.map +1 -1
  416. package/lib/orchestrator/doctor.js +121 -33
  417. package/lib/orchestrator/doctor.js.map +1 -1
  418. package/lib/orchestrator/driver-capabilities.d.ts +4 -0
  419. package/lib/orchestrator/driver-capabilities.d.ts.map +1 -0
  420. package/lib/orchestrator/driver-capabilities.js +13 -0
  421. package/lib/orchestrator/driver-capabilities.js.map +1 -0
  422. package/lib/orchestrator/driver-identity.d.ts +5 -0
  423. package/lib/orchestrator/driver-identity.d.ts.map +1 -0
  424. package/lib/orchestrator/driver-identity.js +51 -0
  425. package/lib/orchestrator/driver-identity.js.map +1 -0
  426. package/lib/orchestrator/experiment-context.d.ts +51 -3
  427. package/lib/orchestrator/experiment-context.d.ts.map +1 -1
  428. package/lib/orchestrator/experiment-context.js.map +1 -1
  429. package/lib/orchestrator/experiment-contracts.d.ts +30 -1
  430. package/lib/orchestrator/experiment-contracts.d.ts.map +1 -1
  431. package/lib/orchestrator/experiment-corpus.d.ts +2 -1
  432. package/lib/orchestrator/experiment-corpus.d.ts.map +1 -1
  433. package/lib/orchestrator/experiment-corpus.js +28 -22
  434. package/lib/orchestrator/experiment-corpus.js.map +1 -1
  435. package/lib/orchestrator/experiment-effects.d.ts +33 -0
  436. package/lib/orchestrator/experiment-effects.d.ts.map +1 -0
  437. package/lib/orchestrator/experiment-effects.js +44 -0
  438. package/lib/orchestrator/experiment-effects.js.map +1 -0
  439. package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -1
  440. package/lib/orchestrator/experiment-evaluation.js +56 -5
  441. package/lib/orchestrator/experiment-evaluation.js.map +1 -1
  442. package/lib/orchestrator/experiment-identity.d.ts +3 -0
  443. package/lib/orchestrator/experiment-identity.d.ts.map +1 -1
  444. package/lib/orchestrator/experiment-identity.js +22 -33
  445. package/lib/orchestrator/experiment-identity.js.map +1 -1
  446. package/lib/orchestrator/experiment-loader.d.ts +8 -3
  447. package/lib/orchestrator/experiment-loader.d.ts.map +1 -1
  448. package/lib/orchestrator/experiment-preflight.d.ts +3 -0
  449. package/lib/orchestrator/experiment-preflight.d.ts.map +1 -0
  450. package/lib/orchestrator/experiment-preflight.js +21 -0
  451. package/lib/orchestrator/experiment-preflight.js.map +1 -0
  452. package/lib/orchestrator/experiment-report.d.ts +90 -1
  453. package/lib/orchestrator/experiment-report.d.ts.map +1 -1
  454. package/lib/orchestrator/experiment-report.js +9 -1
  455. package/lib/orchestrator/experiment-report.js.map +1 -1
  456. package/lib/orchestrator/experiment-runs.d.ts +61 -2
  457. package/lib/orchestrator/experiment-runs.d.ts.map +1 -1
  458. package/lib/orchestrator/experiment-runs.js +13 -5
  459. package/lib/orchestrator/experiment-runs.js.map +1 -1
  460. package/lib/orchestrator/experiment-runtime-identity.d.ts +0 -16
  461. package/lib/orchestrator/experiment-runtime-identity.d.ts.map +1 -1
  462. package/lib/orchestrator/experiment-runtime-identity.js +5 -220
  463. package/lib/orchestrator/experiment-runtime-identity.js.map +1 -1
  464. package/lib/orchestrator/experiment-selection.d.ts.map +1 -1
  465. package/lib/orchestrator/experiment-selection.js +52 -0
  466. package/lib/orchestrator/experiment-selection.js.map +1 -1
  467. package/lib/orchestrator/experiment.d.ts +3 -3
  468. package/lib/orchestrator/experiment.d.ts.map +1 -1
  469. package/lib/orchestrator/experiment.js +26 -21
  470. package/lib/orchestrator/experiment.js.map +1 -1
  471. package/lib/orchestrator/fixture-identity.d.ts +1 -0
  472. package/lib/orchestrator/fixture-identity.d.ts.map +1 -1
  473. package/lib/orchestrator/fixture-identity.js +6 -1
  474. package/lib/orchestrator/fixture-identity.js.map +1 -1
  475. package/lib/orchestrator/fs-read.d.ts +1 -6
  476. package/lib/orchestrator/fs-read.d.ts.map +1 -1
  477. package/lib/orchestrator/fs-read.js +2 -32
  478. package/lib/orchestrator/fs-read.js.map +1 -1
  479. package/lib/orchestrator/grader-experiment.d.ts +33 -3
  480. package/lib/orchestrator/grader-experiment.d.ts.map +1 -1
  481. package/lib/orchestrator/grader-experiment.js +54 -9
  482. package/lib/orchestrator/grader-experiment.js.map +1 -1
  483. package/lib/orchestrator/grading.d.ts +2 -1
  484. package/lib/orchestrator/grading.d.ts.map +1 -1
  485. package/lib/orchestrator/grading.js +46 -31
  486. package/lib/orchestrator/grading.js.map +1 -1
  487. package/lib/orchestrator/harness-catalog-drift.d.ts +22 -0
  488. package/lib/orchestrator/harness-catalog-drift.d.ts.map +1 -0
  489. package/lib/orchestrator/harness-catalog-drift.js +90 -0
  490. package/lib/orchestrator/harness-catalog-drift.js.map +1 -0
  491. package/lib/orchestrator/harness-registry.d.ts +4 -0
  492. package/lib/orchestrator/harness-registry.d.ts.map +1 -0
  493. package/lib/orchestrator/harness-registry.js +5 -0
  494. package/lib/orchestrator/harness-registry.js.map +1 -0
  495. package/lib/orchestrator/index.d.ts +1 -1
  496. package/lib/orchestrator/index.d.ts.map +1 -1
  497. package/lib/orchestrator/index.js +1 -1
  498. package/lib/orchestrator/index.js.map +1 -1
  499. package/lib/orchestrator/list-runs.d.ts +8 -1
  500. package/lib/orchestrator/list-runs.d.ts.map +1 -1
  501. package/lib/orchestrator/list-runs.js +81 -14
  502. package/lib/orchestrator/list-runs.js.map +1 -1
  503. package/lib/orchestrator/optimization-lifecycle.d.ts.map +1 -1
  504. package/lib/orchestrator/optimization-lifecycle.js +3 -1
  505. package/lib/orchestrator/optimization-lifecycle.js.map +1 -1
  506. package/lib/orchestrator/orchestrator.d.ts +18 -2
  507. package/lib/orchestrator/orchestrator.d.ts.map +1 -1
  508. package/lib/orchestrator/orchestrator.js +50 -168
  509. package/lib/orchestrator/orchestrator.js.map +1 -1
  510. package/lib/orchestrator/paired-effects.d.ts +34 -0
  511. package/lib/orchestrator/paired-effects.d.ts.map +1 -0
  512. package/lib/orchestrator/paired-effects.js +158 -0
  513. package/lib/orchestrator/paired-effects.js.map +1 -0
  514. package/lib/orchestrator/provenance.d.ts +5 -1
  515. package/lib/orchestrator/provenance.d.ts.map +1 -1
  516. package/lib/orchestrator/provenance.js +16 -3
  517. package/lib/orchestrator/provenance.js.map +1 -1
  518. package/lib/orchestrator/regrade.d.ts +9 -1
  519. package/lib/orchestrator/regrade.d.ts.map +1 -1
  520. package/lib/orchestrator/rubric-loader.js +1 -1
  521. package/lib/orchestrator/rubric-loader.js.map +1 -1
  522. package/lib/orchestrator/run-dir.d.ts +2 -0
  523. package/lib/orchestrator/run-dir.d.ts.map +1 -1
  524. package/lib/orchestrator/run-dir.js +1 -1
  525. package/lib/orchestrator/run-dir.js.map +1 -1
  526. package/lib/orchestrator/run-execution.d.ts +3 -0
  527. package/lib/orchestrator/run-execution.d.ts.map +1 -1
  528. package/lib/orchestrator/run-execution.js +66 -12
  529. package/lib/orchestrator/run-execution.js.map +1 -1
  530. package/lib/orchestrator/run-lifecycle.d.ts +1 -0
  531. package/lib/orchestrator/run-lifecycle.d.ts.map +1 -1
  532. package/lib/orchestrator/run-lifecycle.js +3 -2
  533. package/lib/orchestrator/run-lifecycle.js.map +1 -1
  534. package/lib/orchestrator/run-workspace.d.ts +10 -0
  535. package/lib/orchestrator/run-workspace.d.ts.map +1 -0
  536. package/lib/orchestrator/run-workspace.js +58 -0
  537. package/lib/orchestrator/run-workspace.js.map +1 -0
  538. package/lib/orchestrator/suite-compare.d.ts +37 -0
  539. package/lib/orchestrator/suite-compare.d.ts.map +1 -1
  540. package/lib/orchestrator/suite-compare.js +27 -17
  541. package/lib/orchestrator/suite-compare.js.map +1 -1
  542. package/lib/orchestrator/suite-runs.d.ts +6 -1
  543. package/lib/orchestrator/suite-runs.d.ts.map +1 -1
  544. package/lib/orchestrator/suite-runs.js +14 -2
  545. package/lib/orchestrator/suite-runs.js.map +1 -1
  546. package/lib/orchestrator/suite-summary.d.ts +77 -0
  547. package/lib/orchestrator/suite-summary.d.ts.map +1 -1
  548. package/lib/orchestrator/suite-summary.js +61 -12
  549. package/lib/orchestrator/suite-summary.js.map +1 -1
  550. package/lib/previewer/artifacts.d.ts +25 -0
  551. package/lib/previewer/artifacts.d.ts.map +1 -0
  552. package/lib/previewer/artifacts.js +180 -0
  553. package/lib/previewer/artifacts.js.map +1 -0
  554. package/lib/previewer/server.d.ts +111 -0
  555. package/lib/previewer/server.d.ts.map +1 -0
  556. package/lib/previewer/server.js +558 -0
  557. package/lib/previewer/server.js.map +1 -0
  558. package/package.json +3 -3
  559. package/skills/lux-answerer/SKILL.md +2 -2
  560. package/src/answerers/claude-code/index.ts +6 -5
  561. package/src/answerers/persona/index.ts +75 -34
  562. package/src/answerers/terminal/index.ts +8 -12
  563. package/src/assertions/authoring.ts +2 -0
  564. package/src/assertions/core/command-exits-zero.ts +61 -7
  565. package/src/assertions/core/event-checks.ts +64 -3
  566. package/src/assertions/core/helpers.ts +3 -6
  567. package/src/assertions/core/index.ts +2 -0
  568. package/src/assertions/core/resource-checks.ts +38 -5
  569. package/src/assertions/rubric/index.ts +68 -13
  570. package/src/assertions/rubric/internal.ts +227 -27
  571. package/src/authoring.ts +345 -2
  572. package/src/cli/bin.ts +2 -12
  573. package/src/cli/command-runtime.ts +20 -9
  574. package/src/cli/doctor.ts +17 -0
  575. package/src/cli/harness-plan.ts +117 -0
  576. package/src/cli/init-templates.ts +238 -0
  577. package/src/cli/init.ts +53 -184
  578. package/src/cli/output-schemas.ts +106 -0
  579. package/src/cli/program.ts +691 -721
  580. package/src/cli/render/reporter.ts +50 -8
  581. package/src/cli/run-options.ts +132 -25
  582. package/src/cli/view.ts +129 -0
  583. package/src/container/driver.ts +211 -0
  584. package/src/container/protocol.ts +48 -0
  585. package/src/container/resources.ts +153 -0
  586. package/src/container/worker.ts +107 -0
  587. package/src/core/action-events.ts +59 -0
  588. package/src/core/agent-activity.ts +236 -0
  589. package/src/core/agent-environment.ts +64 -0
  590. package/src/core/agent-events.ts +17 -0
  591. package/src/core/annotation.ts +2 -1
  592. package/src/core/answerer.ts +9 -0
  593. package/src/core/artifact-evidence.ts +47 -4
  594. package/src/core/assertion.ts +21 -1
  595. package/src/core/case.ts +21 -3
  596. package/src/core/command-verification.ts +74 -0
  597. package/src/core/driver-execution.ts +84 -0
  598. package/src/core/driver-metrics.ts +51 -0
  599. package/src/core/driver.ts +76 -0
  600. package/src/core/duration.ts +52 -0
  601. package/src/core/environment.ts +22 -0
  602. package/src/core/evaluation-clusters.ts +35 -0
  603. package/src/core/events.ts +14 -2
  604. package/src/core/experiment.ts +64 -24
  605. package/src/core/file-tree.ts +35 -0
  606. package/src/core/global-id.ts +26 -0
  607. package/src/core/harness-catalog.ts +100 -0
  608. package/src/core/harness-catalogs/antigravity.ts +24 -0
  609. package/src/core/harness-catalogs/claude-code.ts +25 -0
  610. package/src/core/harness-catalogs/codex.ts +27 -0
  611. package/src/core/harness-catalogs/copilot.ts +46 -0
  612. package/src/core/harness-catalogs/cursor.ts +13 -0
  613. package/src/core/harness-catalogs/grok-build.ts +19 -0
  614. package/src/core/harness-catalogs/index.ts +31 -0
  615. package/src/core/harness-matrix.ts +316 -0
  616. package/src/core/index.ts +12 -0
  617. package/src/core/lifecycle-fixtures.ts +4 -2
  618. package/src/core/model-cli.ts +52 -23
  619. package/src/core/platform-process.ts +58 -10
  620. package/src/core/run.ts +31 -0
  621. package/src/core/usage.ts +8 -0
  622. package/src/core/wire.ts +5 -1
  623. package/src/drivers/antigravity/README.md +171 -0
  624. package/src/drivers/antigravity/artifacts.ts +37 -0
  625. package/src/drivers/antigravity/config.ts +92 -0
  626. package/src/drivers/antigravity/events.ts +290 -0
  627. package/src/drivers/antigravity/index.ts +132 -0
  628. package/src/drivers/antigravity/runtime.ts +94 -0
  629. package/src/drivers/claude-code/deferred-process.ts +118 -0
  630. package/src/drivers/claude-code/index.ts +216 -281
  631. package/src/drivers/claude-code/isolation.ts +228 -0
  632. package/src/drivers/claude-code/parse-events.ts +98 -12
  633. package/src/drivers/codex/app-events.ts +126 -16
  634. package/src/drivers/codex/config.ts +50 -8
  635. package/src/drivers/codex/exec-events.ts +258 -0
  636. package/src/drivers/codex/index.ts +144 -312
  637. package/src/drivers/copilot/README.md +60 -0
  638. package/src/drivers/copilot/config.ts +61 -0
  639. package/src/drivers/copilot/index.ts +310 -0
  640. package/src/drivers/cursor/README.md +66 -0
  641. package/src/drivers/cursor/config.ts +31 -0
  642. package/src/drivers/cursor/index.ts +326 -0
  643. package/src/drivers/cursor/interaction.ts +74 -0
  644. package/src/drivers/grok-build/README.md +112 -0
  645. package/src/drivers/grok-build/config.ts +43 -0
  646. package/src/drivers/grok-build/index.ts +331 -0
  647. package/src/drivers/mcp/index.ts +25 -11
  648. package/src/drivers/shared/acp-events.ts +94 -0
  649. package/src/drivers/shared/acp-interaction.ts +27 -0
  650. package/src/drivers/shared/acp-session.ts +40 -0
  651. package/src/drivers/shared/acp-transport.ts +187 -0
  652. package/src/drivers/shared/artifacts.ts +6 -2
  653. package/src/drivers/shared/experiment-behavior.ts +214 -0
  654. package/src/drivers/shared/experiment-policy.ts +195 -0
  655. package/src/drivers/subprocess/index.ts +55 -12
  656. package/src/index.ts +115 -10
  657. package/src/optimization/reflective.ts +3 -2
  658. package/src/orchestrator/annotation-loader.ts +10 -0
  659. package/src/orchestrator/annotation-store.ts +24 -3
  660. package/src/orchestrator/artifact-origin.ts +50 -0
  661. package/src/orchestrator/campaign-lifecycle.ts +5 -1
  662. package/src/orchestrator/candidates.ts +3 -2
  663. package/src/orchestrator/compare.ts +41 -6
  664. package/src/orchestrator/comparison-identity.ts +2 -0
  665. package/src/orchestrator/config.ts +20 -3
  666. package/src/orchestrator/discover.ts +8 -1
  667. package/src/orchestrator/doctor.ts +189 -28
  668. package/src/orchestrator/driver-capabilities.ts +21 -0
  669. package/src/orchestrator/driver-identity.ts +69 -0
  670. package/src/orchestrator/experiment-context.ts +3 -2
  671. package/src/orchestrator/experiment-corpus.ts +53 -37
  672. package/src/orchestrator/experiment-effects.ts +61 -0
  673. package/src/orchestrator/experiment-evaluation.ts +71 -10
  674. package/src/orchestrator/experiment-identity.ts +42 -48
  675. package/src/orchestrator/experiment-preflight.ts +27 -0
  676. package/src/orchestrator/experiment-report.ts +21 -1
  677. package/src/orchestrator/experiment-runs.ts +11 -4
  678. package/src/orchestrator/experiment-runtime-identity.ts +5 -243
  679. package/src/orchestrator/experiment-selection.ts +77 -0
  680. package/src/orchestrator/experiment.ts +29 -29
  681. package/src/orchestrator/fixture-identity.ts +9 -1
  682. package/src/orchestrator/fs-read.ts +2 -32
  683. package/src/orchestrator/grader-experiment.ts +74 -13
  684. package/src/orchestrator/grading.ts +67 -28
  685. package/src/orchestrator/harness-catalog-drift.ts +132 -0
  686. package/src/orchestrator/harness-registry.ts +12 -0
  687. package/src/orchestrator/index.ts +1 -0
  688. package/src/orchestrator/list-runs.ts +98 -13
  689. package/src/orchestrator/optimization-lifecycle.ts +4 -1
  690. package/src/orchestrator/orchestrator.ts +92 -216
  691. package/src/orchestrator/paired-effects.ts +209 -0
  692. package/src/orchestrator/provenance.ts +23 -3
  693. package/src/orchestrator/rubric-loader.ts +1 -1
  694. package/src/orchestrator/run-dir.ts +8 -1
  695. package/src/orchestrator/run-execution.ts +77 -11
  696. package/src/orchestrator/run-lifecycle.ts +4 -2
  697. package/src/orchestrator/run-workspace.ts +62 -0
  698. package/src/orchestrator/suite-compare.ts +29 -19
  699. package/src/orchestrator/suite-runs.ts +13 -2
  700. package/src/orchestrator/suite-summary.ts +122 -13
  701. package/src/previewer/artifacts.ts +221 -0
  702. package/src/previewer/server.ts +787 -0
  703. package/viewer/app.css +2079 -0
  704. package/viewer/app.js +627 -0
  705. package/viewer/artifact-view.js +48 -0
  706. package/viewer/charts.js +86 -0
  707. package/viewer/detail.js +1237 -0
  708. package/viewer/format.js +129 -0
  709. package/viewer/index.html +151 -0
  710. package/lib/answerers/scripted/index.d.ts +0 -8
  711. package/lib/answerers/scripted/index.d.ts.map +0 -1
  712. package/lib/answerers/scripted/index.js +0 -163
  713. package/lib/answerers/scripted/index.js.map +0 -1
  714. package/lib/cli/skills.d.ts +0 -38
  715. package/lib/cli/skills.d.ts.map +0 -1
  716. package/lib/cli/skills.js +0 -84
  717. package/lib/cli/skills.js.map +0 -1
  718. package/lib/drivers/shared/secure-copy.d.ts.map +0 -1
  719. package/lib/drivers/shared/secure-copy.js.map +0 -1
  720. package/skills/lux/SKILL.md +0 -85
  721. package/skills/lux/references/cli.md +0 -102
  722. package/skills/lux/references/eval-authoring.md +0 -105
  723. package/src/answerers/scripted/index.ts +0 -186
  724. package/src/cli/skills.ts +0 -129
  725. /package/lib/{drivers/shared → core}/secure-copy.d.ts +0 -0
  726. /package/lib/{drivers/shared → core}/secure-copy.js +0 -0
  727. /package/src/{drivers/shared → core}/secure-copy.ts +0 -0
@@ -4,6 +4,7 @@ import {
4
4
  createToolOutcomeAccumulator,
5
5
  emptyRunUsage,
6
6
  type GradingAssertionEntry,
7
+ type GradingReport,
7
8
  harnessUsage,
8
9
  isUsageEmpty,
9
10
  type LifecycleStage,
@@ -18,6 +19,7 @@ import {
18
19
  TurnUsageSchema,
19
20
  totalTokens,
20
21
  } from "../../core/index.js";
22
+ import { hasAgentUsage } from "../../core/usage.js";
21
23
  import type { CaseObserver, SuiteCaseResult, SuiteObserver } from "../../orchestrator/index.js";
22
24
  import {
23
25
  formatAlignedUsage,
@@ -77,7 +79,9 @@ type CaseView = {
77
79
  assertionTotal: number;
78
80
  currentAssertion: string | null;
79
81
  assertions: GradingAssertionEntry[];
82
+ skippedAssertions: NonNullable<GradingReport["skippedAssertions"]>;
80
83
  usage: RunUsage;
84
+ agentUsageReported: boolean;
81
85
  /** Per-API-call agent usage, in order — the split behind `usage.agent`. */
82
86
  agentTurns: TurnUsage[];
83
87
  phaseDurationMs: PhaseDurations | null;
@@ -117,7 +121,13 @@ const statusMark = (status: CaseStatus, theme: Theme): string => {
117
121
 
118
122
  const assertionTally = (view: CaseView): string => {
119
123
  const passed = view.assertions.filter((a) => a.passed).length;
120
- return view.assertions.length === 0 ? "—" : `${passed}/${view.assertions.length}`;
124
+ const evaluated =
125
+ view.assertions.length === 0
126
+ ? "—"
127
+ : `${passed}/${view.assertions.filter((a) => a.passed !== null).length}`;
128
+ return view.skippedAssertions.length > 0
129
+ ? `${evaluated} · ${view.skippedAssertions.length} skipped`
130
+ : evaluated;
121
131
  };
122
132
 
123
133
  /**
@@ -154,6 +164,8 @@ const cell = (text: string, width: number): string => {
154
164
  */
155
165
  const scoreNote = (entry: GradingAssertionEntry): string => {
156
166
  if (entry.errorMessage) return entry.errorMessage;
167
+ if (entry.abstention) return "insufficient evidence";
168
+ if (entry.passed === null) return `informational; score ${formatScore(entry.score)}`;
157
169
  if (entry.passed) return "";
158
170
  const score = formatScore(entry.score);
159
171
  if (entry.threshold > 0) return `score ${score} < ${formatScore(entry.threshold)}`;
@@ -233,7 +245,9 @@ export class ConsoleReporter implements SuiteObserver {
233
245
  assertionTotal: 0,
234
246
  currentAssertion: null,
235
247
  assertions: [],
248
+ skippedAssertions: [],
236
249
  usage: emptyRunUsage(),
250
+ agentUsageReported: false,
237
251
  agentTurns: [],
238
252
  phaseDurationMs: null,
239
253
  runDir: null,
@@ -267,6 +281,13 @@ export class ConsoleReporter implements SuiteObserver {
267
281
  view.toolUnresolved = tools.unresolved;
268
282
  view.toolUnmatchedResults = tools.unmatchedResults;
269
283
  view.toolMalformed = tools.malformedEvents;
284
+ } else if (event.type === "progress" && event.kind === "driver-stderr" && this.verbose) {
285
+ const payload = event.payload as { text?: unknown; truncated?: unknown } | null;
286
+ if (payload && typeof payload.text === "string") {
287
+ this.region.staticLine(this.theme.dim(` [${view.caseId}] ${payload.text}`));
288
+ if (payload.truncated === true)
289
+ this.region.staticLine(this.theme.dim(" [driver stderr truncated]"));
290
+ }
270
291
  } else if (event.type === "progress" && event.kind === "usage") {
271
292
  const turn = TurnUsageSchema.safeParse(event.payload).data;
272
293
  if (turn) view.agentTurns.push(turn);
@@ -299,7 +320,9 @@ export class ConsoleReporter implements SuiteObserver {
299
320
  if (result.errorMessage) view.errorMessage = result.errorMessage;
300
321
  if (result.result) {
301
322
  view.assertions = result.result.grading.assertions;
323
+ view.skippedAssertions = result.result.grading.skippedAssertions ?? [];
302
324
  view.usage = result.result.metadata.usage;
325
+ view.agentUsageReported = hasAgentUsage(result.result.metadata);
303
326
  view.phaseDurationMs = result.result.metadata.phaseDurationMs ?? null;
304
327
  const tools = result.result.metadata.toolOutcomes;
305
328
  if (tools) {
@@ -315,6 +338,7 @@ export class ConsoleReporter implements SuiteObserver {
315
338
  // Assertions reported before the run failed to persist are not results
316
339
  // and must not inflate the closing tally of a case that errored.
317
340
  view.assertions = [];
341
+ view.skippedAssertions = [];
318
342
  }
319
343
 
320
344
  this.region.staticLine(this.finishedLine(view));
@@ -443,15 +467,24 @@ export class ConsoleReporter implements SuiteObserver {
443
467
  Math.max(NAME_MIN, ...view.assertions.map((a) => a.name.length)),
444
468
  );
445
469
  for (const entry of view.assertions) {
446
- const mark = entry.passed ? this.theme.green("✓") : this.theme.red("✗");
470
+ let mark = entry.passed ? this.theme.green("✓") : this.theme.red("✗");
471
+ if (entry.passed === null) mark = this.theme.dim("ℹ");
472
+ if (entry.abstention) mark = this.theme.dim("?");
447
473
  const duration = formatDuration(entry.durationMs).padStart(DURATION_COL);
448
474
  const note = scoreNote(entry);
449
- const suffix = note ? ` ${this.theme.red(note)}` : "";
475
+ const suffix = note
476
+ ? ` ${entry.abstention ? this.theme.dim(note) : this.theme.red(note)}`
477
+ : "";
450
478
  nodes.push({
451
479
  head: `${mark} ${cell(entry.name, width)} ${this.theme.dim(duration)}${suffix}`,
452
480
  body: !entry.passed && entry.comment ? [this.theme.dim(entry.comment)] : [],
453
481
  });
454
482
  }
483
+ for (const skipped of view.skippedAssertions) {
484
+ nodes.push({
485
+ head: `${this.theme.dim("⊘")} ${skipped.name} ${this.theme.dim("skipped: judge disabled")}`,
486
+ });
487
+ }
455
488
 
456
489
  if (view.toolCalls > 0 || view.toolUnmatchedResults > 0 || view.toolMalformed > 0) {
457
490
  const parts = [
@@ -550,15 +583,18 @@ export class ConsoleReporter implements SuiteObserver {
550
583
  }
551
584
 
552
585
  const assertions = this.cases.flatMap((c) => c.assertions);
553
- if (assertions.length > 0) {
586
+ const skippedAssertions = this.cases.flatMap((c) => c.skippedAssertions);
587
+ if (assertions.length > 0 || skippedAssertions.length > 0) {
554
588
  const ok = assertions.filter((a) => a.passed).length;
555
- const bad = assertions.length - ok;
589
+ const bad = assertions.filter((a) => a.passed === false).length;
556
590
  const tally = formatTally(
557
591
  [
558
592
  [ok, this.theme.green("passed")],
559
593
  [bad, this.theme.red("failed")],
594
+ [assertions.filter((a) => a.passed === null).length, this.theme.dim("informational")],
595
+ [skippedAssertions.length, this.theme.dim("skipped")],
560
596
  ],
561
- assertions.length,
597
+ assertions.length + skippedAssertions.length,
562
598
  );
563
599
  lines.push(` ${label("Assertions")}${tally}`);
564
600
  }
@@ -615,11 +651,17 @@ export class ConsoleReporter implements SuiteObserver {
615
651
  emptyRunUsage(),
616
652
  );
617
653
  const harness = harnessUsage(total);
618
- if (isUsageEmpty(total.agent) && isUsageEmpty(harness)) {
654
+ const reported = this.cases.filter(
655
+ (view) => view.agentUsageReported || !isUsageEmpty(this.agentUsageOf(view)),
656
+ ).length;
657
+ if (reported === 0 && isUsageEmpty(total.agent) && isUsageEmpty(harness)) {
619
658
  return live ? [] : [` ${label("Tokens")}${this.theme.dim("none reported")}`];
620
659
  }
621
660
 
622
- const agentText = isUsageEmpty(total.agent) ? this.theme.dim("none") : formatUsage(total.agent);
661
+ const missing = this.cases.length - reported;
662
+ const partial = missing > 0 ? ` (${missing} run${missing === 1 ? "" : "s"} unavailable)` : "";
663
+ const agentText =
664
+ reported === 0 ? this.theme.dim("unavailable") : `${formatUsage(total.agent)}${partial}`;
623
665
  if (live) {
624
666
  const harnessText = isUsageEmpty(harness)
625
667
  ? ""
@@ -1,4 +1,9 @@
1
- import { InvalidArgumentError } from "commander";
1
+ import { existsSync } from "node:fs";
2
+ import { basename, extname, resolve } from "node:path";
3
+ import { Errors } from "incur";
4
+ import type { HarnessFocus, ReasoningEffort } from "../core/index.js";
5
+ import { type DiscoveredCase, type SuiteItem, selectCases } from "../orchestrator/index.js";
6
+ import { planHarnessItems } from "./harness-plan.js";
2
7
 
3
8
  export type RunOptions = {
4
9
  tag?: string[];
@@ -8,28 +13,24 @@ export type RunOptions = {
8
13
  listTags?: boolean;
9
14
  interactive?: boolean;
10
15
  claudeAnswerer?: boolean;
16
+ skipJudge?: boolean;
11
17
  runsRoot?: string;
12
18
  profile?: string;
19
+ driver?: string;
20
+ model?: string;
21
+ effort?: ReasoningEffort;
13
22
  subjectRoot?: string;
14
23
  verbose?: boolean;
15
24
  };
16
25
 
17
- export const collectTags = (value: string, previous: string[]): string[] =>
18
- previous.concat(
19
- value
20
- .split(",")
21
- .map((tag) => tag.trim())
22
- .filter(Boolean),
23
- );
24
-
25
- export const collectValues = (value: string, previous: string[]): string[] => [...previous, value];
26
-
27
26
  export const parseAnnotationAssertion = (
28
27
  value: string,
29
28
  ): [string, { passed: boolean; score?: number }] => {
30
29
  const match = /^(.+)=(pass|fail)(?::(.+))?$/.exec(value);
31
- if (!match?.[1] || !match[2]) {
32
- throw new InvalidArgumentError("--assertion must use id=pass, id=fail, or id=pass:0.8 syntax");
30
+ if (!match?.[1]?.trim() || !match[2]) {
31
+ throw new Errors.ParseError({
32
+ message: "--assertion must use id=pass, id=fail, or id=pass:0.8 syntax",
33
+ });
33
34
  }
34
35
  const score = match[3] === undefined ? undefined : parseUnitInterval(match[3]);
35
36
  return [
@@ -41,19 +42,10 @@ export const parseAnnotationAssertion = (
41
42
  ];
42
43
  };
43
44
 
44
- export const parsePositiveInt = (value: string): number => {
45
- // Number() rejects partial numbers such as "3abc" and "2.9".
45
+ const parseUnitInterval = (value: string): number => {
46
46
  const parsed = Number(value);
47
- if (!Number.isInteger(parsed) || parsed < 1) {
48
- throw new InvalidArgumentError("must be a positive integer");
49
- }
50
- return parsed;
51
- };
52
-
53
- export const parseUnitInterval = (value: string): number => {
54
- const parsed = Number(value);
55
- if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
56
- throw new InvalidArgumentError("must be a number between 0 and 1");
47
+ if (!value.trim() || !Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
48
+ throw new Errors.ParseError({ message: "must be a number between 0 and 1" });
57
49
  }
58
50
  return parsed;
59
51
  };
@@ -80,3 +72,118 @@ export const resolveAnswererOverride = (options: RunOptions): string | undefined
80
72
  if (options.claudeAnswerer) return "claude-code";
81
73
  return undefined;
82
74
  };
75
+
76
+ const caseIdOf = (casePath: string): string => basename(casePath, extname(casePath));
77
+
78
+ export const suiteTitle = (
79
+ patterns: string[],
80
+ tags: string[],
81
+ explicit: SuiteItem[],
82
+ loop: number,
83
+ focus: HarnessFocus,
84
+ ): string => {
85
+ const parts = [...patterns, ...explicit.map((e) => e.id), ...tags.map((t) => `#${t}`)];
86
+ const filter = parts.length > 0 ? ` ${parts.join(" ")}` : "";
87
+ const focusParts = [focus.driver, focus.model, focus.effort].filter(
88
+ (part): part is string => part !== undefined,
89
+ );
90
+ const focused = focusParts.length > 0 ? ` @${focusParts.join(":")}` : "";
91
+ const repeat = loop > 1 ? ` ×${loop}` : "";
92
+ return `run${filter}${focused}${repeat}`;
93
+ };
94
+
95
+ type FilterPartition = { explicit: SuiteItem[]; patterns: string[] };
96
+
97
+ // A filter that names an existing `.ts` file runs that file directly — it may
98
+ // sit outside the discovery root. Everything else is a substring pattern — but
99
+ // a `.ts` filter that resolves to nothing is almost always a typo'd path, so
100
+ // the silent downgrade to a pattern gets called out.
101
+ export const partitionFilters = (filters: string[], cwd: string): FilterPartition => {
102
+ const explicit: SuiteItem[] = [];
103
+ const patterns: string[] = [];
104
+ for (const f of filters) {
105
+ const abs = resolve(cwd, f);
106
+ if (f.endsWith(".ts") && existsSync(abs)) {
107
+ explicit.push({ path: abs, id: caseIdOf(f) });
108
+ } else {
109
+ if (f.endsWith(".ts")) {
110
+ process.stderr.write(`lux: ${abs} does not exist; treating "${f}" as a pattern\n`);
111
+ }
112
+ patterns.push(f);
113
+ }
114
+ }
115
+ return { explicit, patterns };
116
+ };
117
+
118
+ // The selected set — substring/tag matches plus explicitly named files — is
119
+ // the same whether it is run, `--list`ed, or `--list-tags`ed. No filters at
120
+ // all means "everything discovered"; any filter narrows.
121
+ export const selectSuite = (
122
+ cases: DiscoveredCase[],
123
+ { explicit, patterns }: FilterPartition,
124
+ tags: string[],
125
+ ): DiscoveredCase[] => {
126
+ const hasFilter = explicit.length > 0 || patterns.length > 0 || tags.length > 0;
127
+ const byPath = new Map<string, DiscoveredCase>();
128
+ if (!hasFilter) {
129
+ for (const c of cases) byPath.set(c.path, c);
130
+ } else {
131
+ if (patterns.length > 0 || tags.length > 0) {
132
+ for (const c of selectCases(cases, { patterns, tags })) byPath.set(c.path, c);
133
+ }
134
+ for (const e of explicit) {
135
+ const discovered = cases.find((c) => c.path === e.path);
136
+ // Discovery knows the case's declared id; the filename-derived one is
137
+ // only a fallback for files discovery never saw.
138
+ byPath.set(e.path, {
139
+ path: e.path,
140
+ id: discovered?.id ?? e.id,
141
+ relPath: discovered?.relPath ?? e.id,
142
+ tags: discovered?.tags ?? [],
143
+ });
144
+ }
145
+ }
146
+ return [...byPath.values()].sort((a, b) => a.id.localeCompare(b.id));
147
+ };
148
+
149
+ // `--loop` repeats each eval before moving to the next; each repeat gets a
150
+ // `#n` display suffix so the reporter keeps them apart, while `caseId` keeps
151
+ // every repeat filed under one run history.
152
+ export const expandLoop = (base: SuiteItem[], loop: number): SuiteItem[] =>
153
+ loop > 1
154
+ ? base.flatMap((b) =>
155
+ Array.from({ length: loop }, (_, i) => ({
156
+ ...b,
157
+ id: `${b.id} #${i + 1}`,
158
+ caseId: b.caseId ?? b.id,
159
+ })),
160
+ )
161
+ : base;
162
+
163
+ export const planSuiteItems = async (
164
+ selected: readonly { path: string; id: string }[],
165
+ options: Parameters<typeof planHarnessItems>[1],
166
+ ): Promise<SuiteItem[]> => {
167
+ const plan = await planHarnessItems(selected, options);
168
+ for (const skipped of plan.unavailable) {
169
+ process.stderr.write(
170
+ `lux: skipping ${skipped.id}: harness command not found: ${skipped.commands.join(", ")}\n`,
171
+ );
172
+ }
173
+ if (plan.excluded.length > 0) {
174
+ process.stderr.write(
175
+ `lux: the harness focus excludes ${plan.excluded.length} pinned case${plan.excluded.length === 1 ? "" : "s"}: ${plan.excluded.join(", ")}\n`,
176
+ );
177
+ }
178
+ if (plan.items.length === 0) {
179
+ throw new Errors.IncurError({
180
+ code: plan.unavailable.length > 0 ? "NO_RUNNABLE_HARNESSES" : "NO_CASES_MATCHED",
181
+ message:
182
+ plan.unavailable.length > 0
183
+ ? "No cases remain: all selected matrix harnesses are unavailable."
184
+ : "No cases remain after applying the harness focus.",
185
+ exitCode: 1,
186
+ });
187
+ }
188
+ return plan.items;
189
+ };
@@ -0,0 +1,129 @@
1
+ import { resolve } from "node:path";
2
+ import { Errors } from "incur";
3
+ import {
4
+ isExperimentRun,
5
+ listExperimentRuns,
6
+ listRuns,
7
+ listSuiteRuns,
8
+ loadExperimentRun,
9
+ loadLuxConfig,
10
+ loadRunDetail,
11
+ loadSuiteRun,
12
+ } from "../orchestrator/index.js";
13
+ import { openPreviewUrl, startPreviewServer } from "../previewer/server.js";
14
+ import { abortOnInterrupt, ensureDirectory, failWith } from "./command-runtime.js";
15
+
16
+ const SIGINT_EXIT_CODE = 130;
17
+
18
+ export type ViewOptions = {
19
+ runsRoot?: string;
20
+ case?: string;
21
+ suites?: boolean;
22
+ experiments?: boolean;
23
+ web?: boolean;
24
+ port?: number;
25
+ open?: boolean;
26
+ };
27
+
28
+ const previewKind = async (
29
+ initialPath: string | undefined,
30
+ options: ViewOptions,
31
+ ): Promise<"run" | "suite" | "experiment" | undefined> => {
32
+ if (initialPath) {
33
+ if (isExperimentRun(initialPath)) return "experiment";
34
+ if (await loadSuiteRun(initialPath)) return "suite";
35
+ return "run";
36
+ }
37
+ if (options.experiments) return "experiment";
38
+ if (options.suites) return "suite";
39
+ return undefined;
40
+ };
41
+
42
+ export async function* webViewCommand(
43
+ runDirArg: string | undefined,
44
+ options: ViewOptions,
45
+ ): AsyncGenerator<{ url: string; runsRoot: string }, void> {
46
+ const config = await loadLuxConfig(process.cwd());
47
+ const runsRoot = options.runsRoot ? resolve(options.runsRoot) : config.runsRoot;
48
+ const initialPath = runDirArg ? resolve(runDirArg) : undefined;
49
+ if (initialPath && !(await ensureDirectory("view", initialPath))) failWith(1);
50
+ const initialKind = await previewKind(initialPath, options);
51
+ using controller = abortOnInterrupt();
52
+ const preview = await startPreviewServer({
53
+ runsRoot,
54
+ ...(options.port !== undefined ? { port: options.port } : {}),
55
+ ...(initialPath ? { initialPath } : {}),
56
+ ...(initialKind ? { initialKind } : {}),
57
+ ...(options.case ? { caseFilter: options.case } : {}),
58
+ signal: controller.signal,
59
+ });
60
+ try {
61
+ yield { url: preview.url, runsRoot };
62
+ if (options.open !== false) {
63
+ try {
64
+ await openPreviewUrl(preview.url);
65
+ } catch (error) {
66
+ const message = error instanceof Error ? error.message : String(error);
67
+ process.stderr.write(`lux view: could not open a browser (${message})\n`);
68
+ }
69
+ }
70
+ await preview.closed;
71
+ if (controller.signal.aborted) failWith(SIGINT_EXIT_CODE);
72
+ } finally {
73
+ await preview.close();
74
+ }
75
+ }
76
+
77
+ export const viewCommand = async (
78
+ runDirArg: string | undefined,
79
+ options: ViewOptions,
80
+ ): Promise<unknown> => {
81
+ if (options.port !== undefined || options.open === false) {
82
+ throw new Errors.ParseError({ message: "--port and --no-open require --web" });
83
+ }
84
+ if (runDirArg) {
85
+ const path = resolve(runDirArg);
86
+ if (!(await ensureDirectory("view", path))) return;
87
+ if (isExperimentRun(path)) {
88
+ const experiment = await loadExperimentRun(path);
89
+ if (!experiment) {
90
+ throw new Errors.IncurError({
91
+ code: "INVALID_EXPERIMENT",
92
+ message: `Invalid experiment at ${path}.`,
93
+ exitCode: 1,
94
+ });
95
+ }
96
+ return { experimentDir: path, ...experiment };
97
+ }
98
+ const suite = await loadSuiteRun(path);
99
+ if (suite) {
100
+ return { suiteDir: path, ...suite };
101
+ }
102
+ return loadRunDetail(path);
103
+ }
104
+
105
+ const config = await loadLuxConfig(process.cwd());
106
+ const runsRoot = options.runsRoot ? resolve(options.runsRoot) : config.runsRoot;
107
+ const readErrors: Array<{ path: string; message: string }> = [];
108
+ const listingOptions = {
109
+ onReadError: (path: string, error: unknown) => {
110
+ readErrors.push({ path, message: error instanceof Error ? error.message : String(error) });
111
+ },
112
+ };
113
+ if (options.experiments) {
114
+ const experiments = await listExperimentRuns(runsRoot, listingOptions);
115
+ return { runsRoot, experiments, ...(readErrors.length ? { readErrors } : {}) };
116
+ }
117
+ if (options.suites) {
118
+ const suites = await listSuiteRuns(runsRoot, listingOptions);
119
+ return { runsRoot, suites, ...(readErrors.length ? { readErrors } : {}) };
120
+ }
121
+ const all = await listRuns(runsRoot);
122
+ const runs = options.case ? all.filter((run) => run.caseSlug === options.case) : all;
123
+ return {
124
+ runsRoot,
125
+ ...(!options.case ? { suites: await listSuiteRuns(runsRoot, listingOptions) } : {}),
126
+ runs,
127
+ ...(readErrors.length ? { readErrors } : {}),
128
+ };
129
+ };
@@ -0,0 +1,211 @@
1
+ import { realpath } from "node:fs/promises";
2
+ import { resolve, sep } from "node:path";
3
+ import type { AgentDriver, Artifact, DriverEventMap, StartContext } from "../core/driver.js";
4
+ import type { ContainerExecution } from "../core/driver-execution.js";
5
+ import { TypedEmitter } from "../core/emitter.js";
6
+ import {
7
+ type Answer,
8
+ DoneSchema,
9
+ ErrorEventSchema,
10
+ InterruptSchema,
11
+ ProgressSchema,
12
+ type ReadyState,
13
+ ReadyStateSchema,
14
+ } from "../core/events.js";
15
+ import { type ManagedProcess, spawnManagedProcess } from "../core/exec.js";
16
+ import { walkArtifacts } from "../drivers/shared/artifacts.js";
17
+ import { LUX_VERSION } from "../orchestrator/package-version.js";
18
+ import { type Message, readMessages, writeMessage } from "./protocol.js";
19
+ import { prepareContainer } from "./resources.js";
20
+
21
+ export class ContainerDriver extends TypedEmitter<DriverEventMap> implements AgentDriver {
22
+ private process: ManagedProcess | undefined;
23
+ private resources: Awaited<ReturnType<typeof prepareContainer>> | undefined;
24
+ private sequence = 0;
25
+ private pending = new Map<
26
+ number,
27
+ { resolve: (value: unknown) => void; reject: (error: Error) => void }
28
+ >();
29
+ private closing: Promise<void> | undefined;
30
+ private context: StartContext | undefined;
31
+ private terminal = false;
32
+ private readonly abort = () => {
33
+ void this.close().catch(() => {});
34
+ };
35
+
36
+ private readonly name: string;
37
+ private readonly config: unknown;
38
+ private readonly execution: ContainerExecution;
39
+ constructor(name: string, config: unknown, execution: ContainerExecution) {
40
+ super();
41
+ this.name = name;
42
+ this.config = config;
43
+ this.execution = execution;
44
+ JSON.stringify(config, (_key, value: unknown) => {
45
+ if (typeof value === "function" || typeof value === "symbol" || typeof value === "bigint")
46
+ throw new Error("container driver configuration must be JSON serializable");
47
+ return value;
48
+ });
49
+ }
50
+
51
+ private fail = (error: Error): void => {
52
+ for (const pending of this.pending.values()) pending.reject(error);
53
+ this.pending.clear();
54
+ if (!this.terminal && !this.closing) {
55
+ this.terminal = true;
56
+ void this.emit("error", { exitReason: "error", reason: error.message }).catch(() => {});
57
+ }
58
+ };
59
+
60
+ private receive = (message: Message): void => {
61
+ if (message.event) {
62
+ const dispatch = async () => {
63
+ switch (message.event) {
64
+ case "interrupt":
65
+ await this.emit("interrupt", InterruptSchema.parse(message.value));
66
+ break;
67
+ case "progress":
68
+ await this.emit("progress", ProgressSchema.parse(message.value));
69
+ break;
70
+ case "done":
71
+ this.terminal = true;
72
+ await this.emit("done", DoneSchema.parse(message.value));
73
+ break;
74
+ case "error":
75
+ this.terminal = true;
76
+ await this.emit("error", ErrorEventSchema.parse(message.value));
77
+ break;
78
+ default:
79
+ throw new Error("unknown container event");
80
+ }
81
+ if (this.process) writeMessage(this.process.child.stdin, { id: message.id, ack: true });
82
+ };
83
+ void dispatch().catch(this.fail);
84
+ return;
85
+ }
86
+ const pending = this.pending.get(message.id);
87
+ if (!pending) return;
88
+ this.pending.delete(message.id);
89
+ if (message.error !== undefined) pending.reject(new Error(message.error));
90
+ else pending.resolve(message.value);
91
+ };
92
+
93
+ private rpc = (method: string, value?: unknown, timeoutMs = 30_000): Promise<unknown> =>
94
+ new Promise((resolvePromise, reject) => {
95
+ if (!this.process) {
96
+ reject(new Error("container process is unavailable"));
97
+ return;
98
+ }
99
+ const id = ++this.sequence;
100
+ const timer = setTimeout(() => {
101
+ this.pending.delete(id);
102
+ reject(new Error(`container ${method} timed out`));
103
+ }, timeoutMs);
104
+ this.pending.set(id, {
105
+ resolve: (result) => {
106
+ clearTimeout(timer);
107
+ resolvePromise(result);
108
+ },
109
+ reject: (error) => {
110
+ clearTimeout(timer);
111
+ reject(error);
112
+ },
113
+ });
114
+ try {
115
+ writeMessage(this.process.child.stdin, { id, method, value });
116
+ } catch (error) {
117
+ this.pending.get(id)?.reject(error as Error);
118
+ this.pending.delete(id);
119
+ }
120
+ });
121
+
122
+ async start(ctx: StartContext): Promise<ReadyState> {
123
+ this.context = ctx;
124
+ if (ctx.abortSignal.aborted) throw new Error("container run aborted before startup");
125
+ const raw = this.config as { cwd?: string; cwdMode?: string };
126
+ if (raw?.cwdMode === "runDir")
127
+ throw new Error("container drivers must use the artifacts workspace, not cwdMode: runDir");
128
+ if (raw?.cwd && (await realpath(raw.cwd)) !== (await realpath(ctx.artifactsDir)))
129
+ throw new Error("container driver cwd must be the mounted artifacts workspace");
130
+ this.resources = await prepareContainer(this.execution, ctx.artifactsDir);
131
+ try {
132
+ this.process = spawnManagedProcess(this.resources.command, this.resources.args, {
133
+ env: this.resources.env,
134
+ });
135
+ readMessages(this.process.child.stdout, this.receive, this.fail);
136
+ // Harness stderr can contain secrets. The normalized driver protocol is the evidence surface.
137
+ this.process.child.stderr.resume();
138
+ void this.process.exited.then(() => this.fail(new Error("container worker exited")));
139
+ ctx.abortSignal.addEventListener("abort", this.abort, { once: true });
140
+ await this.process.spawned;
141
+ if (ctx.abortSignal.aborted) throw new Error("container run aborted during startup");
142
+ const { abortSignal: _signal, ...context } = ctx;
143
+ const ready = ReadyStateSchema.parse(
144
+ await this.rpc(
145
+ "start",
146
+ {
147
+ version: LUX_VERSION,
148
+ name: this.name,
149
+ config: this.config,
150
+ module: this.execution.driverModule,
151
+ context: {
152
+ ...context,
153
+ artifactsDir: this.resources.root,
154
+ ...(context.fixtures
155
+ ? { fixtures: { ...context.fixtures, rootDir: this.resources.root } }
156
+ : {}),
157
+ runDir: "/tmp/lux-run",
158
+ runsRoot: "/tmp/lux-runs",
159
+ },
160
+ },
161
+ this.execution.startupTimeoutMs ?? 60_000,
162
+ ),
163
+ );
164
+ return {
165
+ ...ready,
166
+ detail: { ...ready.detail, execution: "container", image: this.resources.image },
167
+ };
168
+ } catch (error) {
169
+ await this.close();
170
+ throw error;
171
+ }
172
+ }
173
+
174
+ async respond(answer: Answer): Promise<void> {
175
+ await this.rpc("respond", answer);
176
+ }
177
+ async quiesce(): Promise<void> {
178
+ await this.rpc("quiesce");
179
+ }
180
+ async collect(): Promise<Artifact[]> {
181
+ const root = this.resources?.root;
182
+ if (!root) return [];
183
+ try {
184
+ const artifacts = (await this.rpc("collect")) as Artifact[];
185
+ for (const artifact of artifacts) {
186
+ const path = resolve(artifact.root ?? root, artifact.path);
187
+ if (path !== root && !path.startsWith(`${root}${sep}`))
188
+ throw new Error("container driver returned artifacts outside its mounted workspace");
189
+ }
190
+ } finally {
191
+ await this.close();
192
+ }
193
+ return walkArtifacts(root);
194
+ }
195
+ close(): Promise<void> {
196
+ this.closing ??= (async () => {
197
+ this.context?.abortSignal.removeEventListener("abort", this.abort);
198
+ try {
199
+ if (this.process) {
200
+ await this.rpc("close", undefined, 5_000).catch(() => {});
201
+ this.process.child.stdin.end();
202
+ }
203
+ await this.resources?.cleanup();
204
+ } finally {
205
+ await this.process?.terminate();
206
+ this.fail(new Error("container driver closed"));
207
+ }
208
+ })();
209
+ return this.closing;
210
+ }
211
+ }