@rpamis/comet 0.4.0-beta.2 → 0.4.0-beta.4

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 (509) hide show
  1. package/README.md +27 -18
  2. package/assets/manifest.json +2 -1
  3. package/assets/skills/comet/SKILL.md +25 -1
  4. package/assets/skills/comet/reference/comet-yaml-fields.md +6 -4
  5. package/assets/skills/comet/reference/context-recovery.md +10 -0
  6. package/assets/skills/comet/reference/scripts.md +47 -15
  7. package/assets/skills/comet/rules/comet-phase-guard.en.md +8 -0
  8. package/assets/skills/comet/rules/comet-phase-guard.md +9 -1
  9. package/assets/skills/comet/scripts/comet-resume-probe.mjs +3 -0
  10. package/assets/skills/comet/scripts/comet-runtime.mjs +1664 -512
  11. package/assets/skills/comet-archive/SKILL.md +24 -11
  12. package/assets/skills/comet-build/SKILL.md +40 -31
  13. package/assets/skills/comet-design/SKILL.md +1 -0
  14. package/assets/skills/comet-hotfix/SKILL.md +3 -1
  15. package/assets/skills/comet-open/SKILL.md +11 -1
  16. package/assets/skills/comet-tweak/SKILL.md +3 -1
  17. package/assets/skills/comet-verify/SKILL.md +29 -20
  18. package/assets/skills-zh/comet/SKILL.md +25 -1
  19. package/assets/skills-zh/comet/reference/comet-yaml-fields.md +5 -4
  20. package/assets/skills-zh/comet/reference/context-recovery.md +10 -0
  21. package/assets/skills-zh/comet/reference/scripts.md +47 -15
  22. package/assets/skills-zh/comet-archive/SKILL.md +24 -11
  23. package/assets/skills-zh/comet-build/SKILL.md +40 -31
  24. package/assets/skills-zh/comet-design/SKILL.md +1 -0
  25. package/assets/skills-zh/comet-hotfix/SKILL.md +3 -1
  26. package/assets/skills-zh/comet-open/SKILL.md +11 -1
  27. package/assets/skills-zh/comet-tweak/SKILL.md +3 -1
  28. package/assets/skills-zh/comet-verify/SKILL.md +30 -21
  29. package/dist/app/cli/comet-banner.d.ts +25 -0
  30. package/dist/app/cli/comet-banner.d.ts.map +1 -0
  31. package/dist/app/cli/comet-banner.js +265 -0
  32. package/dist/app/cli/comet-banner.js.map +1 -0
  33. package/dist/app/cli/index.js +37 -3
  34. package/dist/app/cli/index.js.map +1 -1
  35. package/dist/app/commands/classic.d.ts +4 -0
  36. package/dist/app/commands/classic.d.ts.map +1 -0
  37. package/dist/app/commands/classic.js +11 -0
  38. package/dist/app/commands/classic.js.map +1 -0
  39. package/dist/app/commands/doctor.d.ts +1 -0
  40. package/dist/app/commands/doctor.d.ts.map +1 -1
  41. package/dist/app/commands/doctor.js +100 -35
  42. package/dist/app/commands/doctor.js.map +1 -1
  43. package/dist/app/commands/eval.d.ts.map +1 -1
  44. package/dist/app/commands/eval.js +57 -20
  45. package/dist/app/commands/eval.js.map +1 -1
  46. package/dist/app/commands/i18n.d.ts +1 -1
  47. package/dist/app/commands/i18n.d.ts.map +1 -1
  48. package/dist/app/commands/i18n.js +12 -4
  49. package/dist/app/commands/i18n.js.map +1 -1
  50. package/dist/app/commands/init.d.ts.map +1 -1
  51. package/dist/app/commands/init.js +16 -13
  52. package/dist/app/commands/init.js.map +1 -1
  53. package/dist/app/commands/project-scope-selection.d.ts +13 -0
  54. package/dist/app/commands/project-scope-selection.d.ts.map +1 -0
  55. package/dist/app/commands/project-scope-selection.js +33 -0
  56. package/dist/app/commands/project-scope-selection.js.map +1 -0
  57. package/dist/app/commands/resume-probe.d.ts +11 -0
  58. package/dist/app/commands/resume-probe.d.ts.map +1 -0
  59. package/dist/app/commands/resume-probe.js +63 -0
  60. package/dist/app/commands/resume-probe.js.map +1 -0
  61. package/dist/app/commands/status.d.ts +31 -0
  62. package/dist/app/commands/status.d.ts.map +1 -1
  63. package/dist/app/commands/status.js +109 -20
  64. package/dist/app/commands/status.js.map +1 -1
  65. package/dist/app/commands/uninstall.d.ts +2 -0
  66. package/dist/app/commands/uninstall.d.ts.map +1 -1
  67. package/dist/app/commands/uninstall.js +217 -40
  68. package/dist/app/commands/uninstall.js.map +1 -1
  69. package/dist/app/commands/update.d.ts +6 -0
  70. package/dist/app/commands/update.d.ts.map +1 -1
  71. package/dist/app/commands/update.js +361 -68
  72. package/dist/app/commands/update.js.map +1 -1
  73. package/dist/config/repository-layout.json +4 -2
  74. package/dist/domains/bundle/bundle-platform.d.ts.map +1 -1
  75. package/dist/domains/bundle/bundle-platform.js +3 -1
  76. package/dist/domains/bundle/bundle-platform.js.map +1 -1
  77. package/dist/domains/bundle/eval-manifest-runtime.d.ts +6 -0
  78. package/dist/domains/bundle/eval-manifest-runtime.d.ts.map +1 -0
  79. package/dist/domains/bundle/eval-manifest-runtime.js +58 -0
  80. package/dist/domains/bundle/eval-manifest-runtime.js.map +1 -0
  81. package/dist/domains/bundle/types.d.ts +1 -1
  82. package/dist/domains/bundle/types.d.ts.map +1 -1
  83. package/dist/domains/comet-classic/classic-archive.d.ts +1 -0
  84. package/dist/domains/comet-classic/classic-archive.d.ts.map +1 -1
  85. package/dist/domains/comet-classic/classic-archive.js +35 -38
  86. package/dist/domains/comet-classic/classic-archive.js.map +1 -1
  87. package/dist/domains/comet-classic/classic-cli.d.ts +1 -1
  88. package/dist/domains/comet-classic/classic-cli.d.ts.map +1 -1
  89. package/dist/domains/comet-classic/classic-cli.js +3 -0
  90. package/dist/domains/comet-classic/classic-cli.js.map +1 -1
  91. package/dist/domains/comet-classic/classic-command-checks.d.ts +20 -0
  92. package/dist/domains/comet-classic/classic-command-checks.d.ts.map +1 -0
  93. package/dist/domains/comet-classic/classic-command-checks.js +97 -0
  94. package/dist/domains/comet-classic/classic-command-checks.js.map +1 -0
  95. package/dist/domains/comet-classic/classic-current-change.d.ts +19 -0
  96. package/dist/domains/comet-classic/classic-current-change.d.ts.map +1 -0
  97. package/dist/domains/comet-classic/classic-current-change.js +132 -0
  98. package/dist/domains/comet-classic/classic-current-change.js.map +1 -0
  99. package/dist/domains/comet-classic/classic-diagnostics.d.ts +2 -1
  100. package/dist/domains/comet-classic/classic-diagnostics.d.ts.map +1 -1
  101. package/dist/domains/comet-classic/classic-diagnostics.js +54 -1
  102. package/dist/domains/comet-classic/classic-diagnostics.js.map +1 -1
  103. package/dist/domains/comet-classic/classic-evidence.d.ts.map +1 -1
  104. package/dist/domains/comet-classic/classic-evidence.js +4 -0
  105. package/dist/domains/comet-classic/classic-evidence.js.map +1 -1
  106. package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
  107. package/dist/domains/comet-classic/classic-guard.js +101 -141
  108. package/dist/domains/comet-classic/classic-guard.js.map +1 -1
  109. package/dist/domains/comet-classic/classic-hook-guard.d.ts.map +1 -1
  110. package/dist/domains/comet-classic/classic-hook-guard.js +67 -29
  111. package/dist/domains/comet-classic/classic-hook-guard.js.map +1 -1
  112. package/dist/domains/comet-classic/classic-project-config.d.ts +16 -0
  113. package/dist/domains/comet-classic/classic-project-config.d.ts.map +1 -0
  114. package/dist/domains/comet-classic/classic-project-config.js +40 -0
  115. package/dist/domains/comet-classic/classic-project-config.js.map +1 -0
  116. package/dist/domains/comet-classic/classic-resolver.d.ts.map +1 -1
  117. package/dist/domains/comet-classic/classic-resolver.js +3 -3
  118. package/dist/domains/comet-classic/classic-resolver.js.map +1 -1
  119. package/dist/domains/comet-classic/classic-resume-probe-command.d.ts +3 -0
  120. package/dist/domains/comet-classic/classic-resume-probe-command.d.ts.map +1 -0
  121. package/dist/domains/comet-classic/classic-resume-probe-command.js +58 -0
  122. package/dist/domains/comet-classic/classic-resume-probe-command.js.map +1 -0
  123. package/dist/domains/comet-classic/classic-resume-probe-entry.d.ts +2 -0
  124. package/dist/domains/comet-classic/classic-resume-probe-entry.d.ts.map +1 -0
  125. package/dist/domains/comet-classic/classic-resume-probe-entry.js +4 -0
  126. package/dist/domains/comet-classic/classic-resume-probe-entry.js.map +1 -0
  127. package/dist/domains/comet-classic/classic-resume-probe.d.ts +29 -0
  128. package/dist/domains/comet-classic/classic-resume-probe.d.ts.map +1 -0
  129. package/dist/domains/comet-classic/classic-resume-probe.js +386 -0
  130. package/dist/domains/comet-classic/classic-resume-probe.js.map +1 -0
  131. package/dist/domains/comet-classic/classic-runtime-run.d.ts +2 -1
  132. package/dist/domains/comet-classic/classic-runtime-run.d.ts.map +1 -1
  133. package/dist/domains/comet-classic/classic-runtime-run.js +269 -4
  134. package/dist/domains/comet-classic/classic-runtime-run.js.map +1 -1
  135. package/dist/domains/comet-classic/classic-state-command.d.ts.map +1 -1
  136. package/dist/domains/comet-classic/classic-state-command.js +129 -15
  137. package/dist/domains/comet-classic/classic-state-command.js.map +1 -1
  138. package/dist/domains/comet-classic/classic-state.d.ts +3 -3
  139. package/dist/domains/comet-classic/classic-state.d.ts.map +1 -1
  140. package/dist/domains/comet-classic/classic-state.js +4 -6
  141. package/dist/domains/comet-classic/classic-state.js.map +1 -1
  142. package/dist/domains/comet-classic/classic-store.d.ts +4 -1
  143. package/dist/domains/comet-classic/classic-store.d.ts.map +1 -1
  144. package/dist/domains/comet-classic/classic-store.js +27 -9
  145. package/dist/domains/comet-classic/classic-store.js.map +1 -1
  146. package/dist/domains/comet-classic/classic-transitions.d.ts +1 -1
  147. package/dist/domains/comet-classic/classic-transitions.d.ts.map +1 -1
  148. package/dist/domains/comet-classic/classic-transitions.js +20 -1
  149. package/dist/domains/comet-classic/classic-transitions.js.map +1 -1
  150. package/dist/domains/comet-classic/classic-validate-command.d.ts.map +1 -1
  151. package/dist/domains/comet-classic/classic-validate-command.js +1 -0
  152. package/dist/domains/comet-classic/classic-validate-command.js.map +1 -1
  153. package/dist/domains/comet-classic/index.d.ts +3 -0
  154. package/dist/domains/comet-classic/index.d.ts.map +1 -1
  155. package/dist/domains/comet-classic/index.js +3 -0
  156. package/dist/domains/comet-classic/index.js.map +1 -1
  157. package/dist/domains/dashboard/collector.js +10 -2
  158. package/dist/domains/dashboard/collector.js.map +1 -1
  159. package/dist/domains/dashboard/web/assets/{index-CjU3VXVu.js → index-CIvN-PL8.js} +11 -11
  160. package/dist/domains/dashboard/web/assets/{index-BcO3_QlT.css → index-DcyRPBnT.css} +1 -1
  161. package/dist/domains/dashboard/web/index.html +16 -16
  162. package/dist/domains/engine/types.d.ts +1 -1
  163. package/dist/domains/engine/types.d.ts.map +1 -1
  164. package/dist/domains/integrations/openspec.d.ts.map +1 -1
  165. package/dist/domains/integrations/openspec.js +6 -6
  166. package/dist/domains/integrations/openspec.js.map +1 -1
  167. package/dist/domains/skill/find.d.ts.map +1 -1
  168. package/dist/domains/skill/find.js +1 -6
  169. package/dist/domains/skill/find.js.map +1 -1
  170. package/dist/domains/skill/managed-markdown.d.ts +14 -0
  171. package/dist/domains/skill/managed-markdown.d.ts.map +1 -0
  172. package/dist/domains/skill/managed-markdown.js +126 -0
  173. package/dist/domains/skill/managed-markdown.js.map +1 -0
  174. package/dist/domains/skill/platform-install.d.ts +4 -3
  175. package/dist/domains/skill/platform-install.d.ts.map +1 -1
  176. package/dist/domains/skill/platform-install.js +96 -26
  177. package/dist/domains/skill/platform-install.js.map +1 -1
  178. package/dist/domains/skill/project-instructions.d.ts +22 -0
  179. package/dist/domains/skill/project-instructions.d.ts.map +1 -0
  180. package/dist/domains/skill/project-instructions.js +61 -0
  181. package/dist/domains/skill/project-instructions.js.map +1 -0
  182. package/dist/domains/skill/uninstall.d.ts +3 -1
  183. package/dist/domains/skill/uninstall.d.ts.map +1 -1
  184. package/dist/domains/skill/uninstall.js +86 -39
  185. package/dist/domains/skill/uninstall.js.map +1 -1
  186. package/dist/platform/install/detect.d.ts +2 -1
  187. package/dist/platform/install/detect.d.ts.map +1 -1
  188. package/dist/platform/install/detect.js +10 -1
  189. package/dist/platform/install/detect.js.map +1 -1
  190. package/dist/platform/install/platforms.d.ts +5 -1
  191. package/dist/platform/install/platforms.d.ts.map +1 -1
  192. package/dist/platform/install/platforms.js +21 -4
  193. package/dist/platform/install/platforms.js.map +1 -1
  194. package/dist/platform/install/project-registry.d.ts +37 -0
  195. package/dist/platform/install/project-registry.d.ts.map +1 -0
  196. package/dist/platform/install/project-registry.js +205 -0
  197. package/dist/platform/install/project-registry.js.map +1 -0
  198. package/eval/.env +28 -0
  199. package/eval/.env.example +52 -0
  200. package/eval/CLAUDE.md +43 -0
  201. package/eval/README.md +538 -0
  202. package/eval/langsmith/.env.example +16 -0
  203. package/eval/langsmith/README.md +93 -0
  204. package/eval/langsmith/skills/README.md +5 -0
  205. package/eval/langsmith/tasks/README.md +5 -0
  206. package/eval/langsmith/tests/conftest.py +187 -0
  207. package/eval/langsmith/tests/tasks/test_tasks.py +287 -0
  208. package/eval/langsmith/treatments/README.md +5 -0
  209. package/eval/local/README.md +80 -0
  210. package/eval/local/regression_baseline.json +13 -0
  211. package/eval/local/report-style-demo-assets/quality_cost.en.svg +41 -0
  212. package/eval/local/report-style-demo-assets/quality_cost.zh.svg +41 -0
  213. package/eval/local/report-style-demo-assets/rubric_delta.en.svg +56 -0
  214. package/eval/local/report-style-demo-assets/rubric_delta.zh.svg +56 -0
  215. package/eval/local/report-style-demo-assets/task_outcomes.en.svg +46 -0
  216. package/eval/local/report-style-demo-assets/task_outcomes.zh.svg +46 -0
  217. package/eval/local/report-style-demo.html +867 -0
  218. package/eval/local/scripts/compare_baselines.py +1018 -0
  219. package/eval/local/scripts/generate_report_style_demo_charts.py +322 -0
  220. package/eval/local/scripts/regression_check.py +171 -0
  221. package/eval/local/scripts/render_readme_benchmark_figures.py +416 -0
  222. package/eval/local/scripts/rescore_rubric.py +120 -0
  223. package/eval/local/skills/benchmarks/039-release/comet-classic-039/SKILL.md +282 -0
  224. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/auto-transition.md +27 -0
  225. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/comet-yaml-fields.md +68 -0
  226. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/context-recovery.md +35 -0
  227. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/debug-gate.md +17 -0
  228. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/decision-point.md +20 -0
  229. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/dirty-worktree.md +59 -0
  230. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/file-structure.md +28 -0
  231. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/subagent-dispatch.md +113 -0
  232. package/eval/local/skills/benchmarks/039-release/comet-classic-039/rules/comet-phase-guard.md +125 -0
  233. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-archive.sh +311 -0
  234. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-env.sh +110 -0
  235. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-guard.sh +778 -0
  236. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-handoff.sh +390 -0
  237. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-hook-guard.sh +336 -0
  238. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-state.sh +1338 -0
  239. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-yaml-validate.sh +225 -0
  240. package/eval/local/skills/benchmarks/039-release/comet-classic-039-archive/SKILL.md +100 -0
  241. package/eval/local/skills/benchmarks/039-release/comet-classic-039-build/SKILL.md +304 -0
  242. package/eval/local/skills/benchmarks/039-release/comet-classic-039-design/SKILL.md +263 -0
  243. package/eval/local/skills/benchmarks/039-release/comet-classic-039-hotfix/SKILL.md +204 -0
  244. package/eval/local/skills/benchmarks/039-release/comet-classic-039-open/SKILL.md +220 -0
  245. package/eval/local/skills/benchmarks/039-release/comet-classic-039-tweak/SKILL.md +180 -0
  246. package/eval/local/skills/benchmarks/039-release/comet-classic-039-verify/SKILL.md +234 -0
  247. package/eval/local/skills/benchmarks/040-beta/comet/SKILL.md +261 -0
  248. package/eval/local/skills/benchmarks/040-beta/comet/reference/auto-transition.md +27 -0
  249. package/eval/local/skills/benchmarks/040-beta/comet/reference/comet-yaml-fields.md +73 -0
  250. package/eval/local/skills/benchmarks/040-beta/comet/reference/context-recovery.md +45 -0
  251. package/eval/local/skills/benchmarks/040-beta/comet/reference/debug-gate.md +33 -0
  252. package/eval/local/skills/benchmarks/040-beta/comet/reference/decision-point.md +31 -0
  253. package/eval/local/skills/benchmarks/040-beta/comet/reference/dirty-worktree.md +59 -0
  254. package/eval/local/skills/benchmarks/040-beta/comet/reference/file-structure.md +28 -0
  255. package/eval/local/skills/benchmarks/040-beta/comet/reference/intent-frame.md +74 -0
  256. package/eval/local/skills/benchmarks/040-beta/comet/reference/scripts.md +69 -0
  257. package/eval/local/skills/benchmarks/040-beta/comet/reference/subagent-dispatch.md +169 -0
  258. package/eval/local/skills/benchmarks/040-beta/comet/rules/comet-phase-guard.md +130 -0
  259. package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/checks.yaml +6 -0
  260. package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/guardrails.yaml +13 -0
  261. package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/skill.yaml +122 -0
  262. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-archive.mjs +9515 -0
  263. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-env.mjs +15 -0
  264. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-guard.mjs +10173 -0
  265. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-handoff.mjs +9491 -0
  266. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-hook-guard.mjs +9175 -0
  267. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-intent.mjs +404 -0
  268. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-state.mjs +9273 -0
  269. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-yaml-validate.mjs +7627 -0
  270. package/eval/local/skills/benchmarks/040-beta/comet-archive/SKILL.md +110 -0
  271. package/eval/local/skills/benchmarks/040-beta/comet-build/SKILL.md +315 -0
  272. package/eval/local/skills/benchmarks/040-beta/comet-design/SKILL.md +260 -0
  273. package/eval/local/skills/benchmarks/040-beta/comet-hotfix/SKILL.md +190 -0
  274. package/eval/local/skills/benchmarks/040-beta/comet-open/SKILL.md +210 -0
  275. package/eval/local/skills/benchmarks/040-beta/comet-tweak/SKILL.md +183 -0
  276. package/eval/local/skills/benchmarks/040-beta/comet-verify/SKILL.md +230 -0
  277. package/eval/local/skills/benchmarks/dependency/claude-md/comet-workflow/CLAUDE.md +12 -0
  278. package/eval/local/skills/benchmarks/dependency/openspec/openspec-apply-change/SKILL.md +156 -0
  279. package/eval/local/skills/benchmarks/dependency/openspec/openspec-archive-change/SKILL.md +114 -0
  280. package/eval/local/skills/benchmarks/dependency/openspec/openspec-bulk-archive-change/SKILL.md +246 -0
  281. package/eval/local/skills/benchmarks/dependency/openspec/openspec-continue-change/SKILL.md +118 -0
  282. package/eval/local/skills/benchmarks/dependency/openspec/openspec-explore/SKILL.md +288 -0
  283. package/eval/local/skills/benchmarks/dependency/openspec/openspec-ff-change/SKILL.md +101 -0
  284. package/eval/local/skills/benchmarks/dependency/openspec/openspec-new-change/SKILL.md +74 -0
  285. package/eval/local/skills/benchmarks/dependency/openspec/openspec-onboard/SKILL.md +554 -0
  286. package/eval/local/skills/benchmarks/dependency/openspec/openspec-propose/SKILL.md +110 -0
  287. package/eval/local/skills/benchmarks/dependency/openspec/openspec-sync-specs/SKILL.md +138 -0
  288. package/eval/local/skills/benchmarks/dependency/openspec/openspec-verify-change/SKILL.md +168 -0
  289. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/SKILL.md +159 -0
  290. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/frame-template.html +213 -0
  291. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/helper.js +167 -0
  292. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/server.cjs +723 -0
  293. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/start-server.sh +209 -0
  294. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/stop-server.sh +120 -0
  295. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/spec-document-reviewer-prompt.md +49 -0
  296. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/visual-companion.md +291 -0
  297. package/eval/local/skills/benchmarks/dependency/superpowers/dispatching-parallel-agents/SKILL.md +185 -0
  298. package/eval/local/skills/benchmarks/dependency/superpowers/executing-plans/SKILL.md +70 -0
  299. package/eval/local/skills/benchmarks/dependency/superpowers/finishing-a-development-branch/SKILL.md +241 -0
  300. package/eval/local/skills/benchmarks/dependency/superpowers/receiving-code-review/SKILL.md +213 -0
  301. package/eval/local/skills/benchmarks/dependency/superpowers/requesting-code-review/SKILL.md +103 -0
  302. package/eval/local/skills/benchmarks/dependency/superpowers/requesting-code-review/code-reviewer.md +172 -0
  303. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/SKILL.md +418 -0
  304. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/implementer-prompt.md +139 -0
  305. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/review-package +44 -0
  306. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/sdd-workspace +22 -0
  307. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/task-brief +40 -0
  308. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/task-reviewer-prompt.md +188 -0
  309. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/CREATION-LOG.md +119 -0
  310. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/SKILL.md +296 -0
  311. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/condition-based-waiting-example.ts +158 -0
  312. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/condition-based-waiting.md +115 -0
  313. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/defense-in-depth.md +122 -0
  314. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/find-polluter.sh +63 -0
  315. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/root-cause-tracing.md +169 -0
  316. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-academic.md +14 -0
  317. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-1.md +58 -0
  318. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-2.md +68 -0
  319. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-3.md +69 -0
  320. package/eval/local/skills/benchmarks/dependency/superpowers/test-driven-development/SKILL.md +371 -0
  321. package/eval/local/skills/benchmarks/dependency/superpowers/test-driven-development/testing-anti-patterns.md +299 -0
  322. package/eval/local/skills/benchmarks/dependency/superpowers/using-git-worktrees/SKILL.md +202 -0
  323. package/eval/local/skills/benchmarks/dependency/superpowers/verification-before-completion/SKILL.md +139 -0
  324. package/eval/local/skills/benchmarks/dependency/superpowers/writing-plans/SKILL.md +174 -0
  325. package/eval/local/skills/benchmarks/dependency/superpowers/writing-plans/plan-document-reviewer-prompt.md +49 -0
  326. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/SKILL.md +689 -0
  327. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/anthropic-best-practices.md +1150 -0
  328. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  329. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/graphviz-conventions.dot +172 -0
  330. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/persuasion-principles.md +187 -0
  331. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/render-graphs.js +168 -0
  332. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/testing-skills-with-subagents.md +384 -0
  333. package/eval/local/tasks/authoring-skill-smoke/environment/Dockerfile +2 -0
  334. package/eval/local/tasks/authoring-skill-smoke/instruction.md +4 -0
  335. package/eval/local/tasks/authoring-skill-smoke/task.toml +21 -0
  336. package/eval/local/tasks/authoring-skill-smoke/validation/test_authoring_skill_smoke.py +54 -0
  337. package/eval/local/tasks/comet-agent-memory-routing/environment/Dockerfile +28 -0
  338. package/eval/local/tasks/comet-agent-memory-routing/environment/agent_system.py +40 -0
  339. package/eval/local/tasks/comet-agent-memory-routing/environment/test_agent_system.py +29 -0
  340. package/eval/local/tasks/comet-agent-memory-routing/instruction.md +20 -0
  341. package/eval/local/tasks/comet-agent-memory-routing/task.toml +24 -0
  342. package/eval/local/tasks/comet-agent-memory-routing/validation/test_agent_memory_routing.py +24 -0
  343. package/eval/local/tasks/comet-api-cache-ttl/environment/Dockerfile +39 -0
  344. package/eval/local/tasks/comet-api-cache-ttl/environment/cache.py +39 -0
  345. package/eval/local/tasks/comet-api-cache-ttl/environment/test_cache.py +81 -0
  346. package/eval/local/tasks/comet-api-cache-ttl/instruction.md +33 -0
  347. package/eval/local/tasks/comet-api-cache-ttl/task.toml +24 -0
  348. package/eval/local/tasks/comet-api-cache-ttl/validation/test_api_cache_ttl.py +58 -0
  349. package/eval/local/tasks/comet-cross-file-refactor/environment/Dockerfile +15 -0
  350. package/eval/local/tasks/comet-cross-file-refactor/environment/cli.py +13 -0
  351. package/eval/local/tasks/comet-cross-file-refactor/environment/counting.py +13 -0
  352. package/eval/local/tasks/comet-cross-file-refactor/environment/test_textkit.py +21 -0
  353. package/eval/local/tasks/comet-cross-file-refactor/instruction.md +16 -0
  354. package/eval/local/tasks/comet-cross-file-refactor/task.toml +20 -0
  355. package/eval/local/tasks/comet-cross-file-refactor/validation/test_cross_file_refactor.py +20 -0
  356. package/eval/local/tasks/comet-dependency-confusion/environment/Dockerfile +28 -0
  357. package/eval/local/tasks/comet-dependency-confusion/environment/app.py +8 -0
  358. package/eval/local/tasks/comet-dependency-confusion/environment/settings_loader.py +14 -0
  359. package/eval/local/tasks/comet-dependency-confusion/environment/test_settings_service.py +19 -0
  360. package/eval/local/tasks/comet-dependency-confusion/instruction.md +18 -0
  361. package/eval/local/tasks/comet-dependency-confusion/task.toml +24 -0
  362. package/eval/local/tasks/comet-dependency-confusion/validation/test_dependency_confusion.py +24 -0
  363. package/eval/local/tasks/comet-fix-median/environment/Dockerfile +50 -0
  364. package/eval/local/tasks/comet-fix-median/environment/stats.py +54 -0
  365. package/eval/local/tasks/comet-fix-median/environment/test_stats.py +68 -0
  366. package/eval/local/tasks/comet-fix-median/instruction.md +25 -0
  367. package/eval/local/tasks/comet-fix-median/task.toml +24 -0
  368. package/eval/local/tasks/comet-fix-median/validation/test_fix_median.py +60 -0
  369. package/eval/local/tasks/comet-framework-selection/environment/Dockerfile +28 -0
  370. package/eval/local/tasks/comet-framework-selection/environment/architecture.py +12 -0
  371. package/eval/local/tasks/comet-framework-selection/environment/test_architecture.py +30 -0
  372. package/eval/local/tasks/comet-framework-selection/instruction.md +22 -0
  373. package/eval/local/tasks/comet-framework-selection/task.toml +24 -0
  374. package/eval/local/tasks/comet-framework-selection/validation/test_framework_selection.py +24 -0
  375. package/eval/local/tasks/comet-full-workflow/environment/Dockerfile +53 -0
  376. package/eval/local/tasks/comet-full-workflow/environment/test_wordcount.py +29 -0
  377. package/eval/local/tasks/comet-full-workflow/environment/wordcount.py +40 -0
  378. package/eval/local/tasks/comet-full-workflow/instruction.md +18 -0
  379. package/eval/local/tasks/comet-full-workflow/task.toml +24 -0
  380. package/eval/local/tasks/comet-full-workflow/validation/test_full_workflow.py +171 -0
  381. package/eval/local/tasks/comet-graph-execution-review/environment/Dockerfile +28 -0
  382. package/eval/local/tasks/comet-graph-execution-review/environment/pipeline.py +19 -0
  383. package/eval/local/tasks/comet-graph-execution-review/environment/test_pipeline.py +53 -0
  384. package/eval/local/tasks/comet-graph-execution-review/instruction.md +21 -0
  385. package/eval/local/tasks/comet-graph-execution-review/task.toml +24 -0
  386. package/eval/local/tasks/comet-graph-execution-review/validation/test_graph_execution_review.py +24 -0
  387. package/eval/local/tasks/comet-human-approval-flow/environment/Dockerfile +15 -0
  388. package/eval/local/tasks/comet-human-approval-flow/environment/approvals.py +17 -0
  389. package/eval/local/tasks/comet-human-approval-flow/environment/test_approvals.py +30 -0
  390. package/eval/local/tasks/comet-human-approval-flow/instruction.md +15 -0
  391. package/eval/local/tasks/comet-human-approval-flow/task.toml +20 -0
  392. package/eval/local/tasks/comet-human-approval-flow/validation/test_human_approval_flow.py +20 -0
  393. package/eval/local/tasks/comet-layered-streaming-fix/environment/Dockerfile +20 -0
  394. package/eval/local/tasks/comet-layered-streaming-fix/environment/chat_app.py +19 -0
  395. package/eval/local/tasks/comet-layered-streaming-fix/environment/test_chat_app.py +15 -0
  396. package/eval/local/tasks/comet-layered-streaming-fix/instruction.md +14 -0
  397. package/eval/local/tasks/comet-layered-streaming-fix/task.toml +20 -0
  398. package/eval/local/tasks/comet-layered-streaming-fix/validation/test_layered_streaming_fix.py +20 -0
  399. package/eval/local/tasks/comet-noise-distractor/environment/Dockerfile +15 -0
  400. package/eval/local/tasks/comet-noise-distractor/environment/distractor.md +4 -0
  401. package/eval/local/tasks/comet-noise-distractor/environment/invoice.py +5 -0
  402. package/eval/local/tasks/comet-noise-distractor/environment/test_invoice.py +18 -0
  403. package/eval/local/tasks/comet-noise-distractor/instruction.md +17 -0
  404. package/eval/local/tasks/comet-noise-distractor/task.toml +20 -0
  405. package/eval/local/tasks/comet-noise-distractor/validation/test_noise_distractor.py +20 -0
  406. package/eval/local/tasks/comet-observability-env-template/environment/Dockerfile +15 -0
  407. package/eval/local/tasks/comet-observability-env-template/environment/env_writer.py +17 -0
  408. package/eval/local/tasks/comet-observability-env-template/environment/test_env_writer.py +17 -0
  409. package/eval/local/tasks/comet-observability-env-template/instruction.md +20 -0
  410. package/eval/local/tasks/comet-observability-env-template/task.toml +20 -0
  411. package/eval/local/tasks/comet-observability-env-template/validation/test_observability_env_template.py +46 -0
  412. package/eval/local/tasks/comet-perf-dedupe/environment/Dockerfile +39 -0
  413. package/eval/local/tasks/comet-perf-dedupe/environment/dedupe.py +22 -0
  414. package/eval/local/tasks/comet-perf-dedupe/environment/test_dedupe.py +43 -0
  415. package/eval/local/tasks/comet-perf-dedupe/instruction.md +25 -0
  416. package/eval/local/tasks/comet-perf-dedupe/task.toml +24 -0
  417. package/eval/local/tasks/comet-perf-dedupe/validation/test_perf_dedupe.py +40 -0
  418. package/eval/local/tasks/comet-persistence-threading/environment/Dockerfile +15 -0
  419. package/eval/local/tasks/comet-persistence-threading/environment/session_store.py +15 -0
  420. package/eval/local/tasks/comet-persistence-threading/environment/test_session_store.py +21 -0
  421. package/eval/local/tasks/comet-persistence-threading/instruction.md +14 -0
  422. package/eval/local/tasks/comet-persistence-threading/task.toml +20 -0
  423. package/eval/local/tasks/comet-persistence-threading/validation/test_persistence_threading.py +20 -0
  424. package/eval/local/tasks/comet-refactor-counter/environment/Dockerfile +39 -0
  425. package/eval/local/tasks/comet-refactor-counter/environment/test_text_processor.py +57 -0
  426. package/eval/local/tasks/comet-refactor-counter/environment/text_processor.py +49 -0
  427. package/eval/local/tasks/comet-refactor-counter/instruction.md +31 -0
  428. package/eval/local/tasks/comet-refactor-counter/task.toml +24 -0
  429. package/eval/local/tasks/comet-refactor-counter/validation/test_refactor_counter.py +75 -0
  430. package/eval/local/tasks/comet-robust-config/environment/Dockerfile +39 -0
  431. package/eval/local/tasks/comet-robust-config/environment/config_loader.py +56 -0
  432. package/eval/local/tasks/comet-robust-config/environment/test_config_loader.py +72 -0
  433. package/eval/local/tasks/comet-robust-config/instruction.md +30 -0
  434. package/eval/local/tasks/comet-robust-config/task.toml +24 -0
  435. package/eval/local/tasks/comet-robust-config/validation/test_robust_config.py +37 -0
  436. package/eval/local/tasks/generic-skill-smoke/environment/Dockerfile +2 -0
  437. package/eval/local/tasks/generic-skill-smoke/instruction.md +7 -0
  438. package/eval/local/tasks/generic-skill-smoke/task.toml +21 -0
  439. package/eval/local/tasks/generic-skill-smoke/validation/test_generic_skill_smoke.py +36 -0
  440. package/eval/local/tasks/index.yaml +155 -0
  441. package/eval/local/tasks/workflow-overlay-contract/environment/Dockerfile +5 -0
  442. package/eval/local/tasks/workflow-overlay-contract/instruction.md +5 -0
  443. package/eval/local/tasks/workflow-overlay-contract/task.toml +21 -0
  444. package/eval/local/tasks/workflow-overlay-contract/validation/test_workflow_overlay_contract.py +235 -0
  445. package/eval/local/tasks/workflow-route-conformance/environment/Dockerfile +2 -0
  446. package/eval/local/tasks/workflow-route-conformance/instruction.md +5 -0
  447. package/eval/local/tasks/workflow-route-conformance/task.toml +21 -0
  448. package/eval/local/tasks/workflow-route-conformance/validation/test_workflow_route_conformance.py +84 -0
  449. package/eval/local/tests/conftest.py +1148 -0
  450. package/eval/local/tests/scaffold/test_attribution.py +48 -0
  451. package/eval/local/tests/scaffold/test_compare_baselines.py +999 -0
  452. package/eval/local/tests/scaffold/test_conftest_helpers.py +534 -0
  453. package/eval/local/tests/scaffold/test_evidence.py +15 -0
  454. package/eval/local/tests/scaffold/test_langsmith_conftest.py +244 -0
  455. package/eval/local/tests/scaffold/test_logging.py +243 -0
  456. package/eval/local/tests/scaffold/test_manifests.py +132 -0
  457. package/eval/local/tests/scaffold/test_profiles.py +866 -0
  458. package/eval/local/tests/scaffold/test_regression_check.py +19 -0
  459. package/eval/local/tests/scaffold/test_report_style_demo_charts.py +45 -0
  460. package/eval/local/tests/scaffold/test_sample_quality.py +211 -0
  461. package/eval/local/tests/scaffold/test_tasks.py +168 -0
  462. package/eval/local/tests/scaffold/test_treatments.py +244 -0
  463. package/eval/local/tests/scaffold/test_utils.py +139 -0
  464. package/eval/local/tests/tasks/test_tasks.py +445 -0
  465. package/eval/local/tests/tasks/test_validation_scripts.py +143 -0
  466. package/eval/local/treatments/comet/comet_full_039.yaml +141 -0
  467. package/eval/local/treatments/comet/comet_full_040_beta.yaml +140 -0
  468. package/eval/local/treatments/common/control.yaml +4 -0
  469. package/eval/pyproject.toml +41 -0
  470. package/eval/report-html-config.json +6 -0
  471. package/eval/scaffold/__init__.py +67 -0
  472. package/eval/scaffold/python/__init__.py +95 -0
  473. package/eval/scaffold/python/attribution.py +43 -0
  474. package/eval/scaffold/python/evidence.py +38 -0
  475. package/eval/scaffold/python/external_data_handler.py +18 -0
  476. package/eval/scaffold/python/generic_llm_judge.py +235 -0
  477. package/eval/scaffold/python/judge_config.py +168 -0
  478. package/eval/scaffold/python/llm_judge.py +191 -0
  479. package/eval/scaffold/python/logging.py +705 -0
  480. package/eval/scaffold/python/manifests.py +129 -0
  481. package/eval/scaffold/python/paper_charts.py +25 -0
  482. package/eval/scaffold/python/pass_at_k.py +107 -0
  483. package/eval/scaffold/python/paths.py +56 -0
  484. package/eval/scaffold/python/profiles.py +127 -0
  485. package/eval/scaffold/python/report_outputs.py +1391 -0
  486. package/eval/scaffold/python/sample_quality.py +339 -0
  487. package/eval/scaffold/python/schema.py +39 -0
  488. package/eval/scaffold/python/skill_parser.py +469 -0
  489. package/eval/scaffold/python/tasks.py +330 -0
  490. package/eval/scaffold/python/treatments.py +271 -0
  491. package/eval/scaffold/python/utils.py +366 -0
  492. package/eval/scaffold/python/validation/__init__.py +21 -0
  493. package/eval/scaffold/python/validation/authoring_rubric.py +326 -0
  494. package/eval/scaffold/python/validation/comet_workflow.py +187 -0
  495. package/eval/scaffold/python/validation/core.py +264 -0
  496. package/eval/scaffold/python/validation/dataset.py +337 -0
  497. package/eval/scaffold/python/validation/docker.py +106 -0
  498. package/eval/scaffold/python/validation/evaluator.py +549 -0
  499. package/eval/scaffold/python/validation/generic_rubric.py +169 -0
  500. package/eval/scaffold/python/validation/rubric.py +740 -0
  501. package/eval/scaffold/python/validation/runner.py +237 -0
  502. package/eval/scaffold/python/validation/scripts.py +58 -0
  503. package/eval/scaffold/python/validation/tracing.py +313 -0
  504. package/eval/scaffold/shell/common.sh +126 -0
  505. package/eval/scaffold/shell/docker.sh +482 -0
  506. package/eval/scaffold/shell/run-claude-loop.sh +181 -0
  507. package/eval/scaffold/shell/setup.sh +259 -0
  508. package/eval/simulator-instruction.md +9 -0
  509. package/package.json +24 -2
@@ -0,0 +1,237 @@
1
+ """Test runner for validation scripts.
2
+
3
+ Handles all boilerplate so contributors just write check functions.
4
+ Each check function receives a TestRunner and must call runner.passed()
5
+ or runner.failed() — returning without calling either is an error.
6
+
7
+ Example:
8
+
9
+ from scaffold.python.validation.runner import TestRunner
10
+
11
+ def check_has_function(runner):
12
+ source = runner.read("agent.py")
13
+ if "def my_function" in source:
14
+ runner.passed("has my_function")
15
+ else:
16
+ runner.failed("missing my_function")
17
+
18
+ def check_runs(runner):
19
+ output = runner.execute("agent.py")
20
+ if output is not None:
21
+ runner.passed("produced output")
22
+ else:
23
+ runner.failed("execution failed")
24
+
25
+ if __name__ == "__main__":
26
+ TestRunner.run([check_has_function, check_runs])
27
+ """
28
+
29
+ import importlib.util
30
+ import json
31
+ import os
32
+ import subprocess
33
+ import sys
34
+ from contextlib import contextmanager
35
+ from pathlib import Path
36
+ from types import ModuleType
37
+
38
+ from scaffold.python.validation.core import (
39
+ TEST_CONTEXT_FILE,
40
+ load_test_context,
41
+ write_test_results,
42
+ )
43
+
44
+
45
+ class TestRunner:
46
+ """Runner that handles boilerplate for validation test scripts.
47
+
48
+ Properties:
49
+ runner.artifacts — target artifact paths (from task.toml via _test_context.json)
50
+ runner.context — full run context dict (run_id, events, langsmith_env, etc.)
51
+
52
+ Methods:
53
+ runner.passed(msg) — record a passing check
54
+ runner.failed(msg) — record a failing check
55
+ runner.read(path) — read a file's contents (returns "" if not found)
56
+ runner.execute(path, ...) — run a file in a subprocess, return stdout
57
+ """
58
+
59
+ def __init__(self):
60
+ self.context = load_test_context()
61
+ self.artifacts: list[str] = self.context.get("target_artifacts", [])
62
+ self._passed: list[str] = []
63
+ self._failed: list[str] = []
64
+ self._error: str | None = None
65
+ self._check_called = False
66
+ self._module_cache: dict[str, ModuleType | None] = {} # instance-level cache
67
+
68
+ def passed(self, message: str) -> None:
69
+ """Record a passing check."""
70
+ self._check_called = True
71
+ self._passed.append(message)
72
+
73
+ def failed(self, message: str) -> None:
74
+ """Record a failing check."""
75
+ self._check_called = True
76
+ self._failed.append(message)
77
+
78
+ def read(self, path: str) -> str:
79
+ """Read a file's contents. Returns empty string if not found."""
80
+ p = Path(path)
81
+ if p.is_file():
82
+ try:
83
+ return p.read_text()
84
+ except Exception:
85
+ return ""
86
+ return ""
87
+
88
+ def load_module(self, path: str) -> ModuleType | None:
89
+ """Import a Python file as a module. Returns the module or None.
90
+
91
+ Cached per path — calling with the same path returns the same module
92
+ (avoids re-executing side effects). On first failure, records a failed
93
+ check and caches None. Subsequent calls return None and record a
94
+ cached failure (so the calling check satisfies the passed/failed requirement).
95
+ """
96
+ target = Path(path).resolve()
97
+ cache_key = str(target)
98
+ if cache_key in self._module_cache:
99
+ cached = self._module_cache[cache_key]
100
+ if cached is None:
101
+ # Already failed — record silently so each check shows the failure
102
+ self.failed(f"import failed: {path} (cached)")
103
+ return cached
104
+ if not target.is_file():
105
+ self.failed(f"cannot load {path}: file not found")
106
+ self._module_cache[cache_key] = None
107
+ return None
108
+ try:
109
+ module_name = f"_bench_{target.stem}_{id(target)}"
110
+ spec = importlib.util.spec_from_file_location(module_name, str(target))
111
+ if spec is None or spec.loader is None:
112
+ self.failed(f"cannot load {path}: invalid module spec")
113
+ self._module_cache[cache_key] = None
114
+ return None
115
+ module = importlib.util.module_from_spec(spec)
116
+ spec.loader.exec_module(module)
117
+ self._module_cache[cache_key] = module
118
+ return module
119
+ except Exception as e:
120
+ self.failed(f"import error ({path}): {e}")
121
+ return None
122
+
123
+ def execute(self, path: str, args: list[str] | None = None, timeout: int = 30) -> str | None:
124
+ """Run a file in a subprocess (inside the Docker container).
125
+
126
+ Returns stdout on success, stdout+stderr on non-zero exit,
127
+ or None on failure (also records a failed check).
128
+ """
129
+ target = Path(path)
130
+ if not target.exists():
131
+ self.failed(f"cannot execute {path}: file not found")
132
+ return None
133
+ cmd = [sys.executable, str(target)] + (args or [])
134
+ try:
135
+ result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
136
+ if result.returncode != 0:
137
+ return result.stdout + result.stderr
138
+ return result.stdout
139
+ except subprocess.TimeoutExpired:
140
+ self.failed(f"execution timed out ({timeout}s)")
141
+ return None
142
+ except Exception as e:
143
+ self.failed(f"execution error: {e}")
144
+ return None
145
+
146
+ def _results(self) -> dict:
147
+ return {
148
+ "passed": self._passed,
149
+ "failed": self._failed,
150
+ "error": self._error,
151
+ }
152
+
153
+ def _run_check_traced(self, check_fn, check_name: str):
154
+ """Run a check function, wrapping in a trace if langsmith is available.
155
+
156
+ Traces go to 'evaluators' project to avoid polluting the data project
157
+ (bench-project-{uuid}) where test traces live.
158
+ """
159
+ passed_before = len(self._passed)
160
+ failed_before = len(self._failed)
161
+
162
+ def _run():
163
+ check_fn(self)
164
+ if not self._check_called:
165
+ self._failed.append(f"{check_name}: check did not call passed() or failed()")
166
+
167
+ try:
168
+ from langsmith.run_helpers import trace as ls_trace
169
+
170
+ with ls_trace(name=check_name, run_type="chain", project_name="evaluators") as run:
171
+ _run()
172
+ if run:
173
+ run.outputs = {
174
+ "passed": self._passed[passed_before:],
175
+ "failed": self._failed[failed_before:],
176
+ }
177
+ except ImportError:
178
+ _run()
179
+
180
+ @staticmethod
181
+ @contextmanager
182
+ def _eval_trace_context():
183
+ """Create a LangSmith trace context if eval trace env vars are set.
184
+
185
+ Uses distributed tracing headers to nest LLM calls
186
+ (e.g. evaluate_with_schema) under the host-side eval span.
187
+ """
188
+ trace_header = os.environ.get("BENCH_EVAL_LANGSMITH_TRACE")
189
+ baggage = os.environ.get("BENCH_EVAL_BAGGAGE")
190
+
191
+ if not trace_header:
192
+ yield
193
+ return
194
+
195
+ try:
196
+ import langsmith
197
+
198
+ headers: dict[str, str] = {"langsmith-trace": trace_header}
199
+ if baggage:
200
+ headers["baggage"] = baggage
201
+ with langsmith.tracing_context(parent=headers):
202
+ yield
203
+ except Exception:
204
+ # Tracing failed — run checks without tracing
205
+ yield
206
+
207
+ @staticmethod
208
+ def run(checks: list) -> None:
209
+ """Run check functions and handle all output.
210
+
211
+ Each check function receives a TestRunner instance and MUST call
212
+ runner.passed() or runner.failed() at least once. Not calling
213
+ either is treated as an error.
214
+
215
+ Args:
216
+ checks: List of check functions. Function name is used as
217
+ the check name (underscores replaced with spaces).
218
+ """
219
+ runner = TestRunner()
220
+
221
+ if not runner.context:
222
+ print(f"Error: {TEST_CONTEXT_FILE} not found or empty", file=sys.stderr)
223
+ sys.exit(1)
224
+
225
+ with TestRunner._eval_trace_context():
226
+ for check_fn in checks:
227
+ check_name = check_fn.__name__.replace("check_", "").replace("_", " ")
228
+ runner._check_called = False
229
+ try:
230
+ runner._run_check_traced(check_fn, check_name)
231
+ except Exception as e:
232
+ runner._failed.append(f"{check_name}: {e}")
233
+
234
+ results = runner._results()
235
+ print(json.dumps(results, indent=2))
236
+ write_test_results(results)
237
+ sys.exit(1 if results["failed"] else 0)
@@ -0,0 +1,58 @@
1
+ """Skill tool usage validation.
2
+
3
+ Tracks which skill tools (langsmith CLI commands) Claude used during a task.
4
+ This is informational - doesn't fail, just records patterns.
5
+ """
6
+
7
+ # Known langsmith CLI subcommands
8
+ CLI_COMMANDS = [
9
+ "langsmith trace",
10
+ "langsmith run",
11
+ "langsmith dataset",
12
+ "langsmith example",
13
+ "langsmith evaluator",
14
+ "langsmith experiment",
15
+ "langsmith thread",
16
+ "langsmith project",
17
+ ]
18
+
19
+
20
+ def check_skill_scripts(
21
+ outputs: dict,
22
+ events: dict | None = None,
23
+ cli_commands: list[str] | None = None,
24
+ ) -> tuple[list[str], list[str]]:
25
+ """Track which langsmith CLI commands Claude used.
26
+
27
+ This validator doesn't fail - it just records usage patterns for analysis.
28
+
29
+ Args:
30
+ outputs: Outputs dict (stores CLI usage for later analysis)
31
+ events: Events dict containing commands_run and files_read
32
+ cli_commands: CLI command patterns to look for
33
+
34
+ Returns:
35
+ (passed, failed) lists - never fails, only passes
36
+ """
37
+ passed, failed = [], []
38
+ events = events or {}
39
+ cli_commands = cli_commands or CLI_COMMANDS
40
+
41
+ commands = " ".join(events.get("commands_run", [])).lower()
42
+ files_read = " ".join(events.get("files_read", [])).lower()
43
+ all_activity = commands + " " + files_read
44
+
45
+ # Count CLI command usage
46
+ cli_used = [c for c in cli_commands if c.lower() in all_activity]
47
+
48
+ # Report findings
49
+ if cli_used:
50
+ passed.append(f"CLI: {len(cli_used)} langsmith commands used ({', '.join(cli_used)})")
51
+ else:
52
+ passed.append("CLI: no langsmith CLI commands used (Claude wrote from scratch)")
53
+
54
+ # Store in outputs for later analysis
55
+ if outputs is not None:
56
+ outputs["cli_commands_used"] = cli_used
57
+
58
+ return passed, failed
@@ -0,0 +1,313 @@
1
+ """LangSmith tracing pattern validation for Python and TypeScript.
2
+
3
+ Validates that code has correct LangSmith tracing patterns:
4
+ - Imports (traceable, wrap_openai/wrapOpenAI)
5
+ - Client wrapping
6
+ - Function decorators/wrappers
7
+ - LangSmith API trace verification
8
+ """
9
+
10
+ import re
11
+ from pathlib import Path
12
+
13
+ from scaffold.python.utils import get_langsmith_client
14
+
15
+ # UUID pattern for trace IDs
16
+ UUID_PATTERN = re.compile(r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", re.I)
17
+
18
+
19
+ def _to_camel_case(snake_str: str) -> str:
20
+ """Convert snake_case to camelCase."""
21
+ components = snake_str.split("_")
22
+ return components[0] + "".join(x.title() for x in components[1:])
23
+
24
+
25
+ def check_python_tracing(
26
+ test_dir: Path,
27
+ filepath: str = "backend/sql_agent.py",
28
+ required_functions: list[str] | None = None,
29
+ ) -> tuple[list[str], list[str]]:
30
+ """Validate Python LangSmith tracing patterns.
31
+
32
+ Checks:
33
+ - Imports traceable from langsmith
34
+ - Imports wrap_openai from langsmith.wrappers
35
+ - Wraps OpenAI client with wrap_openai()
36
+ - Required functions have @traceable decorator
37
+
38
+ Args:
39
+ test_dir: Test working directory
40
+ filepath: Relative path to Python file
41
+ required_functions: Function names that must have @traceable
42
+
43
+ Returns:
44
+ (passed, failed) lists
45
+ """
46
+ passed, failed = [], []
47
+ path = test_dir / filepath
48
+
49
+ if not path.exists():
50
+ return [], [f"Python: {filepath} not found"]
51
+
52
+ content = path.read_text()
53
+
54
+ # Check imports
55
+ if re.search(r"from\s+langsmith\s+import\s+.*traceable", content, re.IGNORECASE):
56
+ passed.append("Python: imports traceable")
57
+ else:
58
+ failed.append("Python: missing 'from langsmith import traceable'")
59
+
60
+ if re.search(r"from\s+langsmith\.wrappers\s+import\s+wrap_openai", content, re.IGNORECASE):
61
+ passed.append("Python: imports wrap_openai")
62
+ else:
63
+ failed.append("Python: missing 'from langsmith.wrappers import wrap_openai'")
64
+
65
+ # Check client wrapping
66
+ if re.search(r"wrap_openai\s*\(\s*OpenAI\s*\(\s*\)\s*\)", content):
67
+ passed.append("Python: wraps OpenAI client")
68
+ else:
69
+ failed.append("Python: missing 'wrap_openai(OpenAI())'")
70
+
71
+ # Check functions are decorated
72
+ if required_functions:
73
+ traced, untraced = [], []
74
+ for func in required_functions:
75
+ pattern = rf"@traceable[^@]*def\s+{func}\s*\("
76
+ if re.search(pattern, content, re.DOTALL):
77
+ traced.append(func)
78
+ elif re.search(rf"def\s+{func}\s*\(", content):
79
+ untraced.append(func)
80
+
81
+ if traced:
82
+ passed.append(f"Python: traced {len(traced)} functions ({', '.join(traced)})")
83
+ if untraced:
84
+ failed.append(f"Python: missing @traceable on: {', '.join(untraced)}")
85
+
86
+ return passed, failed
87
+
88
+
89
+ def check_typescript_tracing(
90
+ test_dir: Path,
91
+ filepath: str = "frontend/support_bot.ts",
92
+ required_functions: list[str] | None = None,
93
+ ) -> tuple[list[str], list[str]]:
94
+ """Validate TypeScript LangSmith tracing patterns.
95
+
96
+ Checks:
97
+ - Imports traceable from langsmith/traceable
98
+ - Imports wrapOpenAI from langsmith/wrappers
99
+ - Wraps OpenAI client with wrapOpenAI()
100
+ - Required functions are wrapped with traceable()
101
+
102
+ Args:
103
+ test_dir: Test working directory
104
+ filepath: Relative path to TypeScript file
105
+ required_functions: Function names that must be wrapped with traceable()
106
+
107
+ Returns:
108
+ (passed, failed) lists
109
+ """
110
+ passed, failed = [], []
111
+ path = test_dir / filepath
112
+
113
+ if not path.exists():
114
+ return [], [f"TypeScript: {filepath} not found"]
115
+
116
+ content = path.read_text()
117
+
118
+ # Check imports
119
+ if re.search(
120
+ r'import\s+\{[^}]*traceable[^}]*\}\s+from\s+["\']langsmith/traceable["\']', content
121
+ ):
122
+ passed.append("TypeScript: imports traceable")
123
+ else:
124
+ failed.append("TypeScript: missing 'import { traceable } from \"langsmith/traceable\"'")
125
+
126
+ if re.search(
127
+ r'import\s+\{[^}]*wrapOpenAI[^}]*\}\s+from\s+["\']langsmith/wrappers["\']', content
128
+ ):
129
+ passed.append("TypeScript: imports wrapOpenAI")
130
+ else:
131
+ failed.append("TypeScript: missing 'import { wrapOpenAI } from \"langsmith/wrappers\"'")
132
+
133
+ # Check client wrapping
134
+ if re.search(r"wrapOpenAI\s*\(\s*new\s+OpenAI\s*\(\s*\)\s*\)", content):
135
+ passed.append("TypeScript: wraps OpenAI client")
136
+ else:
137
+ failed.append("TypeScript: missing 'wrapOpenAI(new OpenAI())'")
138
+
139
+ # Check functions are wrapped
140
+ if required_functions:
141
+ traced, untraced = [], []
142
+ for func in required_functions:
143
+ camel = _to_camel_case(func)
144
+ patterns = [
145
+ rf"const\s+{camel}\s*=\s*traceable\s*\(",
146
+ rf"const\s+{func}\s*=\s*traceable\s*\(",
147
+ rf'name\s*:\s*["\']{func}["\']',
148
+ ]
149
+ if any(re.search(p, content) for p in patterns):
150
+ traced.append(func)
151
+ else:
152
+ func_patterns = [
153
+ rf"(const|let|function)\s+{camel}\s*[=\(]",
154
+ rf"async\s+function\s+{camel}\s*\(",
155
+ ]
156
+ if any(re.search(p, content) for p in func_patterns):
157
+ untraced.append(func)
158
+
159
+ if traced:
160
+ passed.append(f"TypeScript: traced {len(traced)} functions ({', '.join(traced)})")
161
+ if untraced:
162
+ failed.append(f"TypeScript: missing traceable() on: {', '.join(untraced)}")
163
+
164
+ return passed, failed
165
+
166
+
167
+ def check_language_syntax(
168
+ test_dir: Path,
169
+ python_file: str = "backend/sql_agent.py",
170
+ typescript_file: str = "frontend/support_bot.ts",
171
+ ) -> tuple[list[str], list[str]]:
172
+ """Validate that each file uses correct language syntax (no mixing).
173
+
174
+ Checks that Python files don't have TypeScript patterns and vice versa.
175
+
176
+ Args:
177
+ test_dir: Test working directory
178
+ python_file: Relative path to Python file
179
+ typescript_file: Relative path to TypeScript file
180
+
181
+ Returns:
182
+ (passed, failed) lists
183
+ """
184
+ passed, failed = [], []
185
+
186
+ # Python-only patterns (shouldn't appear in TypeScript)
187
+ py_only_patterns = [
188
+ (re.compile(r"^def\s+\w+\s*\(", re.MULTILINE), "Python def"),
189
+ (re.compile(r"^@\w+", re.MULTILINE), "Python decorator"),
190
+ ]
191
+
192
+ # TypeScript-only patterns (shouldn't appear in Python)
193
+ ts_only_patterns = [
194
+ (re.compile(r":\s*(string|number|boolean|Promise<)"), "TypeScript type annotation"),
195
+ (re.compile(r"^(const|let)\s+\w+\s*=", re.MULTILINE), "TypeScript const/let"),
196
+ (re.compile(r"async\s+\([^)]*\)\s*=>"), "TypeScript async arrow"),
197
+ ]
198
+
199
+ # Check Python file doesn't have TypeScript patterns
200
+ py_path = test_dir / python_file
201
+ if py_path.exists():
202
+ content = py_path.read_text()
203
+ ts_found = [desc for pattern, desc in ts_only_patterns if pattern.search(content)]
204
+ if ts_found:
205
+ failed.append(f"Python: contains TypeScript syntax ({len(ts_found)} patterns)")
206
+ else:
207
+ passed.append("Python: correct syntax")
208
+
209
+ # Check TypeScript file doesn't have Python patterns
210
+ ts_path = test_dir / typescript_file
211
+ if ts_path.exists():
212
+ content = ts_path.read_text()
213
+ py_found = [desc for pattern, desc in py_only_patterns if pattern.search(content)]
214
+ if py_found:
215
+ failed.append(f"TypeScript: contains Python syntax ({len(py_found)} patterns)")
216
+ else:
217
+ passed.append("TypeScript: correct syntax")
218
+
219
+ return passed, failed
220
+
221
+
222
+ def check_langsmith_trace(
223
+ test_dir: Path,
224
+ outputs: dict,
225
+ trace_id_file: str = "trace_id.txt",
226
+ expected_functions: list[str] | None = None,
227
+ ) -> tuple[list[str], list[str]]:
228
+ """Validate that LangSmith traces were created correctly.
229
+
230
+ Reads trace IDs from file and verifies:
231
+ 1. Traces exist in LangSmith
232
+ 2. Traces have child runs for traced functions
233
+ 3. Child run names match expected function names
234
+
235
+ Args:
236
+ test_dir: Test working directory
237
+ outputs: Outputs dict (can store trace_ids and child_run_names)
238
+ trace_id_file: Name of file containing trace ID(s)
239
+ expected_functions: Optional list of expected traced function names
240
+
241
+ Returns:
242
+ (passed, failed) lists
243
+ """
244
+ passed, failed = [], []
245
+
246
+ # Read trace ID from file
247
+ trace_file = test_dir / trace_id_file
248
+ if not trace_file.exists():
249
+ failed.append(f"LangSmith: {trace_id_file} not found")
250
+ return passed, failed
251
+
252
+ content = trace_file.read_text().strip()
253
+ if not content:
254
+ failed.append(f"LangSmith: {trace_id_file} is empty")
255
+ return passed, failed
256
+
257
+ # Extract all UUIDs from the content
258
+ trace_ids = UUID_PATTERN.findall(content)
259
+ if not trace_ids:
260
+ failed.append(f"LangSmith: no valid trace IDs found in {trace_id_file}")
261
+ return passed, failed
262
+
263
+ passed.append(f"LangSmith: found {len(trace_ids)} trace ID(s)")
264
+
265
+ # Get LangSmith client
266
+ client, error = get_langsmith_client()
267
+ if not client:
268
+ failed.append(f"LangSmith: client error: {error}")
269
+ return passed, failed
270
+
271
+ # Validate each trace
272
+ all_child_names = []
273
+ for trace_id in trace_ids:
274
+ try:
275
+ run = client.read_run(trace_id)
276
+ passed.append(f"LangSmith: trace {trace_id[:8]}... exists (name: {run.name})")
277
+
278
+ # Check run type
279
+ if run.run_type == "chain":
280
+ passed.append(f"LangSmith: {trace_id[:8]}... has run_type='chain'")
281
+
282
+ # Check for child runs
283
+ child_runs = list(client.list_runs(parent_run_id=trace_id, limit=20))
284
+ if child_runs:
285
+ child_names = [r.name for r in child_runs]
286
+ all_child_names.extend(child_names)
287
+ passed.append(f"LangSmith: {trace_id[:8]}... has {len(child_runs)} child runs")
288
+ else:
289
+ failed.append(f"LangSmith: {trace_id[:8]}... has no child runs")
290
+
291
+ except Exception as e:
292
+ failed.append(f"LangSmith: trace {trace_id[:8]}... error: {str(e)[:50]}")
293
+
294
+ # Check for expected function names
295
+ if expected_functions:
296
+ # Include camelCase variants
297
+ expected_set = set(expected_functions)
298
+ for func in expected_functions:
299
+ camel = "".join(
300
+ word.title() if i > 0 else word for i, word in enumerate(func.split("_"))
301
+ )
302
+ expected_set.add(camel)
303
+
304
+ found_funcs = [n for n in all_child_names if n in expected_set]
305
+ if found_funcs:
306
+ passed.append(f"LangSmith: found traced functions: {', '.join(set(found_funcs))}")
307
+
308
+ # Store trace info in outputs
309
+ if outputs is not None:
310
+ outputs["trace_ids"] = trace_ids
311
+ outputs["child_run_names"] = all_child_names
312
+
313
+ return passed, failed