@lesliechan721/aw 0.1.0-beta.3

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 (429) hide show
  1. package/dist/authoring/assets/aw-config.d.mts +2 -0
  2. package/dist/authoring/assets/aw-config.mjs +556 -0
  3. package/dist/authoring/assets/aw-config.mjs.map +1 -0
  4. package/dist/authoring/scripts/add-skill.d.mts +2 -0
  5. package/dist/authoring/scripts/add-skill.mjs +355 -0
  6. package/dist/authoring/scripts/add-skill.mjs.map +1 -0
  7. package/dist/authoring/scripts/check-plugin-versions.d.mts +2 -0
  8. package/dist/authoring/scripts/check-plugin-versions.mjs +5 -0
  9. package/dist/authoring/scripts/check-plugin-versions.mjs.map +1 -0
  10. package/dist/authoring/scripts/init-plugin.d.mts +2 -0
  11. package/dist/authoring/scripts/init-plugin.mjs +512 -0
  12. package/dist/authoring/scripts/init-plugin.mjs.map +1 -0
  13. package/dist/authoring/scripts/lib/javascript-import-scanner.d.mts +4 -0
  14. package/dist/authoring/scripts/lib/javascript-import-scanner.mjs +261 -0
  15. package/dist/authoring/scripts/lib/javascript-import-scanner.mjs.map +1 -0
  16. package/dist/authoring/scripts/lib/plugin-root.d.mts +26 -0
  17. package/dist/authoring/scripts/lib/plugin-root.mjs +125 -0
  18. package/dist/authoring/scripts/lib/plugin-root.mjs.map +1 -0
  19. package/dist/authoring/scripts/lib/plugin-version-check.d.mts +55 -0
  20. package/dist/authoring/scripts/lib/plugin-version-check.mjs +777 -0
  21. package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -0
  22. package/dist/authoring/scripts/lib/semver.d.mts +9 -0
  23. package/dist/authoring/scripts/lib/semver.mjs +63 -0
  24. package/dist/authoring/scripts/lib/semver.mjs.map +1 -0
  25. package/dist/authoring/scripts/lib/skill-scaffold.d.mts +124 -0
  26. package/dist/authoring/scripts/lib/skill-scaffold.mjs +374 -0
  27. package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -0
  28. package/dist/authoring/scripts/plugin-status.d.mts +2 -0
  29. package/dist/authoring/scripts/plugin-status.mjs +96 -0
  30. package/dist/authoring/scripts/plugin-status.mjs.map +1 -0
  31. package/dist/authoring/scripts/validate-plugin.d.mts +2 -0
  32. package/dist/authoring/scripts/validate-plugin.mjs +4442 -0
  33. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -0
  34. package/dist/authoring/scripts/validate-skill.d.mts +2 -0
  35. package/dist/authoring/scripts/validate-skill.mjs +126 -0
  36. package/dist/authoring/scripts/validate-skill.mjs.map +1 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.js +8 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/scripts/aw-skill-eval-engine.d.ts +13 -0
  41. package/dist/scripts/aw-skill-eval-engine.js +31 -0
  42. package/dist/scripts/aw-skill-eval-engine.js.map +1 -0
  43. package/dist/scripts/bundle-plugins.d.ts +18 -0
  44. package/dist/scripts/bundle-plugins.js +123 -0
  45. package/dist/scripts/bundle-plugins.js.map +1 -0
  46. package/dist/scripts/codex-eval-app-server.d.ts +89 -0
  47. package/dist/scripts/codex-eval-app-server.js +1228 -0
  48. package/dist/scripts/codex-eval-app-server.js.map +1 -0
  49. package/dist/scripts/codex-eval-isolation.d.ts +61 -0
  50. package/dist/scripts/codex-eval-isolation.js +318 -0
  51. package/dist/scripts/codex-eval-isolation.js.map +1 -0
  52. package/dist/scripts/codex-eval-process-management.d.ts +8 -0
  53. package/dist/scripts/codex-eval-process-management.js +69 -0
  54. package/dist/scripts/codex-eval-process-management.js.map +1 -0
  55. package/dist/scripts/codex-eval-process-tree.d.ts +38 -0
  56. package/dist/scripts/codex-eval-process-tree.js +803 -0
  57. package/dist/scripts/codex-eval-process-tree.js.map +1 -0
  58. package/dist/scripts/codex-eval-runtime-config.d.ts +62 -0
  59. package/dist/scripts/codex-eval-runtime-config.js +843 -0
  60. package/dist/scripts/codex-eval-runtime-config.js.map +1 -0
  61. package/dist/scripts/codex-trigger-eval.d.ts +84 -0
  62. package/dist/scripts/codex-trigger-eval.js +968 -0
  63. package/dist/scripts/codex-trigger-eval.js.map +1 -0
  64. package/dist/scripts/eval-plugin-skills-audited.d.ts +6 -0
  65. package/dist/scripts/eval-plugin-skills-audited.js +261 -0
  66. package/dist/scripts/eval-plugin-skills-audited.js.map +1 -0
  67. package/dist/scripts/eval-plugin-skills.d.ts +45 -0
  68. package/dist/scripts/eval-plugin-skills.js +1586 -0
  69. package/dist/scripts/eval-plugin-skills.js.map +1 -0
  70. package/dist/scripts/eval-run-layout.d.ts +17 -0
  71. package/dist/scripts/eval-run-layout.js +26 -0
  72. package/dist/scripts/eval-run-layout.js.map +1 -0
  73. package/dist/scripts/plugin-eval-contract.d.ts +185 -0
  74. package/dist/scripts/plugin-eval-contract.js +695 -0
  75. package/dist/scripts/plugin-eval-contract.js.map +1 -0
  76. package/dist/scripts/plugin-eval-materializer.d.ts +13 -0
  77. package/dist/scripts/plugin-eval-materializer.js +421 -0
  78. package/dist/scripts/plugin-eval-materializer.js.map +1 -0
  79. package/dist/scripts/plugin-staging.d.ts +43 -0
  80. package/dist/scripts/plugin-staging.js +196 -0
  81. package/dist/scripts/plugin-staging.js.map +1 -0
  82. package/dist/scripts/skill-reporting.d.ts +212 -0
  83. package/dist/scripts/skill-reporting.js +922 -0
  84. package/dist/scripts/skill-reporting.js.map +1 -0
  85. package/dist/scripts/test-plugin-scripts.d.ts +7 -0
  86. package/dist/scripts/test-plugin-scripts.js +674 -0
  87. package/dist/scripts/test-plugin-scripts.js.map +1 -0
  88. package/dist/src/adapters/helpers.d.ts +44 -0
  89. package/dist/src/adapters/helpers.js +95 -0
  90. package/dist/src/adapters/helpers.js.map +1 -0
  91. package/dist/src/authoring/workspace-commands.d.ts +46 -0
  92. package/dist/src/authoring/workspace-commands.js +133 -0
  93. package/dist/src/authoring/workspace-commands.js.map +1 -0
  94. package/dist/src/commands/catalog-publish.d.ts +33 -0
  95. package/dist/src/commands/catalog-publish.js +374 -0
  96. package/dist/src/commands/catalog-publish.js.map +1 -0
  97. package/dist/src/commands/catalog-source.d.ts +111 -0
  98. package/dist/src/commands/catalog-source.js +266 -0
  99. package/dist/src/commands/catalog-source.js.map +1 -0
  100. package/dist/src/commands/console.d.ts +3 -0
  101. package/dist/src/commands/console.js +44 -0
  102. package/dist/src/commands/console.js.map +1 -0
  103. package/dist/src/commands/dependency-operation-plan.d.ts +28 -0
  104. package/dist/src/commands/dependency-operation-plan.js +15 -0
  105. package/dist/src/commands/dependency-operation-plan.js.map +1 -0
  106. package/dist/src/commands/init.d.ts +31 -0
  107. package/dist/src/commands/init.js +63 -0
  108. package/dist/src/commands/init.js.map +1 -0
  109. package/dist/src/commands/options.d.ts +68 -0
  110. package/dist/src/commands/options.js +146 -0
  111. package/dist/src/commands/options.js.map +1 -0
  112. package/dist/src/commands/rebuild-command.d.ts +77 -0
  113. package/dist/src/commands/rebuild-command.js +1681 -0
  114. package/dist/src/commands/rebuild-command.js.map +1 -0
  115. package/dist/src/commands/rebuild-integration.d.ts +94 -0
  116. package/dist/src/commands/rebuild-integration.js +3289 -0
  117. package/dist/src/commands/rebuild-integration.js.map +1 -0
  118. package/dist/src/commands/rebuild-operations.d.ts +110 -0
  119. package/dist/src/commands/rebuild-operations.js +791 -0
  120. package/dist/src/commands/rebuild-operations.js.map +1 -0
  121. package/dist/src/commands/review-publication.d.ts +99 -0
  122. package/dist/src/commands/review-publication.js +904 -0
  123. package/dist/src/commands/review-publication.js.map +1 -0
  124. package/dist/src/commands/runtime.d.ts +176 -0
  125. package/dist/src/commands/runtime.js +746 -0
  126. package/dist/src/commands/runtime.js.map +1 -0
  127. package/dist/src/commands/status-v4.d.ts +102 -0
  128. package/dist/src/commands/status-v4.js +844 -0
  129. package/dist/src/commands/status-v4.js.map +1 -0
  130. package/dist/src/commands/status.d.ts +93 -0
  131. package/dist/src/commands/status.js +442 -0
  132. package/dist/src/commands/status.js.map +1 -0
  133. package/dist/src/commands/wizard.d.ts +57 -0
  134. package/dist/src/commands/wizard.js +58 -0
  135. package/dist/src/commands/wizard.js.map +1 -0
  136. package/dist/src/commands/write-commands.d.ts +7 -0
  137. package/dist/src/commands/write-commands.js +167 -0
  138. package/dist/src/commands/write-commands.js.map +1 -0
  139. package/dist/src/constants.d.ts +25 -0
  140. package/dist/src/constants.js +26 -0
  141. package/dist/src/constants.js.map +1 -0
  142. package/dist/src/generators/agents.d.ts +3 -0
  143. package/dist/src/generators/agents.js +46 -0
  144. package/dist/src/generators/agents.js.map +1 -0
  145. package/dist/src/generators/hooks.d.ts +15 -0
  146. package/dist/src/generators/hooks.js +76 -0
  147. package/dist/src/generators/hooks.js.map +1 -0
  148. package/dist/src/generators/instructions.d.ts +13 -0
  149. package/dist/src/generators/instructions.js +66 -0
  150. package/dist/src/generators/instructions.js.map +1 -0
  151. package/dist/src/generators/local-plugin.d.ts +53 -0
  152. package/dist/src/generators/local-plugin.js +1268 -0
  153. package/dist/src/generators/local-plugin.js.map +1 -0
  154. package/dist/src/generators/permissions.d.ts +10 -0
  155. package/dist/src/generators/permissions.js +37 -0
  156. package/dist/src/generators/permissions.js.map +1 -0
  157. package/dist/src/generators/shared.d.ts +2 -0
  158. package/dist/src/generators/shared.js +15 -0
  159. package/dist/src/generators/shared.js.map +1 -0
  160. package/dist/src/index.d.ts +35 -0
  161. package/dist/src/index.js +2344 -0
  162. package/dist/src/index.js.map +1 -0
  163. package/dist/src/output/command-receipt.d.ts +90 -0
  164. package/dist/src/output/command-receipt.js +129 -0
  165. package/dist/src/output/command-receipt.js.map +1 -0
  166. package/dist/src/output/debug-log.d.ts +4 -0
  167. package/dist/src/output/debug-log.js +97 -0
  168. package/dist/src/output/debug-log.js.map +1 -0
  169. package/dist/src/output/equivalent-command.d.ts +9 -0
  170. package/dist/src/output/equivalent-command.js +39 -0
  171. package/dist/src/output/equivalent-command.js.map +1 -0
  172. package/dist/src/output/model.d.ts +117 -0
  173. package/dist/src/output/model.js +145 -0
  174. package/dist/src/output/model.js.map +1 -0
  175. package/dist/src/output/rebuild-progress.d.ts +21 -0
  176. package/dist/src/output/rebuild-progress.js +138 -0
  177. package/dist/src/output/rebuild-progress.js.map +1 -0
  178. package/dist/src/output/redact.d.ts +3 -0
  179. package/dist/src/output/redact.js +39 -0
  180. package/dist/src/output/redact.js.map +1 -0
  181. package/dist/src/output/reporter.d.ts +9 -0
  182. package/dist/src/output/reporter.js +133 -0
  183. package/dist/src/output/reporter.js.map +1 -0
  184. package/dist/src/portable/commands.d.ts +120 -0
  185. package/dist/src/portable/commands.js +506 -0
  186. package/dist/src/portable/commands.js.map +1 -0
  187. package/dist/src/portable/materializer.d.ts +50 -0
  188. package/dist/src/portable/materializer.js +408 -0
  189. package/dist/src/portable/materializer.js.map +1 -0
  190. package/dist/src/portable/skills-cli.d.ts +43 -0
  191. package/dist/src/portable/skills-cli.js +148 -0
  192. package/dist/src/portable/skills-cli.js.map +1 -0
  193. package/dist/src/tui/components.d.ts +32 -0
  194. package/dist/src/tui/components.js +42 -0
  195. package/dist/src/tui/components.js.map +1 -0
  196. package/dist/src/tui/console-app-v4.d.ts +20 -0
  197. package/dist/src/tui/console-app-v4.js +2613 -0
  198. package/dist/src/tui/console-app-v4.js.map +1 -0
  199. package/dist/src/tui/controller-runtime.d.ts +11 -0
  200. package/dist/src/tui/controller-runtime.js +902 -0
  201. package/dist/src/tui/controller-runtime.js.map +1 -0
  202. package/dist/src/tui/controller.d.ts +367 -0
  203. package/dist/src/tui/controller.js +1724 -0
  204. package/dist/src/tui/controller.js.map +1 -0
  205. package/dist/src/tui/index.d.ts +13 -0
  206. package/dist/src/tui/index.js +14 -0
  207. package/dist/src/tui/index.js.map +1 -0
  208. package/dist/src/tui/keys.d.ts +12 -0
  209. package/dist/src/tui/keys.js +22 -0
  210. package/dist/src/tui/keys.js.map +1 -0
  211. package/dist/src/tui/layout.d.ts +12 -0
  212. package/dist/src/tui/layout.js +19 -0
  213. package/dist/src/tui/layout.js.map +1 -0
  214. package/dist/src/tui/model.d.ts +279 -0
  215. package/dist/src/tui/model.js +652 -0
  216. package/dist/src/tui/model.js.map +1 -0
  217. package/dist/src/tui/prompt.d.ts +8 -0
  218. package/dist/src/tui/prompt.js +242 -0
  219. package/dist/src/tui/prompt.js.map +1 -0
  220. package/dist/src/tui/router.d.ts +153 -0
  221. package/dist/src/tui/router.js +102 -0
  222. package/dist/src/tui/router.js.map +1 -0
  223. package/dist/src/tui/runner.d.ts +11 -0
  224. package/dist/src/tui/runner.js +71 -0
  225. package/dist/src/tui/runner.js.map +1 -0
  226. package/dist/src/tui/theme.d.ts +18 -0
  227. package/dist/src/tui/theme.js +20 -0
  228. package/dist/src/tui/theme.js.map +1 -0
  229. package/dist/src/tui/views.d.ts +57 -0
  230. package/dist/src/tui/views.js +173 -0
  231. package/dist/src/tui/views.js.map +1 -0
  232. package/dist/src/tui/wizard.d.ts +11 -0
  233. package/dist/src/tui/wizard.js +321 -0
  234. package/dist/src/tui/wizard.js.map +1 -0
  235. package/dist/src/types.d.ts +313 -0
  236. package/dist/src/types.js +33 -0
  237. package/dist/src/types.js.map +1 -0
  238. package/dist/src/utils/active-marketplace-runtime-lock.d.ts +12 -0
  239. package/dist/src/utils/active-marketplace-runtime-lock.js +133 -0
  240. package/dist/src/utils/active-marketplace-runtime-lock.js.map +1 -0
  241. package/dist/src/utils/agent-version.d.ts +13 -0
  242. package/dist/src/utils/agent-version.js +172 -0
  243. package/dist/src/utils/agent-version.js.map +1 -0
  244. package/dist/src/utils/artifact-plan.d.ts +26 -0
  245. package/dist/src/utils/artifact-plan.js +444 -0
  246. package/dist/src/utils/artifact-plan.js.map +1 -0
  247. package/dist/src/utils/artifact-renderer.d.ts +124 -0
  248. package/dist/src/utils/artifact-renderer.js +442 -0
  249. package/dist/src/utils/artifact-renderer.js.map +1 -0
  250. package/dist/src/utils/artifact-sources.d.ts +8 -0
  251. package/dist/src/utils/artifact-sources.js +10 -0
  252. package/dist/src/utils/artifact-sources.js.map +1 -0
  253. package/dist/src/utils/aw-home-mutation-lock.d.ts +10 -0
  254. package/dist/src/utils/aw-home-mutation-lock.js +55 -0
  255. package/dist/src/utils/aw-home-mutation-lock.js.map +1 -0
  256. package/dist/src/utils/bundle-integrity.d.ts +3 -0
  257. package/dist/src/utils/bundle-integrity.js +88 -0
  258. package/dist/src/utils/bundle-integrity.js.map +1 -0
  259. package/dist/src/utils/bundle-layout.d.ts +4 -0
  260. package/dist/src/utils/bundle-layout.js +546 -0
  261. package/dist/src/utils/bundle-layout.js.map +1 -0
  262. package/dist/src/utils/catalog-digests.d.ts +8 -0
  263. package/dist/src/utils/catalog-digests.js +108 -0
  264. package/dist/src/utils/catalog-digests.js.map +1 -0
  265. package/dist/src/utils/catalog-manifest-v3.d.ts +2 -0
  266. package/dist/src/utils/catalog-manifest-v3.js +3 -0
  267. package/dist/src/utils/catalog-manifest-v3.js.map +1 -0
  268. package/dist/src/utils/catalog-manifest-v4.d.ts +5 -0
  269. package/dist/src/utils/catalog-manifest-v4.js +106 -0
  270. package/dist/src/utils/catalog-manifest-v4.js.map +1 -0
  271. package/dist/src/utils/catalog-public-error.d.ts +15 -0
  272. package/dist/src/utils/catalog-public-error.js +84 -0
  273. package/dist/src/utils/catalog-public-error.js.map +1 -0
  274. package/dist/src/utils/catalog-runtime-projection.d.ts +36 -0
  275. package/dist/src/utils/catalog-runtime-projection.js +172 -0
  276. package/dist/src/utils/catalog-runtime-projection.js.map +1 -0
  277. package/dist/src/utils/catalog-snapshot.d.ts +8 -0
  278. package/dist/src/utils/catalog-snapshot.js +12 -0
  279. package/dist/src/utils/catalog-snapshot.js.map +1 -0
  280. package/dist/src/utils/catalog-source-cache.d.ts +61 -0
  281. package/dist/src/utils/catalog-source-cache.js +276 -0
  282. package/dist/src/utils/catalog-source-cache.js.map +1 -0
  283. package/dist/src/utils/catalog-source-identity.d.ts +4 -0
  284. package/dist/src/utils/catalog-source-identity.js +118 -0
  285. package/dist/src/utils/catalog-source-identity.js.map +1 -0
  286. package/dist/src/utils/catalog-source-presentation.d.ts +1 -0
  287. package/dist/src/utils/catalog-source-presentation.js +32 -0
  288. package/dist/src/utils/catalog-source-presentation.js.map +1 -0
  289. package/dist/src/utils/catalog-source-references.d.ts +65 -0
  290. package/dist/src/utils/catalog-source-references.js +1418 -0
  291. package/dist/src/utils/catalog-source-references.js.map +1 -0
  292. package/dist/src/utils/catalog-sources.d.ts +39 -0
  293. package/dist/src/utils/catalog-sources.js +293 -0
  294. package/dist/src/utils/catalog-sources.js.map +1 -0
  295. package/dist/src/utils/codex-config.d.ts +124 -0
  296. package/dist/src/utils/codex-config.js +1011 -0
  297. package/dist/src/utils/codex-config.js.map +1 -0
  298. package/dist/src/utils/codex-project-surface.d.ts +3 -0
  299. package/dist/src/utils/codex-project-surface.js +49 -0
  300. package/dist/src/utils/codex-project-surface.js.map +1 -0
  301. package/dist/src/utils/codex-roles.d.ts +71 -0
  302. package/dist/src/utils/codex-roles.js +257 -0
  303. package/dist/src/utils/codex-roles.js.map +1 -0
  304. package/dist/src/utils/codex-skill-staging.d.ts +9 -0
  305. package/dist/src/utils/codex-skill-staging.js +8 -0
  306. package/dist/src/utils/codex-skill-staging.js.map +1 -0
  307. package/dist/src/utils/config-value.d.ts +3 -0
  308. package/dist/src/utils/config-value.js +23 -0
  309. package/dist/src/utils/config-value.js.map +1 -0
  310. package/dist/src/utils/dynamic-skill-tree.d.ts +32 -0
  311. package/dist/src/utils/dynamic-skill-tree.js +436 -0
  312. package/dist/src/utils/dynamic-skill-tree.js.map +1 -0
  313. package/dist/src/utils/file-rules.d.ts +1 -0
  314. package/dist/src/utils/file-rules.js +2 -0
  315. package/dist/src/utils/file-rules.js.map +1 -0
  316. package/dist/src/utils/git-catalog-provider.d.ts +7 -0
  317. package/dist/src/utils/git-catalog-provider.js +510 -0
  318. package/dist/src/utils/git-catalog-provider.js.map +1 -0
  319. package/dist/src/utils/hooks-contract.d.ts +1 -0
  320. package/dist/src/utils/hooks-contract.js +2 -0
  321. package/dist/src/utils/hooks-contract.js.map +1 -0
  322. package/dist/src/utils/json.d.ts +4 -0
  323. package/dist/src/utils/json.js +29 -0
  324. package/dist/src/utils/json.js.map +1 -0
  325. package/dist/src/utils/lifecycle-active-store.d.ts +175 -0
  326. package/dist/src/utils/lifecycle-active-store.js +1276 -0
  327. package/dist/src/utils/lifecycle-active-store.js.map +1 -0
  328. package/dist/src/utils/local-marketplace.d.ts +41 -0
  329. package/dist/src/utils/local-marketplace.js +317 -0
  330. package/dist/src/utils/local-marketplace.js.map +1 -0
  331. package/dist/src/utils/manifest.d.ts +14 -0
  332. package/dist/src/utils/manifest.js +36 -0
  333. package/dist/src/utils/manifest.js.map +1 -0
  334. package/dist/src/utils/marketplace.d.ts +3 -0
  335. package/dist/src/utils/marketplace.js +76 -0
  336. package/dist/src/utils/marketplace.js.map +1 -0
  337. package/dist/src/utils/multi-source-catalog.d.ts +72 -0
  338. package/dist/src/utils/multi-source-catalog.js +402 -0
  339. package/dist/src/utils/multi-source-catalog.js.map +1 -0
  340. package/dist/src/utils/native-cli.d.ts +75 -0
  341. package/dist/src/utils/native-cli.js +435 -0
  342. package/dist/src/utils/native-cli.js.map +1 -0
  343. package/dist/src/utils/orphan-marketplace-cleanup.d.ts +18 -0
  344. package/dist/src/utils/orphan-marketplace-cleanup.js +202 -0
  345. package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -0
  346. package/dist/src/utils/ownership.d.ts +130 -0
  347. package/dist/src/utils/ownership.js +766 -0
  348. package/dist/src/utils/ownership.js.map +1 -0
  349. package/dist/src/utils/path-catalog-provider.d.ts +7 -0
  350. package/dist/src/utils/path-catalog-provider.js +87 -0
  351. package/dist/src/utils/path-catalog-provider.js.map +1 -0
  352. package/dist/src/utils/paths.d.ts +41 -0
  353. package/dist/src/utils/paths.js +138 -0
  354. package/dist/src/utils/paths.js.map +1 -0
  355. package/dist/src/utils/platform-entries.d.ts +1 -0
  356. package/dist/src/utils/platform-entries.js +2 -0
  357. package/dist/src/utils/platform-entries.js.map +1 -0
  358. package/dist/src/utils/platform-support.d.ts +1 -0
  359. package/dist/src/utils/platform-support.js +2 -0
  360. package/dist/src/utils/platform-support.js.map +1 -0
  361. package/dist/src/utils/plugin-authoring-capabilities.d.ts +23 -0
  362. package/dist/src/utils/plugin-authoring-capabilities.js +37 -0
  363. package/dist/src/utils/plugin-authoring-capabilities.js.map +1 -0
  364. package/dist/src/utils/plugin-authoring-capabilities.json +92 -0
  365. package/dist/src/utils/plugin-config-write.d.ts +107 -0
  366. package/dist/src/utils/plugin-config-write.js +565 -0
  367. package/dist/src/utils/plugin-config-write.js.map +1 -0
  368. package/dist/src/utils/plugin-config.d.ts +396 -0
  369. package/dist/src/utils/plugin-config.js +1898 -0
  370. package/dist/src/utils/plugin-config.js.map +1 -0
  371. package/dist/src/utils/plugin-dependencies.d.ts +12 -0
  372. package/dist/src/utils/plugin-dependencies.js +162 -0
  373. package/dist/src/utils/plugin-dependencies.js.map +1 -0
  374. package/dist/src/utils/plugin-release.d.ts +2 -0
  375. package/dist/src/utils/plugin-release.js +2 -0
  376. package/dist/src/utils/plugin-release.js.map +1 -0
  377. package/dist/src/utils/plugin-script-contract.d.ts +1 -0
  378. package/dist/src/utils/plugin-script-contract.js +2 -0
  379. package/dist/src/utils/plugin-script-contract.js.map +1 -0
  380. package/dist/src/utils/plugin-scripts.d.ts +172 -0
  381. package/dist/src/utils/plugin-scripts.js +585 -0
  382. package/dist/src/utils/plugin-scripts.js.map +1 -0
  383. package/dist/src/utils/process-lock.d.ts +47 -0
  384. package/dist/src/utils/process-lock.js +532 -0
  385. package/dist/src/utils/process-lock.js.map +1 -0
  386. package/dist/src/utils/process-tree.d.ts +2 -0
  387. package/dist/src/utils/process-tree.js +2 -0
  388. package/dist/src/utils/process-tree.js.map +1 -0
  389. package/dist/src/utils/project-boundary.d.ts +21 -0
  390. package/dist/src/utils/project-boundary.js +95 -0
  391. package/dist/src/utils/project-boundary.js.map +1 -0
  392. package/dist/src/utils/rendered-contract.d.ts +8 -0
  393. package/dist/src/utils/rendered-contract.js +134 -0
  394. package/dist/src/utils/rendered-contract.js.map +1 -0
  395. package/dist/src/utils/runtime-skill-closure.d.ts +13 -0
  396. package/dist/src/utils/runtime-skill-closure.js +863 -0
  397. package/dist/src/utils/runtime-skill-closure.js.map +1 -0
  398. package/dist/src/utils/skill-authoring.d.ts +1 -0
  399. package/dist/src/utils/skill-authoring.js +2 -0
  400. package/dist/src/utils/skill-authoring.js.map +1 -0
  401. package/dist/src/utils/skill-frontmatter-capabilities.d.ts +201 -0
  402. package/dist/src/utils/skill-frontmatter-capabilities.js +5 -0
  403. package/dist/src/utils/skill-frontmatter-capabilities.js.map +1 -0
  404. package/dist/src/utils/skill-frontmatter-capabilities.json +200 -0
  405. package/dist/src/utils/skill-validation.d.ts +37 -0
  406. package/dist/src/utils/skill-validation.js +326 -0
  407. package/dist/src/utils/skill-validation.js.map +1 -0
  408. package/dist/src/utils/slash-commands.d.ts +1 -0
  409. package/dist/src/utils/slash-commands.js +2 -0
  410. package/dist/src/utils/slash-commands.js.map +1 -0
  411. package/dist/src/utils/state-paths.d.ts +13 -0
  412. package/dist/src/utils/state-paths.js +129 -0
  413. package/dist/src/utils/state-paths.js.map +1 -0
  414. package/dist/src/utils/target-eligibility.d.ts +7 -0
  415. package/dist/src/utils/target-eligibility.js +26 -0
  416. package/dist/src/utils/target-eligibility.js.map +1 -0
  417. package/dist/src/utils/target-order.d.ts +7 -0
  418. package/dist/src/utils/target-order.js +10 -0
  419. package/dist/src/utils/target-order.js.map +1 -0
  420. package/dist/src/utils/template-engine.d.ts +1 -0
  421. package/dist/src/utils/template-engine.js +2 -0
  422. package/dist/src/utils/template-engine.js.map +1 -0
  423. package/dist/src/utils/test-path-fence.d.ts +12 -0
  424. package/dist/src/utils/test-path-fence.js +31 -0
  425. package/dist/src/utils/test-path-fence.js.map +1 -0
  426. package/dist/vitest.config.d.ts +2 -0
  427. package/dist/vitest.config.js +16 -0
  428. package/dist/vitest.config.js.map +1 -0
  429. package/package.json +61 -0
@@ -0,0 +1,1586 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { promisify } from 'node:util';
4
+ import { fileURLToPath } from 'node:url';
5
+ import path from 'node:path';
6
+ import { runProviderProcess, } from '@lesliechan721/agent-skill-eval';
7
+ import fs from 'fs-extra';
8
+ import { readPluginManifest } from '../src/utils/manifest.js';
9
+ import { resolveCliPackageRoot } from '../src/utils/paths.js';
10
+ import { runCodexConversationSuite } from './codex-eval-app-server.js';
11
+ import { assertCodexEvalKeychainWrapperAbsent } from './codex-eval-isolation.js';
12
+ import { resolveCodexEvalProcessManagement } from './codex-eval-process-management.js';
13
+ import { CODEX_EVAL_PROCESS_TREE_ID_ENV, createPosixProcessTreeMonitor, PROCESS_TREE_CLEANUP_UNCONFIRMED_PREFIX, processTreeCleanupIsUnconfirmed, scrubProcessTreeId, terminatePosixProcessTree, terminateWindowsProcessTree, } from './codex-eval-process-tree.js';
14
+ import { assertCodexEvalCanStartWork, createCodexEvalRuntimeCapsule, redactCodexEvalText, redactCodexEvalValue, registerCodexEvalSignalCleanup, resolveCodexEvalRuntimeConfig, } from './codex-eval-runtime-config.js';
15
+ import { runCodexTriggerSuite } from './codex-trigger-eval.js';
16
+ import { combinePluginEvalOutcome, PLUGIN_EVAL_SCHEMA_VERSION, readPluginEvalManifest, readPluginEvalTriggerCases, resolvePluginSkillAuthorRoot, validatePluginEvalConversationCaseDocument, } from './plugin-eval-contract.js';
17
+ import { createPluginEvalRunLayout, writeEvalRunJson, } from './eval-run-layout.js';
18
+ import { materializePluginEvalSubjects, resolveMaterializedSubjectRoot, } from './plugin-eval-materializer.js';
19
+ import { runAwSkillEvalExecutionPlan } from './aw-skill-eval-engine.js';
20
+ import { completeSkillEvalRun, computeAuthorSourceDigest, createSkillEvalTargetKey, createEnvironmentDigest, failSkillEvalRun, pluginReleaseTargets, publishEvalRunCheckpoint, publishEvalRunToBatch, resolveSkillEvalTargetPlan, validateSkillReportTargetSegment, } from './skill-reporting.js';
21
+ const execFileAsync = promisify(execFile);
22
+ const REPO_ROOT_ENV = 'AW_PLUGIN_EVAL_REPO_ROOT';
23
+ const DEFAULT_OBSERVED_PROCESS_EVIDENCE = {
24
+ mode: 'observed',
25
+ inspectionAvailable: true,
26
+ userAcknowledged: false,
27
+ descendantCleanupGuaranteed: false,
28
+ limitation: 'Process-tree inspection observes and cleans known descendants but does not guarantee descendant cleanup.',
29
+ };
30
+ export { terminatePosixProcessTree, terminateWindowsProcessTree };
31
+ function resolveRepoRoot() {
32
+ return path.resolve(resolveCliPackageRoot(), '..', '..');
33
+ }
34
+ function parsePositiveInteger(value, flag) {
35
+ const parsed = Number(value);
36
+ if (!Number.isInteger(parsed) || parsed <= 0) {
37
+ throw new Error(`${flag} requires a positive integer.`);
38
+ }
39
+ return parsed;
40
+ }
41
+ function optionValue(args, index, flag) {
42
+ const value = args[index + 1];
43
+ if (!value || value.startsWith('-')) {
44
+ throw new Error(`${flag} requires a value.`);
45
+ }
46
+ return value;
47
+ }
48
+ function usage() {
49
+ return [
50
+ 'Usage: pnpm plugin:eval <plugin> --skill <skill> [OPTIONS]',
51
+ ' pnpm plugin:eval --aw-skill-eval-plan <plan.json>',
52
+ '',
53
+ 'Options:',
54
+ ' --skill <name> Select exactly one Skill (required)',
55
+ ' --suite <id> Run one suite',
56
+ ' --profile <id> Select one materialization profile',
57
+ ' --split <train|validation|sanity|all>',
58
+ ' --case <id> Run one case (requires --suite)',
59
+ ' --runs <count> Override repetitions per case',
60
+ ' --model <model> Parent Codex model (default: gpt-5.6-luna)',
61
+ ' --model-provider <id> Override the inherited Codex model provider',
62
+ ' --codex-config <path> Read model/provider config from this config.toml',
63
+ ' --no-inherit-codex-config Use a clean official Codex provider config',
64
+ ' --codex-bin <path> Codex executable (default: codex)',
65
+ ' --batch-name <name> Create a named report batch',
66
+ ' --batch-id <id> Append to an existing report batch',
67
+ ' --run-id <id> Use an explicit unique report run id',
68
+ ' --materialize-only Do not start real Codex model sessions',
69
+ ' --allow-environment-skips Diagnostic only; release remains incomplete',
70
+ ' --allow-unmanaged-processes Confirm eval without descendant process tracking',
71
+ ' --aw-skill-eval-plan <path> Run one AwSkillEvalExecutionPlan with aw-skill-eval',
72
+ ].join('\n');
73
+ }
74
+ function awSkillEvalExecutionPlanPath(args) {
75
+ const index = args.indexOf('--aw-skill-eval-plan');
76
+ if (index < 0)
77
+ return undefined;
78
+ if (args.length !== 2 || index !== 0 || !args[1] || args[1].startsWith('-')) {
79
+ throw new Error('--aw-skill-eval-plan requires exactly one plan path and no AW suite options.');
80
+ }
81
+ return path.resolve(args[1]);
82
+ }
83
+ function parseArgs(args) {
84
+ const parsed = {
85
+ codexBin: 'codex',
86
+ inheritCodexConfig: true,
87
+ materializeOnly: false,
88
+ allowEnvironmentSkips: false,
89
+ allowUnmanagedProcesses: false,
90
+ };
91
+ const positional = [];
92
+ for (let index = 0; index < args.length; index += 1) {
93
+ const arg = args[index];
94
+ if (arg === '--') {
95
+ continue;
96
+ }
97
+ if (arg === '--materialize-only') {
98
+ parsed.materializeOnly = true;
99
+ continue;
100
+ }
101
+ if (arg === '--allow-environment-skips') {
102
+ parsed.allowEnvironmentSkips = true;
103
+ continue;
104
+ }
105
+ if (arg === '--allow-unmanaged-processes') {
106
+ parsed.allowUnmanagedProcesses = true;
107
+ continue;
108
+ }
109
+ if (arg === '--no-inherit-codex-config') {
110
+ parsed.inheritCodexConfig = false;
111
+ continue;
112
+ }
113
+ if (arg === '-h' || arg === '--help') {
114
+ throw new Error(usage());
115
+ }
116
+ if (arg === '--skill') {
117
+ parsed.skillName = optionValue(args, index, arg);
118
+ index += 1;
119
+ continue;
120
+ }
121
+ if (arg === '--suite') {
122
+ parsed.suite = optionValue(args, index, arg);
123
+ index += 1;
124
+ continue;
125
+ }
126
+ if (arg === '--profile') {
127
+ parsed.profile = optionValue(args, index, arg);
128
+ index += 1;
129
+ continue;
130
+ }
131
+ if (arg === '--split') {
132
+ const value = optionValue(args, index, arg);
133
+ if (!['train', 'validation', 'sanity', 'all'].includes(value)) {
134
+ throw new Error('--split must be train, validation, sanity, or all.');
135
+ }
136
+ parsed.split = value;
137
+ index += 1;
138
+ continue;
139
+ }
140
+ if (arg === '--case') {
141
+ parsed.caseId = optionValue(args, index, arg);
142
+ index += 1;
143
+ continue;
144
+ }
145
+ if (arg === '--runs') {
146
+ parsed.runs = parsePositiveInteger(optionValue(args, index, arg), arg);
147
+ index += 1;
148
+ continue;
149
+ }
150
+ if (arg === '--model') {
151
+ parsed.model = optionValue(args, index, arg);
152
+ index += 1;
153
+ continue;
154
+ }
155
+ if (arg === '--model-provider') {
156
+ parsed.modelProvider = optionValue(args, index, arg);
157
+ index += 1;
158
+ continue;
159
+ }
160
+ if (arg === '--codex-config') {
161
+ parsed.codexConfig = path.resolve(optionValue(args, index, arg));
162
+ index += 1;
163
+ continue;
164
+ }
165
+ if (arg === '--codex-bin') {
166
+ parsed.codexBin = optionValue(args, index, arg);
167
+ index += 1;
168
+ continue;
169
+ }
170
+ if (arg === '--batch-name') {
171
+ parsed.batchName = optionValue(args, index, arg);
172
+ index += 1;
173
+ continue;
174
+ }
175
+ if (arg === '--batch-id') {
176
+ parsed.batchId = optionValue(args, index, arg);
177
+ index += 1;
178
+ continue;
179
+ }
180
+ if (arg === '--run-id') {
181
+ parsed.runId = optionValue(args, index, arg);
182
+ index += 1;
183
+ continue;
184
+ }
185
+ if (arg.startsWith('-')) {
186
+ throw new Error(`Unknown option "${arg}".\n\n${usage()}`);
187
+ }
188
+ positional.push(arg);
189
+ }
190
+ if (positional.length !== 1) {
191
+ throw new Error(usage());
192
+ }
193
+ if (!parsed.skillName) {
194
+ throw new Error('--skill is required.\n\n' + usage());
195
+ }
196
+ if (parsed.caseId && !parsed.suite) {
197
+ throw new Error('--case requires --suite.');
198
+ }
199
+ if (parsed.caseId) {
200
+ validateSkillReportTargetSegment(parsed.caseId, '--case');
201
+ }
202
+ if (!parsed.inheritCodexConfig && (parsed.codexConfig || parsed.modelProvider)) {
203
+ throw new Error('--no-inherit-codex-config cannot be combined with --codex-config or --model-provider.');
204
+ }
205
+ if (parsed.materializeOnly &&
206
+ (parsed.suite !== undefined ||
207
+ parsed.split !== undefined ||
208
+ parsed.caseId !== undefined ||
209
+ parsed.runs !== undefined ||
210
+ parsed.model !== undefined ||
211
+ parsed.modelProvider !== undefined ||
212
+ parsed.codexConfig !== undefined ||
213
+ parsed.inheritCodexConfig === false ||
214
+ parsed.allowEnvironmentSkips ||
215
+ parsed.allowUnmanagedProcesses)) {
216
+ throw new Error('--materialize-only supports target/profile selection, not suite model-run flags.');
217
+ }
218
+ parsed.pluginName = positional[0];
219
+ if (parsed.pluginName && !/^[a-z0-9][a-z0-9-]*$/u.test(parsed.pluginName)) {
220
+ throw new Error('Plugin name must use lowercase kebab-case without path separators.');
221
+ }
222
+ if (!/^[a-z0-9][a-z0-9-]*$/u.test(parsed.skillName)) {
223
+ throw new Error('Skill name must use lowercase kebab-case without path separators.');
224
+ }
225
+ return parsed;
226
+ }
227
+ export async function runChild(command, args, options) {
228
+ assertCodexEvalCanStartWork();
229
+ const processTreeId = randomUUID();
230
+ const processManagement = options.processManagement ?? DEFAULT_OBSERVED_PROCESS_EVIDENCE;
231
+ const observed = processManagement.mode === 'managed' || processManagement.mode === 'observed';
232
+ if (!observed && (processManagement.mode !== 'unmanaged-confirmed' ||
233
+ !processManagement.userAcknowledged)) {
234
+ throw new Error('Unmanaged process execution requires explicit user confirmation.');
235
+ }
236
+ const abortController = new AbortController();
237
+ let processTreeMonitor;
238
+ let terminationPromise;
239
+ let cleanupDiagnostics = [];
240
+ let cleanupDiagnostic = '';
241
+ const terminateManagedTree = async () => {
242
+ if (!processTreeMonitor)
243
+ return { confirmed: true };
244
+ terminationPromise ??= processTreeMonitor.terminate().catch((error) => [
245
+ `${PROCESS_TREE_CLEANUP_UNCONFIRMED_PREFIX}: ${error instanceof Error ? error.message : String(error)}`,
246
+ ]);
247
+ cleanupDiagnostics = await terminationPromise;
248
+ if (cleanupDiagnostics.length > 0) {
249
+ cleanupDiagnostic = `${cleanupDiagnostics.join('\n')}\n`;
250
+ }
251
+ if (processTreeCleanupIsUnconfirmed(cleanupDiagnostics)) {
252
+ throw new Error(cleanupDiagnostics.join('\n'));
253
+ }
254
+ return { confirmed: true };
255
+ };
256
+ const hooks = observed
257
+ ? {
258
+ onSpawn: ({ pid }) => {
259
+ processTreeMonitor = options.createProcessTreeMonitor
260
+ ? options.createProcessTreeMonitor(pid, processTreeId)
261
+ : createPosixProcessTreeMonitor(pid, { treeId: processTreeId });
262
+ },
263
+ terminateProcessTree: terminateManagedTree,
264
+ }
265
+ : undefined;
266
+ const unregisterSignalCleanup = registerCodexEvalSignalCleanup(async () => {
267
+ abortController.abort();
268
+ if (observed)
269
+ await terminateManagedTree();
270
+ });
271
+ try {
272
+ const result = await runProviderProcess({
273
+ executable: command,
274
+ args,
275
+ cwd: options.cwd,
276
+ env: observed
277
+ ? { ...options.env, [CODEX_EVAL_PROCESS_TREE_ID_ENV]: processTreeId }
278
+ : { ...options.env },
279
+ timeoutMs: options.timeoutMs,
280
+ maxBufferBytes: 20 * 1024 * 1024,
281
+ signal: abortController.signal,
282
+ }, hooks, {
283
+ containment: observed ? 'observed' : 'unmanaged-confirmed',
284
+ });
285
+ let stderr = result.stderr;
286
+ if (result.timedOut) {
287
+ stderr += `${stderr.endsWith('\n') || stderr === '' ? '' : '\n'}` +
288
+ `Suite exceeded central timeout of ${options.timeoutMs}ms.\n`;
289
+ }
290
+ stderr += cleanupDiagnostic;
291
+ const safeStdout = result.stdout.replaceAll(processTreeId, '[process-tree-id]');
292
+ const safeStderr = stderr.replaceAll(processTreeId, '[process-tree-id]');
293
+ if (safeStderr) {
294
+ const rendered = options.redact ? options.redact(safeStderr) : safeStderr;
295
+ options.stderr(rendered.endsWith('\n') ? rendered : `${rendered}\n`);
296
+ }
297
+ return {
298
+ ...result,
299
+ exitCode: processTreeCleanupIsUnconfirmed(cleanupDiagnostics) &&
300
+ result.exitCode === 0
301
+ ? 1
302
+ : result.exitCode,
303
+ stdout: safeStdout,
304
+ stderr: safeStderr,
305
+ processTreeId,
306
+ };
307
+ }
308
+ finally {
309
+ unregisterSignalCleanup();
310
+ }
311
+ }
312
+ function supports(suite, capability) {
313
+ return suite.supports.includes(capability);
314
+ }
315
+ function parseCommandReport(stdout, reportPath, processTreeId) {
316
+ let candidate = stdout.trim();
317
+ if (fs.pathExistsSync(reportPath)) {
318
+ candidate = fs.readFileSync(reportPath, 'utf8').trim();
319
+ }
320
+ candidate = candidate.replaceAll(processTreeId, '[process-tree-id]');
321
+ try {
322
+ const parsed = JSON.parse(candidate);
323
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
324
+ return parsed;
325
+ }
326
+ }
327
+ catch {
328
+ // The caller reports a structured incomplete result below.
329
+ }
330
+ throw new Error('Suite did not produce one JSON report.');
331
+ }
332
+ async function parseCommandCaseResults(report, options) {
333
+ if (!supports(options.suite, 'case'))
334
+ return undefined;
335
+ const expectedIds = options.caseId
336
+ ? [options.caseId]
337
+ : await readCommandSuiteCaseIds(options.pluginRoot, options.suite);
338
+ if (!Array.isArray(report.case_results)) {
339
+ throw new Error('Case-capable command suite must return case_results.');
340
+ }
341
+ const results = report.case_results.map((value, index) => {
342
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
343
+ throw new Error(`case_results[${index}] must be an object.`);
344
+ }
345
+ const row = value;
346
+ if (typeof row.id !== 'string' || !/^[a-z0-9_]+$/u.test(row.id)) {
347
+ throw new Error(`case_results[${index}].id must use lowercase snake_case.`);
348
+ }
349
+ if (!['passed', 'failed', 'needs_review', 'incomplete'].includes(String(row.outcome))) {
350
+ throw new Error(`case_results[${index}].outcome is invalid.`);
351
+ }
352
+ if (typeof row.complete !== 'boolean' || typeof row.mechanical_passed !== 'boolean') {
353
+ throw new Error(`case_results[${index}] must declare complete and mechanical_passed.`);
354
+ }
355
+ const summary = row.summary;
356
+ const diagnostics = row.diagnostics;
357
+ if (summary !== undefined && (!summary || typeof summary !== 'object' || Array.isArray(summary))) {
358
+ throw new Error(`case_results[${index}].summary must be an object.`);
359
+ }
360
+ if (diagnostics !== undefined &&
361
+ (!Array.isArray(diagnostics) || diagnostics.some((entry) => typeof entry !== 'string'))) {
362
+ throw new Error(`case_results[${index}].diagnostics must be a string array.`);
363
+ }
364
+ return {
365
+ id: row.id,
366
+ outcome: row.outcome,
367
+ complete: row.complete,
368
+ mechanicalPassed: row.mechanical_passed,
369
+ ...(summary ? { summary: summary } : {}),
370
+ ...(diagnostics ? { diagnostics: diagnostics } : {}),
371
+ };
372
+ });
373
+ const actualIds = results.map((result) => result.id).sort();
374
+ if (new Set(actualIds).size !== actualIds.length ||
375
+ JSON.stringify(actualIds) !== JSON.stringify([...expectedIds].sort())) {
376
+ throw new Error(`case_results must cover exactly ${JSON.stringify([...expectedIds].sort())}; ` +
377
+ `received ${JSON.stringify(actualIds)}.`);
378
+ }
379
+ return results;
380
+ }
381
+ async function runCommandSuite(options) {
382
+ const sanitize = (report) => redactCodexEvalValue(report, options.codexRuntime);
383
+ const reportName = [
384
+ options.suite.id,
385
+ options.split,
386
+ options.profile,
387
+ options.parsed.caseId,
388
+ ]
389
+ .filter(Boolean)
390
+ .join('-');
391
+ const reportPath = path.join(options.outputRoot, 'reports', `${reportName}.json`);
392
+ const rawReportPath = path.join(options.codexRuntimeHome, 'command-reports', options.pluginName, `${reportName}.json`);
393
+ await fs.ensureDir(path.dirname(reportPath));
394
+ await fs.ensureDir(path.dirname(rawReportPath));
395
+ const commandWorkRoot = path.join(options.workRoot, 'command', reportName);
396
+ await fs.ensureDir(commandWorkRoot);
397
+ const args = [path.resolve(options.pluginRoot, options.suite.entry.replace(/^\.\//u, ''))];
398
+ if (options.split && supports(options.suite, 'split')) {
399
+ args.push('--split', options.split);
400
+ }
401
+ if (supports(options.suite, 'runs')) {
402
+ args.push('--runs', String(options.parsed.runs ?? options.suite.defaultRuns));
403
+ }
404
+ if (options.parsed.caseId && supports(options.suite, 'case')) {
405
+ args.push('--case', options.parsed.caseId);
406
+ }
407
+ if (options.parsed.model && supports(options.suite, 'model')) {
408
+ args.push('--model', options.parsed.model);
409
+ }
410
+ if (options.parsed.codexBin !== 'codex' && supports(options.suite, 'codexBin')) {
411
+ args.push('--codex-bin', options.parsed.codexBin);
412
+ }
413
+ if (supports(options.suite, 'timeout')) {
414
+ args.push('--timeout-ms', String(options.suite.perRunTimeoutMs));
415
+ }
416
+ if (options.parsed.allowEnvironmentSkips &&
417
+ supports(options.suite, 'allowEnvironmentSkips')) {
418
+ args.push('--allow-environment-skips');
419
+ }
420
+ args.push('--output', rawReportPath);
421
+ const result = await runChild(process.execPath, args, {
422
+ cwd: options.subjectRoot,
423
+ env: {
424
+ ...options.env,
425
+ CODEX_HOME: options.codexRuntimeHome,
426
+ AW_CODEX_EVAL_RUNTIME_HOME: options.codexRuntimeHome,
427
+ AW_CODEX_EVAL_MODEL_PROVIDER: options.codexRuntime.modelProvider,
428
+ AW_CODEX_EVAL_SENSITIVE_ENV_NAMES: JSON.stringify(options.codexRuntime.sensitiveEnvironmentNames),
429
+ AW_PLUGIN_EVAL_PROJECT_ROOT: options.subjectRoot,
430
+ AW_PLUGIN_EVAL_PROFILE: options.profile,
431
+ AW_PLUGIN_EVAL_SKILL: options.parsed.skillName,
432
+ AW_PLUGIN_EVAL_OWNER_SKILL: options.parsed.skillName,
433
+ AW_PLUGIN_EVAL_PARTICIPANT_SKILLS: JSON.stringify(options.suite.skills),
434
+ AW_PLUGIN_EVAL_INSTALLED_PLUGINS: JSON.stringify(options.installedPluginNames),
435
+ AW_PLUGIN_EVAL_WORK_ROOT: commandWorkRoot,
436
+ TMPDIR: commandWorkRoot,
437
+ TEMP: commandWorkRoot,
438
+ TMP: commandWorkRoot,
439
+ },
440
+ stderr: options.stderr,
441
+ redact: (value) => redactCodexEvalText(value, options.codexRuntime),
442
+ timeoutMs: options.timeoutMs ?? options.suite.suiteTimeoutMs,
443
+ processManagement: options.processManagement,
444
+ });
445
+ if (result.timedOut) {
446
+ return sanitize({
447
+ id: options.suite.id,
448
+ kind: 'command',
449
+ skills: options.suite.skills,
450
+ profile: options.profile,
451
+ split: options.split,
452
+ outcome: 'incomplete',
453
+ complete: false,
454
+ mechanicalPassed: false,
455
+ qualitativeReview: 'not_required',
456
+ summary: {},
457
+ diagnostics: [
458
+ `Suite exceeded central timeout of ${options.timeoutMs ?? options.suite.suiteTimeoutMs}ms.`,
459
+ `exitCode=${result.exitCode}, signal=${result.signal}`,
460
+ ...(result.stderr.trim() ? [result.stderr.trim()] : []),
461
+ ],
462
+ });
463
+ }
464
+ try {
465
+ const report = redactCodexEvalValue(scrubProcessTreeId(parseCommandReport(result.stdout, rawReportPath, result.processTreeId), result.processTreeId), options.codexRuntime);
466
+ const caseResults = await parseCommandCaseResults(report, {
467
+ pluginRoot: options.pluginRoot,
468
+ suite: options.suite,
469
+ caseId: options.parsed.caseId,
470
+ });
471
+ await fs.writeJson(reportPath, report, { spaces: 2 });
472
+ const complete = report.complete !== false &&
473
+ (caseResults === undefined || caseResults.every((entry) => entry.complete));
474
+ const passed = complete && report.passed === true && result.exitCode === 0;
475
+ const outcome = !complete
476
+ ? 'incomplete'
477
+ : passed
478
+ ? 'passed'
479
+ : 'failed';
480
+ return sanitize({
481
+ id: options.suite.id,
482
+ kind: 'command',
483
+ skills: options.suite.skills,
484
+ profile: options.profile,
485
+ split: options.split,
486
+ outcome,
487
+ complete,
488
+ mechanicalPassed: passed,
489
+ qualitativeReview: 'not_required',
490
+ reportPath: path.relative(options.outputRoot, reportPath).split(path.sep).join('/'),
491
+ ...(caseResults ? { caseResults } : {}),
492
+ summary: report.summary && typeof report.summary === 'object'
493
+ ? report.summary
494
+ : {},
495
+ diagnostics: [
496
+ ...(result.signal ? [`Suite terminated by ${result.signal}.`] : []),
497
+ ...(report.environment_error ? [String(report.environment_error)] : []),
498
+ ],
499
+ });
500
+ }
501
+ catch (error) {
502
+ return sanitize({
503
+ id: options.suite.id,
504
+ kind: 'command',
505
+ skills: options.suite.skills,
506
+ profile: options.profile,
507
+ split: options.split,
508
+ outcome: 'incomplete',
509
+ complete: false,
510
+ mechanicalPassed: false,
511
+ qualitativeReview: 'not_required',
512
+ summary: {},
513
+ diagnostics: [
514
+ error instanceof Error ? error.message : String(error),
515
+ `exitCode=${result.exitCode}, signal=${result.signal}`,
516
+ ...(result.stderr.trim() ? [result.stderr.trim()] : []),
517
+ ],
518
+ });
519
+ }
520
+ }
521
+ function selectedSuites(manifest, parsed) {
522
+ const suites = parsed.suite
523
+ ? manifest.suites.filter((suite) => suite.id === parsed.suite)
524
+ : manifest.suites.filter((suite) => suite.requiredForRelease);
525
+ if (suites.length === 0) {
526
+ throw new Error(`Unknown or non-release suite: ${parsed.suite ?? '(none)'}`);
527
+ }
528
+ return suites;
529
+ }
530
+ function collectCoverageDiagnostics(manifest, parsed) {
531
+ const diagnostics = [];
532
+ if (parsed.suite) {
533
+ diagnostics.push('--suite selected a debug subset of release-required suites.');
534
+ }
535
+ if (parsed.profile) {
536
+ diagnostics.push('--profile selected a debug subset of required materialization profiles.');
537
+ }
538
+ if (parsed.split) {
539
+ diagnostics.push('--split selected a debug subset of release-required splits.');
540
+ }
541
+ if (parsed.caseId) {
542
+ diagnostics.push('--case selected a debug subset of suite cases.');
543
+ }
544
+ if (parsed.runs !== undefined) {
545
+ const reducedSuites = selectedSuites(manifest, parsed).filter((suite) => parsed.runs < suite.defaultRuns);
546
+ if (reducedSuites.length > 0) {
547
+ diagnostics.push(`--runs is below the declared default for suites: ${reducedSuites.map((suite) => suite.id).join(', ')}.`);
548
+ }
549
+ }
550
+ return diagnostics;
551
+ }
552
+ function applyRunCountCoverage(report, suite, parsed) {
553
+ if (parsed.runs === undefined || parsed.runs >= suite.defaultRuns)
554
+ return report;
555
+ return {
556
+ ...report,
557
+ outcome: 'incomplete',
558
+ complete: false,
559
+ ...(report.caseResults ? {
560
+ caseResults: report.caseResults.map((caseResult) => ({
561
+ ...caseResult,
562
+ outcome: 'incomplete',
563
+ complete: false,
564
+ })),
565
+ } : {}),
566
+ diagnostics: [
567
+ ...report.diagnostics,
568
+ `Requested runs ${parsed.runs} are below the declared default ${suite.defaultRuns}.`,
569
+ ],
570
+ };
571
+ }
572
+ function assertSuiteSupportsRequestedOptions(suite, parsed) {
573
+ if (suite.kind !== 'command') {
574
+ if (suite.kind === 'conversation' && parsed.split) {
575
+ throw new Error(`Conversation suite "${suite.id}" does not support --split.`);
576
+ }
577
+ if (parsed.allowEnvironmentSkips) {
578
+ throw new Error(`${suite.kind === 'trigger' ? 'Trigger' : 'Conversation'} suite ` +
579
+ `"${suite.id}" does not support --allow-environment-skips.`);
580
+ }
581
+ return;
582
+ }
583
+ const requested = [
584
+ ['split', parsed.split !== undefined, '--split'],
585
+ ['case', parsed.caseId !== undefined, '--case'],
586
+ ['runs', parsed.runs !== undefined, '--runs'],
587
+ ['model', parsed.model !== undefined, '--model'],
588
+ ['codexBin', parsed.codexBin !== 'codex', '--codex-bin'],
589
+ ['allowEnvironmentSkips', parsed.allowEnvironmentSkips, '--allow-environment-skips'],
590
+ ];
591
+ for (const [capability, enabled, flag] of requested) {
592
+ if (enabled && !supports(suite, capability)) {
593
+ throw new Error(`Suite "${suite.id}" does not support ${flag}.`);
594
+ }
595
+ }
596
+ }
597
+ function resolveSuiteProfiles(suite, parsed) {
598
+ if (!parsed.profile) {
599
+ return suite.profiles;
600
+ }
601
+ if (!suite.profiles.includes(parsed.profile)) {
602
+ throw new Error(`Suite "${suite.id}" does not support profile "${parsed.profile}".`);
603
+ }
604
+ return [parsed.profile];
605
+ }
606
+ function resolveSuiteSplits(suite, parsed) {
607
+ if (parsed.split) {
608
+ if (suite.kind === 'trigger' || (suite.kind === 'command' && supports(suite, 'split'))) {
609
+ return [parsed.split];
610
+ }
611
+ return [null];
612
+ }
613
+ if (parsed.caseId && suite.kind === 'trigger') {
614
+ return ['all'];
615
+ }
616
+ return suite.releaseSplits.length > 0 ? suite.releaseSplits : [null];
617
+ }
618
+ async function readCommandSuiteCaseIds(pluginRoot, suite) {
619
+ if (!suite.cases)
620
+ return [];
621
+ const document = await fs.readJson(path.resolve(pluginRoot, suite.cases.replace(/^\.\//u, '')));
622
+ return (document.evals ?? []).map((entry) => String(entry.id));
623
+ }
624
+ async function readSuiteCaseIds(options) {
625
+ if (options.suite.kind === 'command') {
626
+ return options.suite.cases
627
+ ? readCommandSuiteCaseIds(options.pluginRoot, options.suite)
628
+ : [];
629
+ }
630
+ if (options.suite.kind === 'trigger') {
631
+ const corpus = await readPluginEvalTriggerCases(options.pluginRoot, options.suite);
632
+ return corpus.cases
633
+ .filter((entry) => !options.split || options.split === 'all' || entry.split === options.split)
634
+ .map((entry) => entry.id);
635
+ }
636
+ const casesPath = path.resolve(options.pluginRoot, options.suite.cases.replace(/^\.\//u, ''));
637
+ return validatePluginEvalConversationCaseDocument(await fs.readJson(casesPath), options.manifestSkill, `conversation cases for suite "${options.suite.id}"`).map((entry) => String(entry.id));
638
+ }
639
+ async function releaseTargetCompositions(prepared) {
640
+ const compositions = {};
641
+ for (const suite of prepared.manifest.suites) {
642
+ if (!suite.requiredForRelease || (suite.kind === 'command' && !suite.cases))
643
+ continue;
644
+ for (const profile of suite.profiles) {
645
+ const splits = suite.releaseSplits.length > 0
646
+ ? suite.releaseSplits
647
+ : ['all'];
648
+ for (const split of splits) {
649
+ const caseIds = await readSuiteCaseIds({
650
+ pluginRoot: prepared.sourcePlugin.rootDir,
651
+ manifestSkill: prepared.manifest.skill,
652
+ suite,
653
+ split,
654
+ });
655
+ const prefix = `${suite.kind}/${suite.id}/${profile}/${split}`;
656
+ compositions[`${prefix}/all`] = caseIds.map((caseId) => `${prefix}/${caseId}`);
657
+ }
658
+ }
659
+ }
660
+ return compositions;
661
+ }
662
+ async function preparePluginEval(options) {
663
+ const sourcePlugin = await readPluginManifest(path.join(options.repoRoot, 'plugins', options.pluginName));
664
+ const skillRoot = await resolvePluginSkillAuthorRoot(sourcePlugin.rootDir, options.skillName);
665
+ const manifest = await readPluginEvalManifest(sourcePlugin.rootDir, options.skillName, sourcePlugin.manifest.name);
666
+ const pluginNames = [...new Set(manifest.profiles.flatMap((profile) => profile.plugins.map((plugin) => plugin.name)))];
667
+ const sourcePlugins = [];
668
+ for (const pluginName of pluginNames) {
669
+ const plugin = pluginName === sourcePlugin.manifest.name
670
+ ? sourcePlugin
671
+ : await readPluginManifest(path.join(options.repoRoot, 'plugins', pluginName));
672
+ if (plugin.manifest.name !== pluginName) {
673
+ throw new Error(`Eval profile requested plugin "${pluginName}" but repo source declares ` +
674
+ `"${plugin.manifest.name}".`);
675
+ }
676
+ sourcePlugins.push(plugin);
677
+ }
678
+ const skillOwnersByPlugin = new Map();
679
+ for (const plugin of sourcePlugins) {
680
+ const skills = new Set();
681
+ if (plugin.manifest.skills) {
682
+ const staticRoot = path.resolve(plugin.rootDir, plugin.manifest.skills.replace(/^\.\//u, ''));
683
+ if (await fs.pathExists(staticRoot)) {
684
+ for (const entry of await fs.readdir(staticRoot, { withFileTypes: true })) {
685
+ if (entry.isDirectory())
686
+ skills.add(entry.name);
687
+ }
688
+ }
689
+ }
690
+ for (const target of plugin.manifest.artifacts?.targets ?? []) {
691
+ if (target.target === 'codex.skill' && target.skillKey)
692
+ skills.add(target.skillKey);
693
+ }
694
+ skillOwnersByPlugin.set(plugin.manifest.name, skills);
695
+ }
696
+ for (const profile of manifest.profiles) {
697
+ const owners = new Map();
698
+ for (const installation of profile.plugins) {
699
+ for (const skill of skillOwnersByPlugin.get(installation.name) ?? []) {
700
+ const existing = owners.get(skill);
701
+ if (existing && existing !== installation.name) {
702
+ throw new Error(`Profile "${profile.id}" installs duplicate Codex Skill key "${skill}" ` +
703
+ `from plugins "${existing}" and "${installation.name}".`);
704
+ }
705
+ owners.set(skill, installation.name);
706
+ }
707
+ }
708
+ for (const suite of manifest.suites.filter((suite) => suite.profiles.includes(profile.id))) {
709
+ for (const skill of suite.skills) {
710
+ if (!owners.has(skill)) {
711
+ throw new Error(`Suite "${suite.id}" requires Skill "${skill}", but profile ` +
712
+ `"${profile.id}" does not install a plugin that declares it.`);
713
+ }
714
+ }
715
+ }
716
+ }
717
+ if (options.parsed.profile &&
718
+ !manifest.profiles.some((profile) => profile.id === options.parsed.profile)) {
719
+ throw new Error(`Unknown profile "${options.parsed.profile}".`);
720
+ }
721
+ if (options.parsed.materializeOnly) {
722
+ return { sourcePlugin, sourcePlugins, skillRoot, manifest };
723
+ }
724
+ for (const suite of selectedSuites(manifest, options.parsed)) {
725
+ assertSuiteSupportsRequestedOptions(suite, options.parsed);
726
+ resolveSuiteProfiles(suite, options.parsed);
727
+ const splits = resolveSuiteSplits(suite, options.parsed);
728
+ if (!options.parsed.caseId)
729
+ continue;
730
+ if (suite.kind === 'trigger') {
731
+ const corpus = await readPluginEvalTriggerCases(sourcePlugin.rootDir, suite);
732
+ const matchingSplit = splits[0];
733
+ const match = corpus.cases.some((entry) => entry.id === options.parsed.caseId &&
734
+ (matchingSplit === null || matchingSplit === 'all' || entry.split === matchingSplit));
735
+ if (!match) {
736
+ throw new Error(`Unknown trigger case: ${options.parsed.caseId}`);
737
+ }
738
+ }
739
+ else if (suite.kind === 'conversation') {
740
+ const casesPath = path.resolve(sourcePlugin.rootDir, suite.cases.replace(/^\.\//u, ''));
741
+ const cases = validatePluginEvalConversationCaseDocument(await fs.readJson(casesPath), manifest.skill, `conversation cases for suite "${suite.id}"`);
742
+ if (!cases.some((entry) => entry.id === options.parsed.caseId)) {
743
+ throw new Error(`Unknown conversation case: ${options.parsed.caseId}`);
744
+ }
745
+ }
746
+ else if (suite.cases) {
747
+ const caseIds = await readCommandSuiteCaseIds(sourcePlugin.rootDir, suite);
748
+ if (!caseIds.includes(options.parsed.caseId)) {
749
+ throw new Error(`Unknown command case: ${options.parsed.caseId}`);
750
+ }
751
+ }
752
+ }
753
+ return { sourcePlugin, sourcePlugins, skillRoot, manifest };
754
+ }
755
+ async function readCodexVersion(codexBin, env) {
756
+ try {
757
+ const result = await execFileAsync(codexBin, ['--version'], {
758
+ env,
759
+ timeout: 10_000,
760
+ encoding: 'utf8',
761
+ });
762
+ return result.stdout.trim() || result.stderr.trim() || null;
763
+ }
764
+ catch {
765
+ return null;
766
+ }
767
+ }
768
+ function normalizedSuiteReportPath(reportPath, outputRoot) {
769
+ if (!reportPath)
770
+ return undefined;
771
+ const relative = path.isAbsolute(reportPath)
772
+ ? path.relative(outputRoot, reportPath)
773
+ : reportPath;
774
+ return relative.split(path.sep).join('/');
775
+ }
776
+ function batchRawReportPath(runId, reportPath) {
777
+ return reportPath
778
+ ? path.posix.join('evals', 'runs', runId, 'raw', reportPath)
779
+ : undefined;
780
+ }
781
+ function targetSummaryCaseResult(target) {
782
+ return {
783
+ id: target.case,
784
+ outcome: target.outcome,
785
+ complete: target.complete,
786
+ mechanicalPassed: target.mechanicalPassed,
787
+ qualitativeReview: target.qualitativeReview,
788
+ ...(batchRawReportPath(target.runId, target.reportPath)
789
+ ? { reportPath: batchRawReportPath(target.runId, target.reportPath) }
790
+ : {}),
791
+ sourceRunId: target.runId,
792
+ reused: true,
793
+ summary: target.summary,
794
+ diagnostics: target.diagnostics,
795
+ };
796
+ }
797
+ function effectiveCaseResultFromReport(caseId, report) {
798
+ const source = report.caseResults?.find((entry) => entry.id === caseId);
799
+ const complete = report.complete && (source?.complete ?? true);
800
+ const outcome = !complete ||
801
+ report.outcome === 'incomplete' || source?.outcome === 'incomplete'
802
+ ? 'incomplete'
803
+ : report.outcome === 'failed' || source?.outcome === 'failed'
804
+ ? 'failed'
805
+ : report.outcome === 'needs_review' || source?.outcome === 'needs_review'
806
+ ? 'needs_review'
807
+ : 'passed';
808
+ return {
809
+ id: caseId,
810
+ outcome,
811
+ complete,
812
+ mechanicalPassed: report.mechanicalPassed && (source?.mechanicalPassed ?? true),
813
+ qualitativeReview: source?.qualitativeReview ?? report.qualitativeReview,
814
+ summary: source?.summary ?? report.summary,
815
+ diagnostics: [...new Set([
816
+ ...(source?.diagnostics ?? []),
817
+ ...report.diagnostics,
818
+ ])],
819
+ };
820
+ }
821
+ async function writeCaseEvidenceIndex(options) {
822
+ const name = [options.suite.id, options.split, options.profile, 'case-index']
823
+ .filter(Boolean)
824
+ .join('-');
825
+ const reportPath = path.join(options.outputRoot, 'reports', `${name}.json`);
826
+ await fs.ensureDir(path.dirname(reportPath));
827
+ const temporary = `${reportPath}.${process.pid}.${randomUUID()}.tmp`;
828
+ await fs.writeJson(temporary, {
829
+ schema_version: 1,
830
+ type: 'eval-case-index',
831
+ generated_at: new Date().toISOString(),
832
+ suite: options.suite.id,
833
+ kind: options.suite.kind,
834
+ profile: options.profile,
835
+ split: options.split ?? 'all',
836
+ cases: options.cases.map((entry) => ({
837
+ id: entry.id,
838
+ outcome: entry.outcome,
839
+ complete: entry.complete,
840
+ mechanical_passed: entry.mechanicalPassed,
841
+ qualitative_review: entry.qualitativeReview ?? 'not_required',
842
+ source_run_id: entry.sourceRunId ?? null,
843
+ reused: entry.reused === true,
844
+ report_path: entry.reportPath ?? null,
845
+ })),
846
+ }, { spaces: 2 });
847
+ await fs.rename(temporary, reportPath);
848
+ return path.relative(options.outputRoot, reportPath).split(path.sep).join('/');
849
+ }
850
+ function aggregateCaseSuiteReport(options) {
851
+ const byId = new Map(options.cases.map((entry) => [entry.id, entry]));
852
+ const ordered = options.expectedCaseIds.flatMap((id) => {
853
+ const entry = byId.get(id);
854
+ return entry ? [entry] : [];
855
+ });
856
+ const missing = options.expectedCaseIds.filter((id) => !byId.has(id));
857
+ const complete = missing.length === 0 && ordered.every((entry) => entry.complete);
858
+ const outcome = !complete || ordered.some((entry) => entry.outcome === 'incomplete')
859
+ ? 'incomplete'
860
+ : ordered.some((entry) => entry.outcome === 'failed')
861
+ ? 'failed'
862
+ : ordered.some((entry) => entry.outcome === 'needs_review')
863
+ ? 'needs_review'
864
+ : 'passed';
865
+ const qualitativeReview = options.suite.kind === 'conversation' || ordered.some((entry) => entry.qualitativeReview === 'required')
866
+ ? 'required'
867
+ : 'not_required';
868
+ return {
869
+ id: options.suite.id,
870
+ kind: options.suite.kind,
871
+ skills: options.suite.skills,
872
+ profile: options.profile,
873
+ split: options.split,
874
+ outcome,
875
+ complete,
876
+ mechanicalPassed: ordered.every((entry) => entry.mechanicalPassed),
877
+ qualitativeReview,
878
+ reportPath: options.reportPath,
879
+ caseResults: ordered,
880
+ summary: {
881
+ cases: options.expectedCaseIds.length,
882
+ completed: ordered.filter((entry) => entry.complete).length,
883
+ passed: ordered.filter((entry) => entry.outcome === 'passed').length,
884
+ failed: ordered.filter((entry) => entry.outcome === 'failed').length,
885
+ needsReview: ordered.filter((entry) => entry.outcome === 'needs_review').length,
886
+ incomplete: missing.length + ordered.filter((entry) => !entry.complete).length,
887
+ },
888
+ diagnostics: [
889
+ ...(missing.length > 0 ? [`Missing case evidence: ${missing.join(', ')}.`] : []),
890
+ ...ordered.flatMap((entry) => entry.diagnostics ?? []),
891
+ ],
892
+ };
893
+ }
894
+ function checkpointEvaluation(subjects, report) {
895
+ return {
896
+ generatedAt: new Date().toISOString(),
897
+ outcome: report.outcome,
898
+ complete: report.complete,
899
+ mechanicalPassed: report.mechanicalPassed,
900
+ subjects,
901
+ suites: [report],
902
+ diagnostics: report.diagnostics,
903
+ };
904
+ }
905
+ async function runOnePlugin(options) {
906
+ assertCodexEvalCanStartWork();
907
+ const { sourcePlugin, manifest } = options;
908
+ const outputRoot = options.outputRoot;
909
+ await fs.ensureDir(outputRoot);
910
+ const selectedProfiles = options.parsed.profile
911
+ ? new Set([options.parsed.profile])
912
+ : undefined;
913
+ assertCodexEvalCanStartWork();
914
+ const subjects = await materializePluginEvalSubjects({
915
+ plugin: sourcePlugin,
916
+ plugins: options.sourcePlugins,
917
+ manifest,
918
+ outputRoot,
919
+ workRoot: path.join(options.workRoot, 'materialize'),
920
+ env: options.env,
921
+ selectedProfiles,
922
+ });
923
+ const reports = [];
924
+ if (!options.parsed.materializeOnly) {
925
+ if (!options.layout)
926
+ throw new Error('Real model eval requires a report run layout.');
927
+ suiteLoop: for (const suite of selectedSuites(manifest, options.parsed)) {
928
+ assertCodexEvalCanStartWork();
929
+ for (const profile of resolveSuiteProfiles(suite, options.parsed)) {
930
+ const subject = subjects.find((entry) => entry.profile === profile);
931
+ if (!subject) {
932
+ throw new Error(`Profile "${profile}" was not materialized.`);
933
+ }
934
+ const subjectRoot = resolveMaterializedSubjectRoot(outputRoot, subject);
935
+ for (const split of resolveSuiteSplits(suite, options.parsed)) {
936
+ assertCodexEvalCanStartWork();
937
+ options.stderr(`[plugin:eval] ${sourcePlugin.manifest.name}/${suite.id}` +
938
+ `${split ? `/${split}` : ''} (${profile})\n`);
939
+ const declaredCaseIds = await readSuiteCaseIds({
940
+ pluginRoot: sourcePlugin.rootDir,
941
+ manifestSkill: manifest.skill,
942
+ suite,
943
+ split,
944
+ });
945
+ const expectedCaseIds = options.parsed.caseId
946
+ ? declaredCaseIds.filter((id) => id === options.parsed.caseId)
947
+ : declaredCaseIds;
948
+ if (declaredCaseIds.length > 0 && expectedCaseIds.length === 0) {
949
+ throw new Error(`Unknown ${suite.kind} case: ${options.parsed.caseId}`);
950
+ }
951
+ if (expectedCaseIds.length > 0) {
952
+ const targets = expectedCaseIds.map((caseId) => createSkillEvalTargetKey([
953
+ suite.kind,
954
+ suite.id,
955
+ profile,
956
+ split ?? 'all',
957
+ caseId,
958
+ ]));
959
+ const plan = await resolveSkillEvalTargetPlan({
960
+ layout: options.layout,
961
+ targets,
962
+ });
963
+ const targetByCase = new Map(targets.map((target, index) => [
964
+ expectedCaseIds[index],
965
+ target,
966
+ ]));
967
+ const caseResults = plan.reusable.map(targetSummaryCaseResult);
968
+ const pendingCaseIds = expectedCaseIds.filter((caseId) => plan.pending.includes(targetByCase.get(caseId)));
969
+ if (plan.reusable.length > 0) {
970
+ options.stderr(`[plugin:eval] reuse=${plan.reusable.length} pending=${pendingCaseIds.length} ` +
971
+ `suite=${suite.id} profile=${profile} split=${split ?? 'all'}\n`);
972
+ }
973
+ const recordCase = async (caseId, rawReport) => {
974
+ const report = applyRunCountCoverage({
975
+ ...rawReport,
976
+ reportPath: normalizedSuiteReportPath(rawReport.reportPath, outputRoot),
977
+ }, suite, options.parsed);
978
+ await publishEvalRunCheckpoint({
979
+ layout: options.layout,
980
+ evaluation: checkpointEvaluation(subjects, report),
981
+ caseId,
982
+ });
983
+ const effective = effectiveCaseResultFromReport(caseId, report);
984
+ caseResults.push({
985
+ ...effective,
986
+ ...(report.reportPath ? {
987
+ reportPath: batchRawReportPath(options.layout.runId, report.reportPath),
988
+ } : {}),
989
+ sourceRunId: options.layout.runId,
990
+ reused: false,
991
+ });
992
+ return report;
993
+ };
994
+ const recordedCaseCount = caseResults.length;
995
+ let executionReport = null;
996
+ if (pendingCaseIds.length > 0 && suite.kind === 'conversation') {
997
+ const skillPath = path.join(subjectRoot, '.agents', 'skills', suite.skill, 'SKILL.md');
998
+ if (!(await fs.pathExists(skillPath))) {
999
+ throw new Error(`Conversation suite "${suite.id}" could not find materialized skill ` +
1000
+ `"${suite.skill}" in profile "${profile}".`);
1001
+ }
1002
+ const reportPath = path.join(outputRoot, 'reports', `${suite.id}-${profile}.json`);
1003
+ executionReport = await runCodexConversationSuite({
1004
+ suiteId: suite.id,
1005
+ skillName: suite.skill,
1006
+ skillNames: suite.skills,
1007
+ casesPath: path.resolve(sourcePlugin.rootDir, suite.cases.replace(/^\.\//u, '')),
1008
+ subjectRoot,
1009
+ profile,
1010
+ runs: options.parsed.runs ?? suite.defaultRuns,
1011
+ caseIds: pendingCaseIds,
1012
+ codexBin: options.parsed.codexBin,
1013
+ model: options.parsed.model,
1014
+ codexRuntime: options.codexRuntime,
1015
+ timeoutMs: suite.perRunTimeoutMs,
1016
+ isolation: suite.isolation,
1017
+ sourceEnv: options.modelEnv,
1018
+ reportPath,
1019
+ processManagement: options.processManagement,
1020
+ forbiddenHostRoots: options.sourcePlugins.map((plugin) => plugin.rootDir),
1021
+ workRoot: path.join(options.workRoot, 'conversation'),
1022
+ stopOnIncomplete: true,
1023
+ onCaseCompleted: async (checkpoint) => {
1024
+ await recordCase(checkpoint.caseId, checkpoint.report);
1025
+ },
1026
+ });
1027
+ }
1028
+ else if (pendingCaseIds.length > 0 && suite.kind === 'trigger') {
1029
+ const triggerSplit = split ?? 'all';
1030
+ const reportPath = path.join(outputRoot, 'reports', `${suite.id}-${triggerSplit}-${profile}.json`);
1031
+ executionReport = await runCodexTriggerSuite({
1032
+ suite,
1033
+ split: triggerSplit,
1034
+ subjectRoot,
1035
+ pluginRoot: sourcePlugin.rootDir,
1036
+ profile,
1037
+ runs: options.parsed.runs ?? suite.defaultRuns,
1038
+ caseIds: pendingCaseIds,
1039
+ codexBin: options.parsed.codexBin,
1040
+ model: options.parsed.model,
1041
+ codexRuntime: options.codexRuntime,
1042
+ sourceEnv: options.modelEnv,
1043
+ reportPath,
1044
+ stderr: options.stderr,
1045
+ processManagement: options.processManagement,
1046
+ workRoot: path.join(options.workRoot, 'trigger'),
1047
+ stopOnIncomplete: true,
1048
+ onCaseCompleted: async (checkpoint) => {
1049
+ await recordCase(checkpoint.caseId, checkpoint.report);
1050
+ },
1051
+ });
1052
+ }
1053
+ else if (pendingCaseIds.length > 0 && suite.kind === 'command') {
1054
+ const deadline = Date.now() + suite.suiteTimeoutMs;
1055
+ for (const caseId of pendingCaseIds) {
1056
+ const remaining = Math.max(1, deadline - Date.now());
1057
+ const rawReport = await runCommandSuite({
1058
+ pluginName: sourcePlugin.manifest.name,
1059
+ suite,
1060
+ split,
1061
+ profile,
1062
+ subjectRoot,
1063
+ pluginRoot: sourcePlugin.rootDir,
1064
+ outputRoot,
1065
+ parsed: { ...options.parsed, caseId },
1066
+ env: options.modelEnv,
1067
+ codexRuntime: options.codexRuntime,
1068
+ codexRuntimeHome: options.codexRuntimeHome,
1069
+ processManagement: options.processManagement,
1070
+ installedPluginNames: subject.installedPlugins.map((plugin) => plugin.name),
1071
+ workRoot: options.workRoot,
1072
+ stderr: options.stderr,
1073
+ timeoutMs: remaining,
1074
+ });
1075
+ executionReport = await recordCase(caseId, rawReport);
1076
+ if (rawReport.outcome === 'incomplete')
1077
+ break;
1078
+ }
1079
+ }
1080
+ if (executionReport?.outcome === 'incomplete' &&
1081
+ caseResults.length === recordedCaseCount) {
1082
+ const report = applyRunCountCoverage({
1083
+ ...executionReport,
1084
+ reportPath: normalizedSuiteReportPath(executionReport.reportPath, outputRoot),
1085
+ }, suite, options.parsed);
1086
+ await publishEvalRunCheckpoint({
1087
+ layout: options.layout,
1088
+ evaluation: checkpointEvaluation(subjects, report),
1089
+ });
1090
+ reports.push(report);
1091
+ break suiteLoop;
1092
+ }
1093
+ const indexPath = await writeCaseEvidenceIndex({
1094
+ outputRoot,
1095
+ suite,
1096
+ profile,
1097
+ split,
1098
+ cases: caseResults,
1099
+ });
1100
+ const report = aggregateCaseSuiteReport({
1101
+ suite,
1102
+ profile,
1103
+ split,
1104
+ expectedCaseIds,
1105
+ cases: caseResults,
1106
+ reportPath: indexPath,
1107
+ });
1108
+ reports.push(report);
1109
+ if (report.outcome === 'incomplete')
1110
+ break suiteLoop;
1111
+ continue;
1112
+ }
1113
+ const target = createSkillEvalTargetKey([
1114
+ suite.kind,
1115
+ suite.id,
1116
+ profile,
1117
+ split ?? 'all',
1118
+ 'all',
1119
+ ]);
1120
+ const plan = await resolveSkillEvalTargetPlan({
1121
+ layout: options.layout,
1122
+ targets: [target],
1123
+ });
1124
+ if (plan.reusable.length > 0) {
1125
+ const reused = plan.reusable[0];
1126
+ const reference = targetSummaryCaseResult(reused);
1127
+ const reportPath = await writeCaseEvidenceIndex({
1128
+ outputRoot,
1129
+ suite,
1130
+ profile,
1131
+ split,
1132
+ cases: [reference],
1133
+ });
1134
+ reports.push({
1135
+ id: suite.id,
1136
+ kind: suite.kind,
1137
+ skills: suite.skills,
1138
+ profile,
1139
+ split,
1140
+ outcome: reused.outcome,
1141
+ complete: reused.complete,
1142
+ mechanicalPassed: reused.mechanicalPassed,
1143
+ qualitativeReview: reused.qualitativeReview,
1144
+ reportPath,
1145
+ summary: { ...reused.summary, reusedFromRun: reused.runId },
1146
+ diagnostics: reused.diagnostics,
1147
+ });
1148
+ continue;
1149
+ }
1150
+ if (suite.kind !== 'command') {
1151
+ throw new Error(`Suite "${suite.id}" did not expose its declared cases.`);
1152
+ }
1153
+ const report = applyRunCountCoverage(await runCommandSuite({
1154
+ pluginName: sourcePlugin.manifest.name,
1155
+ suite,
1156
+ split,
1157
+ profile,
1158
+ subjectRoot,
1159
+ pluginRoot: sourcePlugin.rootDir,
1160
+ outputRoot,
1161
+ parsed: options.parsed,
1162
+ env: options.modelEnv,
1163
+ codexRuntime: options.codexRuntime,
1164
+ codexRuntimeHome: options.codexRuntimeHome,
1165
+ processManagement: options.processManagement,
1166
+ installedPluginNames: subject.installedPlugins.map((plugin) => plugin.name),
1167
+ workRoot: options.workRoot,
1168
+ stderr: options.stderr,
1169
+ }), suite, options.parsed);
1170
+ await publishEvalRunCheckpoint({
1171
+ layout: options.layout,
1172
+ evaluation: checkpointEvaluation(subjects, report),
1173
+ });
1174
+ reports.push(report);
1175
+ if (report.outcome === 'incomplete')
1176
+ break suiteLoop;
1177
+ }
1178
+ }
1179
+ }
1180
+ }
1181
+ const reportOutcome = options.parsed.materializeOnly
1182
+ ? 'passed'
1183
+ : combinePluginEvalOutcome(reports);
1184
+ const coverageDiagnostics = collectCoverageDiagnostics(manifest, options.parsed);
1185
+ const coverageComplete = coverageDiagnostics.length === 0;
1186
+ const reportsComplete = options.parsed.materializeOnly ||
1187
+ reports.every((report) => report.complete);
1188
+ const unredactedBundle = {
1189
+ schemaVersion: PLUGIN_EVAL_SCHEMA_VERSION,
1190
+ generatedAt: new Date().toISOString(),
1191
+ plugin: sourcePlugin.manifest.name,
1192
+ skill: manifest.skill,
1193
+ pluginVersion: sourcePlugin.manifest.version,
1194
+ platform: 'codex',
1195
+ codexVersion: options.parsed.materializeOnly
1196
+ ? null
1197
+ : await readCodexVersion(options.parsed.codexBin, options.modelEnv),
1198
+ model: options.parsed.model ?? options.codexRuntime?.model ?? null,
1199
+ modelProvider: options.codexRuntime?.modelProvider ?? null,
1200
+ credentialSource: options.codexRuntime?.credentialSource ?? null,
1201
+ codexConfigDigest: options.codexRuntime?.evidenceDigest ?? null,
1202
+ cliCapsule: options.cliCapsule ?? null,
1203
+ processManagement: options.processManagement,
1204
+ outcome: coverageComplete ? reportOutcome : 'incomplete',
1205
+ complete: coverageComplete && reportsComplete,
1206
+ mechanicalPassed: options.parsed.materializeOnly || reports.every((report) => report.mechanicalPassed),
1207
+ subjects,
1208
+ suites: reports,
1209
+ diagnostics: coverageDiagnostics,
1210
+ };
1211
+ const bundle = options.codexRuntime
1212
+ ? redactCodexEvalValue(unredactedBundle, options.codexRuntime)
1213
+ : unredactedBundle;
1214
+ await fs.writeJson(path.join(outputRoot, 'evaluation.json'), bundle, { spaces: 2 });
1215
+ return bundle;
1216
+ }
1217
+ export async function readSourceRevision(options) {
1218
+ try {
1219
+ const pluginPaths = options.pluginNames.map((pluginName) => `plugins/${pluginName}`);
1220
+ const reportExclusions = options.pluginNames.map((pluginName) => `:(exclude)plugins/${pluginName}/**/reports/**`);
1221
+ const [head, status] = await Promise.all([
1222
+ execFileAsync('git', ['rev-parse', 'HEAD'], {
1223
+ cwd: options.repoRoot,
1224
+ encoding: 'utf8',
1225
+ }),
1226
+ execFileAsync('git', [
1227
+ 'status',
1228
+ '--porcelain=v1',
1229
+ '--',
1230
+ ...pluginPaths,
1231
+ 'packages/cli/scripts',
1232
+ 'packages/cli/src',
1233
+ ...reportExclusions,
1234
+ ], {
1235
+ cwd: options.repoRoot,
1236
+ encoding: 'utf8',
1237
+ }),
1238
+ ]);
1239
+ return {
1240
+ gitHead: head.stdout.trim() || null,
1241
+ inScopeDirty: status.stdout.trim() !== '',
1242
+ };
1243
+ }
1244
+ catch {
1245
+ return { gitHead: null, inScopeDirty: true };
1246
+ }
1247
+ }
1248
+ function publicProcessManagement(value) {
1249
+ return {
1250
+ mode: value.mode,
1251
+ inspectionAvailable: value.inspectionAvailable,
1252
+ userAcknowledged: value.userAcknowledged,
1253
+ descendantCleanupGuaranteed: value.descendantCleanupGuaranteed,
1254
+ ...(value.limitation ? { limitation: value.limitation } : {}),
1255
+ };
1256
+ }
1257
+ async function writePublishedEvalReport(options) {
1258
+ const processManagement = publicProcessManagement(options.bundle.processManagement);
1259
+ const summary = {
1260
+ schemaVersion: 1,
1261
+ runId: options.layout.runId,
1262
+ plugin: options.bundle.plugin,
1263
+ skill: options.bundle.skill,
1264
+ generatedAt: options.bundle.generatedAt,
1265
+ outcome: options.bundle.outcome,
1266
+ complete: options.bundle.complete,
1267
+ mechanicalPassed: options.bundle.mechanicalPassed,
1268
+ codexVersion: options.bundle.codexVersion,
1269
+ model: options.bundle.model,
1270
+ modelProvider: options.bundle.modelProvider,
1271
+ codexConfigDigest: options.bundle.codexConfigDigest,
1272
+ cliCapsule: options.bundle.cliCapsule,
1273
+ processManagement,
1274
+ source: options.sourceRevision,
1275
+ subjects: options.bundle.subjects.map((subject) => ({
1276
+ profile: subject.profile,
1277
+ scope: subject.scope,
1278
+ configDigest: subject.configDigest,
1279
+ bundleDigest: subject.bundleDigest,
1280
+ installedPlugins: subject.installedPlugins,
1281
+ artifacts: subject.artifacts.map((artifact) => ({
1282
+ kind: artifact.kind,
1283
+ ...(artifact.key ? { key: artifact.key } : {}),
1284
+ contentDigest: artifact.contentDigest,
1285
+ })),
1286
+ })),
1287
+ suites: options.bundle.suites.map((suite) => ({
1288
+ id: suite.id,
1289
+ kind: suite.kind,
1290
+ skills: suite.skills,
1291
+ profile: suite.profile,
1292
+ split: suite.split,
1293
+ outcome: suite.outcome,
1294
+ complete: suite.complete,
1295
+ mechanicalPassed: suite.mechanicalPassed,
1296
+ qualitativeReview: suite.qualitativeReview,
1297
+ caseResults: suite.caseResults,
1298
+ summary: suite.summary,
1299
+ })),
1300
+ diagnostics: options.bundle.diagnostics,
1301
+ };
1302
+ await writeEvalRunJson(options.layout.reportRoot, 'summary.json', summary);
1303
+ const suiteRows = summary.suites.map((suite) => `| ${suite.id} | ${suite.skills.join(', ')} | ${suite.profile} | ${suite.split ?? '-'} | ${suite.outcome} |`);
1304
+ const report = [
1305
+ '# Plugin Skill Eval Report',
1306
+ '',
1307
+ `- Plugin: \`${summary.plugin}\``,
1308
+ `- Skill: \`${summary.skill}\``,
1309
+ `- Run: \`${summary.runId}\``,
1310
+ `- Outcome: \`${summary.outcome}\``,
1311
+ `- Complete: \`${summary.complete}\``,
1312
+ `- Process management: \`${processManagement.mode}\``,
1313
+ '',
1314
+ '| Suite | Skills | Profile | Split | Outcome |',
1315
+ '| --- | --- | --- | --- | --- |',
1316
+ ...suiteRows,
1317
+ '',
1318
+ '完整 subject、trace 和 suite 报告保存在同目录的 `raw/`。',
1319
+ '',
1320
+ ].join('\n');
1321
+ await fs.writeFile(path.join(options.layout.reportRoot, 'report.md'), report, 'utf8');
1322
+ }
1323
+ export async function runPluginEvals(args, options = {}) {
1324
+ const stdout = options.stdout ?? ((text) => process.stdout.write(text));
1325
+ const stderr = options.stderr ?? ((text) => process.stderr.write(text));
1326
+ if (args.includes('-h') || args.includes('--help')) {
1327
+ stdout(`${usage()}\n`);
1328
+ return 0;
1329
+ }
1330
+ try {
1331
+ const executionPlanPath = awSkillEvalExecutionPlanPath(args);
1332
+ if (executionPlanPath) {
1333
+ const result = await runAwSkillEvalExecutionPlan(executionPlanPath, {
1334
+ sourceEnv: options.env ?? process.env,
1335
+ platform: options.platform,
1336
+ processTree: options.evalProcessTree,
1337
+ });
1338
+ stdout(`${JSON.stringify(result, null, 2)}\n`);
1339
+ return result.requirementsMet ? 0 : 1;
1340
+ }
1341
+ }
1342
+ catch (error) {
1343
+ stderr(`${error instanceof Error ? error.message : String(error)}\n`);
1344
+ return 2;
1345
+ }
1346
+ let parsed;
1347
+ try {
1348
+ parsed = parseArgs(args);
1349
+ }
1350
+ catch (error) {
1351
+ stderr(`${error instanceof Error ? error.message : String(error)}\n`);
1352
+ return 2;
1353
+ }
1354
+ const env = options.env ?? process.env;
1355
+ const repoRoot = path.resolve(options.repoRoot ?? env[REPO_ROOT_ENV] ?? resolveRepoRoot());
1356
+ let prepared;
1357
+ if ((parsed.batchName ? 1 : 0) + (parsed.batchId ? 1 : 0) !== 1) {
1358
+ if (options.createRunLayout && !parsed.batchName && !parsed.batchId) {
1359
+ parsed.batchName = 'test-batch';
1360
+ }
1361
+ else {
1362
+ stderr('Provide exactly one of --batch-name or --batch-id.\n');
1363
+ return 2;
1364
+ }
1365
+ }
1366
+ try {
1367
+ prepared = await preparePluginEval({
1368
+ repoRoot,
1369
+ pluginName: parsed.pluginName,
1370
+ skillName: parsed.skillName,
1371
+ parsed,
1372
+ });
1373
+ }
1374
+ catch (error) {
1375
+ stderr(`${error instanceof Error ? error.message : String(error)}\n`);
1376
+ return 2;
1377
+ }
1378
+ let codexRuntime;
1379
+ let processManagement = {
1380
+ mode: 'not-applicable',
1381
+ inspectionAvailable: false,
1382
+ userAcknowledged: false,
1383
+ descendantCleanupGuaranteed: false,
1384
+ };
1385
+ if (!parsed.materializeOnly) {
1386
+ try {
1387
+ processManagement = await resolveCodexEvalProcessManagement({
1388
+ allowUnmanaged: parsed.allowUnmanagedProcesses,
1389
+ sourceEnv: env,
1390
+ preflight: () => assertCodexEvalKeychainWrapperAbsent({
1391
+ platform: options.platform,
1392
+ readUserKeychainSearchList: options.readUserKeychainSearchList,
1393
+ }),
1394
+ inspect: options.inspectProcessTree,
1395
+ platform: options.platform,
1396
+ });
1397
+ codexRuntime = await resolveCodexEvalRuntimeConfig({
1398
+ sourceEnv: env,
1399
+ inheritUserConfig: parsed.inheritCodexConfig,
1400
+ configPath: parsed.codexConfig,
1401
+ modelOverride: parsed.model,
1402
+ modelProviderOverride: parsed.modelProvider,
1403
+ });
1404
+ }
1405
+ catch (error) {
1406
+ stderr(`${error instanceof Error ? error.message : String(error)}\n`);
1407
+ return 2;
1408
+ }
1409
+ if (processManagement.mode === 'unmanaged-confirmed') {
1410
+ stderr('[plugin:eval] WARNING: unmanaged process cleanup was explicitly confirmed. ' +
1411
+ 'No process-tree inspection was used, and this run does not track or verify descendant cleanup. ' +
1412
+ 'Timeout and signal cleanup only target the direct child.\n');
1413
+ }
1414
+ }
1415
+ const sourceRevision = await readSourceRevision({
1416
+ repoRoot,
1417
+ pluginNames: prepared.sourcePlugins.map((plugin) => plugin.manifest.name),
1418
+ });
1419
+ const sourceDigest = await computeAuthorSourceDigest(prepared.sourcePlugins.map((plugin) => ({
1420
+ name: plugin.manifest.name,
1421
+ root: plugin.rootDir,
1422
+ })));
1423
+ const environmentDigest = createEnvironmentDigest({
1424
+ nodeVersion: process.version,
1425
+ platform: process.platform,
1426
+ architecture: process.arch,
1427
+ });
1428
+ const harnessRepoRoot = resolveRepoRoot();
1429
+ const harnessDigest = await computeAuthorSourceDigest([
1430
+ { name: 'packages/cli/scripts', root: path.join(harnessRepoRoot, 'packages', 'cli', 'scripts') },
1431
+ { name: 'packages/cli/src', root: path.join(harnessRepoRoot, 'packages', 'cli', 'src') },
1432
+ ]);
1433
+ const requiredTargets = pluginReleaseTargets(prepared.manifest);
1434
+ const targetCompositions = await releaseTargetCompositions(prepared);
1435
+ let runtimeCapsule;
1436
+ let layout;
1437
+ try {
1438
+ runtimeCapsule = codexRuntime
1439
+ ? await createCodexEvalRuntimeCapsule(codexRuntime, env, {
1440
+ cliPackageRoot: resolveCliPackageRoot(),
1441
+ deployCli: options.deployEvalCli,
1442
+ })
1443
+ : undefined;
1444
+ const modelEnvironmentDigest = parsed.materializeOnly ? null : createEnvironmentDigest({
1445
+ model: parsed.model ?? codexRuntime?.model ?? null,
1446
+ modelProvider: codexRuntime?.modelProvider ?? null,
1447
+ codexConfigDigest: codexRuntime?.evidenceDigest ?? null,
1448
+ codexVersion: await readCodexVersion(parsed.codexBin, env),
1449
+ processManagement: publicProcessManagement(processManagement),
1450
+ cliCapsule: runtimeCapsule?.cli ?? null,
1451
+ });
1452
+ layout = await (options.createRunLayout ?? createPluginEvalRunLayout)({
1453
+ repoRoot,
1454
+ plugin: parsed.pluginName,
1455
+ skill: parsed.skillName,
1456
+ batchName: parsed.batchName,
1457
+ batchId: parsed.batchId,
1458
+ runId: parsed.runId,
1459
+ source: {
1460
+ digest: sourceDigest,
1461
+ gitHead: sourceRevision.gitHead,
1462
+ inScopeDirty: sourceRevision.inScopeDirty,
1463
+ },
1464
+ environmentDigest,
1465
+ modelEnvironmentDigest,
1466
+ harnessDigest,
1467
+ requiredTargets,
1468
+ targetCompositions,
1469
+ });
1470
+ }
1471
+ catch (error) {
1472
+ await runtimeCapsule?.cleanup().catch(() => undefined);
1473
+ stderr(`${error instanceof Error ? error.message : String(error)}\n`);
1474
+ return 2;
1475
+ }
1476
+ const startedAt = layout.startedAt;
1477
+ await writeEvalRunJson(layout.reportRoot, 'run.json', {
1478
+ schemaVersion: 1,
1479
+ type: 'plugin-skill-eval',
1480
+ runId: layout.runId,
1481
+ plugin: parsed.pluginName,
1482
+ skill: parsed.skillName,
1483
+ status: 'running',
1484
+ startedAt,
1485
+ pid: layout.pid,
1486
+ host: layout.host,
1487
+ processManagement: publicProcessManagement(processManagement),
1488
+ source: sourceRevision,
1489
+ rawDirectory: 'raw',
1490
+ });
1491
+ stderr(`[plugin:eval] run=${layout.runId} report=${path.relative(repoRoot, layout.reportRoot)}\n`);
1492
+ if (!parsed.materializeOnly) {
1493
+ stderr('[plugin:eval] Model evals can run for tens of minutes or hours. Keep this process ' +
1494
+ 'session open and use the longest responsive wait that the tool allows. A wait timeout ' +
1495
+ 'is not an eval failure. Do not start separate status-poll commands.\n');
1496
+ }
1497
+ let exitCode = 1;
1498
+ try {
1499
+ assertCodexEvalCanStartWork();
1500
+ const bundle = await runOnePlugin({
1501
+ sourcePlugin: prepared.sourcePlugin,
1502
+ sourcePlugins: prepared.sourcePlugins,
1503
+ manifest: prepared.manifest,
1504
+ parsed,
1505
+ outputRoot: layout.rawRoot,
1506
+ workRoot: layout.workRoot,
1507
+ processManagement,
1508
+ env,
1509
+ modelEnv: runtimeCapsule?.env ?? env,
1510
+ codexRuntime: runtimeCapsule?.runtime ?? codexRuntime,
1511
+ cliCapsule: runtimeCapsule?.cli ?? null,
1512
+ codexRuntimeHome: runtimeCapsule?.home,
1513
+ layout,
1514
+ stderr,
1515
+ });
1516
+ await runtimeCapsule?.cleanup();
1517
+ runtimeCapsule = undefined;
1518
+ await writePublishedEvalReport({
1519
+ layout,
1520
+ bundle,
1521
+ sourceRevision,
1522
+ });
1523
+ const batchSummary = parsed.materializeOnly
1524
+ ? await publishEvalRunToBatch({
1525
+ repoRoot,
1526
+ layout,
1527
+ evaluation: bundle,
1528
+ caseId: parsed.caseId,
1529
+ requiredTargets,
1530
+ })
1531
+ : await completeSkillEvalRun({ layout, evaluation: bundle });
1532
+ stdout(`${JSON.stringify({
1533
+ schemaVersion: PLUGIN_EVAL_SCHEMA_VERSION,
1534
+ batchId: layout.batchId,
1535
+ batchDir: path.relative(repoRoot, layout.batchRoot).split(path.sep).join('/'),
1536
+ batchSummary,
1537
+ runId: layout.runId,
1538
+ reportDir: path.relative(repoRoot, layout.reportRoot).split(path.sep).join('/'),
1539
+ bundle,
1540
+ }, null, 2)}\n`);
1541
+ exitCode = bundle.outcome === 'failed' || bundle.outcome === 'incomplete' ? 1 : 0;
1542
+ }
1543
+ catch (error) {
1544
+ const message = error instanceof Error ? error.stack ?? error.message : String(error);
1545
+ const safeMessage = codexRuntime ? redactCodexEvalText(message, codexRuntime) : message;
1546
+ stderr(`${parsed.pluginName}: ${safeMessage}\n`);
1547
+ await fs.writeFile(path.join(layout.rawRoot, 'error.txt'), `${safeMessage}\n`, 'utf8');
1548
+ try {
1549
+ await failSkillEvalRun({
1550
+ layout,
1551
+ message: safeMessage,
1552
+ });
1553
+ }
1554
+ catch (refreshError) {
1555
+ stderr(`Failed to mark the report run as failed: ${refreshError instanceof Error ? refreshError.message : String(refreshError)}\n`);
1556
+ }
1557
+ exitCode = 1;
1558
+ }
1559
+ finally {
1560
+ try {
1561
+ await runtimeCapsule?.cleanup();
1562
+ }
1563
+ catch (error) {
1564
+ stderr(`Runtime capsule cleanup failed: ${error instanceof Error ? error.message : String(error)}\n`);
1565
+ exitCode = 1;
1566
+ }
1567
+ try {
1568
+ await layout.cleanupWork();
1569
+ }
1570
+ catch (error) {
1571
+ stderr(`Eval work directory cleanup failed: ${error instanceof Error ? error.message : String(error)}\n`);
1572
+ exitCode = 1;
1573
+ }
1574
+ }
1575
+ return exitCode;
1576
+ }
1577
+ const currentEntryPath = fileURLToPath(import.meta.url);
1578
+ if (process.argv[1] && path.resolve(process.argv[1]) === currentEntryPath) {
1579
+ runPluginEvals(process.argv.slice(2)).then((exitCode) => {
1580
+ process.exitCode = exitCode;
1581
+ }).catch((error) => {
1582
+ console.error(error instanceof Error ? error.stack ?? error.message : String(error));
1583
+ process.exitCode = 1;
1584
+ });
1585
+ }
1586
+ //# sourceMappingURL=eval-plugin-skills.js.map