@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,186 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { load as loadYaml } from "js-yaml";
4
+ import { z } from "zod";
5
+ import {
6
+ type Answer,
7
+ type Answerer,
8
+ type AnswererPlugin,
9
+ formatZodIssues,
10
+ type Interrupt,
11
+ InterruptKindSchema,
12
+ } from "../../core/index.js";
13
+ import { approveAnswer } from "../shared.js";
14
+
15
+ const MatchSchema = z
16
+ .object({
17
+ kind: InterruptKindSchema.optional(),
18
+ id: z.string().optional(),
19
+ question_contains: z.string().optional(),
20
+ question_matches: z.string().optional(),
21
+ request_contains: z.string().optional(),
22
+ })
23
+ .strict();
24
+
25
+ const AnsweredAskSchema = z.object({ answer: z.string() }).strict();
26
+ const AnsweredApproveSchema = z
27
+ .object({ approved: z.boolean(), reason: z.string().optional() })
28
+ .strict();
29
+ const AnsweredCustomSchema = z.object({ payload: z.unknown() }).strict();
30
+
31
+ const RuleSchema = z.union([
32
+ z.object({ match: MatchSchema, answer: z.string() }).strict(),
33
+ z.object({ match: MatchSchema, approved: z.boolean(), reason: z.string().optional() }).strict(),
34
+ z.object({ match: MatchSchema, payload: z.unknown() }).strict(),
35
+ z.object({ default: AnsweredAskSchema }).strict(),
36
+ z.object({ default: AnsweredApproveSchema }).strict(),
37
+ z.object({ default: AnsweredCustomSchema }).strict(),
38
+ ]);
39
+
40
+ const FixtureSchema = z.array(RuleSchema);
41
+
42
+ export const ScriptedAnswererConfigSchema = z.object({ fixturePath: z.string() }).strict();
43
+
44
+ export type ScriptedAnswererConfig = z.infer<typeof ScriptedAnswererConfigSchema>;
45
+
46
+ type Rule = z.infer<typeof RuleSchema>;
47
+
48
+ /** A rule vetted at load time: kind/body cross-checked, regex pre-compiled. */
49
+ type PreparedRule = { rule: Rule; questionPattern: RegExp | undefined };
50
+
51
+ const ruleLabel = (path: string, index: number): string => `rule ${index + 1} of ${path}`;
52
+
53
+ const bodyKind = (rule: Rule): Interrupt["kind"] => {
54
+ const body = "default" in rule ? rule.default : rule;
55
+ if ("answer" in body) return "ask";
56
+ if ("approved" in body) return "approve";
57
+ return "custom";
58
+ };
59
+
60
+ const matchableKind = (m: z.infer<typeof MatchSchema>): Interrupt["kind"] | undefined => {
61
+ if (m.kind) return m.kind;
62
+ if (m.question_contains !== undefined || m.question_matches !== undefined) return "ask";
63
+ if (m.request_contains !== undefined) return "approve";
64
+ return undefined;
65
+ };
66
+
67
+ const compileQuestionPattern = (rule: Rule, path: string, index: number): RegExp | undefined => {
68
+ if (!("match" in rule) || rule.match.question_matches === undefined) return undefined;
69
+ try {
70
+ return new RegExp(rule.match.question_matches);
71
+ } catch (err) {
72
+ throw new Error(
73
+ `scripted: invalid question_matches in ${ruleLabel(path, index)}: ${
74
+ err instanceof Error ? err.message : String(err)
75
+ }`,
76
+ );
77
+ }
78
+ };
79
+
80
+ // The rule's match fields and answer body are independently valid shapes, so
81
+ // their interrupt kinds still need a semantic cross-check.
82
+ const prepareRule = (rule: Rule, path: string, index: number): PreparedRule => {
83
+ if ("match" in rule) {
84
+ const wanted = matchableKind(rule.match);
85
+ const answered = bodyKind(rule);
86
+ if (wanted !== undefined && wanted !== answered) {
87
+ throw new Error(
88
+ `scripted: ${ruleLabel(path, index)} matches ${wanted} interrupts but its body answers ${answered}`,
89
+ );
90
+ }
91
+ }
92
+ return { rule, questionPattern: compileQuestionPattern(rule, path, index) };
93
+ };
94
+
95
+ const matches = ({ rule, questionPattern }: PreparedRule, interrupt: Interrupt): boolean => {
96
+ if (!("match" in rule)) return false;
97
+ const m = rule.match;
98
+ if (m.kind && m.kind !== interrupt.kind) return false;
99
+ if (m.id && m.id !== interrupt.id) return false;
100
+ if (m.question_contains) {
101
+ if (interrupt.kind !== "ask") return false;
102
+ if (!interrupt.question.includes(m.question_contains)) return false;
103
+ }
104
+ if (questionPattern) {
105
+ if (interrupt.kind !== "ask") return false;
106
+ if (!questionPattern.test(interrupt.question)) return false;
107
+ }
108
+ if (m.request_contains) {
109
+ if (interrupt.kind !== "approve") return false;
110
+ if (!interrupt.request.includes(m.request_contains)) return false;
111
+ }
112
+ return true;
113
+ };
114
+
115
+ // A fixture may carry one default per interrupt kind; the shape of the
116
+ // default's body is what says which kind it can answer.
117
+ const defaultAnswersKind = (rule: Rule, kind: Interrupt["kind"]): boolean => {
118
+ if (!("default" in rule)) return false;
119
+ const body = rule.default;
120
+ if (kind === "ask") return "answer" in body;
121
+ if (kind === "approve") return "approved" in body;
122
+ return "payload" in body;
123
+ };
124
+
125
+ const buildAnswer = (rule: Rule, interrupt: Interrupt): Answer => {
126
+ const body = "default" in rule ? rule.default : rule;
127
+ if (interrupt.kind === "ask") {
128
+ if (!("answer" in body)) {
129
+ throw new Error(`scripted: rule for ask interrupt missing 'answer' (id=${interrupt.id})`);
130
+ }
131
+ return { kind: "ask", id: interrupt.id, text: body.answer };
132
+ }
133
+ if (interrupt.kind === "approve") {
134
+ if (!("approved" in body)) {
135
+ throw new Error(
136
+ `scripted: rule for approve interrupt missing 'approved' (id=${interrupt.id})`,
137
+ );
138
+ }
139
+ return approveAnswer(interrupt.id, body.approved, body.reason);
140
+ }
141
+ if (!("payload" in body)) {
142
+ throw new Error(`scripted: rule for custom interrupt missing 'payload' (id=${interrupt.id})`);
143
+ }
144
+ return { kind: "custom", id: interrupt.id, payload: body.payload };
145
+ };
146
+
147
+ class ScriptedAnswererImpl implements Answerer {
148
+ private rules: PreparedRule[] = [];
149
+ private readonly config: ScriptedAnswererConfig;
150
+
151
+ constructor(config: ScriptedAnswererConfig) {
152
+ this.config = config;
153
+ }
154
+
155
+ async prepare(): Promise<void> {
156
+ const path = resolve(this.config.fixturePath);
157
+ const raw = loadYaml(await readFile(path, "utf-8"));
158
+ const parsed = FixtureSchema.safeParse(raw);
159
+ if (!parsed.success) {
160
+ throw new Error(`scripted: invalid fixture at ${path}: ${formatZodIssues(parsed.error)}`);
161
+ }
162
+ this.rules = parsed.data.map((rule, index) => prepareRule(rule, path, index));
163
+ }
164
+
165
+ async answer(interrupt: Interrupt): Promise<Answer> {
166
+ const matched = this.rules.find((r) => matches(r, interrupt));
167
+ if (matched) {
168
+ return buildAnswer(matched.rule, interrupt);
169
+ }
170
+ const fallback = this.rules.find((r) => defaultAnswersKind(r.rule, interrupt.kind));
171
+ if (fallback) {
172
+ return buildAnswer(fallback.rule, interrupt);
173
+ }
174
+ throw new Error(
175
+ `scripted: no rule matched interrupt (kind=${interrupt.kind}, id=${interrupt.id}) and no default provided`,
176
+ );
177
+ }
178
+
179
+ async close(): Promise<void> {}
180
+ }
181
+
182
+ export const scriptedAnswerer: AnswererPlugin<ScriptedAnswererConfig> = {
183
+ name: "scripted",
184
+ configSchema: ScriptedAnswererConfigSchema,
185
+ create: (config) => new ScriptedAnswererImpl(config),
186
+ };
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import type { Answer } from "../core/index.js";
3
+
4
+ /**
5
+ * The approve-reply wire shape shared by every answerer. Lenient on
6
+ * `reason`: replies come from an LLM or hand-written JSON, and a malformed
7
+ * reason must not invalidate a well-formed approval decision.
8
+ */
9
+ export const ApproveReplySchema = z.object({
10
+ approved: z.boolean(),
11
+ reason: z.string().optional().catch(undefined),
12
+ });
13
+
14
+ export const approveAnswer = (
15
+ id: string,
16
+ approved: boolean,
17
+ reason?: string | undefined,
18
+ ): Answer => ({
19
+ kind: "approve",
20
+ id,
21
+ approved,
22
+ ...(reason !== undefined ? { reason } : {}),
23
+ });
@@ -0,0 +1,117 @@
1
+ import { stdin, stdout } from "node:process";
2
+ import { createInterface, type Interface } from "node:readline/promises";
3
+ import { z } from "zod";
4
+ import type {
5
+ Answer,
6
+ Answerer,
7
+ AnswererContext,
8
+ AnswererPlugin,
9
+ Interrupt,
10
+ } from "../../core/index.js";
11
+ import { approveAnswer } from "../shared.js";
12
+
13
+ export const TerminalAnswererConfigSchema = z
14
+ .object({
15
+ maxAnswerWaitMs: z.number().positive().default(600_000),
16
+ })
17
+ .strict();
18
+
19
+ export type TerminalAnswererConfig = z.infer<typeof TerminalAnswererConfigSchema>;
20
+
21
+ const contextSuffix = (context: unknown): string => {
22
+ if (context === undefined) return "";
23
+ return `\nContext: ${JSON.stringify(context, null, 2)}`;
24
+ };
25
+
26
+ const promptFor = (interrupt: Interrupt): string => {
27
+ if (interrupt.kind === "ask") {
28
+ return `\nAgent question: ${interrupt.question}${contextSuffix(interrupt.context)}\nAnswer: `;
29
+ }
30
+ if (interrupt.kind === "approve") {
31
+ return `\nAgent approval request: ${interrupt.request}${contextSuffix(interrupt.context)}\nApprove? [y/N]: `;
32
+ }
33
+ return `\nAgent requested custom input: ${JSON.stringify(interrupt.payload, null, 2)}${contextSuffix(interrupt.context)}\nJSON response: `;
34
+ };
35
+
36
+ export const parseTerminalAnswer = (line: string, interrupt: Interrupt): Answer => {
37
+ if (interrupt.kind === "ask") {
38
+ return { kind: "ask", id: interrupt.id, text: line };
39
+ }
40
+ if (interrupt.kind === "approve") {
41
+ const normalized = line.trim().toLowerCase();
42
+ if (normalized === "y" || normalized === "yes") {
43
+ return approveAnswer(interrupt.id, true);
44
+ }
45
+ if (normalized === "" || normalized === "n" || normalized === "no") {
46
+ return approveAnswer(interrupt.id, false);
47
+ }
48
+ throw new Error("terminal answerer: approval must be yes/y or no/n");
49
+ }
50
+ try {
51
+ return { kind: "custom", id: interrupt.id, payload: JSON.parse(line) };
52
+ } catch (error) {
53
+ throw new Error(
54
+ `terminal answerer: custom response must be JSON: ${
55
+ error instanceof Error ? error.message : String(error)
56
+ }`,
57
+ );
58
+ }
59
+ };
60
+
61
+ class TerminalAnswererImpl implements Answerer {
62
+ private interface: Interface | null = null;
63
+ private readonly maxAnswerWaitMs: number;
64
+
65
+ constructor(config: TerminalAnswererConfig) {
66
+ this.maxAnswerWaitMs = config.maxAnswerWaitMs;
67
+ }
68
+
69
+ async prepare(): Promise<void> {
70
+ if (!stdin.isTTY || !stdout.isTTY) {
71
+ throw new Error(
72
+ "terminal answerer: --interactive requires an attached terminal; " +
73
+ "use a scripted/model answerer in CI or --claude-answerer from the Claude plugin",
74
+ );
75
+ }
76
+ this.interface = createInterface({ input: stdin, output: stdout, terminal: true });
77
+ }
78
+
79
+ async answer(interrupt: Interrupt, ctx: AnswererContext): Promise<Answer> {
80
+ if (!this.interface) throw new Error("terminal answerer: not prepared");
81
+ const controller = new AbortController();
82
+ const abort = (): void => controller.abort();
83
+ const timeout = setTimeout(abort, this.maxAnswerWaitMs);
84
+ if (ctx.abortSignal?.aborted) abort();
85
+ else ctx.abortSignal?.addEventListener("abort", abort, { once: true });
86
+ try {
87
+ const line = await this.interface.question(promptFor(interrupt), {
88
+ signal: controller.signal,
89
+ });
90
+ return parseTerminalAnswer(line, interrupt);
91
+ } catch (error) {
92
+ if (controller.signal.aborted) {
93
+ throw new Error(
94
+ ctx.abortSignal?.aborted
95
+ ? "terminal answerer: run aborted before an answer arrived"
96
+ : `terminal answerer: timed out after ${this.maxAnswerWaitMs}ms`,
97
+ { cause: error },
98
+ );
99
+ }
100
+ throw error;
101
+ } finally {
102
+ clearTimeout(timeout);
103
+ ctx.abortSignal?.removeEventListener("abort", abort);
104
+ }
105
+ }
106
+
107
+ async close(): Promise<void> {
108
+ this.interface?.close();
109
+ this.interface = null;
110
+ }
111
+ }
112
+
113
+ export const terminalAnswerer: AnswererPlugin<TerminalAnswererConfig> = {
114
+ name: "terminal",
115
+ configSchema: TerminalAnswererConfigSchema,
116
+ create: (config) => new TerminalAnswererImpl(config),
117
+ };
@@ -0,0 +1,94 @@
1
+ import { resolve } from "node:path";
2
+ import { z } from "zod";
3
+ import { type AssertionImpl, exec, hasRunArtifactEvidenceBoundary } from "../../core/index.js";
4
+ import {
5
+ baseAssertionFields,
6
+ commandEnvironment,
7
+ inspectAssertionPath,
8
+ LocationSchema,
9
+ resolveLocationRoot,
10
+ } from "./helpers.js";
11
+
12
+ export const CommandExitsZeroConfigSchema = z
13
+ .object({
14
+ type: z.literal("command-exits-zero"),
15
+ command: z.string(),
16
+ cwd: z.string().optional(),
17
+ in: LocationSchema,
18
+ env: z.record(z.string(), z.string()).optional(),
19
+ /**
20
+ * Parent variables to add to the minimal toolchain environment. Set to
21
+ * `true` only when the command deliberately needs the entire Lux process
22
+ * environment, including credentials.
23
+ */
24
+ inheritEnv: z.union([z.array(z.string().min(1)), z.literal(true)]).default([]),
25
+ timeoutMs: z.number().positive().default(120_000),
26
+ ...baseAssertionFields,
27
+ })
28
+ .strict();
29
+ export type CommandExitsZeroConfig = z.infer<typeof CommandExitsZeroConfigSchema>;
30
+
31
+ export const commandExitsZeroAssertion: AssertionImpl<CommandExitsZeroConfig> = {
32
+ type: "command-exits-zero",
33
+ configSchema: CommandExitsZeroConfigSchema,
34
+ evaluate: async (config, run, ctx) => {
35
+ let root = resolveLocationRoot(run, config.in);
36
+ if (config.cwd) {
37
+ if (hasRunArtifactEvidenceBoundary(run)) {
38
+ const inspected = await inspectAssertionPath(run, "cwd", config.cwd);
39
+ if (!inspected.stats?.isDirectory()) {
40
+ const comment =
41
+ inspected.issue ??
42
+ (inspected.stats ? `${config.cwd} is not a directory` : `${config.cwd} not found`);
43
+ return { passed: false, score: 0, comment };
44
+ }
45
+ root = inspected.target;
46
+ } else {
47
+ root = resolve(run.runDir, config.cwd);
48
+ }
49
+ }
50
+ const parentEnv = commandEnvironment(process.env, config.inheritEnv);
51
+ // The whole command line is one shell string with no interpolation, so
52
+ // `shell: true` is safe here; exec() gives it a real process-group
53
+ // timeout and an output cap the old hand-rolled spawn lacked.
54
+ let result: Awaited<ReturnType<typeof exec>>;
55
+ try {
56
+ result = await exec(config.command, [], {
57
+ cwd: root,
58
+ env: { ...parentEnv, ...config.env },
59
+ shell: true,
60
+ timeoutMs: config.timeoutMs,
61
+ maxBuffer: 4_000,
62
+ ...(ctx?.abortSignal ? { signal: ctx.abortSignal } : {}),
63
+ });
64
+ } catch (err) {
65
+ const message = err instanceof Error ? err.message : String(err);
66
+ return {
67
+ passed: false,
68
+ score: 0,
69
+ comment: message,
70
+ errorMessage: message,
71
+ detail: { error: message },
72
+ };
73
+ }
74
+ const passed = result.exitCode === 0 && !result.timedOut;
75
+ const comment = result.timedOut
76
+ ? `command timed out after ${config.timeoutMs}ms`
77
+ : `'${config.command}' exited ${result.exitCode}${result.signal ? ` (signal ${result.signal})` : ""}`;
78
+ return {
79
+ passed,
80
+ score: passed ? 1 : 0,
81
+ comment,
82
+ detail: {
83
+ exitCode: result.exitCode,
84
+ signal: result.signal,
85
+ durationMs: result.durationMs,
86
+ timedOut: result.timedOut,
87
+ stdout: result.stdout,
88
+ stderr: result.stderr,
89
+ stdoutTruncated: result.stdoutTruncated,
90
+ stderrTruncated: result.stderrTruncated,
91
+ },
92
+ };
93
+ },
94
+ };
@@ -0,0 +1,138 @@
1
+ import { z } from "zod";
2
+ import type { AssertionImpl, RunEvent } from "../../core/index.js";
3
+ import { inRange, isToolCallEvent, type ProgressEvent, weightThresholdFields } from "./helpers.js";
4
+
5
+ const isInterruptEvent = (e: RunEvent): e is Extract<RunEvent, { type: "interrupt" }> =>
6
+ e.type === "interrupt";
7
+
8
+ const toolCallName = (e: ProgressEvent): string | undefined => {
9
+ const payload = e.payload as { name?: unknown } | null | undefined;
10
+ return typeof payload?.name === "string" ? payload.name : undefined;
11
+ };
12
+
13
+ /** Present when a subagent made the call; absent for the main agent (or if the driver doesn't report it). */
14
+ const parentToolUseId = (e: ProgressEvent): string | undefined => {
15
+ const payload = e.payload as { parentToolUseId?: unknown } | null | undefined;
16
+ return typeof payload?.parentToolUseId === "string" ? payload.parentToolUseId : undefined;
17
+ };
18
+
19
+ export type AgentScope = "any" | "main" | "subagent";
20
+
21
+ /**
22
+ * Public for custom-assertion authors: whether a progress event belongs to
23
+ * the requested scope — the "main" agent, a spawned "subagent", or "any".
24
+ */
25
+ export const matchesAgentScope = (e: ProgressEvent, by: AgentScope = "any"): boolean => {
26
+ if (by === "any") return true;
27
+ const spawned = parentToolUseId(e) !== undefined;
28
+ return by === "subagent" ? spawned : !spawned;
29
+ };
30
+
31
+ export const ToolCalledConfigSchema = z
32
+ .object({
33
+ type: z.literal("tool-called"),
34
+ name: z.string(),
35
+ minTimes: z.number().int().nonnegative().optional(),
36
+ maxTimes: z.number().int().nonnegative().optional(),
37
+ /** Whose calls count: "main" agent, "subagent", or "any". */
38
+ by: z.enum(["any", "main", "subagent"]).default("any"),
39
+ ...weightThresholdFields,
40
+ })
41
+ .strict()
42
+ .refine((c) => c.minTimes === undefined || c.maxTimes === undefined || c.minTimes <= c.maxTimes, {
43
+ message: "minTimes must be <= maxTimes",
44
+ });
45
+ export type ToolCalledConfig = z.infer<typeof ToolCalledConfigSchema>;
46
+
47
+ export const toolCalledAssertion: AssertionImpl<ToolCalledConfig> = {
48
+ type: "tool-called",
49
+ configSchema: ToolCalledConfigSchema,
50
+ evaluate: async (config, run) => {
51
+ const calls = run.events
52
+ .filter(isToolCallEvent)
53
+ .filter((e) => matchesAgentScope(e, config.by))
54
+ .filter((e) => toolCallName(e) === config.name).length;
55
+ // `maxTimes: 0` means "never called"; defaulting min to 1 would make it unsatisfiable.
56
+ const min = config.minTimes ?? (config.maxTimes === undefined ? 1 : 0);
57
+ const { passed, comment } = inRange(calls, min, config.maxTimes);
58
+ const scope = config.by === "any" ? "" : ` by ${config.by}`;
59
+ return {
60
+ passed,
61
+ score: passed ? 1 : 0,
62
+ comment: `tool '${config.name}' called ${calls}×${scope} (${comment})`,
63
+ detail: { calls },
64
+ };
65
+ },
66
+ };
67
+
68
+ export const ToolCallCountConfigSchema = z
69
+ .object({
70
+ type: z.literal("tool-call-count"),
71
+ name: z.string().optional(),
72
+ min: z.number().int().nonnegative().optional(),
73
+ max: z.number().int().nonnegative().optional(),
74
+ by: z.enum(["any", "main", "subagent"]).default("any"),
75
+ ...weightThresholdFields,
76
+ })
77
+ .strict()
78
+ // With neither bound the assertion is vacuous — it would always pass.
79
+ .refine((c) => c.min !== undefined || c.max !== undefined, {
80
+ message: "set at least one of min or max",
81
+ })
82
+ .refine((c) => c.min === undefined || c.max === undefined || c.min <= c.max, {
83
+ message: "min must be <= max",
84
+ });
85
+ export type ToolCallCountConfig = z.infer<typeof ToolCallCountConfigSchema>;
86
+
87
+ export const toolCallCountAssertion: AssertionImpl<ToolCallCountConfig> = {
88
+ type: "tool-call-count",
89
+ configSchema: ToolCallCountConfigSchema,
90
+ evaluate: async (config, run) => {
91
+ const calls = run.events
92
+ .filter(isToolCallEvent)
93
+ .filter((e) => matchesAgentScope(e, config.by))
94
+ .filter((e) => !config.name || toolCallName(e) === config.name).length;
95
+ const { passed, comment } = inRange(calls, config.min, config.max);
96
+ return {
97
+ passed,
98
+ score: passed ? 1 : 0,
99
+ comment: `${calls} tool call${calls === 1 ? "" : "s"}${config.name ? ` for '${config.name}'` : ""} (${comment})`,
100
+ detail: { calls },
101
+ };
102
+ },
103
+ };
104
+
105
+ export const InterruptCountConfigSchema = z
106
+ .object({
107
+ type: z.literal("interrupt-count"),
108
+ kind: z.enum(["ask", "approve", "custom"]).optional(),
109
+ min: z.number().int().nonnegative().optional(),
110
+ max: z.number().int().nonnegative().optional(),
111
+ ...weightThresholdFields,
112
+ })
113
+ .strict()
114
+ // With neither bound the assertion is vacuous — it would always pass.
115
+ .refine((c) => c.min !== undefined || c.max !== undefined, {
116
+ message: "set at least one of min or max",
117
+ })
118
+ .refine((c) => c.min === undefined || c.max === undefined || c.min <= c.max, {
119
+ message: "min must be <= max",
120
+ });
121
+ export type InterruptCountConfig = z.infer<typeof InterruptCountConfigSchema>;
122
+
123
+ export const interruptCountAssertion: AssertionImpl<InterruptCountConfig> = {
124
+ type: "interrupt-count",
125
+ configSchema: InterruptCountConfigSchema,
126
+ evaluate: async (config, run) => {
127
+ const count = run.events
128
+ .filter(isInterruptEvent)
129
+ .filter((e) => !config.kind || e.kind === config.kind).length;
130
+ const { passed, comment } = inRange(count, config.min, config.max);
131
+ return {
132
+ passed,
133
+ score: passed ? 1 : 0,
134
+ comment: `${count} ${config.kind ?? "any-kind"} interrupt${count === 1 ? "" : "s"} (${comment})`,
135
+ detail: { count },
136
+ };
137
+ },
138
+ };