@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,314 @@
1
+ /**
2
+ * Terminal primitives for the live runner. Hand-rolled: the CLI needs
3
+ * perhaps 40 lines of this, and a dependency here would have to ship as a
4
+ * runtime dep of the published package for the sake of its `bin`.
5
+ */
6
+
7
+ // Assembled from a variable so the escape byte never appears as a literal
8
+ // control character inside a regex or string constant.
9
+ const ESC = String.fromCharCode(27);
10
+ const ANSI_PATTERN = new RegExp(`${ESC}\\[[0-9;?]*[A-Za-z]`, "g");
11
+ const ANSI_PREFIX = new RegExp(`^${ESC}\\[[0-9;?]*[A-Za-z]`);
12
+ const RESET = `${ESC}[0m`;
13
+
14
+ const CURSOR_HIDE = `${ESC}[?25l`;
15
+ const CURSOR_SHOW = `${ESC}[?25h`;
16
+ const ERASE_BELOW = `${ESC}[0J`;
17
+ const cursorUp = (rows: number): string => (rows > 0 ? `${ESC}[${rows}A` : "");
18
+
19
+ export const stripAnsi = (text: string): string => text.replace(ANSI_PATTERN, "");
20
+
21
+ /**
22
+ * Code points we render that occupy two terminal cells. The CJK/emoji block
23
+ * ranges cover most of it; the explicit set is the handful of pre-emoji
24
+ * symbols (⚡ especially) that default to emoji presentation and therefore
25
+ * render wide despite living below U+1F300.
26
+ */
27
+ const WIDE_SINGLETONS = new Set([0x231a, 0x231b, 0x23f0, 0x23f3, 0x26a1, 0x2705, 0x274c, 0x2b50]);
28
+
29
+ const charWidth = (codePoint: number): number => {
30
+ if (WIDE_SINGLETONS.has(codePoint)) return 2;
31
+ if (codePoint >= 0x1100 && codePoint <= 0x115f) return 2;
32
+ if (codePoint >= 0x2e80 && codePoint <= 0xa4cf) return 2;
33
+ if (codePoint >= 0xac00 && codePoint <= 0xd7a3) return 2;
34
+ if (codePoint >= 0xf900 && codePoint <= 0xfaff) return 2;
35
+ if (codePoint >= 0xfe30 && codePoint <= 0xfe6f) return 2;
36
+ if (codePoint >= 0xff00 && codePoint <= 0xff60) return 2;
37
+ if (codePoint >= 0xffe0 && codePoint <= 0xffe6) return 2;
38
+ if (codePoint >= 0x1f300 && codePoint <= 0x1faff) return 2;
39
+ return 1;
40
+ };
41
+
42
+ const graphemes = new Intl.Segmenter(undefined, { granularity: "grapheme" });
43
+
44
+ // Per-code-point counting over-counts ZWJ emoji sequences (a family emoji is
45
+ // seven code points but one two-cell glyph), so width is measured per
46
+ // grapheme cluster: any wide code point inside makes the whole cluster wide.
47
+ const clusterWidth = (cluster: string): number => {
48
+ for (const char of cluster) {
49
+ if (charWidth(char.codePointAt(0) ?? 0) === 2) return 2;
50
+ }
51
+ return 1;
52
+ };
53
+
54
+ export const visibleWidth = (text: string): number => {
55
+ let width = 0;
56
+ for (const { segment } of graphemes.segment(stripAnsi(text))) width += clusterWidth(segment);
57
+ return width;
58
+ };
59
+
60
+ /**
61
+ * Cut `text` to `maxWidth` visible cells, counting styling as zero-width.
62
+ * A line wider than the terminal would wrap, and a wrapped line breaks the
63
+ * cursor arithmetic the live region depends on — so every painted row goes
64
+ * through here.
65
+ */
66
+ export const truncate = (text: string, maxWidth: number): string => {
67
+ if (maxWidth <= 0) return "";
68
+ if (visibleWidth(text) <= maxWidth) return text;
69
+
70
+ let out = "";
71
+ let width = 0;
72
+ let index = 0;
73
+ let styled = false;
74
+
75
+ scan: while (index < text.length) {
76
+ if (text.startsWith(ESC, index)) {
77
+ const sequence = text.slice(index).match(ANSI_PREFIX)?.[0];
78
+ if (!sequence) break;
79
+ out += sequence;
80
+ styled = true;
81
+ index += sequence.length;
82
+ continue;
83
+ }
84
+ // Segment the plain-text run up to the next escape so a grapheme cluster
85
+ // is never split mid-sequence.
86
+ const nextEsc = text.indexOf(ESC, index);
87
+ const run = text.slice(index, nextEsc === -1 ? text.length : nextEsc);
88
+ for (const { segment } of graphemes.segment(run)) {
89
+ const next = width + clusterWidth(segment);
90
+ // Reserve one cell for the ellipsis.
91
+ if (next > maxWidth - 1) break scan;
92
+ out += segment;
93
+ width = next;
94
+ }
95
+ index += run.length;
96
+ }
97
+ return `${out}…${styled ? RESET : ""}`;
98
+ };
99
+
100
+ export type Theme = {
101
+ bold: (s: string) => string;
102
+ dim: (s: string) => string;
103
+ green: (s: string) => string;
104
+ red: (s: string) => string;
105
+ yellow: (s: string) => string;
106
+ cyan: (s: string) => string;
107
+ inverse: (s: string) => string;
108
+ };
109
+
110
+ const wrap =
111
+ (open: string, close: string) =>
112
+ (s: string): string =>
113
+ `${ESC}[${open}m${s}${ESC}[${close}m`;
114
+
115
+ const plain = (s: string): string => s;
116
+
117
+ export const makeTheme = (color: boolean): Theme =>
118
+ color
119
+ ? {
120
+ bold: wrap("1", "22"),
121
+ dim: wrap("2", "22"),
122
+ green: wrap("32", "39"),
123
+ red: wrap("31", "39"),
124
+ yellow: wrap("33", "39"),
125
+ cyan: wrap("36", "39"),
126
+ inverse: wrap("7", "27"),
127
+ }
128
+ : {
129
+ bold: plain,
130
+ dim: plain,
131
+ green: plain,
132
+ red: plain,
133
+ yellow: plain,
134
+ cyan: plain,
135
+ inverse: plain,
136
+ };
137
+
138
+ /**
139
+ * Honour the two conventions users actually rely on: `NO_COLOR` to force
140
+ * plain output anywhere, `FORCE_COLOR` to keep colour through a pipe (CI
141
+ * log viewers that render ANSI).
142
+ */
143
+ export const shouldColor = (stream: NodeJS.WriteStream, env: NodeJS.ProcessEnv): boolean => {
144
+ if (env.NO_COLOR) return false;
145
+ if (env.FORCE_COLOR) return env.FORCE_COLOR !== "0";
146
+ return Boolean(stream.isTTY);
147
+ };
148
+
149
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] as const;
150
+
151
+ export const spinnerFrame = (tick: number): string =>
152
+ SPINNER_FRAMES[tick % SPINNER_FRAMES.length] ?? "-";
153
+
154
+ type Patched = {
155
+ stream: NodeJS.WriteStream;
156
+ original: (chunk: string) => void;
157
+ restore: () => void;
158
+ };
159
+
160
+ export type LiveRegionOptions = {
161
+ stdout?: NodeJS.WriteStream | undefined;
162
+ /** Force live painting on/off. Defaults to `stdout.isTTY`. */
163
+ live?: boolean | undefined;
164
+ frameIntervalMs?: number | undefined;
165
+ };
166
+
167
+ /**
168
+ * A block of lines pinned to the bottom of the terminal, repainted on a
169
+ * timer so elapsed clocks tick. Anything else that writes to the terminal
170
+ * while it is active is intercepted, printed *above* the block, and the
171
+ * block repainted underneath — otherwise a stray write lands mid-frame and
172
+ * every subsequent cursor-up is off by one. Off a TTY the whole mechanism
173
+ * collapses to plain `staticLine` writes.
174
+ */
175
+ export class LiveRegion {
176
+ private readonly stdout: NodeJS.WriteStream;
177
+ private readonly writeRaw: (chunk: string) => void;
178
+ private readonly frameIntervalMs: number;
179
+ readonly live: boolean;
180
+
181
+ private renderFrame: () => string[] = () => [];
182
+ private paintedRows = 0;
183
+ private timer: NodeJS.Timeout | null = null;
184
+ private patched: Patched[] = [];
185
+ private held = new Map<NodeJS.WriteStream, string>();
186
+ private started = false;
187
+
188
+ constructor(options: LiveRegionOptions = {}) {
189
+ this.stdout = options.stdout ?? process.stdout;
190
+ // Captured before any interception, so the region's own paints never
191
+ // recurse back through the patched writer.
192
+ const original = this.stdout.write.bind(this.stdout);
193
+ this.writeRaw = (chunk) => {
194
+ original(chunk);
195
+ };
196
+ this.live = options.live ?? Boolean(this.stdout.isTTY);
197
+ this.frameIntervalMs = options.frameIntervalMs ?? 80;
198
+ }
199
+
200
+ start(renderFrame: () => string[]): void {
201
+ this.renderFrame = renderFrame;
202
+ if (!this.live || this.started) return;
203
+ this.started = true;
204
+ this.writeRaw(CURSOR_HIDE);
205
+ this.intercept(process.stderr);
206
+ this.timer = setInterval(() => this.repaint(), this.frameIntervalMs);
207
+ // Never let the repaint timer be the reason the process stays alive.
208
+ this.timer.unref();
209
+ // Interrupt handling belongs to the CLI, which has a run to unwind; the
210
+ // region only guarantees the cursor comes back however the process ends.
211
+ process.once("exit", this.onExit);
212
+ this.paint();
213
+ }
214
+
215
+ /**
216
+ * Print a permanent line above the live block. Before `start()` and after
217
+ * `stop()` there is no block to move, so the line goes straight out — which
218
+ * is also exactly the non-TTY behaviour.
219
+ */
220
+ staticLine(text: string): void {
221
+ if (!this.live || !this.started) {
222
+ this.writeRaw(`${text}\n`);
223
+ return;
224
+ }
225
+ this.clear();
226
+ this.writeRaw(`${text}\n`);
227
+ this.paint();
228
+ }
229
+
230
+ repaint(): void {
231
+ if (!this.live || !this.started) return;
232
+ this.clear();
233
+ this.paint();
234
+ }
235
+
236
+ stop(): void {
237
+ if (!this.live || !this.started) return;
238
+ this.started = false;
239
+ if (this.timer) clearInterval(this.timer);
240
+ this.timer = null;
241
+ this.clear();
242
+ for (const { stream, original, restore } of this.patched) {
243
+ const rest = this.held.get(stream);
244
+ if (rest) original(`${rest}\n`);
245
+ restore();
246
+ }
247
+ this.patched = [];
248
+ this.held.clear();
249
+ this.writeRaw(CURSOR_SHOW);
250
+ process.off("exit", this.onExit);
251
+ }
252
+
253
+ private readonly onExit = (): void => {
254
+ if (this.started) this.writeRaw(CURSOR_SHOW);
255
+ };
256
+
257
+ private clear(): void {
258
+ if (this.paintedRows === 0) return;
259
+ this.writeRaw(cursorUp(this.paintedRows) + ERASE_BELOW);
260
+ this.paintedRows = 0;
261
+ }
262
+
263
+ private paint(): void {
264
+ const columns = this.stdout.columns ?? 80;
265
+ const maxRows = Math.max(1, (this.stdout.rows ?? 24) - 1);
266
+ const lines = this.renderFrame()
267
+ .slice(-maxRows)
268
+ .map((line) => truncate(line, columns - 1));
269
+ if (lines.length === 0) return;
270
+ this.writeRaw(lines.map((line) => `${line}\n`).join(""));
271
+ this.paintedRows = lines.length;
272
+ }
273
+
274
+ /**
275
+ * Buffer a foreign stream to whole lines before letting it through: a
276
+ * half-written line cannot be painted over cleanly, and the subprocess
277
+ * driver relays agent stderr in arbitrary chunks.
278
+ */
279
+ private intercept(stream: NodeJS.WriteStream): void {
280
+ if (!stream.isTTY) return;
281
+ const original = stream.write.bind(stream);
282
+ const emit = (chunk: string): void => {
283
+ original(chunk);
284
+ };
285
+ const patched = (
286
+ chunk: string | Uint8Array,
287
+ encoding?: unknown,
288
+ callback?: unknown,
289
+ ): boolean => {
290
+ const done = typeof encoding === "function" ? encoding : callback;
291
+ const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf-8");
292
+ const buffered = (this.held.get(stream) ?? "") + text;
293
+ const lastBreak = buffered.lastIndexOf("\n");
294
+ if (lastBreak === -1) {
295
+ this.held.set(stream, buffered);
296
+ } else {
297
+ this.held.set(stream, buffered.slice(lastBreak + 1));
298
+ this.clear();
299
+ emit(buffered.slice(0, lastBreak + 1));
300
+ this.paint();
301
+ }
302
+ if (typeof done === "function") (done as () => void)();
303
+ return true;
304
+ };
305
+ stream.write = patched as unknown as typeof stream.write;
306
+ this.patched.push({
307
+ stream,
308
+ original: emit,
309
+ restore: () => {
310
+ stream.write = original as typeof stream.write;
311
+ },
312
+ });
313
+ }
314
+ }
@@ -0,0 +1,82 @@
1
+ import { InvalidArgumentError } from "commander";
2
+
3
+ export type RunOptions = {
4
+ tag?: string[];
5
+ loop?: number;
6
+ concurrency?: number;
7
+ list?: boolean;
8
+ listTags?: boolean;
9
+ interactive?: boolean;
10
+ claudeAnswerer?: boolean;
11
+ runsRoot?: string;
12
+ profile?: string;
13
+ subjectRoot?: string;
14
+ verbose?: boolean;
15
+ };
16
+
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
+ export const parseAnnotationAssertion = (
28
+ value: string,
29
+ ): [string, { passed: boolean; score?: number }] => {
30
+ 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");
33
+ }
34
+ const score = match[3] === undefined ? undefined : parseUnitInterval(match[3]);
35
+ return [
36
+ match[1],
37
+ {
38
+ passed: match[2] === "pass",
39
+ ...(score !== undefined ? { score } : {}),
40
+ },
41
+ ];
42
+ };
43
+
44
+ export const parsePositiveInt = (value: string): number => {
45
+ // Number() rejects partial numbers such as "3abc" and "2.9".
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");
57
+ }
58
+ return parsed;
59
+ };
60
+
61
+ export const resolveConcurrency = (
62
+ options: Pick<RunOptions, "concurrency" | "interactive" | "claudeAnswerer">,
63
+ configured: number,
64
+ ): { concurrency: number; note?: string } => {
65
+ const requested = options.concurrency ?? configured;
66
+ let liveFlag: "--interactive" | "--claude-answerer" | null = null;
67
+ if (options.interactive) liveFlag = "--interactive";
68
+ else if (options.claudeAnswerer) liveFlag = "--claude-answerer";
69
+ if (liveFlag && requested > 1) {
70
+ return {
71
+ concurrency: 1,
72
+ note: `lux: ${liveFlag} is a live session; running one case at a time (ignoring concurrency ${requested})\n`,
73
+ };
74
+ }
75
+ return { concurrency: requested };
76
+ };
77
+
78
+ export const resolveAnswererOverride = (options: RunOptions): string | undefined => {
79
+ if (options.interactive) return "terminal";
80
+ if (options.claudeAnswerer) return "claude-code";
81
+ return undefined;
82
+ };
@@ -0,0 +1,129 @@
1
+ import { lstat, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join, relative, resolve, sep } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { z } from "zod";
6
+
7
+ const PlatformSchema = z.enum(["claude", "claude-code", "codex", "all"]);
8
+ export type SkillsPlatform = z.infer<typeof PlatformSchema>;
9
+ const SkillNameSchema = z.enum(["lux", "lux-answerer"]);
10
+ export type BundledSkillName = z.infer<typeof SkillNameSchema>;
11
+
12
+ const InstallSkillsOptionsSchema = z
13
+ .object({
14
+ cwd: z.string().min(1),
15
+ platform: PlatformSchema,
16
+ project: z.boolean().default(false),
17
+ dir: z.string().min(1).optional(),
18
+ name: SkillNameSchema.optional(),
19
+ })
20
+ .strict();
21
+
22
+ export interface InstalledSkill {
23
+ name: BundledSkillName;
24
+ platform: "claude-code" | "codex";
25
+ path: string;
26
+ }
27
+
28
+ const BUNDLED_SKILLS = [
29
+ {
30
+ name: "lux",
31
+ description: "Author and drive coding-agent evals with Lux",
32
+ platforms: ["claude-code", "codex"],
33
+ },
34
+ {
35
+ name: "lux-answerer",
36
+ description: "Play a simulated user for a running Lux eval",
37
+ platforms: ["claude-code"],
38
+ },
39
+ ] as const satisfies readonly {
40
+ name: BundledSkillName;
41
+ description: string;
42
+ platforms: readonly ("claude-code" | "codex")[];
43
+ }[];
44
+
45
+ export const formatSkillsList = (): string =>
46
+ BUNDLED_SKILLS.map(
47
+ ({ name, description, platforms }) => `${name}\t${description}\t${platforms.join(",")}`,
48
+ ).join("\n");
49
+
50
+ const targetsFor = (
51
+ platform: SkillsPlatform,
52
+ cwd: string,
53
+ project: boolean,
54
+ dir?: string,
55
+ name?: BundledSkillName,
56
+ ): (InstalledSkill & { source: string })[] => {
57
+ const platforms =
58
+ platform === "all"
59
+ ? (["claude-code", "codex"] as const)
60
+ : ([platform === "claude" ? "claude-code" : platform] as const);
61
+ const scopeRoot = project ? resolve(cwd) : homedir();
62
+ const skills = name ? BUNDLED_SKILLS.filter((skill) => skill.name === name) : BUNDLED_SKILLS;
63
+ return platforms.flatMap((platformName) =>
64
+ skills
65
+ .filter((skill) =>
66
+ (skill.platforms as readonly ("claude-code" | "codex")[]).includes(platformName),
67
+ )
68
+ .map((skill) => ({
69
+ name: skill.name,
70
+ platform: platformName,
71
+ source: fileURLToPath(new URL(`../../skills/${skill.name}`, import.meta.url)),
72
+ path: dir
73
+ ? join(resolve(dir), skill.name)
74
+ : join(
75
+ scopeRoot,
76
+ platformName === "claude-code" ? ".claude" : ".codex",
77
+ "skills",
78
+ skill.name,
79
+ ),
80
+ })),
81
+ );
82
+ };
83
+
84
+ const copySkillDirectory = async (source: string, target: string): Promise<void> => {
85
+ const sourceInfo = await lstat(source);
86
+ if (!sourceInfo.isDirectory() || sourceInfo.isSymbolicLink()) {
87
+ throw new Error(`lux skills: bundled skill source is not a real directory: ${source}`);
88
+ }
89
+ await mkdir(target, { recursive: true });
90
+ for (const entry of await readdir(source, { withFileTypes: true })) {
91
+ const sourcePath = join(source, entry.name);
92
+ const targetPath = join(target, entry.name);
93
+ if (entry.isSymbolicLink()) {
94
+ throw new Error(`lux skills: bundled skill contains a symbolic link: ${sourcePath}`);
95
+ }
96
+ if (entry.isDirectory()) {
97
+ await copySkillDirectory(sourcePath, targetPath);
98
+ } else if (entry.isFile()) {
99
+ await mkdir(dirname(targetPath), { recursive: true });
100
+ await writeFile(targetPath, await readFile(sourcePath));
101
+ } else {
102
+ throw new Error(`lux skills: bundled skill contains an unsupported entry: ${sourcePath}`);
103
+ }
104
+ }
105
+ };
106
+
107
+ export const installSkills = async (
108
+ options: z.input<typeof InstallSkillsOptionsSchema>,
109
+ ): Promise<InstalledSkill[]> => {
110
+ const parsed = InstallSkillsOptionsSchema.parse(options);
111
+ const targets = targetsFor(parsed.platform, parsed.cwd, parsed.project, parsed.dir, parsed.name);
112
+ if (targets.length === 0) {
113
+ throw new Error(
114
+ `lux skills: '${parsed.name}' is not available for platform '${parsed.platform}'`,
115
+ );
116
+ }
117
+ for (const target of targets) await copySkillDirectory(target.source, target.path);
118
+ return targets.map(({ source: _, ...installed }) => installed);
119
+ };
120
+
121
+ export const formatSkillsInstall = (installed: InstalledSkill[], cwd: string): string =>
122
+ installed
123
+ .map(
124
+ ({ name, platform, path }) =>
125
+ `installed ${name} skill for ${platform} at ${
126
+ relative(cwd, path).split(sep).join("/") || "."
127
+ }`,
128
+ )
129
+ .join("\n");
@@ -0,0 +1,104 @@
1
+ import { z } from "zod";
2
+ import { formatZodIssues } from "./zod.js";
3
+
4
+ const ExpectedBooleanLabelSchema = z
5
+ .object({
6
+ passed: z.boolean(),
7
+ score: z.number().min(0).max(1).optional(),
8
+ })
9
+ .strict();
10
+
11
+ export const GraderAnnotationSchema = z
12
+ .object({
13
+ /** Stable label identity within the dataset. */
14
+ id: z.string().min(1),
15
+ /** Persisted Lux run containing the evidence to grade. */
16
+ runDir: z.string().min(1),
17
+ /** Candidate-relative declarative rubric whose assertions grade this run. */
18
+ rubricPath: z
19
+ .string()
20
+ .min(1)
21
+ .transform((path) => path.replaceAll("\\", "/")),
22
+ /** Optional selection labels used by experiment split selectors. */
23
+ tags: z.array(z.string()).default([]),
24
+ expected: z
25
+ .object({
26
+ casePassed: z.boolean().optional(),
27
+ caseScore: z.number().min(0).max(1).optional(),
28
+ assertions: z.record(z.string(), ExpectedBooleanLabelSchema).default({}),
29
+ })
30
+ .strict(),
31
+ /** Whether the label was independently authored or generated as test data. */
32
+ source: z.enum(["human", "synthetic"]),
33
+ annotator: z.string().min(1).optional(),
34
+ labeledAt: z.string().datetime().optional(),
35
+ reviewer: z.string().min(1).optional(),
36
+ /** Human rationale supplied to the rubric optimizer on mismatches. */
37
+ feedback: z.string().optional(),
38
+ meta: z.record(z.string(), z.unknown()).optional(),
39
+ })
40
+ .strict()
41
+ .superRefine((annotation, ctx) => {
42
+ if (
43
+ annotation.expected.casePassed === undefined &&
44
+ annotation.expected.caseScore === undefined &&
45
+ Object.keys(annotation.expected.assertions).length === 0
46
+ ) {
47
+ ctx.addIssue({
48
+ code: "custom",
49
+ path: ["expected"],
50
+ message: "annotation requires a case pass/score label or at least one assertion label",
51
+ });
52
+ }
53
+ if (
54
+ annotation.rubricPath.startsWith("/") ||
55
+ annotation.rubricPath.split(/[\\/]/).includes("..")
56
+ ) {
57
+ ctx.addIssue({
58
+ code: "custom",
59
+ path: ["rubricPath"],
60
+ message: "rubricPath must stay within the experiment subject root",
61
+ });
62
+ }
63
+ if (!annotation.rubricPath.toLowerCase().endsWith(".json")) {
64
+ ctx.addIssue({
65
+ code: "custom",
66
+ path: ["rubricPath"],
67
+ message: "grader experiments require a declarative .json rubric",
68
+ });
69
+ }
70
+ });
71
+ export type GraderAnnotation = z.output<typeof GraderAnnotationSchema>;
72
+
73
+ export const GraderAnnotationDatasetSchema = z
74
+ .object({
75
+ schemaVersion: z.literal(1),
76
+ annotations: z.array(GraderAnnotationSchema).min(1),
77
+ meta: z.record(z.string(), z.unknown()).optional(),
78
+ })
79
+ .strict()
80
+ .superRefine((dataset, ctx) => {
81
+ const ids = new Set<string>();
82
+ for (const [index, annotation] of dataset.annotations.entries()) {
83
+ if (ids.has(annotation.id)) {
84
+ ctx.addIssue({
85
+ code: "custom",
86
+ path: ["annotations", index, "id"],
87
+ message: `duplicate annotation id '${annotation.id}'`,
88
+ });
89
+ }
90
+ ids.add(annotation.id);
91
+ }
92
+ });
93
+ export type GraderAnnotationDatasetInput = z.input<typeof GraderAnnotationDatasetSchema>;
94
+ export type GraderAnnotationDataset = z.output<typeof GraderAnnotationDatasetSchema>;
95
+
96
+ export const defineGraderAnnotations = (
97
+ input: GraderAnnotationDatasetInput,
98
+ ): GraderAnnotationDataset => {
99
+ const parsed = GraderAnnotationDatasetSchema.safeParse(input);
100
+ if (!parsed.success) {
101
+ throw new Error(`Invalid Lux grader annotations: ${formatZodIssues(parsed.error)}`);
102
+ }
103
+ return parsed.data;
104
+ };
@@ -0,0 +1,75 @@
1
+ import { z } from "zod";
2
+ import type { Answer, Interrupt } from "./events.js";
3
+ import { type TokenUsage, TokenUsageSchema } from "./usage.js";
4
+
5
+ export type AnswerHistoryEntry = {
6
+ interrupt: Interrupt;
7
+ answer: Answer;
8
+ durationMs: number;
9
+ };
10
+
11
+ export type AnswererContext = {
12
+ persona: string | null;
13
+ prompt: string;
14
+ history: AnswerHistoryEntry[];
15
+ runDir: string;
16
+ /**
17
+ * Fires when the run is being torn down. Answerers that spawn subprocesses
18
+ * or block on external input must abandon the in-flight answer, or a
19
+ * Ctrl-C leaves billable agent calls running past the run's end.
20
+ */
21
+ abortSignal?: AbortSignal;
22
+ /**
23
+ * Persists a model-attempt start before a model-backed answerer invokes its
24
+ * provider.
25
+ */
26
+ recordModelAttemptStart?: (kind: "answerer") => Promise<string>;
27
+ /**
28
+ * Atomically settles one model-backed answer and re-checks campaign limits
29
+ * before another interrupt may invoke the provider.
30
+ */
31
+ recordModelAttemptComplete?: (
32
+ attemptId: string,
33
+ accounting: AnswererModelCallAccounting,
34
+ ) => Promise<void>;
35
+ };
36
+
37
+ export const AnswererModelCallAccountingSchema = z
38
+ .object({
39
+ usage: TokenUsageSchema,
40
+ costUsd: z.number().nonnegative().optional(),
41
+ unpricedModelCalls: z.number().int().nonnegative(),
42
+ })
43
+ .strict();
44
+ export type AnswererModelCallAccounting = z.infer<typeof AnswererModelCallAccountingSchema>;
45
+
46
+ export const AnswererModelAccountingSchema = z
47
+ .object({
48
+ calls: z.number().int().nonnegative(),
49
+ reportedCostUsd: z.number().nonnegative(),
50
+ unpricedModelCalls: z.number().int().nonnegative(),
51
+ })
52
+ .strict();
53
+ export type AnswererModelAccounting = z.infer<typeof AnswererModelAccountingSchema>;
54
+
55
+ export interface Answerer {
56
+ prepare(ctx: AnswererContext): Promise<void>;
57
+ /**
58
+ * Must settle within a bounded time (every bundled answerer enforces its
59
+ * own wait budget). Drivers pause their idle clock while a question is
60
+ * outstanding — the user's thinking time is not the agent's — so an
61
+ * answer() that never settles hangs the run until its abort signal fires.
62
+ */
63
+ answer(interrupt: Interrupt, ctx: AnswererContext): Promise<Answer>;
64
+ close(): Promise<void>;
65
+ /** Tokens spent playing the user, accumulated across every answer. */
66
+ usage?(): TokenUsage;
67
+ /** Model calls made by the answerer, kept separate from the subject driver. */
68
+ modelAccounting?(): AnswererModelAccounting;
69
+ }
70
+
71
+ export type AnswererPlugin<Cfg = unknown> = {
72
+ name: string;
73
+ configSchema?: z.ZodTypeAny;
74
+ create: (config: Cfg) => Answerer | Promise<Answerer>;
75
+ };