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,120 @@
1
+ import { existsSync, readFileSync, realpathSync } from 'node:fs'
2
+ import { dirname, isAbsolute, relative, resolve } from 'node:path'
3
+ import { createHash } from 'node:crypto'
4
+
5
+ export interface InstructionSetComponent { key: string; modelConfig?: string; text: string }
6
+ export interface InstructionSetManifest { name: string; description?: string | null; shape: string[]; components: InstructionSetComponent[] }
7
+
8
+ // Keep file-backed component reads within the same text budget used by prompt
9
+ // tooling; request assembly never asks Node to allocate an unbounded body.
10
+ export const MAX_INSTRUCTION_SET_COMPONENT_BYTES = 512 * 1024
11
+
12
+ const fail = (code: string): never => { throw new Error(code) }
13
+ const sha256 = (value: string) => createHash('sha256').update(value, 'utf8').digest('hex')
14
+
15
+ function hasPinnedComponents(material: unknown): boolean {
16
+ if (!material || typeof material !== 'object') return false
17
+ const pinned = (material as Record<string, unknown>).pinnedComponents
18
+ return Boolean(pinned && typeof pinned === 'object' && Object.keys(pinned).length > 0)
19
+ }
20
+
21
+ export function loadInstructionSetManifest(path: string): InstructionSetManifest {
22
+ let value: unknown
23
+ let source: string
24
+ try { source = readFileSync(path, 'utf8') } catch { return fail('instruction_set_path_not_found') }
25
+ try { value = JSON.parse(source) } catch { return fail('instruction_set_manifest_invalid_json') }
26
+ if (!value || typeof value !== 'object') return fail('instruction_set_manifest_invalid')
27
+ const input = value as Record<string, unknown>
28
+ if (typeof input.name !== 'string' || input.name.trim() === '') return fail('instruction_set_manifest_invalid_name')
29
+ const hasDescription = Object.hasOwn(input, 'description')
30
+ if (hasDescription && input.description !== null && typeof input.description !== 'string') return fail('instruction_set_manifest_invalid_description')
31
+ const description = hasDescription
32
+ ? input.description === '' ? null : input.description as string | null
33
+ : undefined
34
+ if (hasPinnedComponents(input.default)) return fail('instruction_set_component_unavailable')
35
+ if (!Array.isArray(input.shape) || input.shape.length === 0 || input.shape.some(key => typeof key !== 'string' || key === '') || new Set(input.shape).size !== input.shape.length) return fail('instruction_set_manifest_invalid_shape')
36
+ if (!Array.isArray(input.components)) return fail('instruction_set_manifest_invalid_components')
37
+ let root: string
38
+ try { root = realpathSync(dirname(path)) } catch { return fail('instruction_set_path_not_found') }
39
+ const seen = new Set<string>()
40
+ const loadedComponents: Array<InstructionSetComponent & { changedSinceSync: boolean; hasSyncBaseline: boolean }> = []
41
+ for (const raw of input.components) {
42
+ if (!raw || typeof raw !== 'object') return fail('instruction_set_manifest_invalid_component')
43
+ const component = raw as Record<string, unknown>
44
+ if (typeof component.key !== 'string' || component.key === '' || !input.shape.includes(component.key)) return fail(component.key && !input.shape.includes(component.key) ? 'instruction_set_key_outside_shape' : 'instruction_set_manifest_invalid_component')
45
+ const modelConfig = component.modelConfig === undefined ? undefined : component.modelConfig
46
+ if (modelConfig !== undefined && (typeof modelConfig !== 'string' || modelConfig === '')) return fail('instruction_set_manifest_invalid_component')
47
+ const identity = `${component.key}\u0000${modelConfig ?? ''}`; if (seen.has(identity)) return fail('instruction_set_duplicate_component'); seen.add(identity)
48
+ let text: string
49
+ if (typeof component.text === 'string' && component.path === undefined) text = component.text
50
+ else if (typeof component.path === 'string' && component.text === undefined) {
51
+ if (isAbsolute(component.path)) return fail('instruction_set_path_escape')
52
+ const candidate = resolve(root, component.path)
53
+ if (relative(root, candidate).startsWith('..')) return fail('instruction_set_path_escape')
54
+ if (!existsSync(candidate)) return fail('instruction_set_path_not_found')
55
+ let target: string; try { target = realpathSync(candidate) } catch { return fail('instruction_set_path_not_found') }
56
+ if (relative(root, target).startsWith('..')) return fail('instruction_set_path_escape')
57
+ try { text = readFileSync(target, 'utf8') } catch { return fail('instruction_set_path_not_found') }
58
+ if (Buffer.byteLength(text, 'utf8') > MAX_INSTRUCTION_SET_COMPONENT_BYTES) return fail('instruction_set_component_too_large')
59
+ } else return fail('instruction_set_manifest_invalid_component')
60
+ if (Buffer.byteLength(text, 'utf8') > MAX_INSTRUCTION_SET_COMPONENT_BYTES) return fail('instruction_set_component_too_large')
61
+ const hasSyncBaseline = typeof component.syncedContentSha256 === 'string'
62
+ if (component.syncedContentSha256 !== undefined && (!hasSyncBaseline || !/^[a-f0-9]{64}$/u.test(component.syncedContentSha256 as string))) return fail('instruction_set_manifest_invalid_component')
63
+ loadedComponents.push({
64
+ key: component.key,
65
+ ...(modelConfig === undefined ? {} : { modelConfig }),
66
+ text,
67
+ hasSyncBaseline,
68
+ changedSinceSync: hasSyncBaseline && sha256(text) !== component.syncedContentSha256,
69
+ })
70
+ }
71
+ for (const key of input.shape) if (!loadedComponents.some(component => component.key === key)) return fail('instruction_set_missing_shape_key')
72
+ const defaultIdentity = input.default && typeof input.default === 'object'
73
+ && typeof (input.default as Record<string, unknown>).modelConfigIdentity === 'string'
74
+ ? (input.default as Record<string, unknown>).modelConfigIdentity as string
75
+ : null
76
+ let components = loadedComponents
77
+ if (defaultIdentity) {
78
+ if (input.manifestVersion === 1 && (input.shape as string[]).some(key => {
79
+ const bare = loadedComponents.find(component => component.key === key && component.modelConfig === undefined)
80
+ const tagged = loadedComponents.find(component => component.key === key && component.modelConfig === defaultIdentity)
81
+ return bare && tagged && (!bare.hasSyncBaseline || !tagged.hasSyncBaseline)
82
+ })) return fail('instruction_set_sync_baseline_missing')
83
+ const changedDefaultKeys = new Set(loadedComponents.flatMap(component => (
84
+ component.modelConfig === undefined && component.hasSyncBaseline && component.changedSinceSync
85
+ ? [component.key]
86
+ : []
87
+ )))
88
+ const changedSameIdentityKeys = new Set(loadedComponents.flatMap(component => (
89
+ component.modelConfig === defaultIdentity && component.hasSyncBaseline && component.changedSinceSync
90
+ ? [component.key]
91
+ : []
92
+ )))
93
+ if ([...changedDefaultKeys].some(key => changedSameIdentityKeys.has(key))) return fail('instruction_set_conflicting_synced_edits')
94
+ if (changedDefaultKeys.size > 0) {
95
+ components = loadedComponents.filter(component => (
96
+ component.modelConfig !== defaultIdentity || !changedDefaultKeys.has(component.key)
97
+ ))
98
+ }
99
+ }
100
+ const namedProfiles = new Set([
101
+ ...(components.some(component => component.modelConfig === undefined) && defaultIdentity
102
+ ? [defaultIdentity]
103
+ : []),
104
+ ...components.flatMap(component => component.modelConfig ? [component.modelConfig] : []),
105
+ ])
106
+ const namedProfileHasPins = Array.isArray(input.profiles) && input.profiles.some(profile => {
107
+ if (!profile || typeof profile !== 'object') return false
108
+ const value = profile as Record<string, unknown>
109
+ return typeof value.modelConfigIdentity === 'string'
110
+ && namedProfiles.has(value.modelConfigIdentity)
111
+ && hasPinnedComponents(value.production)
112
+ })
113
+ if (namedProfileHasPins) return fail('instruction_set_component_unavailable')
114
+ return {
115
+ name: input.name,
116
+ ...(hasDescription ? { description } : {}),
117
+ shape: input.shape as string[],
118
+ components: components.map(({ key, modelConfig, text }) => ({ key, ...(modelConfig === undefined ? {} : { modelConfig }), text })),
119
+ }
120
+ }
@@ -0,0 +1,306 @@
1
+ import { authedFetch } from './http.js'
2
+ import { loadInstructionSetManifest, MAX_INSTRUCTION_SET_COMPONENT_BYTES, type InstructionSetManifest } from './instruction-set-manifest.js'
3
+ import { sanitizeHumanInlineText, sanitizeTerminalText } from './json-response.js'
4
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs'
5
+ import { join } from 'node:path'
6
+ import { createHash, randomUUID } from 'node:crypto'
7
+
8
+ export interface InstructionSetsCommandIo {
9
+ json: boolean
10
+ print: (line: string) => void
11
+ resolveProjectSlug: (provided: string | null) => Promise<string>
12
+ }
13
+
14
+ function positionalArgs(args: string[]): string[] {
15
+ const values: string[] = []
16
+ for (let index = 0; index < args.length; index += 1) {
17
+ const value = args[index]!
18
+ if (value.startsWith('--')) {
19
+ if (argValue(args, value) !== null) index += 1
20
+ continue
21
+ }
22
+ values.push(value)
23
+ }
24
+ return values
25
+ }
26
+
27
+ function argValue(args: string[], flag: string): string | null {
28
+ const index = args.indexOf(flag)
29
+ return index === -1 || !args[index + 1] || args[index + 1]!.startsWith('--')
30
+ ? null
31
+ : args[index + 1]!
32
+ }
33
+
34
+ async function responsePayload(response: Response, action: string): Promise<Record<string, unknown>> {
35
+ const payload = await response.json().catch(() => ({})) as Record<string, unknown>
36
+ if (!response.ok) {
37
+ throw new Error(`${action} failed (${response.status}): ${typeof payload.error === 'string' ? payload.error : response.statusText}`)
38
+ }
39
+ return payload
40
+ }
41
+
42
+ const SAFE_SEGMENT = /^[A-Za-z0-9._-]+$/u
43
+ export interface SyncComponent { body?: string; repoPath?: string; contentSha?: string; commitSha?: string }
44
+ export interface SyncMaterial { profileVersionId: string; versionNumber: number; modelConfigIdentity: string; resolvedFrom: string; components: Record<string, SyncComponent> }
45
+ export interface SyncProfile { modelConfigIdentity: string; resolvedFrom: string; production: SyncMaterial | null }
46
+ export interface SyncSet { name: string; slug?: string; description?: string | null; shape: string[]; default: SyncMaterial; profiles: SyncProfile[]; filteredTo?: string[] }
47
+ function safeSegment(value: string) { if (!SAFE_SEGMENT.test(value) || value === '.' || value === '..' || value.startsWith('.')) throw new Error('instruction_set_path_unsafe') }
48
+ function slug(identity: string) { return identity.replaceAll('/', '__').replace(/[^A-Za-z0-9._-]/gu, '_') }
49
+ function stable(value: unknown): string { return `${JSON.stringify(value, null, 2)}\n` }
50
+ function sha256(value: string): string { return createHash('sha256').update(value, 'utf8').digest('hex') }
51
+
52
+ export interface SyncFileOps { writeFileSync: typeof writeFileSync; renameSync?: typeof renameSync }
53
+
54
+ function writeMaterial(root: string, material: SyncMaterial, shape: string[], manifestRoot: string, fileOps: SyncFileOps = { writeFileSync }) {
55
+ const files: Record<string, string> = {}
56
+ const syncedContentSha256: Record<string, string> = {}
57
+ const pinnedComponents: Record<string, unknown> = {}
58
+ for (const key of [...shape].sort()) {
59
+ safeSegment(key)
60
+ const component = material.components[key]
61
+ if (typeof component?.body === 'string') {
62
+ const relative = `${manifestRoot}/${key}.md`
63
+ files[key] = relative
64
+ const target = join(root, ...relative.split('/'))
65
+ mkdirSync(join(target, '..'), { recursive: true })
66
+ fileOps.writeFileSync(target, component.body)
67
+ syncedContentSha256[key] = sha256(component.body)
68
+ } else if (component?.repoPath && component?.contentSha && component?.commitSha) pinnedComponents[key] = { repoPath: component.repoPath, contentSha: component.contentSha, commitSha: component.commitSha }
69
+ else throw new Error('instruction_set_unresolvable')
70
+ }
71
+ return { profileVersionId: material.profileVersionId, versionNumber: material.versionNumber, modelConfigIdentity: material.modelConfigIdentity, resolvedFrom: material.resolvedFrom, files, syncedContentSha256, ...(Object.keys(pinnedComponents).length ? { pinnedComponents } : {}) }
72
+ }
73
+
74
+ // Only the scratch paths THIS run created are ever removed; a user's own
75
+ // `.<set>.*.bak` in --out is never touched (PR #1668 review).
76
+ function removeOwnScratch(paths: Array<string | null>) {
77
+ for (const path of paths) if (path && existsSync(path)) rmSync(path, { recursive: true, force: true })
78
+ }
79
+
80
+ function existingDestinationIsSynced(destination: string, name: string) {
81
+ try {
82
+ if (!statSync(destination).isDirectory()) return false
83
+ const manifest = JSON.parse(readFileSync(join(destination, 'manifest.json'), 'utf8')) as { manifestVersion?: number; name?: string }
84
+ return manifest.manifestVersion === 1 && manifest.name === name
85
+ } catch { return false }
86
+ }
87
+
88
+ export function syncToDisk(out: string, set: SyncSet, fileOps: SyncFileOps = { writeFileSync }) {
89
+ safeSegment(set.name)
90
+ for (const key of set.shape) safeSegment(key)
91
+ const profileSlugs = new Set<string>()
92
+ for (const profile of set.profiles) {
93
+ const value = slug(profile.modelConfigIdentity)
94
+ safeSegment(value)
95
+ if (profileSlugs.has(value)) throw new Error('instruction_set_slug_collision')
96
+ profileSlugs.add(value)
97
+ }
98
+ mkdirSync(out, { recursive: true })
99
+ const destination = join(out, set.name)
100
+ if (existsSync(destination) && !existingDestinationIsSynced(destination, set.name)) throw new Error('instruction_set_sync_destination_not_synced')
101
+ const temp = join(out, `.${set.name}.${randomUUID()}.tmp`)
102
+ const move = fileOps.renameSync || renameSync
103
+ let backup: string | null = null
104
+ mkdirSync(temp)
105
+ try {
106
+ const defaultMaterial = writeMaterial(temp, set.default, set.shape, 'default', fileOps)
107
+ const profiles = set.profiles.map(profile => ({
108
+ modelConfigIdentity: profile.modelConfigIdentity, slug: slug(profile.modelConfigIdentity), resolvedFrom: profile.resolvedFrom,
109
+ production: profile.production ? writeMaterial(temp, profile.production, set.shape, `profiles/${slug(profile.modelConfigIdentity)}`, fileOps) : null,
110
+ })).sort((a, b) => a.modelConfigIdentity.localeCompare(b.modelConfigIdentity))
111
+ const components = [
112
+ ...Object.entries(defaultMaterial.files).map(([key, path]) => ({ key, path, syncedContentSha256: defaultMaterial.syncedContentSha256[key] })),
113
+ ...profiles.flatMap(profile => profile.production
114
+ ? Object.entries(profile.production.files).map(([key, path]) => ({ key, modelConfig: profile.modelConfigIdentity, path, syncedContentSha256: profile.production!.syncedContentSha256[key] }))
115
+ : []),
116
+ ]
117
+ const manifest = { manifestVersion: 1, name: set.name, ...(Object.hasOwn(set, 'description') ? { description: set.description ?? null } : {}), shape: set.shape, components, default: defaultMaterial, profiles, ...(set.filteredTo ? { filteredTo: [...set.filteredTo].sort() } : {}) }
118
+ fileOps.writeFileSync(join(temp, 'manifest.json'), stable(manifest))
119
+ backup = join(out, `.${set.name}.${randomUUID()}.bak`)
120
+ if (existsSync(destination)) move(destination, backup)
121
+ try { move(temp, destination) } catch (error) { if (existsSync(backup)) move(backup, destination); throw error }
122
+ removeOwnScratch([backup])
123
+ } catch (error) {
124
+ removeOwnScratch([temp])
125
+ if (backup && existsSync(backup) && !existsSync(destination)) move(backup, destination)
126
+ removeOwnScratch([backup])
127
+ throw error
128
+ }
129
+ }
130
+
131
+ export async function instructionSetsCommand(args: string[], io: InstructionSetsCommandIo): Promise<number> {
132
+ const positionals = positionalArgs(args)
133
+ const [subcommand, reference] = positionals
134
+ if (subcommand === 'default' && reference === 'move') {
135
+ const version = argValue(args, '--version')
136
+ if (!version || !/^[0-9]+$/u.test(version) || Number(version) < 1) throw new Error('--version must be a positive integer')
137
+ }
138
+ let writeManifest: InstructionSetManifest | undefined
139
+ if (subcommand === 'create' || subcommand === 'push') {
140
+ if (!reference || reference.startsWith('--')) throw new Error(subcommand === 'create'
141
+ ? 'Usage: orizu instructions create <manifest> --project <team/project> [--runner-version <id>] [--model-config <identity>] [--json]'
142
+ : 'Usage: orizu instructions push <manifest> --project <team/project> [--set <slug-or-exact-name>] [--runner-version <id>] [--json]')
143
+ writeManifest = loadInstructionSetManifest(reference)
144
+ }
145
+ const project = await io.resolveProjectSlug(argValue(args, '--project'))
146
+ if (subcommand === 'default') {
147
+ const operation = reference; const set = positionals[2]; const identity = argValue(args, '--model-config'); const version = argValue(args, '--version')
148
+ if ((operation !== 'show' && operation !== 'move') || !set) throw new Error('Usage: orizu instructions default show|move <set> --project <team/project> [--model-config <identity> --version <n>] [--json]')
149
+ if (operation === 'move' && (!identity || !version || !/^[0-9]+$/u.test(version) || Number(version) < 1)) throw new Error('--version must be a positive integer')
150
+ const path = `/api/cli/instruction-sets/${encodeURIComponent(set)}/default?project=${encodeURIComponent(project)}`
151
+ if (operation === 'show') {
152
+ const payload = await responsePayload(await authedFetch(path, { method: 'GET' }), 'Instruction sets default show')
153
+ if (io.json) io.print(JSON.stringify(payload)); else io.print(`Default: v${(payload.default as { versionNumber?: number } | undefined)?.versionNumber ?? '?'}`)
154
+ return 0
155
+ }
156
+ if (!io.json) {
157
+ const impact = await responsePayload(await authedFetch(path, { method: 'GET' }), 'Instruction sets default show')
158
+ const resolvesToDefault = Array.isArray(impact.resolvesToDefault) ? impact.resolvesToDefault.filter((item): item is string => typeof item === 'string') : []
159
+ io.print(`These model configs resolve to the default: ${resolvesToDefault.join(', ')}`)
160
+ }
161
+ const payload = await responsePayload(await authedFetch(path, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ modelConfigIdentity: identity, versionNumber: Number(version) }) }), 'Instruction sets default move')
162
+ if (io.json) io.print(JSON.stringify(payload)); else io.print(`Default moved to ${identity} v${version}`)
163
+ return 0
164
+ }
165
+ if (subcommand === 'shape') {
166
+ const operation = reference; const set = positionals[2]; const key = argValue(args, '--key'); const from = argValue(args, '--from')
167
+ if ((operation !== 'add' && operation !== 'remove') || !set || !key || (operation === 'add' && !from)) throw new Error('Usage: orizu instructions shape add|remove <set> --project <team/project> --key <key> [--from <manifest>] [--json]')
168
+ let component: { body: string } | undefined
169
+ if (operation === 'add') {
170
+ let manifest: unknown
171
+ try { manifest = JSON.parse(readFileSync(from!, 'utf8')) } catch { throw new Error('instruction_set_manifest_invalid_json') }
172
+ const source = manifest && typeof manifest === 'object' && Array.isArray((manifest as { components?: unknown }).components)
173
+ ? (manifest as { components: unknown[] }).components.find((item): item is { key?: unknown; text?: unknown } => Boolean(item && typeof item === 'object' && (item as { key?: unknown }).key === key))
174
+ : undefined
175
+ if (!source || typeof source.text !== 'string' || Buffer.byteLength(source.text, 'utf8') > MAX_INSTRUCTION_SET_COMPONENT_BYTES) throw new Error(`Instruction set manifest has no component for key: ${key}`)
176
+ component = { body: source.text }
177
+ }
178
+ const payload = await responsePayload(await authedFetch(`/api/cli/instruction-sets/${encodeURIComponent(set)}/shape?project=${encodeURIComponent(project)}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ operation, key, ...(component ? { component } : {}) }) }), `Instruction sets shape ${operation}`)
179
+ if (io.json) io.print(JSON.stringify(payload)); else {
180
+ io.print(`Shape ${operation === 'add' ? 'added' : 'removed'}: ${key}`)
181
+ const affected = Array.isArray(payload.affected) ? payload.affected : []
182
+ const identities = [...new Set(affected.flatMap(pointer => pointer && typeof pointer === 'object' && typeof (pointer as { modelConfigIdentity?: unknown }).modelConfigIdentity === 'string' ? [(pointer as { modelConfigIdentity: string }).modelConfigIdentity] : []))]
183
+ if (identities.length) io.print(`${set} does not resolve for these model configs until the pointers move: ${identities.join(', ')}`)
184
+ for (const pointer of affected) if (pointer && typeof pointer === 'object') {
185
+ const item = pointer as { modelConfigIdentity?: unknown; pointer?: unknown; stalePointerVersionNumber?: unknown; headVersionNumber?: unknown; branchedFromVersionNumber?: unknown }
186
+ if (typeof item.modelConfigIdentity === 'string' && (item.pointer === 'production' || item.pointer === 'default') && typeof item.headVersionNumber === 'number') {
187
+ const command = item.pointer === 'production' ? 'profiles promote' : 'default move'
188
+ const operatorAction = item.pointer === 'production' ? 'promote' : 'default move'
189
+ if (typeof item.stalePointerVersionNumber === 'number' && typeof item.branchedFromVersionNumber === 'number' && item.branchedFromVersionNumber !== item.stalePointerVersionNumber) io.print(`${operatorAction} would move ${item.pointer} from v${item.stalePointerVersionNumber}'s text to v${item.headVersionNumber} = v${item.branchedFromVersionNumber}'s text + ${key}`)
190
+ io.print(`Follow up: instructions ${command} ${set} --project ${project} --model-config ${item.modelConfigIdentity} --version ${item.headVersionNumber}`)
191
+ }
192
+ }
193
+ }
194
+ return 0
195
+ }
196
+ if (subcommand === 'profiles') {
197
+ const operation = reference; const set = positionals[2]; const identity = argValue(args, '--model-config')
198
+ if ((operation !== 'new' && operation !== 'promote' && operation !== 'rollback') || !set || !identity) throw new Error('Usage: orizu instructions profiles new|promote|rollback <set> --project <team/project> --model-config <identity> [--version <n>|--to <n>] [--json]')
199
+ const encodedSet = encodeURIComponent(set); const encodedIdentity = encodeURIComponent(identity)
200
+ const version = argValue(args, '--version'); const to = argValue(args, '--to')
201
+ if ((operation === 'promote' && (!version || !/^[0-9]+$/u.test(version) || Number(version) < 1)) || (operation === 'rollback' && (!to || !/^[0-9]+$/u.test(to) || Number(to) < 1))) throw new Error(operation === 'promote' ? '--version must be a positive integer' : '--to must be a positive integer')
202
+ const path = operation === 'new' ? `/api/cli/instruction-sets/${encodedSet}/profiles` : operation === 'promote' ? `/api/cli/instruction-sets/${encodedSet}/profiles/${encodedIdentity}/label` : `/api/cli/instruction-sets/${encodedSet}/profiles/${encodedIdentity}/rollback`
203
+ const body = operation === 'new' ? { modelConfigIdentity: identity } : operation === 'promote' ? { versionNumber: Number(version) } : { to: Number(to) }
204
+ const payload = await responsePayload(await authedFetch(`${path}?project=${encodeURIComponent(project)}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) }), `Instruction sets profiles ${operation}`)
205
+ if (io.json) io.print(JSON.stringify(payload))
206
+ else {
207
+ const profile = payload.profile as { modelConfigIdentity?: string; versionNumber?: number } | undefined
208
+ io.print(`${profile?.modelConfigIdentity || identity}: v${profile?.versionNumber ?? '?'} ${operation === 'new' ? 'created' : operation === 'promote' ? 'promoted' : 'rolled back'}`)
209
+ const mirrored = payload.mirroredPromptLabel as { promptName?: unknown; promptId?: unknown } | undefined
210
+ if (mirrored && (typeof mirrored.promptName === 'string' || typeof mirrored.promptId === 'string')) io.print(`also moved production for prompt ${typeof mirrored.promptName === 'string' ? mirrored.promptName : mirrored.promptId} (default profile → prompt label)`)
211
+ }
212
+ return 0
213
+ }
214
+ if (subcommand === 'create' || subcommand === 'push') {
215
+ const manifest = writeManifest!; const modelConfig = argValue(args, '--model-config'); const runnerVersion = argValue(args, '--runner-version')
216
+ const setReference = argValue(args, '--set') || manifest.name
217
+ const path = subcommand === 'create' ? '/api/cli/instruction-sets' : `/api/cli/instruction-sets/${encodeURIComponent(setReference)}/versions`
218
+ const body = subcommand === 'create'
219
+ ? { ...manifest, ...(modelConfig ? { modelConfigIdentity: modelConfig } : {}), ...(runnerVersion ? { runnerVersionId: runnerVersion } : {}) }
220
+ : { shape: manifest.shape, components: manifest.components, ...(Object.hasOwn(manifest, 'description') ? { description: manifest.description } : {}), ...(runnerVersion ? { runnerVersionId: runnerVersion } : {}) }
221
+ const payload = await responsePayload(await authedFetch(`${path}?project=${encodeURIComponent(project)}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) }), `Instruction sets ${subcommand}`)
222
+ if (io.json) io.print(JSON.stringify(payload))
223
+ else {
224
+ const set = payload.instructionSet as { name?: string; profiles?: unknown[] } | undefined
225
+ const pushed = Array.isArray(payload.pushed) ? payload.pushed : []
226
+ const unchanged = Array.isArray(payload.unchanged) ? payload.unchanged : []
227
+ const skipped = Array.isArray(payload.skipped) ? payload.skipped : []
228
+ if (subcommand === 'create') {
229
+ const profiles = Array.isArray(set?.profiles) ? set.profiles : []
230
+ io.print(`${set?.name || manifest.name}: ${profiles.length} profile(s) created`)
231
+ } else {
232
+ const describe = (value: unknown) => {
233
+ if (typeof value === 'string') return value
234
+ if (value && typeof value === 'object') {
235
+ const row = value as { modelConfigIdentity?: unknown; versionNumber?: unknown }
236
+ return `${typeof row.modelConfigIdentity === 'string' ? row.modelConfigIdentity : 'unknown'}${typeof row.versionNumber === 'number' ? ` v${row.versionNumber}` : ''}`
237
+ }
238
+ return 'unknown'
239
+ }
240
+ io.print(`${set?.name || manifest.name}: pushed ${pushed.map(describe).join(', ') || 'none'}; unchanged ${unchanged.map(describe).join(', ') || 'none'}; skipped ${skipped.map(describe).join(', ') || 'none'}`)
241
+ }
242
+ }
243
+ return 0
244
+ }
245
+ if (subcommand === 'archive' || subcommand === 'restore') {
246
+ if (!reference || reference.startsWith('--')) throw new Error(`Usage: orizu instructions ${subcommand} <slug-or-exact-name> --project <team/project> [--json]`)
247
+ const archived = subcommand === 'archive'
248
+ const payload = await responsePayload(await authedFetch(`/api/cli/instruction-sets/${encodeURIComponent(reference)}?project=${encodeURIComponent(project)}`, {
249
+ method: 'PATCH',
250
+ headers: { 'content-type': 'application/json' },
251
+ body: JSON.stringify({ archived }),
252
+ }), `Instructions ${subcommand}`)
253
+ if (io.json) io.print(JSON.stringify(payload))
254
+ else {
255
+ const set = payload.instructionSet as { name?: string; slug?: string } | undefined
256
+ const identity = set?.slug && set.slug !== set.name ? `${set.name || reference} (${set.slug})` : set?.name || set?.slug || reference
257
+ io.print(`${archived ? 'Archived' : 'Restored'} instruction set ${identity}`)
258
+ }
259
+ return 0
260
+ }
261
+ const status = argValue(args, '--status') || 'active'
262
+ if (subcommand !== 'list' && subcommand !== 'show' && subcommand !== 'sync') throw new Error('Usage: orizu instructions list|show|sync|archive|restore')
263
+ if (subcommand === 'sync') {
264
+ const output = argValue(args, '--out')
265
+ if (!reference || !output) throw new Error('Usage: orizu instructions sync <set> --out <dir> --project <team/project> [--model-config <identity>] [--json]')
266
+ const modelConfig = argValue(args, '--model-config')
267
+ const path = `/api/cli/instruction-sets/${encodeURIComponent(reference)}/sync?project=${encodeURIComponent(project)}${modelConfig ? `&modelConfig=${encodeURIComponent(modelConfig)}` : ''}`
268
+ const payload = await responsePayload(await authedFetch(path, { method: 'GET' }), 'Instruction sets sync')
269
+ const set = payload.instructionSet as SyncSet
270
+ if (!set || (set.slug !== reference && set.name !== reference) || (modelConfig && (!Array.isArray(set.filteredTo) || set.filteredTo.length !== 1 || set.filteredTo[0] !== modelConfig))) {
271
+ throw new Error('instruction_set_sync_response_mismatch')
272
+ }
273
+ syncToDisk(output, set)
274
+ if (io.json) io.print(JSON.stringify(payload)); else io.print(`Synced ${set.name} to ${join(output, set.name)}`)
275
+ return 0
276
+ }
277
+ if (subcommand === 'show' && (!reference || reference.startsWith('--'))) throw new Error('Instruction set name is required')
278
+ if (status !== 'active' && status !== 'archived' && status !== 'all') throw new Error('--status must be active, archived, or all')
279
+
280
+ const query = `project=${encodeURIComponent(project)}&status=${encodeURIComponent(status)}`
281
+ const path = subcommand === 'list'
282
+ ? `/api/cli/instruction-sets?${query}`
283
+ : `/api/cli/instruction-sets/${encodeURIComponent(reference!)}?${query}`
284
+ const payload = await responsePayload(await authedFetch(path, { method: 'GET' }), `Instruction sets ${subcommand}`)
285
+ if (io.json) {
286
+ io.print(JSON.stringify(payload))
287
+ return 0
288
+ }
289
+ if (subcommand === 'list') {
290
+ const sets = Array.isArray(payload.instructionSets) ? payload.instructionSets : []
291
+ for (const item of sets) {
292
+ const set = item as { name?: string; slug?: string; description?: string | null; shape?: string[]; status?: string }
293
+ io.print(`${set.name || 'unnamed'}${set.slug ? ` [${set.slug}]` : ''}${set.status === 'archived' ? ' [archived]' : ''}${set.shape ? ` (${set.shape.join(', ')})` : ''}`)
294
+ if (set.description) io.print(` ${sanitizeHumanInlineText(sanitizeTerminalText, set.description)}`)
295
+ }
296
+ return 0
297
+ }
298
+ const set = payload.instructionSet as { name?: string; description?: string | null; shape?: string[]; status?: string; default?: { versionNumber?: number } | null; profiles?: Array<{ modelConfigIdentity?: string | null; production?: { versionNumber?: number } | null; latestVersionNumber?: number | null }> } | undefined
299
+ io.print(`${set?.name || reference}${set?.status === 'archived' ? ' [archived]' : ''}: ${set?.shape?.join(', ') || ''}`)
300
+ if (set?.description) io.print(`Description: ${sanitizeHumanInlineText(sanitizeTerminalText, set.description)}`)
301
+ if (set?.default) io.print(`Default: v${set.default.versionNumber ?? '?'}`)
302
+ for (const profile of set?.profiles || []) {
303
+ io.print(`${profile.modelConfigIdentity || 'unspecified'}: production ${profile.production ? `v${profile.production.versionNumber}` : '—'}, latest ${profile.latestVersionNumber ?? '—'}`)
304
+ }
305
+ return 0
306
+ }
@@ -1,6 +1,8 @@
1
1
  import { readFileSync } from 'fs'
2
2
  import { basename } from 'path'
3
3
 
4
+ import { hasCanonicalReportMarkdownContent } from './report-markdown-blankness.js'
5
+
4
6
  export const MARKDOWN_REPORT_MAX_BYTES = 2 * 1024 * 1024
5
7
 
6
8
  function getArg(args: readonly string[], name: string): string | null {
@@ -20,6 +22,12 @@ function rejectDashPrefixedOptionValue(name: string, value: string | null) {
20
22
  }
21
23
  }
22
24
 
25
+ function rejectMissingOptionValue(args: readonly string[], name: string) {
26
+ if (args.some((arg, index) => arg === name && index + 1 >= args.length)) {
27
+ throw new Error(`${name} requires a value`)
28
+ }
29
+ }
30
+
23
31
  function readSourceFile(pathArg: string): string {
24
32
  const expandedPath = expandHomePath(pathArg)
25
33
  try {
@@ -42,6 +50,16 @@ export function readMarkdownReportInput(
42
50
  args: readonly string[],
43
51
  reportLabel: 'Optimization' | 'Prompt' | 'Task'
44
52
  ): MarkdownReportInput | null {
53
+ if (args.some(arg => arg.startsWith('--report='))) {
54
+ throw new Error('use --report <markdown|@file> with a space, not =')
55
+ }
56
+ if (args.some(arg => arg.startsWith('--report-file='))) {
57
+ throw new Error('use --report-file <path> with a space, not =')
58
+ }
59
+
60
+ rejectMissingOptionValue(args, '--report')
61
+ rejectMissingOptionValue(args, '--report-file')
62
+
45
63
  const report = getArg(args, '--report')
46
64
  const reportFile = getArg(args, '--report-file')
47
65
 
@@ -69,7 +87,7 @@ export function readMarkdownReportInput(
69
87
  sourceName = 'inline'
70
88
  }
71
89
 
72
- if (!markdown.trim()) {
90
+ if (!hasCanonicalReportMarkdownContent(markdown)) {
73
91
  throw new Error(`${reportLabel} report markdown must not be blank`)
74
92
  }
75
93
  if (Buffer.byteLength(markdown, 'utf8') > MARKDOWN_REPORT_MAX_BYTES) {
@@ -0,0 +1,119 @@
1
+ import { readFileSync } from 'node:fs'
2
+
3
+ import { authedFetch } from './http.js'
4
+
5
+ export type CliFetcher = (path: string, init?: RequestInit) => Promise<Response>
6
+
7
+ export interface ModelConfigSettingsVersion {
8
+ versionNumber: number
9
+ settings: Record<string, unknown>
10
+ }
11
+
12
+ export interface ModelConfig {
13
+ identity: string
14
+ displayName: string
15
+ currentSettingsVersion: ModelConfigSettingsVersion
16
+ createdAt: string
17
+ }
18
+
19
+ export interface ModelConfigsCommandIo {
20
+ json: boolean
21
+ print: (line: string) => void
22
+ fetcher?: CliFetcher
23
+ resolveProjectSlug?: (arg: string | null) => Promise<string>
24
+ }
25
+
26
+ function argValue(args: string[], flag: string): string | null {
27
+ const index = args.lastIndexOf(flag)
28
+ return index === -1 || !args[index + 1] || args[index + 1]!.startsWith('--') ? null : args[index + 1]!
29
+ }
30
+
31
+ function positionalArgs(args: string[]): string[] {
32
+ const values: string[] = []
33
+ for (let index = 0; index < args.length; index += 1) {
34
+ if (args[index]!.startsWith('--')) {
35
+ if (args[index + 1] && !args[index + 1]!.startsWith('--')) index += 1
36
+ } else values.push(args[index]!)
37
+ }
38
+ return values
39
+ }
40
+
41
+ function readSettings(value: string | null, defaultToEmpty = false): Record<string, unknown> {
42
+ if (!value) {
43
+ if (defaultToEmpty) return {}
44
+ throw new Error('--settings is required')
45
+ }
46
+ const source = value.startsWith('@') ? readFileSync(value.slice(1), 'utf8') : value
47
+ const parsed: unknown = JSON.parse(source)
48
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
49
+ throw new Error('--settings must contain a JSON object')
50
+ }
51
+ return parsed as Record<string, unknown>
52
+ }
53
+
54
+ async function responseMessage(response: Response): Promise<string> {
55
+ try {
56
+ const body = await response.clone().json() as Record<string, unknown>
57
+ return typeof body.error === 'string' ? body.error : response.statusText
58
+ } catch {
59
+ return response.statusText
60
+ }
61
+ }
62
+
63
+ async function requestJson(fetcher: CliFetcher, path: string, init?: RequestInit): Promise<unknown> {
64
+ const response = await fetcher(path, init)
65
+ if (!response.ok) throw new Error(`Model config request failed (${response.status}): ${await responseMessage(response)}`)
66
+ return response.json()
67
+ }
68
+
69
+ function renderModelConfig(config: ModelConfig): string {
70
+ return `${config.identity} ${config.displayName} v${config.currentSettingsVersion.versionNumber}`
71
+ }
72
+
73
+ export async function modelConfigsCommand(args: string[], io: ModelConfigsCommandIo): Promise<number> {
74
+ const positional = positionalArgs(args)
75
+ const [command, action, identity] = positional
76
+ const resolveProjectSlug = io.resolveProjectSlug
77
+ if (!resolveProjectSlug) throw new Error('Project resolver unavailable')
78
+ const projectArg = argValue(args, '--project')
79
+ const project = projectArg || await resolveProjectSlug(null)
80
+ const fetcher = io.fetcher ?? authedFetch
81
+ const root = `/api/cli/model-configs?project=${encodeURIComponent(project)}`
82
+ let result: unknown
83
+
84
+ if (command === 'list' && !action) {
85
+ result = await requestJson(fetcher, root, { method: 'GET' })
86
+ if (io.json) io.print(JSON.stringify(result))
87
+ else for (const config of ((result as { modelConfigs?: ModelConfig[] }).modelConfigs || [])) io.print(renderModelConfig(config))
88
+ return 0
89
+ }
90
+ if (command === 'show' && action && !identity) {
91
+ result = await requestJson(fetcher, `/api/cli/model-configs/${encodeURIComponent(action)}?project=${encodeURIComponent(project)}`, { method: 'GET' })
92
+ } else if (command === 'create' && action && !identity) {
93
+ result = await requestJson(fetcher, root, {
94
+ method: 'POST', headers: { 'content-type': 'application/json' },
95
+ body: JSON.stringify({ identity: action, displayName: argValue(args, '--name') || action, settings: readSettings(argValue(args, '--settings'), true) }),
96
+ })
97
+ } else if (command === 'settings' && action === 'set' && identity) {
98
+ result = await requestJson(fetcher, `/api/cli/model-configs/${encodeURIComponent(identity)}/settings?project=${encodeURIComponent(project)}`, {
99
+ method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ settings: readSettings(argValue(args, '--settings')) }),
100
+ })
101
+ } else if (command === 'copy' && action && !identity) {
102
+ const to = argValue(args, '--to')
103
+ if (!to) throw new Error('--to is required')
104
+ result = await requestJson(fetcher, `/api/cli/model-configs/${encodeURIComponent(action)}/copy?project=${encodeURIComponent(project)}`, {
105
+ method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ to }),
106
+ })
107
+ } else {
108
+ io.print('Usage: orizu model-configs <create|list|show|settings set|copy> [--project <team/project>] [--json]')
109
+ return 1
110
+ }
111
+
112
+ if (io.json) {
113
+ io.print(JSON.stringify(result))
114
+ } else {
115
+ const config = (result as { modelConfig: ModelConfig }).modelConfig
116
+ io.print(renderModelConfig(config))
117
+ }
118
+ return 0
119
+ }
@@ -0,0 +1,41 @@
1
+ import { extractErrorMessage } from './error-response.js'
2
+ import { sanitizeTerminalText } from './json-response.js'
3
+
4
+ export interface OptimizationsPromoteIo {
5
+ json: boolean
6
+ print: (line: string) => void
7
+ resolveProjectSlug: (projectArg: string | null) => Promise<string>
8
+ fetcher: (path: string, init?: RequestInit) => Promise<Response>
9
+ }
10
+
11
+ function option(args: readonly string[], name: string): string | null {
12
+ const index = args.indexOf(name)
13
+ return index === -1 || !args[index + 1] || args[index + 1].startsWith('--') ? null : args[index + 1]
14
+ }
15
+
16
+ export async function promoteOptimizationCommand(args: string[], io: OptimizationsPromoteIo): Promise<void> {
17
+ const runId = args.find(arg => !arg.startsWith('--') && arg !== option(args, '--candidate') && arg !== option(args, '--label') && arg !== option(args, '--project'))
18
+ const candidateId = option(args, '--candidate')
19
+ const label = option(args, '--label')
20
+ if (!runId || !candidateId || (label !== null && label !== 'production')) {
21
+ throw new Error('Usage: orizu optimizations promote <run-id> --candidate <id> [--label production] [--project <team/project>] [--json]')
22
+ }
23
+ const project = await io.resolveProjectSlug(option(args, '--project'))
24
+ const response = await io.fetcher(`/api/cli/optimization-runs/${encodeURIComponent(runId)}/promote?project=${encodeURIComponent(project)}`, {
25
+ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ candidateId, label }),
26
+ })
27
+ if (!response.ok) throw new Error(`Failed to promote optimization candidate: ${await extractErrorMessage(response)}`)
28
+ const data = await response.json() as { promptVersionId?: string; profileVersionId?: string; components?: Array<{ key: string; status: string }> }
29
+ if (io.json) {
30
+ io.print(JSON.stringify(data.profileVersionId
31
+ ? { profileVersionId: data.profileVersionId, components: data.components ?? [] }
32
+ : { promptVersionId: data.promptVersionId }))
33
+ return
34
+ }
35
+ if (data.profileVersionId) {
36
+ io.print(`Promoted profile version ${sanitizeTerminalText(data.profileVersionId)}`)
37
+ for (const component of data.components ?? []) io.print(`${sanitizeTerminalText(component.key)}: ${sanitizeTerminalText(component.status)}`)
38
+ return
39
+ }
40
+ io.print(`Promoted prompt version ${sanitizeTerminalText(data.promptVersionId ?? '')}`)
41
+ }