orizu 0.5.19 → 0.5.21

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 (378) hide show
  1. package/README.md +23 -0
  2. package/dist/archive-artifacts-cli.d.ts +50 -0
  3. package/dist/archive-artifacts-cli.d.ts.map +1 -0
  4. package/dist/artifact-archive.d.ts +48 -0
  5. package/dist/artifact-archive.d.ts.map +1 -0
  6. package/dist/artifact-pull.d.ts +22 -0
  7. package/dist/artifact-pull.d.ts.map +1 -0
  8. package/dist/banner.d.ts +3 -0
  9. package/dist/banner.d.ts.map +1 -0
  10. package/dist/connectors-cli.d.ts +31 -0
  11. package/dist/connectors-cli.d.ts.map +1 -0
  12. package/dist/credentials.d.ts +46 -0
  13. package/dist/credentials.d.ts.map +1 -0
  14. package/dist/csv.d.ts +49 -0
  15. package/dist/csv.d.ts.map +1 -0
  16. package/dist/dataset-download.d.ts +6 -0
  17. package/dist/dataset-download.d.ts.map +1 -0
  18. package/dist/dataset-edit-rows.d.ts +10 -0
  19. package/dist/dataset-edit-rows.d.ts.map +1 -0
  20. package/dist/dataset-upload-snapshot.d.ts +13 -0
  21. package/dist/dataset-upload-snapshot.d.ts.map +1 -0
  22. package/dist/daytona-slice-rehearsal.d.ts +89 -0
  23. package/dist/daytona-slice-rehearsal.d.ts.map +1 -0
  24. package/dist/daytona-slice.d.ts +106 -0
  25. package/dist/daytona-slice.d.ts.map +1 -0
  26. package/dist/deploy-key-merge-core.d.ts +121 -0
  27. package/dist/deploy-key-merge-core.d.ts.map +1 -0
  28. package/dist/diff-comments-cli.d.ts +12 -0
  29. package/dist/diff-comments-cli.d.ts.map +1 -0
  30. package/dist/diff-comments-cli.js +21 -2
  31. package/dist/egress-allowlist-cli.d.ts +23 -0
  32. package/dist/egress-allowlist-cli.d.ts.map +1 -0
  33. package/dist/egress-policy.d.ts +108 -0
  34. package/dist/egress-policy.d.ts.map +1 -0
  35. package/dist/error-response.d.ts +9 -0
  36. package/dist/error-response.d.ts.map +1 -0
  37. package/dist/file-parser.d.ts +5 -0
  38. package/dist/file-parser.d.ts.map +1 -0
  39. package/dist/gepa-engine-dispatch.d.ts +9 -0
  40. package/dist/gepa-engine-dispatch.d.ts.map +1 -0
  41. package/dist/gepa-engine-dispatch.js +307 -0
  42. package/dist/gepa-python-command.d.ts +6 -0
  43. package/dist/gepa-python-command.d.ts.map +1 -0
  44. package/dist/gepa-python-command.js +26 -0
  45. package/dist/gepa-python-paths.d.ts +6 -0
  46. package/dist/gepa-python-paths.d.ts.map +1 -0
  47. package/dist/gepa-python-paths.js +42 -0
  48. package/dist/git-credential.d.ts +69 -0
  49. package/dist/git-credential.d.ts.map +1 -0
  50. package/dist/git-recovery-environment.d.ts +31 -0
  51. package/dist/git-recovery-environment.d.ts.map +1 -0
  52. package/dist/github-setup.d.ts +122 -0
  53. package/dist/github-setup.d.ts.map +1 -0
  54. package/dist/global-flags.d.ts +12 -0
  55. package/dist/global-flags.d.ts.map +1 -0
  56. package/dist/help.d.ts +46 -0
  57. package/dist/help.d.ts.map +1 -0
  58. package/dist/help.js +93 -25
  59. package/dist/hosted-boot.d.ts +273 -0
  60. package/dist/hosted-boot.d.ts.map +1 -0
  61. package/dist/hosted-bootstrap-rehearsal.d.ts +86 -0
  62. package/dist/hosted-bootstrap-rehearsal.d.ts.map +1 -0
  63. package/dist/hosted-bootstrap.d.ts +188 -0
  64. package/dist/hosted-bootstrap.d.ts.map +1 -0
  65. package/dist/hosted-broker-server.d.ts +50 -0
  66. package/dist/hosted-broker-server.d.ts.map +1 -0
  67. package/dist/hosted-git-http-server.d.ts +36 -0
  68. package/dist/hosted-git-http-server.d.ts.map +1 -0
  69. package/dist/hosted-harness-claude.d.ts +195 -0
  70. package/dist/hosted-harness-claude.d.ts.map +1 -0
  71. package/dist/hosted-harness-opencode.d.ts +227 -0
  72. package/dist/hosted-harness-opencode.d.ts.map +1 -0
  73. package/dist/hosted-harness.d.ts +118 -0
  74. package/dist/hosted-harness.d.ts.map +1 -0
  75. package/dist/hosted-harvest.d.ts +68 -0
  76. package/dist/hosted-harvest.d.ts.map +1 -0
  77. package/dist/hosted-headless.d.ts +72 -0
  78. package/dist/hosted-headless.d.ts.map +1 -0
  79. package/dist/hosted-loop-lifecycle.d.ts +206 -0
  80. package/dist/hosted-loop-lifecycle.d.ts.map +1 -0
  81. package/dist/hosted-loop.d.ts +170 -0
  82. package/dist/hosted-loop.d.ts.map +1 -0
  83. package/dist/hosted-run-event-sink.d.ts +222 -0
  84. package/dist/hosted-run-event-sink.d.ts.map +1 -0
  85. package/dist/hosted-runtime-assets.d.ts +186 -0
  86. package/dist/hosted-runtime-assets.d.ts.map +1 -0
  87. package/dist/hosted-session-cli.d.ts +258 -0
  88. package/dist/hosted-session-cli.d.ts.map +1 -0
  89. package/dist/hosted-skill-staging.d.ts +73 -0
  90. package/dist/hosted-skill-staging.d.ts.map +1 -0
  91. package/dist/http.d.ts +8 -0
  92. package/dist/http.d.ts.map +1 -0
  93. package/dist/index.d.ts +22 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +119 -129
  96. package/dist/instruction-set-gepa-launch.d.ts +3 -0
  97. package/dist/instruction-set-gepa-launch.d.ts.map +1 -0
  98. package/dist/instruction-set-gepa-launch.js +15 -0
  99. package/dist/instruction-set-loader.d.ts +6 -0
  100. package/dist/instruction-set-loader.d.ts.map +1 -0
  101. package/dist/instruction-set-loader.js +59 -0
  102. package/dist/instruction-set-manifest.d.ts +14 -0
  103. package/dist/instruction-set-manifest.d.ts.map +1 -0
  104. package/dist/instruction-set-manifest.js +162 -0
  105. package/dist/instruction-sets-cli.d.ts +40 -0
  106. package/dist/instruction-sets-cli.d.ts.map +1 -0
  107. package/dist/instruction-sets-cli.js +361 -0
  108. package/dist/json-response.d.ts +4 -0
  109. package/dist/json-response.d.ts.map +1 -0
  110. package/dist/jsonl-stream.d.ts +8 -0
  111. package/dist/jsonl-stream.d.ts.map +1 -0
  112. package/dist/kill-switch-cli.d.ts +30 -0
  113. package/dist/kill-switch-cli.d.ts.map +1 -0
  114. package/dist/loopback-serve.d.ts +25 -0
  115. package/dist/loopback-serve.d.ts.map +1 -0
  116. package/dist/manifests-cli.d.ts +22 -0
  117. package/dist/manifests-cli.d.ts.map +1 -0
  118. package/dist/markdown-report-input.d.ts +7 -0
  119. package/dist/markdown-report-input.d.ts.map +1 -0
  120. package/dist/markdown-report-input.js +15 -1
  121. package/dist/merge-job.d.ts +155 -0
  122. package/dist/merge-job.d.ts.map +1 -0
  123. package/dist/model-configs-cli.d.ts +19 -0
  124. package/dist/model-configs-cli.d.ts.map +1 -0
  125. package/dist/model-configs-cli.js +104 -0
  126. package/dist/optimization-export-cli.d.ts +19 -0
  127. package/dist/optimization-export-cli.d.ts.map +1 -0
  128. package/dist/optimizations-list-cli.d.ts +20 -0
  129. package/dist/optimizations-list-cli.d.ts.map +1 -0
  130. package/dist/optimizations-promote-cli.d.ts +8 -0
  131. package/dist/optimizations-promote-cli.d.ts.map +1 -0
  132. package/dist/optimizations-promote-cli.js +34 -0
  133. package/dist/option-validation.d.ts +15 -0
  134. package/dist/option-validation.d.ts.map +1 -0
  135. package/dist/preview-runtime.d.ts +63 -0
  136. package/dist/preview-runtime.d.ts.map +1 -0
  137. package/dist/prompt-draft-push.d.ts +60 -0
  138. package/dist/prompt-draft-push.d.ts.map +1 -0
  139. package/dist/prompt-label-cli.d.ts +11 -0
  140. package/dist/prompt-label-cli.d.ts.map +1 -0
  141. package/dist/prompt-label-cli.js +29 -0
  142. package/dist/prompt-length-wire.d.ts +28 -0
  143. package/dist/prompt-length-wire.d.ts.map +1 -0
  144. package/dist/prompt-length-wire.js +2 -2
  145. package/dist/prompt-report-cli.d.ts +10 -0
  146. package/dist/prompt-report-cli.d.ts.map +1 -0
  147. package/dist/prompt-report-cli.js +2 -2
  148. package/dist/prompt-summary-table.d.ts +15 -0
  149. package/dist/prompt-summary-table.d.ts.map +1 -0
  150. package/dist/prompt-summary-table.js +6 -0
  151. package/dist/registration-tag-warning.d.ts +32 -0
  152. package/dist/registration-tag-warning.d.ts.map +1 -0
  153. package/dist/report-comments-cli.d.ts +16 -0
  154. package/dist/report-comments-cli.d.ts.map +1 -0
  155. package/dist/report-markdown-blankness.d.ts +2 -0
  156. package/dist/report-markdown-blankness.d.ts.map +1 -0
  157. package/dist/report-markdown-blankness.js +6 -0
  158. package/dist/report-replacement-warning.d.ts +17 -0
  159. package/dist/report-replacement-warning.d.ts.map +1 -0
  160. package/dist/report-replacement-warning.js +31 -0
  161. package/dist/repository-backup-core.d.ts +225 -0
  162. package/dist/repository-backup-core.d.ts.map +1 -0
  163. package/dist/repository-recovery-manifest.d.ts +83 -0
  164. package/dist/repository-recovery-manifest.d.ts.map +1 -0
  165. package/dist/run-event-digest.d.ts +74 -0
  166. package/dist/run-event-digest.d.ts.map +1 -0
  167. package/dist/runner-dir-verify.d.ts +66 -0
  168. package/dist/runner-dir-verify.d.ts.map +1 -0
  169. package/dist/runner-instruction-set-contract.d.ts +24 -0
  170. package/dist/runner-instruction-set-contract.d.ts.map +1 -0
  171. package/dist/runner-instruction-set-contract.js +50 -0
  172. package/dist/sandbox-hygiene.d.ts +45 -0
  173. package/dist/sandbox-hygiene.d.ts.map +1 -0
  174. package/dist/sandbox-provider.d.ts +193 -0
  175. package/dist/sandbox-provider.d.ts.map +1 -0
  176. package/dist/scorer-draft-push.d.ts +50 -0
  177. package/dist/scorer-draft-push.d.ts.map +1 -0
  178. package/dist/scorers-cli.d.ts +20 -0
  179. package/dist/scorers-cli.d.ts.map +1 -0
  180. package/dist/scorers-cli.js +22 -0
  181. package/dist/scorers-verify-parity-bridge.d.ts +16 -0
  182. package/dist/scorers-verify-parity-bridge.d.ts.map +1 -0
  183. package/dist/scorers-verify-parity-bridge.js +90 -0
  184. package/dist/scorers-verify-parity.d.ts +81 -0
  185. package/dist/scorers-verify-parity.d.ts.map +1 -0
  186. package/dist/scorers-verify-parity.js +502 -0
  187. package/dist/scores-accept-cli.d.ts +21 -0
  188. package/dist/scores-accept-cli.d.ts.map +1 -0
  189. package/dist/secret-redaction.d.ts +47 -0
  190. package/dist/secret-redaction.d.ts.map +1 -0
  191. package/dist/session-timeline.d.ts +54 -0
  192. package/dist/session-timeline.d.ts.map +1 -0
  193. package/dist/setup-prompt.d.ts +5 -0
  194. package/dist/setup-prompt.d.ts.map +1 -0
  195. package/dist/skill-installer.d.ts +68 -0
  196. package/dist/skill-installer.d.ts.map +1 -0
  197. package/dist/skilled-proposer-launch.d.ts +7 -0
  198. package/dist/skilled-proposer-launch.d.ts.map +1 -0
  199. package/dist/skilled-proposer-launch.js +60 -0
  200. package/dist/smoke.d.ts +102 -0
  201. package/dist/smoke.d.ts.map +1 -0
  202. package/dist/start-intent.d.ts +12 -0
  203. package/dist/start-intent.d.ts.map +1 -0
  204. package/dist/task-assignment-manifest.d.ts +15 -0
  205. package/dist/task-assignment-manifest.d.ts.map +1 -0
  206. package/dist/task-create-error.d.ts +18 -0
  207. package/dist/task-create-error.d.ts.map +1 -0
  208. package/dist/team-connectors-cli.d.ts +29 -0
  209. package/dist/team-connectors-cli.d.ts.map +1 -0
  210. package/dist/types.d.ts +39 -0
  211. package/dist/types.d.ts.map +1 -0
  212. package/dist/vercel-sandbox-provider.d.ts +156 -0
  213. package/dist/vercel-sandbox-provider.d.ts.map +1 -0
  214. package/dist/workbench-cli.d.ts +233 -0
  215. package/dist/workbench-cli.d.ts.map +1 -0
  216. package/dist/workspace-sync.d.ts +207 -0
  217. package/dist/workspace-sync.d.ts.map +1 -0
  218. package/dist/workspace.d.ts +92 -0
  219. package/dist/workspace.d.ts.map +1 -0
  220. package/dist/zip-draft-push.d.ts +55 -0
  221. package/dist/zip-draft-push.d.ts.map +1 -0
  222. package/package.json +15 -2
  223. package/requirements/README.md +138 -0
  224. package/requirements/skilled-proposer.in +66 -0
  225. package/requirements/skilled-proposer.lock +265 -0
  226. package/scripts/build-cli-dist.mjs +30 -0
  227. package/scripts/ensure-skilled-proposer-venv.mjs +5 -0
  228. package/scripts/orizu-source-checkout.d.mts +1 -0
  229. package/scripts/orizu-source-checkout.mjs +10 -0
  230. package/scripts/refresh-skilled-proposer-lock.mjs +256 -0
  231. package/scripts/vendor-gepa-python.mjs +187 -4
  232. package/src/diff-comments-cli.ts +41 -3
  233. package/src/gepa-engine-dispatch.ts +340 -0
  234. package/src/gepa-python-command.ts +31 -0
  235. package/src/gepa-python-paths.ts +56 -0
  236. package/src/help.ts +95 -25
  237. package/src/index.ts +131 -166
  238. package/src/instruction-set-gepa-launch.ts +28 -0
  239. package/src/instruction-set-loader.ts +37 -0
  240. package/src/instruction-set-manifest.ts +120 -0
  241. package/src/instruction-sets-cli.ts +306 -0
  242. package/src/markdown-report-input.ts +19 -1
  243. package/src/model-configs-cli.ts +119 -0
  244. package/src/optimizations-promote-cli.ts +41 -0
  245. package/src/prompt-label-cli.ts +55 -0
  246. package/src/prompt-length-wire.ts +1 -1
  247. package/src/prompt-report-cli.ts +2 -2
  248. package/src/prompt-summary-table.ts +12 -0
  249. package/src/report-markdown-blankness.ts +6 -0
  250. package/src/report-replacement-warning.ts +35 -0
  251. package/src/runner-instruction-set-contract.ts +64 -0
  252. package/src/scorers-cli.ts +40 -0
  253. package/src/scorers-verify-parity-bridge.ts +90 -0
  254. package/src/scorers-verify-parity.ts +564 -0
  255. package/src/skilled-proposer-launch.ts +89 -0
  256. package/src/skilled-proposer-venv-manager.mjs +757 -0
  257. package/tsconfig.json +2 -0
  258. package/vendor/gepa-python/LICENSE +7 -0
  259. package/vendor/gepa-python/manifest.json +107 -0
  260. package/vendor/gepa-python/src/gepa/__init__.py +22 -0
  261. package/vendor/gepa-python/src/gepa/adapters/__init__.py +0 -0
  262. package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/__init__.py +1 -0
  263. package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
  264. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/__init__.py +26 -0
  265. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/confidence_adapter.py +618 -0
  266. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/scoring.py +206 -0
  267. package/vendor/gepa-python/src/gepa/adapters/default_adapter/__init__.py +0 -0
  268. package/vendor/gepa-python/src/gepa/adapters/default_adapter/default_adapter.py +206 -0
  269. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/__init__.py +0 -0
  270. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/dspy_adapter.py +525 -0
  271. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/instruction_proposal.py +500 -0
  272. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/__init__.py +6 -0
  273. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
  274. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/full_program_adapter.py +269 -0
  275. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/__init__.py +56 -0
  276. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
  277. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
  278. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
  279. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
  280. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
  281. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
  282. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
  283. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
  284. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
  285. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
  286. package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/__init__.py +11 -0
  287. package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/langchain_adapter.py +261 -0
  288. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/__init__.py +37 -0
  289. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_adapter.py +693 -0
  290. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_client.py +364 -0
  291. package/vendor/gepa-python/src/gepa/adapters/optimize_anything_adapter/optimize_anything_adapter.py +879 -0
  292. package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/__init__.py +0 -0
  293. package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
  294. package/vendor/gepa-python/src/gepa/api.py +468 -0
  295. package/vendor/gepa-python/src/gepa/core/__init__.py +0 -0
  296. package/vendor/gepa-python/src/gepa/core/adapter.py +227 -0
  297. package/vendor/gepa-python/src/gepa/core/callbacks.py +551 -0
  298. package/vendor/gepa-python/src/gepa/core/data_loader.py +74 -0
  299. package/vendor/gepa-python/src/gepa/core/engine.py +1025 -0
  300. package/vendor/gepa-python/src/gepa/core/result.py +271 -0
  301. package/vendor/gepa-python/src/gepa/core/state.py +706 -0
  302. package/vendor/gepa-python/src/gepa/examples/__init__.py +0 -0
  303. package/vendor/gepa-python/src/gepa/examples/aime.py +24 -0
  304. package/vendor/gepa-python/src/gepa/examples/anymaths-bench/eval_default.py +111 -0
  305. package/vendor/gepa-python/src/gepa/examples/anymaths-bench/train_anymaths.py +177 -0
  306. package/vendor/gepa-python/src/gepa/examples/mcp_adapter/__init__.py +4 -0
  307. package/vendor/gepa-python/src/gepa/examples/mcp_adapter/mcp_optimization_example.py +456 -0
  308. package/vendor/gepa-python/src/gepa/examples/rag_adapter/__init__.py +9 -0
  309. package/vendor/gepa-python/src/gepa/examples/rag_adapter/rag_optimization.py +824 -0
  310. package/vendor/gepa-python/src/gepa/examples/terminal-bench/train_terminus.py +161 -0
  311. package/vendor/gepa-python/src/gepa/gepa_utils.py +117 -0
  312. package/vendor/gepa-python/src/gepa/gskill/__init__.py +1 -0
  313. package/vendor/gepa-python/src/gepa/gskill/gskill/__init__.py +0 -0
  314. package/vendor/gepa-python/src/gepa/gskill/gskill/cost_tracker.py +194 -0
  315. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/__init__.py +0 -0
  316. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code.py +1117 -0
  317. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code_skills.py +613 -0
  318. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/mini_swe_agent.py +440 -0
  319. package/vendor/gepa-python/src/gepa/gskill/gskill/experiment_logger.py +367 -0
  320. package/vendor/gepa-python/src/gepa/gskill/gskill/swe_fitness_fn.py +209 -0
  321. package/vendor/gepa-python/src/gepa/gskill/gskill/swe_harness.py +352 -0
  322. package/vendor/gepa-python/src/gepa/gskill/gskill/train_optimize_anything.py +830 -0
  323. package/vendor/gepa-python/src/gepa/image.py +104 -0
  324. package/vendor/gepa-python/src/gepa/lm.py +261 -0
  325. package/vendor/gepa-python/src/gepa/logging/__init__.py +0 -0
  326. package/vendor/gepa-python/src/gepa/logging/experiment_tracker.py +457 -0
  327. package/vendor/gepa-python/src/gepa/logging/logger.py +75 -0
  328. package/vendor/gepa-python/src/gepa/logging/utils.py +130 -0
  329. package/vendor/gepa-python/src/gepa/optimize_anything.py +1701 -0
  330. package/vendor/gepa-python/src/gepa/proposer/__init__.py +0 -0
  331. package/vendor/gepa-python/src/gepa/proposer/base.py +53 -0
  332. package/vendor/gepa-python/src/gepa/proposer/merge.py +403 -0
  333. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/__init__.py +0 -0
  334. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/base.py +64 -0
  335. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflection_lm.py +178 -0
  336. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflective_mutation.py +641 -0
  337. package/vendor/gepa-python/src/gepa/py.typed +0 -0
  338. package/vendor/gepa-python/src/gepa/strategies/__init__.py +0 -0
  339. package/vendor/gepa-python/src/gepa/strategies/acceptance.py +66 -0
  340. package/vendor/gepa-python/src/gepa/strategies/batch_sampler.py +103 -0
  341. package/vendor/gepa-python/src/gepa/strategies/candidate_selector.py +82 -0
  342. package/vendor/gepa-python/src/gepa/strategies/component_selector.py +36 -0
  343. package/vendor/gepa-python/src/gepa/strategies/eval_policy.py +64 -0
  344. package/vendor/gepa-python/src/gepa/strategies/instruction_proposal.py +153 -0
  345. package/vendor/gepa-python/src/gepa/strategies/proposal_sampling.py +128 -0
  346. package/vendor/gepa-python/src/gepa/strategies/proposal_selection.py +84 -0
  347. package/vendor/gepa-python/src/gepa/utils/__init__.py +63 -0
  348. package/vendor/gepa-python/src/gepa/utils/code_execution.py +626 -0
  349. package/vendor/gepa-python/src/gepa/utils/stdio_capture.py +145 -0
  350. package/vendor/gepa-python/src/gepa/utils/stop_condition.py +230 -0
  351. package/vendor/gepa-python/src/gepa/visualization.py +359 -0
  352. package/vendor/orizu-gepa/pyproject.toml +18 -0
  353. package/vendor/orizu-gepa/src/orizu_gepa_connector/__init__.py +9 -0
  354. package/vendor/orizu-gepa/src/orizu_gepa_connector/__main__.py +5 -0
  355. package/vendor/orizu-gepa/src/orizu_gepa_connector/adapter.py +138 -0
  356. package/vendor/orizu-gepa/src/orizu_gepa_connector/callbacks.py +666 -0
  357. package/vendor/orizu-gepa/src/orizu_gepa_connector/cli.py +7 -0
  358. package/vendor/orizu-gepa/src/orizu_gepa_connector/engine.py +269 -0
  359. package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +52 -0
  360. package/vendor/orizu-gepa/src/orizu_gepa_connector/preflight.py +64 -0
  361. package/vendor/orizu-gepa/src/orizu_gepa_connector/reflection.py +186 -0
  362. package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +721 -0
  363. package/vendor/orizu-gepa/src/orizu_gepa_connector/skilled_proposer_bridge.py +381 -0
  364. package/vendor/orizu-gepa/src/orizu_gepa_connector/stop_conditions.py +55 -0
  365. package/vendor/orizu-gepa/src/orizu_gepa_connector/translator.py +203 -0
  366. package/vendor/orizu-gepa-python/pyproject.toml +1 -1
  367. package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +1 -0
  368. package/vendor/orizu-gepa-python/src/orizu_gepa/client.py +52 -7
  369. package/vendor/orizu-gepa-python/src/orizu_gepa/local_log.py +52 -0
  370. package/vendor/orizu-gepa-python/src/orizu_gepa/optimizer.py +10 -5
  371. package/vendor/orizu-gepa-python/src/orizu_gepa/reflection.py +323 -68
  372. package/vendor/orizu-gepa-python/src/orizu_gepa/runner.py +207 -13
  373. package/vendor/skills/orizu-cli/SKILL.md +3 -1
  374. package/vendor/skills/orizu-cli/references/cli-reference.md +85 -1
  375. package/vendor/skills/orizu-cli/references/migrate-existing-gepa-setup.md +303 -0
  376. package/vendor/skills/orizu-cli/references/optimization-reports.md +1 -1
  377. package/vendor/skills/orizu-cli/references/optimization-with-gepa.md +26 -1
  378. package/vendor/skills/orizu-cli/references/prompt-control-plane.md +113 -10
@@ -0,0 +1,613 @@
1
+ """
2
+ Evaluate testset with Claude Code using proper Claude Code Skills.
3
+
4
+ This is a variant of evaluate_claude_code.py that installs skills as proper
5
+ Claude Code skills (.claude/skills/<repo>/SKILL.md with YAML frontmatter)
6
+ instead of plain CLAUDE.md files.
7
+
8
+ See: https://code.claude.com/docs/en/skills
9
+
10
+ Usage is identical to evaluate_claude_code.py:
11
+ python -m src.evaluate.claude_code_skills --config gepa_results/logs/run_xxx/config.json --use-skills
12
+ """
13
+
14
+ import argparse
15
+ import json
16
+ import os
17
+ import sys
18
+ import uuid
19
+ from concurrent.futures import ThreadPoolExecutor, as_completed
20
+ from datetime import datetime
21
+ from pathlib import Path
22
+ from typing import Any
23
+
24
+ import docker
25
+
26
+ # Import all shared utilities from the original evaluate_claude_code module.
27
+ # This avoids duplicating data loading, image management, verification, etc.
28
+ from gskill.evaluate.claude_code import (
29
+ # Result types
30
+ ClaudeCodeResult,
31
+ ensure_claude_code_image,
32
+ # Docker image management
33
+ get_base_image_name,
34
+ load_test_ids,
35
+ load_testset_by_ids,
36
+ load_testset_from_config,
37
+ save_test_ids,
38
+ # Verification
39
+ verify_patch_with_harness,
40
+ )
41
+ from gskill.evaluate.claude_code import (
42
+ # Original Claude Code runner (imported as private; we wrap it)
43
+ run_claude_code_in_container as _run_claude_code_in_container,
44
+ )
45
+ from swebench.harness.constants import (
46
+ DOCKER_USER,
47
+ DOCKER_WORKDIR,
48
+ KEY_INSTANCE_ID,
49
+ )
50
+
51
+ # ============================================================================
52
+ # Skill Installation (the key difference from evaluate_claude_code.py)
53
+ # ============================================================================
54
+
55
+
56
+ def format_skill_md(skills_content: str, repo_name: str) -> str:
57
+ """
58
+ Wrap raw skills text with proper SKILL.md YAML frontmatter.
59
+
60
+ The frontmatter follows the Claude Code skill spec:
61
+ https://code.claude.com/docs/en/skills
62
+
63
+ Args:
64
+ skills_content: Raw skills text (e.g. contents of best_skills.txt)
65
+ repo_name: Repository name (e.g. "blevesearch__bleve")
66
+
67
+ Returns:
68
+ Complete SKILL.md content with frontmatter
69
+ """
70
+ # Clean repo name for the `name` field (lowercase, hyphens only)
71
+ skill_name = repo_name.replace("__", "-").replace("_", "-").lower()
72
+
73
+ # Build an informative description so Claude knows when to apply the skill
74
+ human_repo = repo_name.replace("__", "/").replace("_", "-")
75
+ description = (
76
+ f"Expert bug-fixing skills optimized for the {human_repo} repository. "
77
+ f"Contains repo-specific patterns, diagnostic strategies, and "
78
+ f"step-by-step workflows for efficiently finding and resolving bugs "
79
+ f"in this codebase. Use when debugging issues, fixing failing tests, "
80
+ f"or resolving reported bugs."
81
+ )
82
+
83
+ return f"---\nname: {skill_name}-bugfix\ndescription: {description}\n---\n\n{skills_content}"
84
+
85
+
86
+ def install_skill_in_container(
87
+ container,
88
+ skills_content: str,
89
+ repo_name: str,
90
+ ) -> None:
91
+ """
92
+ Install skills as a proper Claude Code skill inside the container.
93
+
94
+ Creates:
95
+ <workdir>/.claude/skills/<repo_name>/SKILL.md
96
+
97
+ with YAML frontmatter so Claude Code discovers and loads it automatically.
98
+
99
+ Args:
100
+ container: Running Docker container
101
+ skills_content: Raw skills text
102
+ repo_name: Repository name used as the skill directory name
103
+ """
104
+ from swebench.harness.docker_utils import copy_to_container
105
+
106
+ skill_md = format_skill_md(skills_content, repo_name)
107
+ skill_dir = f"{DOCKER_WORKDIR}/.claude/skills/{repo_name}"
108
+
109
+ # Create the skill directory structure
110
+ container.exec_run(f"mkdir -p {skill_dir}", user="root")
111
+
112
+ # Write SKILL.md into the container
113
+ skill_file_local = Path(f"/tmp/skill_{uuid.uuid4().hex[:8]}.md")
114
+ skill_file_container = Path(f"{skill_dir}/SKILL.md")
115
+ try:
116
+ skill_file_local.write_text(skill_md)
117
+ copy_to_container(container, skill_file_local, skill_file_container)
118
+ container.exec_run("sync", user="root")
119
+ # Make the whole .claude tree readable
120
+ container.exec_run(f"chmod -R 755 {DOCKER_WORKDIR}/.claude", user="root")
121
+ print(f" Installed skill at .claude/skills/{repo_name}/SKILL.md ({len(skill_md)} chars)")
122
+ finally:
123
+ skill_file_local.unlink(missing_ok=True)
124
+
125
+
126
+ # ============================================================================
127
+ # Wrapped Claude Code Runner
128
+ # ============================================================================
129
+
130
+
131
+ def run_claude_code_in_container(
132
+ task: dict,
133
+ container,
134
+ timeout: int = 1800,
135
+ poll_interval: int = 10,
136
+ skills: str | None = None,
137
+ repo_name: str | None = None,
138
+ ) -> ClaudeCodeResult:
139
+ """
140
+ Run Claude Code with skills installed as a proper SKILL.md.
141
+
142
+ This wraps the original run_claude_code_in_container: if skills are
143
+ provided, they are first installed as .claude/skills/<repo>/SKILL.md,
144
+ then the original runner is called with skills=None (so it skips
145
+ CLAUDE.md creation).
146
+
147
+ Args:
148
+ task: Task instance dict
149
+ container: Running Docker container
150
+ timeout: Maximum time to wait (seconds)
151
+ poll_interval: How often to check for completion (seconds)
152
+ skills: Optional raw skills content
153
+ repo_name: Repository name for the skill directory
154
+
155
+ Returns:
156
+ ClaudeCodeResult with patch and status
157
+ """
158
+ if skills:
159
+ effective_repo = repo_name or task.get("repo", "").split("/")[-1] or "default"
160
+ install_skill_in_container(container, skills, effective_repo)
161
+
162
+ # Delegate to original runner with skills=None (skill already installed)
163
+ return _run_claude_code_in_container(task, container, timeout=timeout, poll_interval=poll_interval, skills=None)
164
+
165
+
166
+ # ============================================================================
167
+ # Evaluation Functions (thin overrides that thread repo_name through)
168
+ # ============================================================================
169
+
170
+
171
+ def evaluate_single_task(
172
+ task: dict,
173
+ claude_image: str,
174
+ timeout: int = 1800,
175
+ verify_timeout: int = 300,
176
+ skills: str | None = None,
177
+ repo_name: str | None = None,
178
+ ) -> dict[str, Any]:
179
+ """
180
+ Evaluate a single task with Claude Code (skill-aware version).
181
+
182
+ Identical to evaluate_claude_code.evaluate_single_task except that
183
+ skills are installed as .claude/skills/<repo>/SKILL.md.
184
+ """
185
+ instance_id = task[KEY_INSTANCE_ID]
186
+ container = None
187
+
188
+ try:
189
+ client = docker.from_env()
190
+ client.ping()
191
+ except Exception as e:
192
+ return {
193
+ "instance_id": instance_id,
194
+ "claude_success": False,
195
+ "test_passed": False,
196
+ "patch": "",
197
+ "claude_output": "",
198
+ "test_output": "",
199
+ "duration_seconds": 0,
200
+ "error": f"Docker connection failed: {e!s}",
201
+ }
202
+
203
+ try:
204
+ container_name = f"claude-code-{instance_id}.{uuid.uuid4().hex[:8]}"
205
+ container = client.containers.create(
206
+ image=claude_image,
207
+ name=container_name,
208
+ user=DOCKER_USER,
209
+ detach=True,
210
+ command="tail -f /dev/null",
211
+ platform="linux/x86_64",
212
+ mem_limit="10g",
213
+ )
214
+ container.start()
215
+
216
+ val = container.exec_run(
217
+ f"git checkout {instance_id}",
218
+ workdir=DOCKER_WORKDIR,
219
+ user=DOCKER_USER,
220
+ )
221
+ if val.exit_code != 0:
222
+ raise RuntimeError(f"Failed to checkout {instance_id}: {val.output.decode()}")
223
+
224
+ # Uses our skill-aware run_claude_code_in_container
225
+ result = run_claude_code_in_container(task, container, timeout=timeout, skills=skills, repo_name=repo_name)
226
+
227
+ passed = False
228
+ test_output = ""
229
+ if result.patch.strip():
230
+ passed, test_output = verify_patch_with_harness(task, result.patch, timeout=verify_timeout)
231
+ else:
232
+ test_output = "No patch generated"
233
+
234
+ return {
235
+ "instance_id": instance_id,
236
+ "claude_success": result.success,
237
+ "test_passed": passed,
238
+ "patch": result.patch,
239
+ "claude_output": result.output[:5000],
240
+ "test_output": test_output[:5000],
241
+ "duration_seconds": result.duration_seconds,
242
+ "error": result.error,
243
+ }
244
+
245
+ except Exception as e:
246
+ import traceback
247
+
248
+ return {
249
+ "instance_id": instance_id,
250
+ "claude_success": False,
251
+ "test_passed": False,
252
+ "patch": "",
253
+ "claude_output": "",
254
+ "test_output": "",
255
+ "duration_seconds": 0,
256
+ "error": f"{e!s}\n{traceback.format_exc()}",
257
+ }
258
+
259
+ finally:
260
+ if container:
261
+ try:
262
+ container.stop()
263
+ container.remove()
264
+ except Exception:
265
+ pass
266
+
267
+
268
+ def evaluate_testset(
269
+ test_data: list[dict],
270
+ output_dir: Path,
271
+ n_workers: int = 4,
272
+ timeout: int = 1800,
273
+ verify_timeout: int = 300,
274
+ skills: str | None = None,
275
+ run_config: dict[str, Any] | None = None,
276
+ repo_name: str | None = None,
277
+ ) -> dict[str, Any]:
278
+ """
279
+ Evaluate all tasks in testset (skill-aware version).
280
+
281
+ Identical to evaluate_claude_code.evaluate_testset except that skills
282
+ are installed as proper Claude Code skills.
283
+ """
284
+ output_dir.mkdir(parents=True, exist_ok=True)
285
+
286
+ # Ensure Claude Code images exist for all unique base images
287
+ print("\n" + "=" * 70)
288
+ print("Preparing Claude Code Docker images...")
289
+ print("=" * 70)
290
+
291
+ image_cache: dict[str, str] = {}
292
+ for task in test_data:
293
+ base_image = get_base_image_name(task)
294
+ if base_image not in image_cache:
295
+ claude_image = ensure_claude_code_image(task)
296
+ image_cache[base_image] = claude_image
297
+
298
+ print(f"Prepared {len(image_cache)} Claude Code image(s)")
299
+
300
+ # Evaluate tasks
301
+ print("\n" + "=" * 70)
302
+ print(f"Evaluating {len(test_data)} tasks with Claude Code...")
303
+ print(f"Workers: {n_workers}, Timeout: {timeout}s")
304
+ if skills:
305
+ print(f"Skills: installed as .claude/skills/{repo_name or '<auto>'}/SKILL.md")
306
+ print("=" * 70 + "\n")
307
+
308
+ results: list[dict[str, Any]] = []
309
+
310
+ def process_task(task):
311
+ base_image = get_base_image_name(task)
312
+ claude_image = image_cache[base_image]
313
+ return evaluate_single_task(
314
+ task,
315
+ claude_image,
316
+ timeout,
317
+ verify_timeout,
318
+ skills=skills,
319
+ repo_name=repo_name,
320
+ )
321
+
322
+ if n_workers <= 1:
323
+ for i, task in enumerate(test_data):
324
+ print(f"[{i + 1}/{len(test_data)}] {task[KEY_INSTANCE_ID][:50]}...")
325
+ result = process_task(task)
326
+ results.append(result)
327
+
328
+ status = "✓ PASS" if result["test_passed"] else "✗ FAIL"
329
+ print(f" {status} ({result['duration_seconds']:.1f}s)")
330
+
331
+ with open(output_dir / "results.jsonl", "a") as f:
332
+ f.write(json.dumps(result) + "\n")
333
+ else:
334
+ with ThreadPoolExecutor(max_workers=n_workers) as executor:
335
+ futures = {executor.submit(process_task, task): task for task in test_data}
336
+
337
+ for i, future in enumerate(as_completed(futures)):
338
+ task = futures[future]
339
+ try:
340
+ result = future.result()
341
+ except Exception as e:
342
+ result = {
343
+ "instance_id": task[KEY_INSTANCE_ID],
344
+ "claude_success": False,
345
+ "test_passed": False,
346
+ "error": str(e),
347
+ }
348
+
349
+ results.append(result)
350
+
351
+ status = "✓ PASS" if result.get("test_passed") else "✗ FAIL"
352
+ print(f"[{i + 1}/{len(test_data)}] {result['instance_id'][:50]}: {status}")
353
+
354
+ with open(output_dir / "results.jsonl", "a") as f:
355
+ f.write(json.dumps(result) + "\n")
356
+
357
+ # Compute summary
358
+ passed = sum(1 for r in results if r.get("test_passed"))
359
+ claude_success = sum(1 for r in results if r.get("claude_success"))
360
+ total = len(results)
361
+
362
+ summary = {
363
+ "run_config": run_config or {},
364
+ "total": total,
365
+ "passed": passed,
366
+ "pass_rate": passed / total if total > 0 else 0,
367
+ "claude_generated_patches": claude_success,
368
+ "claude_patch_rate": claude_success / total if total > 0 else 0,
369
+ "avg_duration": (sum(r.get("duration_seconds", 0) for r in results) / total if total > 0 else 0),
370
+ "results": results,
371
+ }
372
+
373
+ with open(output_dir / "summary.json", "w") as f:
374
+ json.dump(summary, f, indent=2)
375
+
376
+ print("\n" + "=" * 70)
377
+ print("EVALUATION COMPLETE")
378
+ print("=" * 70)
379
+ print(f"Total tasks: {total}")
380
+ print(f"Claude generated patches: {claude_success}/{total} ({summary['claude_patch_rate']:.1%})")
381
+ print(f"Tests passed: {passed}/{total} ({summary['pass_rate']:.1%})")
382
+ print(f"Average duration: {summary['avg_duration']:.1f}s")
383
+ print(f"Results saved to: {output_dir}")
384
+
385
+ return summary
386
+
387
+
388
+ # ============================================================================
389
+ # CLI (same arguments as evaluate_claude_code.py)
390
+ # ============================================================================
391
+
392
+
393
+ def main():
394
+ parser = argparse.ArgumentParser(
395
+ description="Evaluate testset with Claude Code (proper Skills variant)",
396
+ formatter_class=argparse.RawDescriptionHelpFormatter,
397
+ epilog="""
398
+ This script is identical to evaluate_claude_code.py except that --use-skills
399
+ installs skills as .claude/skills/<repo>/SKILL.md (with YAML frontmatter)
400
+ instead of a plain CLAUDE.md file.
401
+
402
+ See: https://code.claude.com/docs/en/skills
403
+
404
+ Examples:
405
+ # Evaluate with proper Claude Code skills
406
+ python -m src.evaluate.claude_code_skills --config gepa_results/logs/run_xxx/config.json --use-skills
407
+
408
+ # Evaluate without skills (identical to evaluate_claude_code.py)
409
+ python -m src.evaluate.claude_code_skills --config gepa_results/logs/run_xxx/config.json
410
+ """,
411
+ )
412
+
413
+ parser.add_argument(
414
+ "--config",
415
+ type=str,
416
+ required=True,
417
+ help="Path to config.json from a GEPA run",
418
+ )
419
+ parser.add_argument(
420
+ "--extract-ids",
421
+ type=str,
422
+ default=None,
423
+ help="Extract test IDs to this file and exit",
424
+ )
425
+ parser.add_argument(
426
+ "--output",
427
+ type=str,
428
+ default=None,
429
+ help="Output directory for results (default: gepa_results/claude_code/<run_id>)",
430
+ )
431
+ parser.add_argument(
432
+ "--workers",
433
+ type=int,
434
+ default=4,
435
+ help="Number of parallel workers (default: 4)",
436
+ )
437
+ parser.add_argument(
438
+ "--timeout",
439
+ type=int,
440
+ default=1800,
441
+ help="Timeout for Claude Code in seconds (default: 1800)",
442
+ )
443
+ parser.add_argument(
444
+ "--verify-timeout",
445
+ type=int,
446
+ default=300,
447
+ help="Timeout for test verification in seconds (default: 300)",
448
+ )
449
+ parser.add_argument(
450
+ "--ids-file",
451
+ type=str,
452
+ default=None,
453
+ help="Load test IDs from file instead of reconstructing from config",
454
+ )
455
+ parser.add_argument(
456
+ "--dry-run",
457
+ action="store_true",
458
+ help="Only prepare images and show what would be run, don't execute",
459
+ )
460
+ parser.add_argument(
461
+ "--limit",
462
+ type=int,
463
+ default=None,
464
+ help="Limit number of tasks to evaluate (for testing)",
465
+ )
466
+ parser.add_argument(
467
+ "--model",
468
+ type=str,
469
+ default="sonnet",
470
+ choices=["sonnet", "opus", "haiku", "default"],
471
+ help="Claude Code model to use (default: sonnet = Claude Sonnet 4.5)",
472
+ )
473
+ parser.add_argument(
474
+ "--use-skills",
475
+ action="store_true",
476
+ help="Load best_skills.txt and install as .claude/skills/<repo>/SKILL.md in the repo",
477
+ )
478
+
479
+ args = parser.parse_args()
480
+
481
+ # Verify Docker connection
482
+ try:
483
+ client = docker.from_env()
484
+ client.ping()
485
+ print(f"Docker connection OK (DOCKER_HOST={os.environ.get('DOCKER_HOST', 'default')})")
486
+ except Exception as e:
487
+ print(f"ERROR: Cannot connect to Docker: {e}")
488
+ print("Please ensure Docker is running:")
489
+ print(" Rootless: systemctl --user start docker")
490
+ print(" Standard: sudo systemctl start docker")
491
+ sys.exit(1)
492
+
493
+ # Load config
494
+ with open(args.config) as f:
495
+ config = json.load(f)
496
+
497
+ run_id = config.get("run_id", Path(args.config).parent.name)
498
+ repo = config["repo"]
499
+
500
+ # Set model environment variable for Claude Code
501
+ os.environ["CLAUDE_CODE_MODEL"] = args.model
502
+ print(f"Using Claude Code model: {args.model}")
503
+
504
+ # Load testset
505
+ if args.ids_file:
506
+ print(f"Loading test IDs from {args.ids_file}")
507
+ test_ids = load_test_ids(args.ids_file)
508
+ test_data = load_testset_by_ids(test_ids, repo)
509
+ print(f"Loaded {len(test_data)} tasks from IDs file")
510
+ else:
511
+ test_data, _ = load_testset_from_config(args.config)
512
+
513
+ # Extract IDs mode
514
+ if args.extract_ids:
515
+ save_test_ids(test_data, args.extract_ids)
516
+ return
517
+
518
+ # Set output directory
519
+ if args.output:
520
+ output_dir = Path(args.output)
521
+ else:
522
+ output_dir = Path("gepa_results/claude_code") / f"{run_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
523
+
524
+ # Apply limit
525
+ if args.limit and args.limit < len(test_data):
526
+ print(f"Limiting to first {args.limit} tasks (out of {len(test_data)})")
527
+ test_data = test_data[: args.limit]
528
+
529
+ # Save test IDs for reference
530
+ output_dir.mkdir(parents=True, exist_ok=True)
531
+ save_test_ids(test_data, str(output_dir / "test_ids.txt"))
532
+
533
+ # Save config copy
534
+ with open(output_dir / "source_config.json", "w") as f:
535
+ json.dump(config, f, indent=2)
536
+
537
+ # Load skills from config directory if requested
538
+ config_dir = Path(args.config).parent
539
+ skills = None
540
+ repo_name = repo # e.g. "blevesearch__bleve"
541
+ if args.use_skills:
542
+ skills_path = config_dir / "prompts" / "best_skills.txt"
543
+ if skills_path.exists():
544
+ skills = skills_path.read_text()
545
+ print(f"Loaded skills from {skills_path} ({len(skills)} chars)")
546
+ print(f"Will install as .claude/skills/{repo_name}/SKILL.md (proper Claude Code skill)")
547
+ # Save copy of raw skills
548
+ with open(output_dir / "skills_raw.txt", "w") as f:
549
+ f.write(skills)
550
+ # Also save the formatted SKILL.md for reference
551
+ with open(output_dir / "SKILL.md", "w") as f:
552
+ f.write(format_skill_md(skills, repo_name))
553
+ else:
554
+ print(f"WARNING: Skills file not found: {skills_path}")
555
+
556
+ # Dry run mode
557
+ if args.dry_run:
558
+ print("\n" + "=" * 70)
559
+ print("DRY RUN - Preparing images only")
560
+ print("=" * 70)
561
+
562
+ image_cache = {}
563
+ for task in test_data:
564
+ base_image = get_base_image_name(task)
565
+ if base_image not in image_cache:
566
+ claude_image = ensure_claude_code_image(task)
567
+ image_cache[base_image] = claude_image
568
+
569
+ print(f"\nPrepared {len(image_cache)} Claude Code image(s)")
570
+ print(f"Would evaluate {len(test_data)} tasks")
571
+ if skills:
572
+ print(f"Skills mode: .claude/skills/{repo_name}/SKILL.md")
573
+ print(f"Test IDs saved to: {output_dir / 'test_ids.txt'}")
574
+
575
+ return {
576
+ "dry_run": True,
577
+ "num_tasks": len(test_data),
578
+ "images": list(image_cache.values()),
579
+ }
580
+
581
+ # Build run configuration metadata
582
+ run_config = {
583
+ "model": args.model,
584
+ "use_skills": args.use_skills,
585
+ "skills_format": "claude_code_skill" if args.use_skills else None,
586
+ "skills_path": (str(config_dir / "prompts" / "best_skills.txt") if args.use_skills else None),
587
+ "config_path": str(Path(args.config).resolve()),
588
+ "source_run_id": run_id,
589
+ "repo": repo,
590
+ "workers": args.workers,
591
+ "timeout": args.timeout,
592
+ "verify_timeout": args.verify_timeout,
593
+ "num_tasks": len(test_data),
594
+ "timestamp": datetime.now().isoformat(),
595
+ }
596
+
597
+ # Run evaluation
598
+ summary = evaluate_testset(
599
+ test_data=test_data,
600
+ output_dir=output_dir,
601
+ n_workers=args.workers,
602
+ timeout=args.timeout,
603
+ verify_timeout=args.verify_timeout,
604
+ skills=skills,
605
+ run_config=run_config,
606
+ repo_name=repo_name,
607
+ )
608
+
609
+ return summary
610
+
611
+
612
+ if __name__ == "__main__":
613
+ main()