freeharness 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +108 -0
  3. package/README.md +134 -0
  4. package/canonical/HARVEST.yaml +858 -0
  5. package/canonical/PROVENANCE.yaml +740 -0
  6. package/canonical/agents/README.md +95 -0
  7. package/canonical/agents/agentic-architect.md +18 -0
  8. package/canonical/agents/database-reviewer.md +41 -0
  9. package/canonical/agents/explorer-ai-engineer-analyst.md +65 -0
  10. package/canonical/agents/pr-reviewer.md +96 -0
  11. package/canonical/agents/python-reviewer.md +55 -0
  12. package/canonical/agents/report-formatter.md +19 -0
  13. package/canonical/agents/security-reviewer.md +53 -0
  14. package/canonical/agents/test-writer.md +34 -0
  15. package/canonical/commands/fh-context.md +37 -0
  16. package/canonical/evals/promptfoo.redteam.yaml +108 -0
  17. package/canonical/hooks/cost-prices.json +14 -0
  18. package/canonical/hooks/freeharness-auto-memory.mjs +158 -0
  19. package/canonical/hooks/freeharness-config-guard.mjs +162 -0
  20. package/canonical/hooks/freeharness-context-monitor.mjs +198 -0
  21. package/canonical/hooks/freeharness-converge.mjs +227 -0
  22. package/canonical/hooks/freeharness-cost-tracker.mjs +1027 -0
  23. package/canonical/hooks/freeharness-memory-guard.mjs +57 -0
  24. package/canonical/hooks/freeharness-output-pruner.mjs +333 -0
  25. package/canonical/hooks/freeharness-precompact.mjs +323 -0
  26. package/canonical/hooks/freeharness-repeat-tool.mjs +208 -0
  27. package/canonical/hooks/freeharness-security-guidance.mjs +164 -0
  28. package/canonical/hooks/freeharness-session-start +583 -0
  29. package/canonical/hooks/hooks.auto-memory.claude-code.json +16 -0
  30. package/canonical/hooks/hooks.claude-code.json +17 -0
  31. package/canonical/hooks/hooks.config-guard.claude-code.json +16 -0
  32. package/canonical/hooks/hooks.context-monitor.claude-code.json +15 -0
  33. package/canonical/hooks/hooks.converge.claude-code.json +15 -0
  34. package/canonical/hooks/hooks.cost-tracker.claude-code.json +37 -0
  35. package/canonical/hooks/hooks.memory-guard.claude-code.json +16 -0
  36. package/canonical/hooks/hooks.output-pruner.claude-code.json +16 -0
  37. package/canonical/hooks/hooks.precompact.claude-code.json +15 -0
  38. package/canonical/hooks/hooks.repeat-tool.claude-code.json +25 -0
  39. package/canonical/hooks/hooks.security-guidance.claude-code.json +16 -0
  40. package/canonical/mcp/servers.json +20 -0
  41. package/canonical/openspec/config.base.yaml +89 -0
  42. package/canonical/openspec/schema.spec-driven.yaml +277 -0
  43. package/canonical/openspec/templates/data-contract.md +36 -0
  44. package/canonical/openspec/templates/design.md +84 -0
  45. package/canonical/openspec/templates/eval-plan.md +33 -0
  46. package/canonical/openspec/templates/follow-ups.md +2 -0
  47. package/canonical/openspec/templates/proposal.md +45 -0
  48. package/canonical/openspec/templates/spec.md +42 -0
  49. package/canonical/openspec/templates/tasks.md +38 -0
  50. package/canonical/profiles/local-llamacpp.LOCAL-MODELS.md +47 -0
  51. package/canonical/profiles/local-llamacpp.json +27 -0
  52. package/canonical/profiles/local-ollama.json +20 -0
  53. package/canonical/profiles/mcp.json +91 -0
  54. package/canonical/rules/CLAUDE.md +78 -0
  55. package/canonical/rules/project-CLAUDE.template.md +62 -0
  56. package/canonical/rules/routing.md +20 -0
  57. package/canonical/rules/safety.md +41 -0
  58. package/canonical/settings/settings.cache-hygiene.claude-code.json +5 -0
  59. package/canonical/skills/agent-evaluation/SKILL.md +102 -0
  60. package/canonical/skills/agent-evaluation/assets/evaluation_report_template.md +206 -0
  61. package/canonical/skills/agent-evaluation/evals/cases.yaml +106 -0
  62. package/canonical/skills/agent-evaluation/references/dataset-preparation.md +351 -0
  63. package/canonical/skills/agent-evaluation/references/scorers-constraints.md +165 -0
  64. package/canonical/skills/agent-evaluation/references/scorers.md +431 -0
  65. package/canonical/skills/agent-evaluation/references/setup-guide.md +252 -0
  66. package/canonical/skills/agent-evaluation/references/tracing-integration.md +164 -0
  67. package/canonical/skills/agent-evaluation/references/troubleshooting.md +514 -0
  68. package/canonical/skills/agent-evaluation/scripts/analyze_results.py +462 -0
  69. package/canonical/skills/agent-evaluation/scripts/create_dataset_template.py +382 -0
  70. package/canonical/skills/agent-evaluation/scripts/list_datasets.py +273 -0
  71. package/canonical/skills/agent-evaluation/scripts/run_evaluation_template.py +309 -0
  72. package/canonical/skills/agent-evaluation/scripts/setup_mlflow.py +353 -0
  73. package/canonical/skills/agent-evaluation/scripts/utils/__init__.py +27 -0
  74. package/canonical/skills/agent-evaluation/scripts/utils/env_validation.py +123 -0
  75. package/canonical/skills/agent-evaluation/scripts/utils/tracing_utils.py +108 -0
  76. package/canonical/skills/agent-evaluation/scripts/validate_agent_tracing.py +148 -0
  77. package/canonical/skills/agent-evaluation/scripts/validate_auth.py +240 -0
  78. package/canonical/skills/agent-evaluation/scripts/validate_environment.py +185 -0
  79. package/canonical/skills/agent-evaluation/scripts/validate_tracing_runtime.py +318 -0
  80. package/canonical/skills/agentic-architecture/SKILL.md +41 -0
  81. package/canonical/skills/agentic-architecture/evals/cases.yaml +94 -0
  82. package/canonical/skills/agentic-architecture/reference/context-engineering.md +75 -0
  83. package/canonical/skills/agentic-architecture/reference/patterns.md +76 -0
  84. package/canonical/skills/agentic-architecture/reference/reliability-observability.md +94 -0
  85. package/canonical/skills/agentic-architecture/reference/review-framework.md +59 -0
  86. package/canonical/skills/code-review/SKILL.md +52 -0
  87. package/canonical/skills/code-review/evals/cases.yaml +197 -0
  88. package/canonical/skills/git-workflow/SKILL.md +41 -0
  89. package/canonical/skills/git-workflow/evals/cases.yaml +92 -0
  90. package/canonical/skills/local-code/SKILL.md +24 -0
  91. package/canonical/skills/local-code/evals/cases.yaml +85 -0
  92. package/canonical/skills/local-code/scripts/query_llama.py +68 -0
  93. package/canonical/skills/report-formatting/SKILL.md +62 -0
  94. package/canonical/skills/report-formatting/evals/cases.yaml +83 -0
  95. package/canonical/skills/report-formatting/reference/ARCHITECTURE.md +135 -0
  96. package/canonical/skills/report-formatting/reference/HELPERS.md +120 -0
  97. package/canonical/skills/report-formatting/reference/PPTX.md +136 -0
  98. package/canonical/skills/report-formatting/reference/RELEASE.md +99 -0
  99. package/canonical/skills/report-formatting/reference/TEMPLATES.md +48 -0
  100. package/canonical/skills/report-formatting/reference/authoring.md +66 -0
  101. package/canonical/skills/report-formatting/scripts/architecture-template.md +271 -0
  102. package/canonical/skills/report-formatting/scripts/assets/claro-logo.png +0 -0
  103. package/canonical/skills/report-formatting/scripts/assets/claro-wordmark.svg +1 -0
  104. package/canonical/skills/report-formatting/scripts/build-architecture.js +57 -0
  105. package/canonical/skills/report-formatting/scripts/build-md-claro.js +224 -0
  106. package/canonical/skills/report-formatting/scripts/build-release.js +51 -0
  107. package/canonical/skills/report-formatting/scripts/check-env.js +58 -0
  108. package/canonical/skills/report-formatting/scripts/docmodel.js +283 -0
  109. package/canonical/skills/report-formatting/scripts/example-build.js +119 -0
  110. package/canonical/skills/report-formatting/scripts/example_build_ArchitectureReview_docx.js +195 -0
  111. package/canonical/skills/report-formatting/scripts/example_build_ExecutiveReport_docx.js +114 -0
  112. package/canonical/skills/report-formatting/scripts/package.json +17 -0
  113. package/canonical/skills/report-formatting/scripts/pptx/example_build_StatusReport_pptx.py +223 -0
  114. package/canonical/skills/report-formatting/scripts/pptx/example_build_WeeklyStatus_pptx.py +245 -0
  115. package/canonical/skills/report-formatting/scripts/pptx/pptx_office.py +144 -0
  116. package/canonical/skills/report-formatting/scripts/pptx/requirements.txt +7 -0
  117. package/canonical/skills/report-formatting/scripts/pptx/status_report_blocks.py +193 -0
  118. package/canonical/skills/report-formatting/scripts/pptx/theme_claro_pptx.py +473 -0
  119. package/canonical/skills/report-formatting/scripts/release-template.md +80 -0
  120. package/canonical/skills/report-formatting/scripts/render-mermaid.js +105 -0
  121. package/canonical/skills/report-formatting/scripts/theme-claro.js +403 -0
  122. package/canonical/skills/subagent-driven-development/SKILL.md +60 -0
  123. package/canonical/skills/subagent-driven-development/evals/cases.yaml +208 -0
  124. package/canonical/skills/subagent-driven-development/reference/brief.md +91 -0
  125. package/canonical/skills/subagent-driven-development/reference/handoff.md +118 -0
  126. package/canonical/skills/subagent-driven-development/scripts/validate-handoff.mjs +850 -0
  127. package/canonical/skills/systematic-debugging/SKILL.md +44 -0
  128. package/canonical/skills/systematic-debugging/evals/cases.yaml +90 -0
  129. package/canonical/skills/test-driven-development/SKILL.md +42 -0
  130. package/canonical/skills/test-driven-development/evals/cases.yaml +86 -0
  131. package/canonical/skills/test-driven-development/reference/writing-good-tests.md +52 -0
  132. package/canonical/skills/verification-before-completion/SKILL.md +53 -0
  133. package/canonical/skills/verification-before-completion/evals/cases.yaml +107 -0
  134. package/dist/adapters/content/language-lint.d.ts +46 -0
  135. package/dist/adapters/content/language-lint.js +191 -0
  136. package/dist/adapters/harness/claude-code.d.ts +57 -0
  137. package/dist/adapters/harness/claude-code.js +385 -0
  138. package/dist/adapters/harness/index.d.ts +3 -0
  139. package/dist/adapters/harness/index.js +17 -0
  140. package/dist/adapters/harness/opencode.d.ts +7 -0
  141. package/dist/adapters/harness/opencode.js +166 -0
  142. package/dist/adapters/harness/plugin.d.ts +22 -0
  143. package/dist/adapters/harness/plugin.js +257 -0
  144. package/dist/adapters/memory/doctor.d.ts +480 -0
  145. package/dist/adapters/memory/doctor.js +1217 -0
  146. package/dist/adapters/memory/vendored.d.ts +150 -0
  147. package/dist/adapters/memory/vendored.js +487 -0
  148. package/dist/adapters/package/node.d.ts +9 -0
  149. package/dist/adapters/package/node.js +20 -0
  150. package/dist/adapters/prompt/readline.d.ts +19 -0
  151. package/dist/adapters/prompt/readline.js +53 -0
  152. package/dist/adapters/sync/diff.d.ts +43 -0
  153. package/dist/adapters/sync/diff.js +380 -0
  154. package/dist/cli/cleanup.d.ts +86 -0
  155. package/dist/cli/cleanup.js +382 -0
  156. package/dist/cli/cost.d.ts +304 -0
  157. package/dist/cli/cost.js +501 -0
  158. package/dist/cli/doctor.d.ts +205 -0
  159. package/dist/cli/doctor.js +654 -0
  160. package/dist/cli/executor.d.ts +5 -0
  161. package/dist/cli/executor.js +48 -0
  162. package/dist/cli/plugin-validate.d.ts +37 -0
  163. package/dist/cli/plugin-validate.js +256 -0
  164. package/dist/cli/prefix.d.ts +68 -0
  165. package/dist/cli/prefix.js +218 -0
  166. package/dist/cli/profile.d.ts +170 -0
  167. package/dist/cli/profile.js +285 -0
  168. package/dist/cli/runner.d.ts +10 -0
  169. package/dist/cli/runner.js +27 -0
  170. package/dist/cli/uninstall.d.ts +65 -0
  171. package/dist/cli/uninstall.js +147 -0
  172. package/dist/index.d.ts +8 -0
  173. package/dist/index.js +989 -0
  174. package/dist/infra/dogfood.d.ts +31 -0
  175. package/dist/infra/dogfood.js +51 -0
  176. package/dist/infra/fsutil.d.ts +40 -0
  177. package/dist/infra/fsutil.js +143 -0
  178. package/dist/infra/manifest.d.ts +76 -0
  179. package/dist/infra/manifest.js +92 -0
  180. package/dist/infra/paths.d.ts +19 -0
  181. package/dist/infra/paths.js +74 -0
  182. package/dist/infra/routing.d.ts +4 -0
  183. package/dist/infra/routing.js +7 -0
  184. package/node_modules/@freeharness/core/dist/context.d.ts +30 -0
  185. package/node_modules/@freeharness/core/dist/context.js +1 -0
  186. package/node_modules/@freeharness/core/dist/index.d.ts +5 -0
  187. package/node_modules/@freeharness/core/dist/index.js +6 -0
  188. package/node_modules/@freeharness/core/dist/planner.d.ts +13 -0
  189. package/node_modules/@freeharness/core/dist/planner.js +18 -0
  190. package/node_modules/@freeharness/core/dist/ports.d.ts +90 -0
  191. package/node_modules/@freeharness/core/dist/ports.js +1 -0
  192. package/node_modules/@freeharness/core/dist/registry.d.ts +41 -0
  193. package/node_modules/@freeharness/core/dist/registry.js +124 -0
  194. package/node_modules/@freeharness/core/dist/tiers.d.ts +30 -0
  195. package/node_modules/@freeharness/core/dist/tiers.js +99 -0
  196. package/node_modules/@freeharness/core/package.json +34 -0
  197. package/node_modules/@freeharness/sdd/PROVENANCE.yaml +175 -0
  198. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.d.ts +2 -0
  199. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.js +166 -0
  200. package/node_modules/@freeharness/sdd/dist/src/index.d.ts +14 -0
  201. package/node_modules/@freeharness/sdd/dist/src/index.js +11 -0
  202. package/node_modules/@freeharness/sdd/dist/src/init.d.ts +39 -0
  203. package/node_modules/@freeharness/sdd/dist/src/init.js +190 -0
  204. package/node_modules/@freeharness/sdd/dist/src/root-resolver.d.ts +8 -0
  205. package/node_modules/@freeharness/sdd/dist/src/root-resolver.js +32 -0
  206. package/node_modules/@freeharness/sdd/dist/src/shim/archive.d.ts +81 -0
  207. package/node_modules/@freeharness/sdd/dist/src/shim/archive.js +483 -0
  208. package/node_modules/@freeharness/sdd/dist/src/shim/context.d.ts +4 -0
  209. package/node_modules/@freeharness/sdd/dist/src/shim/context.js +48 -0
  210. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.d.ts +57 -0
  211. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.js +279 -0
  212. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.d.ts +67 -0
  213. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.js +460 -0
  214. package/node_modules/@freeharness/sdd/dist/src/shim/list.d.ts +5 -0
  215. package/node_modules/@freeharness/sdd/dist/src/shim/list.js +95 -0
  216. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.d.ts +6 -0
  217. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.js +150 -0
  218. package/node_modules/@freeharness/sdd/dist/src/shim/schemas.d.ts +4 -0
  219. package/node_modules/@freeharness/sdd/dist/src/shim/schemas.js +23 -0
  220. package/node_modules/@freeharness/sdd/dist/src/shim/shared.d.ts +56 -0
  221. package/node_modules/@freeharness/sdd/dist/src/shim/shared.js +140 -0
  222. package/node_modules/@freeharness/sdd/dist/src/shim/status.d.ts +8 -0
  223. package/node_modules/@freeharness/sdd/dist/src/shim/status.js +85 -0
  224. package/node_modules/@freeharness/sdd/dist/src/shim/validate.d.ts +6 -0
  225. package/node_modules/@freeharness/sdd/dist/src/shim/validate.js +229 -0
  226. package/node_modules/@freeharness/sdd/dist/src/validate-change.d.ts +40 -0
  227. package/node_modules/@freeharness/sdd/dist/src/validate-change.js +114 -0
  228. package/node_modules/@freeharness/sdd/dist/src/validate.d.ts +24 -0
  229. package/node_modules/@freeharness/sdd/dist/src/validate.js +72 -0
  230. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.d.ts +130 -0
  231. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.js +981 -0
  232. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.d.ts +46 -0
  233. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.js +128 -0
  234. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.d.ts +26 -0
  235. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.js +32 -0
  236. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.d.ts +50 -0
  237. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.js +394 -0
  238. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.d.ts +15 -0
  239. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.js +49 -0
  240. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.d.ts +71 -0
  241. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.js +164 -0
  242. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.d.ts +11 -0
  243. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.js +21 -0
  244. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.d.ts +102 -0
  245. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.js +230 -0
  246. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.d.ts +18 -0
  247. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.js +138 -0
  248. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.d.ts +82 -0
  249. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.js +333 -0
  250. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.d.ts +12 -0
  251. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.js +110 -0
  252. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.d.ts +11 -0
  253. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.js +32 -0
  254. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.d.ts +33 -0
  255. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.js +149 -0
  256. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.d.ts +39 -0
  257. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.js +49 -0
  258. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.d.ts +12 -0
  259. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.js +31 -0
  260. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.d.ts +10 -0
  261. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.js +10 -0
  262. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.d.ts +12 -0
  263. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.js +26 -0
  264. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.d.ts +28 -0
  265. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.js +41 -0
  266. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.d.ts +23 -0
  267. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.js +25 -0
  268. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.d.ts +72 -0
  269. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.js +76 -0
  270. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.d.ts +39 -0
  271. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.js +53 -0
  272. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.d.ts +62 -0
  273. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.js +7 -0
  274. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.d.ts +35 -0
  275. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.js +47 -0
  276. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.d.ts +33 -0
  277. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.js +55 -0
  278. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.d.ts +11 -0
  279. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.js +11 -0
  280. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.d.ts +48 -0
  281. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.js +99 -0
  282. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.d.ts +19 -0
  283. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.js +18 -0
  284. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.d.ts +18 -0
  285. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.js +4 -0
  286. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.d.ts +19 -0
  287. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.js +207 -0
  288. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.d.ts +12 -0
  289. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.js +409 -0
  290. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.d.ts +9 -0
  291. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.js +673 -0
  292. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.d.ts +9 -0
  293. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.js +230 -0
  294. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.d.ts +12 -0
  295. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.js +550 -0
  296. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.d.ts +8 -0
  297. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.js +107 -0
  298. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.d.ts +12 -0
  299. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.js +228 -0
  300. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.d.ts +9 -0
  301. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.js +147 -0
  302. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.d.ts +9 -0
  303. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.js +571 -0
  304. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.d.ts +12 -0
  305. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.js +322 -0
  306. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.d.ts +7 -0
  307. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.js +7 -0
  308. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.d.ts +9 -0
  309. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.js +518 -0
  310. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.d.ts +9 -0
  311. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.js +176 -0
  312. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.d.ts +9 -0
  313. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.js +344 -0
  314. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.d.ts +39 -0
  315. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.js +54 -0
  316. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.d.ts +35 -0
  317. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.js +171 -0
  318. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.d.ts +27 -0
  319. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.js +210 -0
  320. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.d.ts +14 -0
  321. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.js +48 -0
  322. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.d.ts +22 -0
  323. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.js +186 -0
  324. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.d.ts +65 -0
  325. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.js +409 -0
  326. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.d.ts +55 -0
  327. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.js +98 -0
  328. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.d.ts +8 -0
  329. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.js +77 -0
  330. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.d.ts +44 -0
  331. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.js +116 -0
  332. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.d.ts +12 -0
  333. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.js +17 -0
  334. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.d.ts +72 -0
  335. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.js +30 -0
  336. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.d.ts +3 -0
  337. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.js +3 -0
  338. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.d.ts +17 -0
  339. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.js +14 -0
  340. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.d.ts +39 -0
  341. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.js +114 -0
  342. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.d.ts +45 -0
  343. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.js +105 -0
  344. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.d.ts +15 -0
  345. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.js +56 -0
  346. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.d.ts +17 -0
  347. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.js +1 -0
  348. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.d.ts +94 -0
  349. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.js +756 -0
  350. package/node_modules/@freeharness/sdd/package.json +57 -0
  351. package/node_modules/@freeharness/sdd/vendor/openspec/LICENSE.upstream +22 -0
  352. package/node_modules/@freeharness/sdd/vendor/openspec/assets/schema.upstream.yaml +232 -0
  353. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/README.md +19 -0
  354. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-apply-change/SKILL.md +187 -0
  355. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-archive-change/SKILL.md +181 -0
  356. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-bulk-archive-change/SKILL.md +338 -0
  357. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-continue-change/SKILL.md +117 -0
  358. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-explore/SKILL.md +342 -0
  359. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-ff-change/SKILL.md +116 -0
  360. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-new-change/SKILL.md +76 -0
  361. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-onboard/SKILL.md +560 -0
  362. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-propose/SKILL.md +162 -0
  363. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-sync-specs/SKILL.md +261 -0
  364. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-update-change/SKILL.md +90 -0
  365. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-verify-change/SKILL.md +174 -0
  366. package/package.json +70 -0
  367. package/provenance/canonical.PROVENANCE.yaml +740 -0
  368. package/provenance/claude-mem.LICENSE.upstream +202 -0
  369. package/provenance/memory.PROVENANCE.yaml +399 -0
  370. package/provenance/sdd.PROVENANCE.yaml +175 -0
  371. package/vendor-licenses/caveman.LICENSE +27 -0
  372. package/vendor-licenses/deepseek-harness.LICENSE +21 -0
  373. package/vendor-licenses/ecc.LICENSE +21 -0
  374. package/vendor-licenses/pi.LICENSE +21 -0
  375. package/vendor-licenses/superpowers.LICENSE +21 -0
@@ -0,0 +1,382 @@
1
+ """
2
+ Generate a template script for creating MLflow evaluation datasets.
3
+
4
+ This script creates a customized Python script for dataset creation,
5
+ handling both OSS MLflow and Databricks Unity Catalog scenarios.
6
+
7
+ Usage:
8
+ # Minimum required
9
+ python create_dataset_template.py --test-cases-file test_cases.txt
10
+
11
+ # With custom dataset name
12
+ python create_dataset_template.py --test-cases-file test_cases.txt --dataset-name my-eval
13
+
14
+ # For Databricks Unity Catalog
15
+ python create_dataset_template.py --test-cases-file test_cases.txt \\
16
+ --catalog main --schema ml --table eval_v1
17
+ """
18
+
19
+ import argparse
20
+ import datetime
21
+ import os
22
+ import subprocess
23
+ import sys
24
+
25
+ from utils import check_databricks_config, validate_env_vars
26
+
27
+
28
+ def parse_arguments():
29
+ """Parse command-line arguments."""
30
+ parser = argparse.ArgumentParser(description="Generate dataset creation script")
31
+ parser.add_argument(
32
+ "--test-cases-file",
33
+ required=True,
34
+ help="File with test cases (one per line, minimum 10)",
35
+ )
36
+ parser.add_argument(
37
+ "--dataset-name",
38
+ help="Dataset name (auto-generated if not provided)",
39
+ )
40
+ parser.add_argument("--catalog", help="UC catalog name (for Databricks)")
41
+ parser.add_argument("--schema", help="UC schema name (for Databricks)")
42
+ parser.add_argument("--table", help="UC table name (for Databricks)")
43
+ parser.add_argument("--output", default="create_evaluation_dataset.py", help="Output file name")
44
+ return parser.parse_args()
45
+
46
+
47
+ def load_test_cases_from_file(file_path: str) -> list[str]:
48
+ """Load test cases from file (one per line)."""
49
+ try:
50
+ with open(file_path) as f:
51
+ test_cases = [line.strip() for line in f if line.strip()]
52
+
53
+ if len(test_cases) < 10:
54
+ print(f"✗ File has only {len(test_cases)} test cases (minimum: 10)")
55
+ print(" Please add more test cases to the file")
56
+ sys.exit(1)
57
+
58
+ print(f"✓ Loaded {len(test_cases)} test cases from {file_path}")
59
+ return test_cases
60
+
61
+ except FileNotFoundError:
62
+ print(f"✗ File not found: {file_path}")
63
+ sys.exit(1)
64
+ except Exception as e:
65
+ print(f"✗ Error reading file: {e}")
66
+ sys.exit(1)
67
+
68
+
69
+ def get_uc_catalogs():
70
+ """Get available Unity Catalog catalogs."""
71
+ try:
72
+ code = """
73
+ from databricks import sdk
74
+ w = sdk.WorkspaceClient()
75
+ catalogs = w.catalogs.list()
76
+ for catalog in catalogs:
77
+ print(catalog.name)
78
+ """
79
+ result = subprocess.run(["python", "-c", code], capture_output=True, text=True, check=True)
80
+ return [line.strip() for line in result.stdout.strip().split("\n") if line.strip()]
81
+ except Exception:
82
+ return []
83
+
84
+
85
+ def get_uc_schemas(catalog: str):
86
+ """Get available schemas in a catalog."""
87
+ try:
88
+ code = f"""
89
+ from databricks import sdk
90
+ w = sdk.WorkspaceClient()
91
+ schemas = w.schemas.list(catalog_name='{catalog}')
92
+ for schema in schemas:
93
+ print(schema.name)
94
+ """
95
+ result = subprocess.run(["python", "-c", code], capture_output=True, text=True, check=True)
96
+ return [line.strip() for line in result.stdout.strip().split("\n") if line.strip()]
97
+ except Exception:
98
+ return []
99
+
100
+
101
+ def generate_dataset_creation_code(
102
+ tracking_uri: str,
103
+ experiment_id: str,
104
+ dataset_name: str,
105
+ test_cases: list[str],
106
+ catalog: str = None,
107
+ schema: str = None,
108
+ table: str = None,
109
+ ) -> str:
110
+ """Generate Python code for creating the dataset."""
111
+
112
+ # Escape test cases for Python code
113
+ test_cases_repr = repr(test_cases)
114
+
115
+ if catalog and schema and table:
116
+ # Databricks Unity Catalog version
117
+ uc_name = f"{catalog}.{schema}.{table}"
118
+ return f'''#!/usr/bin/env python3
119
+ """
120
+ Create MLflow evaluation dataset.
121
+
122
+ Generated by create_dataset_template.py
123
+ """
124
+
125
+ import mlflow
126
+ from mlflow.genai.datasets import create_dataset
127
+
128
+ # Set tracking URI
129
+ mlflow.set_tracking_uri("{tracking_uri}")
130
+
131
+ # Configuration
132
+ DATASET_NAME = "{uc_name}"
133
+ EXPERIMENT_ID = "{experiment_id}"
134
+
135
+ # Test cases
136
+ TEST_CASES = {test_cases_repr}
137
+
138
+ print("=" * 60)
139
+ print("Creating MLflow Evaluation Dataset")
140
+ print("=" * 60)
141
+ print(f"Dataset: {{DATASET_NAME}}")
142
+ print(f"Test cases: {{len(TEST_CASES)}}")
143
+ print()
144
+
145
+ # Create dataset
146
+ print("Creating dataset...")
147
+ try:
148
+ dataset = create_dataset(
149
+ name=DATASET_NAME,
150
+ source={{
151
+ "inputs": [
152
+ {{"query": query}}
153
+ for query in TEST_CASES
154
+ ]
155
+ }},
156
+ targets=[
157
+ {{"expected_output": "TODO: Add expected output"}}
158
+ for _ in TEST_CASES
159
+ ],
160
+ experiment_id=[EXPERIMENT_ID]
161
+ )
162
+
163
+ print(f"✓ Dataset created: {{DATASET_NAME}}")
164
+ print(f" Location: Unity Catalog table")
165
+ print(f" Queries: {{len(TEST_CASES)}}")
166
+ print()
167
+ print("=" * 60)
168
+ print("Next Steps")
169
+ print("=" * 60)
170
+ print()
171
+ print("1. Verify dataset in Databricks Unity Catalog")
172
+ print(f"2. Use in evaluation: python scripts/run_evaluation_template.py --dataset-name {uc_name}")
173
+ print()
174
+
175
+ except Exception as e:
176
+ print(f"✗ Error creating dataset: {{e}}")
177
+ import traceback
178
+ traceback.print_exc()
179
+ exit(1)
180
+ '''
181
+ else:
182
+ # OSS MLflow version (non-UC)
183
+ return f'''#!/usr/bin/env python3
184
+ """
185
+ Create MLflow evaluation dataset.
186
+
187
+ Generated by create_dataset_template.py
188
+ """
189
+
190
+ import mlflow
191
+ from mlflow.genai.datasets import create_dataset
192
+
193
+ # Set tracking URI
194
+ mlflow.set_tracking_uri("{tracking_uri}")
195
+
196
+ # Configuration
197
+ DATASET_NAME = "{dataset_name}"
198
+ EXPERIMENT_ID = "{experiment_id}"
199
+
200
+ # Test cases
201
+ TEST_CASES = {test_cases_repr}
202
+
203
+ print("=" * 60)
204
+ print("Creating MLflow Evaluation Dataset")
205
+ print("=" * 60)
206
+ print(f"Dataset: {{DATASET_NAME}}")
207
+ print(f"Test cases: {{len(TEST_CASES)}}")
208
+ print()
209
+
210
+ # Create dataset
211
+ print("Creating dataset...")
212
+ try:
213
+ dataset = create_dataset(
214
+ name=DATASET_NAME,
215
+ source={{
216
+ "inputs": [
217
+ {{"query": query}}
218
+ for query in TEST_CASES
219
+ ]
220
+ }},
221
+ targets=[
222
+ {{"expected_output": "TODO: Add expected output"}}
223
+ for _ in TEST_CASES
224
+ ],
225
+ experiment_id=[EXPERIMENT_ID]
226
+ )
227
+
228
+ print(f"✓ Dataset created: {{DATASET_NAME}}")
229
+ print(f" Queries: {{len(TEST_CASES)}}")
230
+ print()
231
+ print("=" * 60)
232
+ print("Next Steps")
233
+ print("=" * 60)
234
+ print()
235
+ print("1. Verify dataset: python scripts/list_datasets.py")
236
+ print(f"2. Use in evaluation: python scripts/run_evaluation_template.py --dataset-name {{DATASET_NAME}}")
237
+ print()
238
+
239
+ except Exception as e:
240
+ print(f"✗ Error creating dataset: {{e}}")
241
+ import traceback
242
+ traceback.print_exc()
243
+ exit(1)
244
+ '''
245
+
246
+
247
+ def main():
248
+ """Main workflow."""
249
+ args = parse_arguments()
250
+
251
+ print("=" * 60)
252
+ print("MLflow Dataset Creation Template Generator")
253
+ print("=" * 60)
254
+ print()
255
+
256
+ # Check environment
257
+ errors = validate_env_vars()
258
+ if errors:
259
+ print("✗ Environment validation failed:")
260
+ for error in errors:
261
+ print(f" - {error}")
262
+ print("\nRun scripts/setup_mlflow.py first")
263
+ sys.exit(1)
264
+
265
+ tracking_uri = os.getenv("MLFLOW_TRACKING_URI")
266
+ experiment_id = os.getenv("MLFLOW_EXPERIMENT_ID")
267
+
268
+ print(f"Tracking URI: {tracking_uri}")
269
+ print(f"Experiment ID: {experiment_id}")
270
+ print()
271
+
272
+ # Load test cases
273
+ print("Loading test cases...")
274
+ test_cases = load_test_cases_from_file(args.test_cases_file)
275
+ print()
276
+
277
+ # Check if Databricks
278
+ is_databricks, profile = check_databricks_config()
279
+
280
+ # Handle dataset configuration
281
+ if is_databricks:
282
+ print("✓ Detected Databricks configuration")
283
+ print()
284
+
285
+ # Check if UC args provided
286
+ if args.catalog and args.schema and args.table:
287
+ catalog = args.catalog
288
+ schema = args.schema
289
+ table = args.table
290
+ print(f"Using Unity Catalog: {catalog}.{schema}.{table}")
291
+ elif args.catalog or args.schema or args.table:
292
+ print("✗ For Databricks UC, all three args are required:")
293
+ print(" --catalog, --schema, --table")
294
+ sys.exit(1)
295
+ else:
296
+ # Try to get catalogs
297
+ print("Fetching available catalogs...")
298
+ catalogs = get_uc_catalogs()
299
+
300
+ if not catalogs:
301
+ print("✗ Could not fetch catalogs")
302
+ print(" Please specify manually:")
303
+ print(" --catalog <catalog> --schema <schema> --table <table>")
304
+ sys.exit(1)
305
+
306
+ # Auto-select first catalog
307
+ catalog = catalogs[0]
308
+ print(f"✓ Found {len(catalogs)} catalog(s), using: {catalog}")
309
+
310
+ # Get schemas
311
+ print(f"Fetching schemas in {catalog}...")
312
+ schemas = get_uc_schemas(catalog)
313
+
314
+ if not schemas:
315
+ print("✗ Could not fetch schemas")
316
+ print(" Please specify manually:")
317
+ print(" --catalog <catalog> --schema <schema> --table <table>")
318
+ sys.exit(1)
319
+
320
+ # Auto-select first schema
321
+ schema = schemas[0]
322
+ print(f"✓ Found {len(schemas)} schema(s), using: {schema}")
323
+
324
+ # Auto-generate table name
325
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
326
+ table = f"eval_{timestamp}"
327
+ print(f"✓ Auto-generated table name: {table}")
328
+
329
+ print()
330
+ dataset_name = None # UC uses catalog.schema.table
331
+ else:
332
+ # Non-Databricks: use simple dataset name
333
+ catalog = schema = table = None
334
+
335
+ if args.dataset_name:
336
+ dataset_name = args.dataset_name
337
+ print(f"Using dataset name: {dataset_name}")
338
+ else:
339
+ # Auto-generate dataset name
340
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
341
+ dataset_name = f"agent-eval-{timestamp}"
342
+ print(f"✓ Auto-generated dataset name: {dataset_name}")
343
+ print()
344
+
345
+ # Generate code
346
+ print("=" * 60)
347
+ print("Generating Dataset Creation Script")
348
+ print("=" * 60)
349
+
350
+ code = generate_dataset_creation_code(
351
+ tracking_uri, experiment_id, dataset_name, test_cases, catalog, schema, table
352
+ )
353
+
354
+ # Write to file
355
+ output_file = args.output
356
+ with open(output_file, "w") as f:
357
+ f.write(code)
358
+
359
+ print(f"\n✓ Script generated: {output_file}")
360
+ print()
361
+
362
+ # Make executable
363
+ try:
364
+ os.chmod(output_file, 0o755)
365
+ print(f"✓ Made executable: chmod +x {output_file}")
366
+ except Exception:
367
+ pass
368
+
369
+ print()
370
+ print("=" * 60)
371
+ print("Next Steps")
372
+ print("=" * 60)
373
+ print()
374
+ print(f"1. Review the generated script: {output_file}")
375
+ print(f"2. Execute it: python {output_file}")
376
+ print("3. Verify dataset was created: python scripts/list_datasets.py")
377
+ print()
378
+ print("=" * 60)
379
+
380
+
381
+ if __name__ == "__main__":
382
+ main()
@@ -0,0 +1,273 @@
1
+ """
2
+ List and compare MLflow evaluation datasets in an experiment.
3
+
4
+ This script discovers existing datasets before prompting to create new ones,
5
+ preventing duplicate work and helping users make informed choices.
6
+
7
+ Features:
8
+ - Diversity metrics (query length variability, unique vocabulary)
9
+ - Timeout protection for large experiments
10
+ - Multiple output formats (table, JSON, names-only)
11
+ - Sample query preview
12
+
13
+ Usage:
14
+ python scripts/list_datasets.py # Table format (default)
15
+ python scripts/list_datasets.py --format json # JSON output
16
+ python scripts/list_datasets.py --format names-only # Names only (for piping)
17
+ python scripts/list_datasets.py --detailed # Include diversity analysis
18
+
19
+ Environment variables required:
20
+ MLFLOW_TRACKING_URI
21
+ MLFLOW_EXPERIMENT_ID
22
+ """
23
+
24
+ import argparse
25
+ import json
26
+ import os
27
+ import signal
28
+ import sys
29
+
30
+ import numpy as np
31
+
32
+ from mlflow import MlflowClient
33
+ from mlflow.genai.datasets import get_dataset
34
+ from utils import validate_env_vars
35
+
36
+
37
+ class TimeoutError(Exception):
38
+ """Custom timeout exception."""
39
+
40
+
41
+ def timeout_handler(signum, frame):
42
+ """Handle timeout signal."""
43
+ raise TimeoutError()
44
+
45
+
46
+ def parse_arguments():
47
+ """Parse command-line arguments."""
48
+ parser = argparse.ArgumentParser(description="List and compare MLflow evaluation datasets")
49
+ parser.add_argument("--dataset-name", help="Specific dataset to display")
50
+ parser.add_argument(
51
+ "--show-samples", type=int, default=5, help="Number of sample queries to show (default: 5)"
52
+ )
53
+ parser.add_argument(
54
+ "--format",
55
+ choices=["table", "json", "names-only"],
56
+ default="table",
57
+ help="Output format (default: table)",
58
+ )
59
+ parser.add_argument(
60
+ "--timeout",
61
+ type=int,
62
+ default=30,
63
+ help="Timeout in seconds for dataset search (default: 30)",
64
+ )
65
+ parser.add_argument(
66
+ "--detailed", action="store_true", help="Include detailed diversity analysis (slower)"
67
+ )
68
+ return parser.parse_args()
69
+
70
+
71
+ def calculate_diversity_metrics(queries):
72
+ """Calculate diversity metrics for a list of queries."""
73
+ if not queries:
74
+ return 0.0, 0.0, 0.0
75
+
76
+ # Query length statistics
77
+ lengths = [len(q) for q in queries]
78
+ avg_length = np.mean(lengths)
79
+ std_length = np.std(lengths)
80
+
81
+ # Unique word count (simple diversity measure)
82
+ all_words = set()
83
+ for query in queries:
84
+ words = query.lower().split()
85
+ all_words.update(words)
86
+
87
+ unique_word_ratio = len(all_words) / len(queries) if queries else 0
88
+
89
+ return avg_length, std_length, unique_word_ratio
90
+
91
+
92
+ def classify_diversity(std_length, unique_word_ratio, query_count):
93
+ """Classify diversity as HIGH, MEDIUM, or LOW."""
94
+ # Heuristics based on variability and vocabulary
95
+ if query_count < 5:
96
+ return "LOW (too few queries)"
97
+
98
+ if std_length > 30 and unique_word_ratio > 5:
99
+ return "HIGH"
100
+ elif std_length > 15 and unique_word_ratio > 3:
101
+ return "MEDIUM"
102
+ else:
103
+ return "LOW"
104
+
105
+
106
+ def get_datasets_with_timeout(client, experiment_ids, timeout_seconds):
107
+ """Get datasets with timeout protection."""
108
+ # Set alarm for timeout
109
+ signal.signal(signal.SIGALRM, timeout_handler)
110
+ signal.alarm(timeout_seconds)
111
+
112
+ try:
113
+ datasets = client.search_datasets(experiment_ids=experiment_ids)
114
+ signal.alarm(0) # Cancel alarm
115
+ return datasets
116
+ except TimeoutError:
117
+ signal.alarm(0)
118
+ print(f"⚠ Dataset search timed out after {timeout_seconds}s")
119
+ print(" Try: --timeout <seconds> to increase timeout")
120
+ return []
121
+ except Exception as e:
122
+ signal.alarm(0)
123
+ print(f"✗ Error searching datasets: {str(e)[:100]}")
124
+ return []
125
+
126
+
127
+ def print_table_format(dataset_info, args):
128
+ """Print datasets in table format."""
129
+ if not dataset_info:
130
+ print("\n✗ No datasets found in this experiment")
131
+ print("\nTo create a new dataset:")
132
+ print(" python scripts/create_dataset_template.py --test-cases-file test_cases.txt")
133
+ return
134
+
135
+ print(f"\n✓ Found {len(dataset_info)} dataset(s):")
136
+ print("=" * 80)
137
+
138
+ for i, info in enumerate(dataset_info, 1):
139
+ print(f"\n{i}. {info['name']}")
140
+ print(f" Queries: {info.get('count', '?')}")
141
+
142
+ if args.detailed:
143
+ if "avg_length" in info:
144
+ print(f" Avg length: {info['avg_length']:.1f} chars")
145
+ print(f" Std length: {info['std_length']:.1f} chars")
146
+ print(f" Unique words/query: {info['unique_word_ratio']:.1f}")
147
+ print(f" Diversity: {info.get('diversity', 'N/A')}")
148
+
149
+ if "samples" in info:
150
+ print(f"\n Sample queries:")
151
+ for j, sample in enumerate(info["samples"], 1):
152
+ preview = sample[:60] + "..." if len(sample) > 60 else sample
153
+ print(f" {j}. {preview}")
154
+
155
+ print("\n" + "=" * 80)
156
+ print("\nTo use a dataset in evaluation:")
157
+ print(' python scripts/run_evaluation_template.py --dataset-name "dataset_name"')
158
+
159
+
160
+ def print_json_format(dataset_info):
161
+ """Print datasets in JSON format."""
162
+ print(json.dumps(dataset_info, indent=2))
163
+
164
+
165
+ def print_names_only(dataset_info):
166
+ """Print dataset names only (one per line)."""
167
+ for info in dataset_info:
168
+ print(info["name"])
169
+
170
+
171
+ def main():
172
+ """Main workflow."""
173
+ args = parse_arguments()
174
+
175
+ print("=" * 80)
176
+ print("MLflow Evaluation Datasets")
177
+ print("=" * 80)
178
+
179
+ # Check environment using utility
180
+ errors = validate_env_vars()
181
+ if errors:
182
+ print("\n✗ Environment validation failed:")
183
+ for error in errors:
184
+ print(f" - {error}")
185
+ print("\nRun scripts/setup_mlflow.py to configure environment")
186
+ sys.exit(1)
187
+
188
+ experiment_id = os.getenv("MLFLOW_EXPERIMENT_ID")
189
+ print(f"\nExperiment ID: {experiment_id}")
190
+
191
+ # Get datasets
192
+ print("\nSearching for datasets...")
193
+ client = MlflowClient()
194
+
195
+ try:
196
+ if args.dataset_name:
197
+ # Search for specific dataset
198
+ print(f" Looking for: {args.dataset_name}")
199
+ datasets = get_datasets_with_timeout(client, [experiment_id], args.timeout)
200
+ datasets = [d for d in datasets if d.name == args.dataset_name]
201
+
202
+ if not datasets:
203
+ print(f"\n✗ Dataset '{args.dataset_name}' not found")
204
+ sys.exit(1)
205
+ else:
206
+ # Get all datasets
207
+ datasets = get_datasets_with_timeout(client, [experiment_id], args.timeout)
208
+
209
+ except Exception as e:
210
+ print(f"\n✗ Error: {str(e)[:200]}")
211
+ sys.exit(1)
212
+
213
+ # Process datasets
214
+ dataset_info = []
215
+
216
+ for dataset in datasets:
217
+ info = {"name": dataset.name}
218
+
219
+ # Try to load dataset for detailed info
220
+ if args.detailed or args.show_samples > 0:
221
+ try:
222
+ ds = get_dataset(dataset.name)
223
+ df = ds.to_df()
224
+
225
+ info["count"] = len(df)
226
+
227
+ # Extract queries (flexible extraction from various input formats)
228
+ queries = []
229
+ for _, row in df.iterrows():
230
+ inputs = row.get("inputs", {})
231
+ if isinstance(inputs, dict):
232
+ # Try common keys first, then use first non-empty value
233
+ query = (
234
+ inputs.get("query")
235
+ or inputs.get("question")
236
+ or inputs.get("input")
237
+ or inputs.get("prompt")
238
+ or next((v for v in inputs.values() if v), str(inputs))
239
+ )
240
+ queries.append(str(query))
241
+ else:
242
+ # If inputs is not a dict, use it directly
243
+ queries.append(str(inputs))
244
+
245
+ # Calculate diversity metrics
246
+ if queries and args.detailed:
247
+ avg_len, std_len, unique_ratio = calculate_diversity_metrics(queries)
248
+ info["avg_length"] = avg_len
249
+ info["std_length"] = std_len
250
+ info["unique_word_ratio"] = unique_ratio
251
+ info["diversity"] = classify_diversity(std_len, unique_ratio, len(queries))
252
+
253
+ # Sample queries
254
+ if queries and args.show_samples > 0:
255
+ info["samples"] = queries[: args.show_samples]
256
+
257
+ except Exception as e:
258
+ info["count"] = "?"
259
+ info["error"] = str(e)[:50]
260
+
261
+ dataset_info.append(info)
262
+
263
+ # Output in requested format
264
+ if args.format == "json":
265
+ print_json_format(dataset_info)
266
+ elif args.format == "names-only":
267
+ print_names_only(dataset_info)
268
+ else: # table
269
+ print_table_format(dataset_info, args)
270
+
271
+
272
+ if __name__ == "__main__":
273
+ main()