genoma-evolution 1.0.0

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 (445) hide show
  1. package/.brv/.obsidian/app.json +1 -0
  2. package/.brv/.obsidian/appearance.json +1 -0
  3. package/.brv/.obsidian/core-plugins.json +33 -0
  4. package/.brv/.obsidian/graph.json +22 -0
  5. package/.brv/.obsidian/workspace.json +195 -0
  6. package/.brv/Sin ti/314/201tulo 1.canvas" +1 -0
  7. package/.brv/Sin ti/314/201tulo 2.canvas" +1 -0
  8. package/.brv/Sin ti/314/201tulo.canvas" +1 -0
  9. package/.brv/_queue_status.json +1 -0
  10. package/.brv/config.json +5 -0
  11. package/.brv/context-tree/_index.md +60 -0
  12. package/.brv/context-tree/_manifest.json +165 -0
  13. package/.brv/context-tree/backend/_index.md +24 -0
  14. package/.brv/context-tree/backend/backend/_index.md +40 -0
  15. package/.brv/context-tree/backend/backend/init.abstract.md +0 -0
  16. package/.brv/context-tree/backend/backend/init.md +27 -0
  17. package/.brv/context-tree/backend/backend/init.overview.md +29 -0
  18. package/.brv/context-tree/backend/backend/job_tracker.abstract.md +1 -0
  19. package/.brv/context-tree/backend/backend/job_tracker.md +273 -0
  20. package/.brv/context-tree/backend/backend/job_tracker.overview.md +31 -0
  21. package/.brv/context-tree/backend/backend/main.abstract.md +0 -0
  22. package/.brv/context-tree/backend/backend/main.md +1292 -0
  23. package/.brv/context-tree/backend/backend/main.overview.md +30 -0
  24. package/.brv/context-tree/backend/backend/requirements.abstract.md +1 -0
  25. package/.brv/context-tree/backend/backend/requirements.md +37 -0
  26. package/.brv/context-tree/backend/backend/requirements.overview.md +28 -0
  27. package/.brv/context-tree/docs/_index.md +37 -0
  28. package/.brv/context-tree/docs/api/_index.md +54 -0
  29. package/.brv/context-tree/docs/api/context.md +11 -0
  30. package/.brv/context-tree/docs/api/hermes_api_openapi_specification.abstract.md +0 -0
  31. package/.brv/context-tree/docs/api/hermes_api_openapi_specification.md +468 -0
  32. package/.brv/context-tree/docs/api/hermes_api_openapi_specification.overview.md +44 -0
  33. package/.brv/context-tree/frontend/_index.md +48 -0
  34. package/.brv/context-tree/frontend/hermes_dashboard/_index.md +31 -0
  35. package/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.abstract.md +0 -0
  36. package/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.md +41 -0
  37. package/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.overview.md +34 -0
  38. package/.brv/context-tree/frontend/src/_index.md +53 -0
  39. package/.brv/context-tree/frontend/src/components/_index.md +52 -0
  40. package/.brv/context-tree/frontend/src/components/sidebar_navigation_component.abstract.md +0 -0
  41. package/.brv/context-tree/frontend/src/components/sidebar_navigation_component.md +161 -0
  42. package/.brv/context-tree/frontend/src/components/sidebar_navigation_component.overview.md +32 -0
  43. package/.brv/context-tree/frontend/src/context.md +10 -0
  44. package/.brv/context-tree/frontend/src/functioncallingpage.abstract.md +0 -0
  45. package/.brv/context-tree/frontend/src/functioncallingpage.md +34 -0
  46. package/.brv/context-tree/frontend/src/functioncallingpage.overview.md +26 -0
  47. package/.brv/context-tree/frontend/src/lib/_index.md +48 -0
  48. package/.brv/context-tree/frontend/src/lib/api_client_library.abstract.md +1 -0
  49. package/.brv/context-tree/frontend/src/lib/api_client_library.md +403 -0
  50. package/.brv/context-tree/frontend/src/lib/api_client_library.overview.md +69 -0
  51. package/.brv/context-tree/frontend/src/page.abstract.md +0 -0
  52. package/.brv/context-tree/frontend/src/page.md +103 -0
  53. package/.brv/context-tree/frontend/src/page.overview.md +7 -0
  54. package/.brv/context-tree/frontend/src/settingspage.abstract.md +0 -0
  55. package/.brv/context-tree/frontend/src/settingspage.md +124 -0
  56. package/.brv/context-tree/frontend/src/settingspage.overview.md +34 -0
  57. package/.brv/context-tree/frontend/src/sidebar.abstract.md +0 -0
  58. package/.brv/context-tree/frontend/src/sidebar.md +170 -0
  59. package/.brv/context-tree/frontend/src/sidebar.overview.md +25 -0
  60. package/.brv/context-tree/meta/_index.md +24 -0
  61. package/.brv/context-tree/meta/curation_context/_index.md +24 -0
  62. package/.brv/context-tree/meta/curation_context/empty_context.abstract.md +4 -0
  63. package/.brv/context-tree/meta/curation_context/empty_context.md +35 -0
  64. package/.brv/context-tree/meta/curation_context/empty_context.overview.md +20 -0
  65. package/.brv/dream-log/drm-1777341062653.json +33 -0
  66. package/.brv/dream-state.json +8 -0
  67. package/.brv/dream.lock +0 -0
  68. package/.brv/review-backups/docs/api/hermes_api_openapi_specification.md +468 -0
  69. package/.claude/settings.local.json +7 -0
  70. package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/app.json +1 -0
  71. package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/appearance.json +1 -0
  72. package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/core-plugins.json +33 -0
  73. package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/graph.json +22 -0
  74. package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/workspace.json +195 -0
  75. package/.claude/worktrees/phase-2-mcp/.brv/Sin t/303/255tulo 1.canvas" +1 -0
  76. package/.claude/worktrees/phase-2-mcp/.brv/Sin t/303/255tulo 2.canvas" +1 -0
  77. package/.claude/worktrees/phase-2-mcp/.brv/Sin t/303/255tulo.canvas" +1 -0
  78. package/.claude/worktrees/phase-2-mcp/.brv/_queue_status.json +1 -0
  79. package/.claude/worktrees/phase-2-mcp/.brv/config.json +5 -0
  80. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/_index.md +60 -0
  81. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/_manifest.json +165 -0
  82. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/_index.md +24 -0
  83. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/_index.md +40 -0
  84. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/init.abstract.md +0 -0
  85. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/init.md +27 -0
  86. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/init.overview.md +29 -0
  87. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/job_tracker.abstract.md +1 -0
  88. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/job_tracker.md +273 -0
  89. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/job_tracker.overview.md +31 -0
  90. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/main.abstract.md +0 -0
  91. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/main.md +1292 -0
  92. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/main.overview.md +30 -0
  93. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/requirements.abstract.md +1 -0
  94. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/requirements.md +37 -0
  95. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/requirements.overview.md +28 -0
  96. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/_index.md +37 -0
  97. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/_index.md +54 -0
  98. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/context.md +11 -0
  99. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/hermes_api_openapi_specification.abstract.md +0 -0
  100. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/hermes_api_openapi_specification.md +468 -0
  101. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/hermes_api_openapi_specification.overview.md +44 -0
  102. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/_index.md +48 -0
  103. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/_index.md +31 -0
  104. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.abstract.md +0 -0
  105. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.md +41 -0
  106. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.overview.md +34 -0
  107. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/_index.md +53 -0
  108. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/_index.md +52 -0
  109. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/sidebar_navigation_component.abstract.md +0 -0
  110. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/sidebar_navigation_component.md +161 -0
  111. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/sidebar_navigation_component.overview.md +32 -0
  112. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/context.md +10 -0
  113. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/functioncallingpage.abstract.md +0 -0
  114. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/functioncallingpage.md +34 -0
  115. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/functioncallingpage.overview.md +26 -0
  116. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/_index.md +48 -0
  117. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/api_client_library.abstract.md +1 -0
  118. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/api_client_library.md +403 -0
  119. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/api_client_library.overview.md +69 -0
  120. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/page.abstract.md +0 -0
  121. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/page.md +103 -0
  122. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/page.overview.md +7 -0
  123. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/settingspage.abstract.md +0 -0
  124. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/settingspage.md +124 -0
  125. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/settingspage.overview.md +34 -0
  126. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/sidebar.abstract.md +0 -0
  127. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/sidebar.md +170 -0
  128. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/sidebar.overview.md +25 -0
  129. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/_index.md +24 -0
  130. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/_index.md +24 -0
  131. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/empty_context.abstract.md +4 -0
  132. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/empty_context.md +35 -0
  133. package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/empty_context.overview.md +20 -0
  134. package/.claude/worktrees/phase-2-mcp/.brv/dream-log/drm-1777341062653.json +33 -0
  135. package/.claude/worktrees/phase-2-mcp/.brv/dream-state.json +8 -0
  136. package/.claude/worktrees/phase-2-mcp/.brv/dream.lock +0 -0
  137. package/.claude/worktrees/phase-2-mcp/.brv/review-backups/docs/api/hermes_api_openapi_specification.md +468 -0
  138. package/.claude/worktrees/phase-2-mcp/.claude/settings.local.json +13 -0
  139. package/.claude/worktrees/phase-2-mcp/.kilocode/package-lock.json +378 -0
  140. package/.claude/worktrees/phase-2-mcp/.kilocode/package.json +5 -0
  141. package/.claude/worktrees/phase-2-mcp/AGENTS.md +5 -0
  142. package/.claude/worktrees/phase-2-mcp/CLAUDE.md +29 -0
  143. package/.claude/worktrees/phase-2-mcp/QA_AUDIT_PLAN.md +156 -0
  144. package/.claude/worktrees/phase-2-mcp/README.md +316 -0
  145. package/.claude/worktrees/phase-2-mcp/agent-agnostic-evolution-dashboard.md +405 -0
  146. package/.claude/worktrees/phase-2-mcp/backend/__init__.py +0 -0
  147. package/.claude/worktrees/phase-2-mcp/backend/collectors/__init__.py +0 -0
  148. package/.claude/worktrees/phase-2-mcp/backend/collectors/claude_code_collector.py +277 -0
  149. package/.claude/worktrees/phase-2-mcp/backend/collectors/hermes_collector.py +68 -0
  150. package/.claude/worktrees/phase-2-mcp/backend/curator.py +512 -0
  151. package/.claude/worktrees/phase-2-mcp/backend/eval/__init__.py +19 -0
  152. package/.claude/worktrees/phase-2-mcp/backend/eval/engine.py +116 -0
  153. package/.claude/worktrees/phase-2-mcp/backend/eval/scorers.py +201 -0
  154. package/.claude/worktrees/phase-2-mcp/backend/generate_dataset.py +86 -0
  155. package/.claude/worktrees/phase-2-mcp/backend/job_tracker.py +232 -0
  156. package/.claude/worktrees/phase-2-mcp/backend/main.py +1746 -0
  157. package/.claude/worktrees/phase-2-mcp/backend/mcp_server.py +250 -0
  158. package/.claude/worktrees/phase-2-mcp/backend/promethean/__init__.py +24 -0
  159. package/.claude/worktrees/phase-2-mcp/backend/promethean/cycle_orchestrator.py +270 -0
  160. package/.claude/worktrees/phase-2-mcp/backend/promethean/delta_validator.py +191 -0
  161. package/.claude/worktrees/phase-2-mcp/backend/promethean/dspy_compiler.py +315 -0
  162. package/.claude/worktrees/phase-2-mcp/backend/promethean/gepa_strategist.py +213 -0
  163. package/.claude/worktrees/phase-2-mcp/backend/promethean/models.py +260 -0
  164. package/.claude/worktrees/phase-2-mcp/backend/promethean/skill_deployer.py +195 -0
  165. package/.claude/worktrees/phase-2-mcp/backend/promethean/trace_ingestion.py +142 -0
  166. package/.claude/worktrees/phase-2-mcp/backend/requirements.txt +6 -0
  167. package/.claude/worktrees/phase-2-mcp/backend/sdd_evolve.py +459 -0
  168. package/.claude/worktrees/phase-2-mcp/backend/skill_detector.py +227 -0
  169. package/.claude/worktrees/phase-2-mcp/backend/skill_registry.py +289 -0
  170. package/.claude/worktrees/phase-2-mcp/backend/storage/__init__.py +5 -0
  171. package/.claude/worktrees/phase-2-mcp/backend/storage/run_store.py +393 -0
  172. package/.claude/worktrees/phase-2-mcp/backend/storage/schema.sql +99 -0
  173. package/.claude/worktrees/phase-2-mcp/backend/validate_evolution.py +267 -0
  174. package/.claude/worktrees/phase-2-mcp/components.json +28 -0
  175. package/.claude/worktrees/phase-2-mcp/docs/api/hermes-api.openapi.yaml +438 -0
  176. package/.claude/worktrees/phase-2-mcp/docs/hero.svg +148 -0
  177. package/.claude/worktrees/phase-2-mcp/eslint.config.mjs +18 -0
  178. package/.claude/worktrees/phase-2-mcp/install.sh +245 -0
  179. package/.claude/worktrees/phase-2-mcp/next-env.d.ts +6 -0
  180. package/.claude/worktrees/phase-2-mcp/next.config.ts +32 -0
  181. package/.claude/worktrees/phase-2-mcp/package-lock.json +11936 -0
  182. package/.claude/worktrees/phase-2-mcp/package.json +41 -0
  183. package/.claude/worktrees/phase-2-mcp/pnpm-workspace.yaml +4 -0
  184. package/.claude/worktrees/phase-2-mcp/postcss.config.mjs +7 -0
  185. package/.claude/worktrees/phase-2-mcp/public/file.svg +1 -0
  186. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Bold.otf +0 -0
  187. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Heavy.otf +0 -0
  188. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Medium.otf +0 -0
  189. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Regular.otf +0 -0
  190. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Semibold.otf +0 -0
  191. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Bold.otf +0 -0
  192. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Heavy.otf +0 -0
  193. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Medium.otf +0 -0
  194. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Regular.otf +0 -0
  195. package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Semibold.otf +0 -0
  196. package/.claude/worktrees/phase-2-mcp/public/globe.svg +1 -0
  197. package/.claude/worktrees/phase-2-mcp/public/next.svg +1 -0
  198. package/.claude/worktrees/phase-2-mcp/public/theme-preview.html +257 -0
  199. package/.claude/worktrees/phase-2-mcp/public/vercel.svg +1 -0
  200. package/.claude/worktrees/phase-2-mcp/public/window.svg +1 -0
  201. package/.claude/worktrees/phase-2-mcp/run.sh +26 -0
  202. package/.claude/worktrees/phase-2-mcp/skills-lock.json +10 -0
  203. package/.claude/worktrees/phase-2-mcp/specs/event-schema.md +223 -0
  204. package/.claude/worktrees/phase-2-mcp/specs/examples/run.jsonl +3 -0
  205. package/.claude/worktrees/phase-2-mcp/src/app/api/[...path]/route.ts +55 -0
  206. package/.claude/worktrees/phase-2-mcp/src/app/api/auth/token/route.ts +22 -0
  207. package/.claude/worktrees/phase-2-mcp/src/app/evolution/page.tsx +589 -0
  208. package/.claude/worktrees/phase-2-mcp/src/app/favicon.ico +0 -0
  209. package/.claude/worktrees/phase-2-mcp/src/app/globals.css +321 -0
  210. package/.claude/worktrees/phase-2-mcp/src/app/layout.tsx +63 -0
  211. package/.claude/worktrees/phase-2-mcp/src/app/page.tsx +70 -0
  212. package/.claude/worktrees/phase-2-mcp/src/app/skills/page.tsx +369 -0
  213. package/.claude/worktrees/phase-2-mcp/src/components/ApiConfigCard.tsx +199 -0
  214. package/.claude/worktrees/phase-2-mcp/src/components/ColorBends.css +1 -0
  215. package/.claude/worktrees/phase-2-mcp/src/components/ColorBends.d.ts +1 -0
  216. package/.claude/worktrees/phase-2-mcp/src/components/ColorBends.jsx +1 -0
  217. package/.claude/worktrees/phase-2-mcp/src/components/CoreLoopToggle.tsx +111 -0
  218. package/.claude/worktrees/phase-2-mcp/src/components/EnvironmentStatus.tsx +176 -0
  219. package/.claude/worktrees/phase-2-mcp/src/components/EvolutionBackground.tsx +1 -0
  220. package/.claude/worktrees/phase-2-mcp/src/components/ReactQueryProvider.tsx +24 -0
  221. package/.claude/worktrees/phase-2-mcp/src/components/Sidebar.tsx +247 -0
  222. package/.claude/worktrees/phase-2-mcp/src/components/SkillDiffViewer.tsx +154 -0
  223. package/.claude/worktrees/phase-2-mcp/src/components/ThemeAwareBackground.tsx +67 -0
  224. package/.claude/worktrees/phase-2-mcp/src/components/ThemeToggle.tsx +54 -0
  225. package/.claude/worktrees/phase-2-mcp/src/components/WelcomeHero.tsx +77 -0
  226. package/.claude/worktrees/phase-2-mcp/src/components/bits/ClickSpark.tsx +116 -0
  227. package/.claude/worktrees/phase-2-mcp/src/components/bits/CountUp.tsx +98 -0
  228. package/.claude/worktrees/phase-2-mcp/src/components/bits/DarkSelect.tsx +95 -0
  229. package/.claude/worktrees/phase-2-mcp/src/components/bits/DecryptedText.tsx +161 -0
  230. package/.claude/worktrees/phase-2-mcp/src/components/bits/ElectricBorder.tsx +184 -0
  231. package/.claude/worktrees/phase-2-mcp/src/components/bits/GlitchText.tsx +34 -0
  232. package/.claude/worktrees/phase-2-mcp/src/components/bits/ShinyText.tsx +55 -0
  233. package/.claude/worktrees/phase-2-mcp/src/components/bits/SpotlightCard.tsx +42 -0
  234. package/.claude/worktrees/phase-2-mcp/src/components/bits/TextType.tsx +95 -0
  235. package/.claude/worktrees/phase-2-mcp/src/components/bits/index.ts +9 -0
  236. package/.claude/worktrees/phase-2-mcp/src/components/pages/CuratorPage.tsx +632 -0
  237. package/.claude/worktrees/phase-2-mcp/src/components/pages/DatasetPage.tsx +271 -0
  238. package/.claude/worktrees/phase-2-mcp/src/components/pages/EvolutionPage.tsx +676 -0
  239. package/.claude/worktrees/phase-2-mcp/src/components/pages/FunctionCallingPage.tsx +1 -0
  240. package/.claude/worktrees/phase-2-mcp/src/components/pages/LogsPage.tsx +272 -0
  241. package/.claude/worktrees/phase-2-mcp/src/components/pages/MetricsPage.tsx +246 -0
  242. package/.claude/worktrees/phase-2-mcp/src/components/pages/OverviewPage.tsx +420 -0
  243. package/.claude/worktrees/phase-2-mcp/src/components/pages/SettingsPage.tsx +88 -0
  244. package/.claude/worktrees/phase-2-mcp/src/components/pages/SkillStudioPage.tsx +376 -0
  245. package/.claude/worktrees/phase-2-mcp/src/components/ui/animated-theme-toggler.tsx +97 -0
  246. package/.claude/worktrees/phase-2-mcp/src/components/ui/button.tsx +67 -0
  247. package/.claude/worktrees/phase-2-mcp/src/components/ui/card.tsx +103 -0
  248. package/.claude/worktrees/phase-2-mcp/src/components/ui/input.tsx +19 -0
  249. package/.claude/worktrees/phase-2-mcp/src/components/ui/separator.tsx +28 -0
  250. package/.claude/worktrees/phase-2-mcp/src/components/ui/sheet.tsx +147 -0
  251. package/.claude/worktrees/phase-2-mcp/src/components/ui/sidebar.tsx +702 -0
  252. package/.claude/worktrees/phase-2-mcp/src/components/ui/skeleton.tsx +13 -0
  253. package/.claude/worktrees/phase-2-mcp/src/components/ui/theme-toggle.tsx +272 -0
  254. package/.claude/worktrees/phase-2-mcp/src/components/ui/tooltip.tsx +57 -0
  255. package/.claude/worktrees/phase-2-mcp/src/hooks/use-mobile.ts +19 -0
  256. package/.claude/worktrees/phase-2-mcp/src/lib/api.ts +455 -0
  257. package/.claude/worktrees/phase-2-mcp/src/lib/queryClient.ts +12 -0
  258. package/.claude/worktrees/phase-2-mcp/src/lib/utils.ts +6 -0
  259. package/.claude/worktrees/phase-2-mcp/stitch/agent_dashboard/DESIGN_SPEC.md +521 -0
  260. package/.claude/worktrees/phase-2-mcp/stitch/agent_dashboard/prototype.html +676 -0
  261. package/.claude/worktrees/phase-2-mcp/stitch/curator_workspace/code.html +448 -0
  262. package/.claude/worktrees/phase-2-mcp/stitch/curator_workspace/screen.png +0 -0
  263. package/.claude/worktrees/phase-2-mcp/stitch/datasets/code.html +479 -0
  264. package/.claude/worktrees/phase-2-mcp/stitch/datasets/screen.png +0 -0
  265. package/.claude/worktrees/phase-2-mcp/stitch/evolution_history/code.html +461 -0
  266. package/.claude/worktrees/phase-2-mcp/stitch/evolution_history/screen.png +0 -0
  267. package/.claude/worktrees/phase-2-mcp/stitch/hermes_dashboard/DESIGN.md +192 -0
  268. package/.claude/worktrees/phase-2-mcp/stitch/hermes_dashboard/DESIGN_SPEC.md +455 -0
  269. package/.claude/worktrees/phase-2-mcp/stitch/hermes_overview/code.html +399 -0
  270. package/.claude/worktrees/phase-2-mcp/stitch/hermes_overview/screen.png +0 -0
  271. package/.claude/worktrees/phase-2-mcp/stitch/live_logs/code.html +324 -0
  272. package/.claude/worktrees/phase-2-mcp/stitch/live_logs/screen.png +0 -0
  273. package/.claude/worktrees/phase-2-mcp/stitch/skill_hub/code.html +596 -0
  274. package/.claude/worktrees/phase-2-mcp/stitch/skill_hub/screen.png +0 -0
  275. package/.claude/worktrees/phase-2-mcp/stitch/system_metrics/code.html +527 -0
  276. package/.claude/worktrees/phase-2-mcp/stitch/system_metrics/screen.png +0 -0
  277. package/.claude/worktrees/phase-2-mcp/stitch/system_settings/code.html +257 -0
  278. package/.claude/worktrees/phase-2-mcp/stitch/system_settings/screen.png +0 -0
  279. package/.claude/worktrees/phase-2-mcp/test_dashboard.py +201 -0
  280. package/.claude/worktrees/phase-2-mcp/tests/collectors/__init__.py +0 -0
  281. package/.claude/worktrees/phase-2-mcp/tests/collectors/fixtures/sample_session.jsonl +7 -0
  282. package/.claude/worktrees/phase-2-mcp/tests/collectors/test_claude_code_collector.py +171 -0
  283. package/.claude/worktrees/phase-2-mcp/tests/collectors/test_hermes_collector.py +167 -0
  284. package/.claude/worktrees/phase-2-mcp/tests/eval/test_engine.py +234 -0
  285. package/.claude/worktrees/phase-2-mcp/tests/eval/test_scorers.py +249 -0
  286. package/.claude/worktrees/phase-2-mcp/tests/storage/__init__.py +0 -0
  287. package/.claude/worktrees/phase-2-mcp/tests/storage/test_run_store.py +359 -0
  288. package/.claude/worktrees/phase-2-mcp/tests/test_curator.py +559 -0
  289. package/.claude/worktrees/phase-2-mcp/tests/test_mcp_server.py +114 -0
  290. package/.claude/worktrees/phase-2-mcp/tsconfig.json +34 -0
  291. package/.env.example +72 -0
  292. package/.kilocode/package-lock.json +378 -0
  293. package/.kilocode/package.json +5 -0
  294. package/AGENTS.md +5 -0
  295. package/CLAUDE.md +29 -0
  296. package/QA_AUDIT_PLAN.md +156 -0
  297. package/README.md +355 -0
  298. package/agent-agnostic-evolution-dashboard.md +405 -0
  299. package/backend/__init__.py +0 -0
  300. package/backend/collectors/__init__.py +0 -0
  301. package/backend/collectors/claude_code_collector.py +277 -0
  302. package/backend/collectors/hermes_collector.py +68 -0
  303. package/backend/curator.py +512 -0
  304. package/backend/eval/__init__.py +19 -0
  305. package/backend/eval/engine.py +116 -0
  306. package/backend/eval/scorers.py +201 -0
  307. package/backend/generate_dataset.py +86 -0
  308. package/backend/job_tracker.py +232 -0
  309. package/backend/main.py +1746 -0
  310. package/backend/mcp_server.py +250 -0
  311. package/backend/promethean/__init__.py +24 -0
  312. package/backend/promethean/cycle_orchestrator.py +270 -0
  313. package/backend/promethean/delta_validator.py +191 -0
  314. package/backend/promethean/dspy_compiler.py +315 -0
  315. package/backend/promethean/gepa_strategist.py +213 -0
  316. package/backend/promethean/models.py +260 -0
  317. package/backend/promethean/skill_deployer.py +195 -0
  318. package/backend/promethean/trace_ingestion.py +142 -0
  319. package/backend/requirements.txt +6 -0
  320. package/backend/sdd_evolve.py +459 -0
  321. package/backend/skill_detector.py +227 -0
  322. package/backend/skill_registry.py +289 -0
  323. package/backend/storage/__init__.py +5 -0
  324. package/backend/storage/run_store.py +393 -0
  325. package/backend/storage/schema.sql +99 -0
  326. package/backend/validate_evolution.py +267 -0
  327. package/bin/genoma.js +250 -0
  328. package/components.json +28 -0
  329. package/docs/api/hermes-api.openapi.yaml +438 -0
  330. package/docs/hero.svg +148 -0
  331. package/eslint.config.mjs +18 -0
  332. package/install.sh +245 -0
  333. package/next-env.d.ts +6 -0
  334. package/next.config.ts +32 -0
  335. package/package.json +46 -0
  336. package/pnpm-workspace.yaml +4 -0
  337. package/postcss.config.mjs +7 -0
  338. package/public/file.svg +1 -0
  339. package/public/fonts/SF-Pro-Display-Bold.otf +0 -0
  340. package/public/fonts/SF-Pro-Display-Heavy.otf +0 -0
  341. package/public/fonts/SF-Pro-Display-Medium.otf +0 -0
  342. package/public/fonts/SF-Pro-Display-Regular.otf +0 -0
  343. package/public/fonts/SF-Pro-Display-Semibold.otf +0 -0
  344. package/public/fonts/SF-Pro-Text-Bold.otf +0 -0
  345. package/public/fonts/SF-Pro-Text-Heavy.otf +0 -0
  346. package/public/fonts/SF-Pro-Text-Medium.otf +0 -0
  347. package/public/fonts/SF-Pro-Text-Regular.otf +0 -0
  348. package/public/fonts/SF-Pro-Text-Semibold.otf +0 -0
  349. package/public/globe.svg +1 -0
  350. package/public/next.svg +1 -0
  351. package/public/theme-preview.html +257 -0
  352. package/public/vercel.svg +1 -0
  353. package/public/window.svg +1 -0
  354. package/run.sh +26 -0
  355. package/scripts/postinstall.js +50 -0
  356. package/skills-lock.json +10 -0
  357. package/specs/event-schema.md +223 -0
  358. package/specs/examples/run.jsonl +3 -0
  359. package/src/app/api/[...path]/route.ts +55 -0
  360. package/src/app/api/auth/token/route.ts +22 -0
  361. package/src/app/evolution/page.tsx +589 -0
  362. package/src/app/favicon.ico +0 -0
  363. package/src/app/globals.css +321 -0
  364. package/src/app/layout.tsx +63 -0
  365. package/src/app/page.tsx +70 -0
  366. package/src/app/skills/page.tsx +369 -0
  367. package/src/components/ApiConfigCard.tsx +199 -0
  368. package/src/components/ColorBends.css +1 -0
  369. package/src/components/ColorBends.d.ts +1 -0
  370. package/src/components/ColorBends.jsx +1 -0
  371. package/src/components/CoreLoopToggle.tsx +111 -0
  372. package/src/components/EnvironmentStatus.tsx +176 -0
  373. package/src/components/EvolutionBackground.tsx +1 -0
  374. package/src/components/ReactQueryProvider.tsx +24 -0
  375. package/src/components/Sidebar.tsx +247 -0
  376. package/src/components/SkillDiffViewer.tsx +154 -0
  377. package/src/components/ThemeAwareBackground.tsx +67 -0
  378. package/src/components/ThemeToggle.tsx +54 -0
  379. package/src/components/WelcomeHero.tsx +77 -0
  380. package/src/components/bits/ClickSpark.tsx +116 -0
  381. package/src/components/bits/CountUp.tsx +98 -0
  382. package/src/components/bits/DarkSelect.tsx +95 -0
  383. package/src/components/bits/DecryptedText.tsx +161 -0
  384. package/src/components/bits/ElectricBorder.tsx +184 -0
  385. package/src/components/bits/GlitchText.tsx +34 -0
  386. package/src/components/bits/ShinyText.tsx +55 -0
  387. package/src/components/bits/SpotlightCard.tsx +42 -0
  388. package/src/components/bits/TextType.tsx +95 -0
  389. package/src/components/bits/index.ts +9 -0
  390. package/src/components/pages/CuratorPage.tsx +632 -0
  391. package/src/components/pages/DatasetPage.tsx +271 -0
  392. package/src/components/pages/EvolutionPage.tsx +676 -0
  393. package/src/components/pages/FunctionCallingPage.tsx +1 -0
  394. package/src/components/pages/LogsPage.tsx +272 -0
  395. package/src/components/pages/MetricsPage.tsx +246 -0
  396. package/src/components/pages/OverviewPage.tsx +420 -0
  397. package/src/components/pages/SettingsPage.tsx +88 -0
  398. package/src/components/pages/SkillStudioPage.tsx +376 -0
  399. package/src/components/ui/animated-theme-toggler.tsx +97 -0
  400. package/src/components/ui/button.tsx +67 -0
  401. package/src/components/ui/card.tsx +103 -0
  402. package/src/components/ui/input.tsx +19 -0
  403. package/src/components/ui/separator.tsx +28 -0
  404. package/src/components/ui/sheet.tsx +147 -0
  405. package/src/components/ui/sidebar.tsx +702 -0
  406. package/src/components/ui/skeleton.tsx +13 -0
  407. package/src/components/ui/theme-toggle.tsx +272 -0
  408. package/src/components/ui/tooltip.tsx +57 -0
  409. package/src/hooks/use-mobile.ts +19 -0
  410. package/src/lib/api.ts +455 -0
  411. package/src/lib/queryClient.ts +12 -0
  412. package/src/lib/utils.ts +6 -0
  413. package/stitch/agent_dashboard/DESIGN_SPEC.md +521 -0
  414. package/stitch/agent_dashboard/prototype.html +676 -0
  415. package/stitch/curator_workspace/code.html +448 -0
  416. package/stitch/curator_workspace/screen.png +0 -0
  417. package/stitch/datasets/code.html +479 -0
  418. package/stitch/datasets/screen.png +0 -0
  419. package/stitch/evolution_history/code.html +461 -0
  420. package/stitch/evolution_history/screen.png +0 -0
  421. package/stitch/hermes_dashboard/DESIGN.md +192 -0
  422. package/stitch/hermes_dashboard/DESIGN_SPEC.md +455 -0
  423. package/stitch/hermes_overview/code.html +399 -0
  424. package/stitch/hermes_overview/screen.png +0 -0
  425. package/stitch/live_logs/code.html +324 -0
  426. package/stitch/live_logs/screen.png +0 -0
  427. package/stitch/skill_hub/code.html +596 -0
  428. package/stitch/skill_hub/screen.png +0 -0
  429. package/stitch/system_metrics/code.html +527 -0
  430. package/stitch/system_metrics/screen.png +0 -0
  431. package/stitch/system_settings/code.html +257 -0
  432. package/stitch/system_settings/screen.png +0 -0
  433. package/test_dashboard.py +201 -0
  434. package/tests/collectors/__init__.py +0 -0
  435. package/tests/collectors/fixtures/sample_session.jsonl +7 -0
  436. package/tests/collectors/test_claude_code_collector.py +171 -0
  437. package/tests/collectors/test_hermes_collector.py +167 -0
  438. package/tests/eval/test_engine.py +234 -0
  439. package/tests/eval/test_scorers.py +249 -0
  440. package/tests/storage/__init__.py +0 -0
  441. package/tests/storage/test_run_store.py +359 -0
  442. package/tests/test_curator.py +559 -0
  443. package/tests/test_e2e_npm.py +621 -0
  444. package/tests/test_mcp_server.py +114 -0
  445. package/tsconfig.json +34 -0
@@ -0,0 +1,116 @@
1
+ """Evaluation engine orchestrating multiple scorers."""
2
+
3
+ from typing import Optional
4
+
5
+ from backend.eval.scorers import (
6
+ EvalScore,
7
+ OutcomeScorer,
8
+ ToolEfficiencyScorer,
9
+ TokenCostScorer,
10
+ ErrorRecoveryScorer,
11
+ DeltaScorer,
12
+ )
13
+ from backend.promethean.models import CanonicalRun
14
+ from backend.storage import RunStore
15
+
16
+
17
+ class EvaluationEngine:
18
+ """Evaluate canonical runs using composable scorers."""
19
+
20
+ DEFAULT_SCORERS = [
21
+ OutcomeScorer(),
22
+ ToolEfficiencyScorer(),
23
+ TokenCostScorer(),
24
+ ErrorRecoveryScorer(),
25
+ DeltaScorer(),
26
+ ]
27
+
28
+ def __init__(self, store: Optional[RunStore] = None, scorers: Optional[list] = None):
29
+ self.store = store or RunStore()
30
+ self.scorers = scorers if scorers is not None else self.DEFAULT_SCORERS
31
+
32
+ def evaluate(self, run: CanonicalRun) -> list[EvalScore]:
33
+ """Run applicable scorers on a run. Return list of scores."""
34
+ scores = []
35
+ for scorer in self.scorers:
36
+ if scorer.applies_to(run):
37
+ score = scorer.score(run)
38
+ if score: # DeltaScorer may return None
39
+ scores.append(score)
40
+ # Optionally save to storage
41
+ if self.store and hasattr(run, "run_id"):
42
+ try:
43
+ self._save_score(run.run_id, score)
44
+ except Exception:
45
+ pass
46
+ return scores
47
+
48
+ def evaluate_batch(self, runs: list[CanonicalRun]) -> dict:
49
+ """Evaluate batch of runs. Return {total, evaluated, errors}."""
50
+ result = {"total": len(runs), "evaluated": 0, "errors": 0}
51
+ for run in runs:
52
+ try:
53
+ self.evaluate(run)
54
+ result["evaluated"] += 1
55
+ except Exception:
56
+ result["errors"] += 1
57
+ return result
58
+
59
+ def get_aggregate_score(self, run: CanonicalRun) -> float:
60
+ """Weighted average of all applicable scores."""
61
+ scores = self.evaluate(run)
62
+ if not scores:
63
+ return 0.5 # Default if no scorers apply
64
+
65
+ # Equal weighting for now; can be customized per scorer
66
+ total = sum(s.score for s in scores)
67
+ return total / len(scores)
68
+
69
+ def detect_regression(
70
+ self, baseline_run_id: str, evolved_run_id: str, threshold: float = 0.05
71
+ ) -> dict:
72
+ """Compare baseline and evolved runs. Return {delta, regression, improvement, neutral}."""
73
+ baseline = self.store.get_run(baseline_run_id)
74
+ evolved = self.store.get_run(evolved_run_id)
75
+
76
+ if not baseline or not evolved:
77
+ return {
78
+ "error": "One or both runs not found",
79
+ "baseline_found": baseline is not None,
80
+ "evolved_found": evolved is not None,
81
+ }
82
+
83
+ baseline_score = self.get_aggregate_score(baseline)
84
+ evolved_score = self.get_aggregate_score(evolved)
85
+ delta = evolved_score - baseline_score
86
+
87
+ return {
88
+ "baseline_run_id": baseline_run_id,
89
+ "evolved_run_id": evolved_run_id,
90
+ "baseline_score": round(baseline_score, 3),
91
+ "evolved_score": round(evolved_score, 3),
92
+ "delta": round(delta, 3),
93
+ "threshold": threshold,
94
+ "regression": delta < -threshold,
95
+ "improvement": delta > threshold,
96
+ "neutral": abs(delta) <= threshold,
97
+ }
98
+
99
+ def _save_score(self, run_id: str, score: EvalScore):
100
+ """Save evaluation score to storage (optional)."""
101
+ conn = self.store.connect()
102
+ try:
103
+ conn.execute(
104
+ """INSERT INTO eval_scores (run_id, scorer, score, passed, details)
105
+ VALUES (?, ?, ?, ?, ?)""",
106
+ (
107
+ run_id,
108
+ score.scorer,
109
+ score.score,
110
+ 1 if score.passed else 0,
111
+ str(score.details),
112
+ ),
113
+ )
114
+ conn.commit()
115
+ finally:
116
+ self.store.close(conn)
@@ -0,0 +1,201 @@
1
+ """Evaluation scorers for CanonicalRun instances."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Optional
5
+
6
+ from backend.promethean.models import CanonicalRun
7
+
8
+
9
+ @dataclass
10
+ class EvalScore:
11
+ """Result of applying a scorer to a run."""
12
+
13
+ scorer: str
14
+ score: float # 0.0 to 1.0
15
+ passed: bool
16
+ details: dict = field(default_factory=dict)
17
+
18
+
19
+ class OutcomeScorer:
20
+ """Score based on run outcome."""
21
+
22
+ name = "outcome"
23
+
24
+ def score(self, run: CanonicalRun) -> EvalScore:
25
+ """Map outcome to score: success=1.0, partial=0.5, failure=0.0, unknown=0.3."""
26
+ outcome_map = {
27
+ "success": 1.0,
28
+ "partial": 0.5,
29
+ "failure": 0.0,
30
+ "unknown": 0.3,
31
+ }
32
+ score = outcome_map.get(run.outcome, 0.3)
33
+ return EvalScore(
34
+ scorer=self.name,
35
+ score=score,
36
+ passed=score > 0.5,
37
+ details={"outcome": run.outcome},
38
+ )
39
+
40
+ def applies_to(self, run: CanonicalRun) -> bool:
41
+ """Applies to all runs."""
42
+ return True
43
+
44
+
45
+ class ToolEfficiencyScorer:
46
+ """Score based on tool call efficiency (unique_tools / total_calls)."""
47
+
48
+ name = "tool_efficiency"
49
+
50
+ def score(self, run: CanonicalRun) -> EvalScore:
51
+ """Calculate tool efficiency ratio. Pass if > 0.3."""
52
+ if not run.tool_calls:
53
+ return EvalScore(
54
+ scorer=self.name,
55
+ score=1.0,
56
+ passed=True,
57
+ details={"reason": "no_tools_used"},
58
+ )
59
+
60
+ total = len(run.tool_calls)
61
+ unique = len(set(tc.name for tc in run.tool_calls))
62
+ ratio = unique / total if total > 0 else 0.0
63
+
64
+ return EvalScore(
65
+ scorer=self.name,
66
+ score=ratio,
67
+ passed=ratio > 0.3,
68
+ details={
69
+ "unique_tools": unique,
70
+ "total_calls": total,
71
+ "efficiency_ratio": round(ratio, 2),
72
+ },
73
+ )
74
+
75
+ def applies_to(self, run: CanonicalRun) -> bool:
76
+ """Applies to runs with tool calls."""
77
+ return len(run.tool_calls) > 0
78
+
79
+
80
+ class TokenCostScorer:
81
+ """Score based on token usage: lower is better (up to 50k tokens)."""
82
+
83
+ name = "token_cost"
84
+
85
+ def score(self, run: CanonicalRun) -> EvalScore:
86
+ """Score = max(0, 1 - tokens/50000). Pass if < 50k."""
87
+ if not run.metrics or not run.metrics.input_tokens:
88
+ return EvalScore(
89
+ scorer=self.name,
90
+ score=1.0,
91
+ passed=True,
92
+ details={"reason": "no_metrics"},
93
+ )
94
+
95
+ total_tokens = (run.metrics.input_tokens or 0) + (run.metrics.output_tokens or 0)
96
+ threshold = 50000
97
+ score = max(0.0, 1.0 - (total_tokens / threshold))
98
+
99
+ return EvalScore(
100
+ scorer=self.name,
101
+ score=score,
102
+ passed=total_tokens < threshold,
103
+ details={
104
+ "input_tokens": run.metrics.input_tokens,
105
+ "output_tokens": run.metrics.output_tokens,
106
+ "total_tokens": total_tokens,
107
+ "threshold": threshold,
108
+ },
109
+ )
110
+
111
+ def applies_to(self, run: CanonicalRun) -> bool:
112
+ """Applies to runs with metrics."""
113
+ return run.metrics is not None
114
+
115
+
116
+ class ErrorRecoveryScorer:
117
+ """Score based on error handling: success with no errors = 1.0, success with errors = 0.8, failure = 0.0."""
118
+
119
+ name = "error_recovery"
120
+
121
+ def score(self, run: CanonicalRun) -> EvalScore:
122
+ """Score based on outcome and error presence."""
123
+ if run.outcome == "success":
124
+ if not run.errors:
125
+ score = 1.0
126
+ else:
127
+ score = 0.8
128
+ passed = True
129
+ elif run.outcome == "partial":
130
+ score = 0.5
131
+ passed = False
132
+ else: # failure or unknown
133
+ score = 0.0
134
+ passed = False
135
+
136
+ return EvalScore(
137
+ scorer=self.name,
138
+ score=score,
139
+ passed=passed,
140
+ details={
141
+ "outcome": run.outcome,
142
+ "error_count": len(run.errors),
143
+ "has_errors": len(run.errors) > 0,
144
+ },
145
+ )
146
+
147
+ def applies_to(self, run: CanonicalRun) -> bool:
148
+ """Applies to all runs."""
149
+ return True
150
+
151
+
152
+ class DeltaScorer:
153
+ """Score based on delta validation (Hermes-specific).
154
+
155
+ Only applies to Hermes runs with context.skill_name.
156
+ Integrates with existing DeltaValidator from promethean module.
157
+ """
158
+
159
+ name = "delta"
160
+
161
+ def score(self, run: CanonicalRun) -> Optional[EvalScore]:
162
+ """Run delta validation if applicable. Return None if not applicable."""
163
+ if not self.applies_to(run):
164
+ return None
165
+
166
+ # Try to import DeltaValidator
167
+ try:
168
+ from backend.promethean.delta_validator import get_validator
169
+
170
+ validator = get_validator()
171
+ skill_name = run.context.get("skill_name")
172
+
173
+ # Get baseline from context or infer
174
+ baseline = run.context.get("baseline_version")
175
+ if not baseline:
176
+ baseline = "unknown"
177
+
178
+ # Run validation
179
+ result = validator.validate(skill_name, baseline=baseline)
180
+
181
+ # Map validation result to score
182
+ passed = result.get("passed", False)
183
+ score = 1.0 if passed else 0.0
184
+
185
+ return EvalScore(
186
+ scorer=self.name,
187
+ score=score,
188
+ passed=passed,
189
+ details=result,
190
+ )
191
+ except Exception:
192
+ # DeltaValidator not available or error occurred
193
+ return None
194
+
195
+ def applies_to(self, run: CanonicalRun) -> bool:
196
+ """Applies to Hermes runs with skill_name in context."""
197
+ return (
198
+ run.agent_name == "hermes"
199
+ and run.context
200
+ and "skill_name" in run.context
201
+ )
@@ -0,0 +1,86 @@
1
+ """
2
+ Dataset Generator — Genera ejemplos de validación sintéticos para skills.
3
+
4
+ Usage:
5
+ python generate_dataset.py --skill code-review --count 10 --output ~/.hermes/datasets/code-review/train.jsonl
6
+ """
7
+ import argparse
8
+ import json
9
+ import sys
10
+ from pathlib import Path
11
+ from openai import OpenAI
12
+
13
+ OLLAMA_BASE = "http://localhost:11434/v1"
14
+ OLLAMA_MODEL = "gemma4:31b-cloud"
15
+
16
+ client = OpenAI(base_url=OLLAMA_BASE, api_key="ollama")
17
+
18
+ SKILL_PROMPTS = {
19
+ "code-review": """Para la skill 'code-review', generá exactamente {count} ejemplos de revisión de código.
20
+ Cada ejemplo debe ser un objeto JSON con:
21
+ - "input": código con bugs/problemas (Python, TypeScript, o Go)
22
+ - "expected": la revisión esperada (bugs específicos que deberían detectarse)
23
+
24
+ Cubrí estos casos:
25
+ 1. Python: SQL injection, type hints faltantes, async mal usado, raw dicts en vez de Pydantic
26
+ 2. TypeScript/React: useEffect sin deps, componentes no memoizados, keys faltantes en maps
27
+ 3. Go: error handling ignorado, goroutines sin sync, nil pointer dereference
28
+ 4. General: dead code, secretos hardcodeados, logs con PII
29
+
30
+ IMPORTANTE: El expected NO debe ser el código corregido, sino una LISTA de bugs que deben detectarse.
31
+
32
+ OUTPUT: Array JSON de objetos {{"input": "...", "expected": "..."}}. Sin markdown fences.
33
+ Generá EXACTAMENTE {count} ejemplos. Comenzá YA:""",
34
+ }
35
+
36
+
37
+ def generate_dataset(skill: str, count: int, output_path: str):
38
+ prompt = SKILL_PROMPTS.get(skill, SKILL_PROMPTS["code-review"]).format(count=count)
39
+
40
+ print(f"🎯 Generating {count} examples for '{skill}'...", flush=True)
41
+
42
+ resp = client.chat.completions.create(
43
+ model=OLLAMA_MODEL,
44
+ messages=[
45
+ {"role": "system", "content": "Sos un experto en code review. Generás datasets de validación en JSON. Output: solo JSON válido, sin explicaciones."},
46
+ {"role": "user", "content": prompt}
47
+ ],
48
+ temperature=0.7,
49
+ max_tokens=4000,
50
+ )
51
+
52
+ raw = resp.choices[0].message.content or ""
53
+ raw = raw.strip()
54
+ if raw.startswith("```"):
55
+ raw = raw.split("```")[1]
56
+ if raw.startswith("json"):
57
+ raw = raw[4:]
58
+ raw = raw.strip()
59
+
60
+ try:
61
+ examples = json.loads(raw)
62
+ except json.JSONDecodeError:
63
+ print(f"❌ Failed to parse JSON. Raw output:", file=sys.stderr)
64
+ print(raw[:500], file=sys.stderr)
65
+ sys.exit(1)
66
+
67
+ if not isinstance(examples, list):
68
+ examples = [examples]
69
+
70
+ # Write to file
71
+ out = Path(output_path)
72
+ out.parent.mkdir(parents=True, exist_ok=True)
73
+ with open(out, "w") as f:
74
+ for ex in examples:
75
+ f.write(json.dumps(ex, ensure_ascii=False) + "\n")
76
+
77
+ print(f"✅ Saved {len(examples)} examples to {out}")
78
+
79
+
80
+ if __name__ == "__main__":
81
+ parser = argparse.ArgumentParser(description="Generate synthetic validation dataset")
82
+ parser.add_argument("--skill", required=True, help="Skill name")
83
+ parser.add_argument("--count", type=int, default=10, help="Number of examples")
84
+ parser.add_argument("--output", required=True, help="Output .jsonl file")
85
+ args = parser.parse_args()
86
+ generate_dataset(args.skill, args.count, args.output)
@@ -0,0 +1,232 @@
1
+ """Evolution job tracking — persistent state for active and completed jobs."""
2
+
3
+ import json
4
+ import re
5
+ import uuid
6
+ import asyncio
7
+ from datetime import datetime
8
+ from enum import Enum
9
+ from pathlib import Path
10
+ from dataclasses import dataclass, field, asdict
11
+ from typing import Optional
12
+
13
+ LOG_DIR = Path.home() / ".hermes" / "evolution-logs"
14
+
15
+
16
+ class JobStatus(str, Enum):
17
+ QUEUED = "queued"
18
+ LOADING_SKILL = "loading_skill"
19
+ BUILDING_DATASET = "building_dataset"
20
+ VALIDATING = "validating"
21
+ CONFIGURING = "configuring"
22
+ OPTIMIZING = "optimizing"
23
+ EVALUATING = "evaluating"
24
+ SAVING = "saving"
25
+ COMPLETED = "completed"
26
+ FAILED = "failed"
27
+
28
+
29
+ # Phases in order (for progress calculation)
30
+ PHASE_ORDER = [
31
+ JobStatus.LOADING_SKILL,
32
+ JobStatus.BUILDING_DATASET,
33
+ JobStatus.VALIDATING,
34
+ JobStatus.CONFIGURING,
35
+ JobStatus.OPTIMIZING,
36
+ JobStatus.EVALUATING,
37
+ JobStatus.SAVING,
38
+ ]
39
+
40
+
41
+ @dataclass
42
+ class EvolutionJob:
43
+ id: str
44
+ skill_name: str
45
+ status: JobStatus = JobStatus.QUEUED
46
+ iterations: int = 3
47
+ current_iteration: int = 0
48
+ pid: Optional[int] = None
49
+ started_at: str = ""
50
+ completed_at: str = ""
51
+ baseline_score: Optional[float] = None
52
+ current_best_score: Optional[float] = None
53
+ evolved_score: Optional[float] = None
54
+ improvement: Optional[float] = None
55
+ error: str = ""
56
+ logs: list[str] = field(default_factory=list)
57
+
58
+ def to_dict(self) -> dict:
59
+ d = asdict(self)
60
+ d["status"] = self.status.value
61
+ return d
62
+
63
+ @property
64
+ def progress(self) -> float:
65
+ """0.0 to 1.0 progress estimate."""
66
+ if self.status == JobStatus.COMPLETED:
67
+ return 1.0
68
+ if self.status == JobStatus.FAILED:
69
+ return 0.0
70
+ if self.status == JobStatus.QUEUED:
71
+ return 0.0
72
+
73
+ # Phase-based progress
74
+ phase_idx = 0
75
+ try:
76
+ phase_idx = PHASE_ORDER.index(self.status)
77
+ except ValueError:
78
+ pass
79
+
80
+ phase_weight = 1.0 / len(PHASE_ORDER)
81
+
82
+ # Within OPTIMIZING phase, use iteration progress
83
+ if self.status == JobStatus.OPTIMIZING and self.iterations > 0:
84
+ iter_progress = self.current_iteration / self.iterations
85
+ base = phase_idx * phase_weight
86
+ return base + (iter_progress * phase_weight)
87
+
88
+ return phase_idx * phase_weight
89
+
90
+ def add_log(self, message: str):
91
+ timestamp = datetime.now().isoformat()[:19]
92
+ self.logs.append(f"[{timestamp}] {message}")
93
+ # Keep last 500 lines
94
+ if len(self.logs) > 500:
95
+ self.logs = self.logs[-500:]
96
+
97
+ def save_log(self):
98
+ LOG_DIR.mkdir(parents=True, exist_ok=True)
99
+ log_file = LOG_DIR / f"{self.id}.json"
100
+ log_file.write_text(json.dumps(self.to_dict(), indent=2))
101
+
102
+
103
+ class JobTracker:
104
+ def __init__(self):
105
+ self._jobs: dict[str, EvolutionJob] = {}
106
+ self._processes: dict[str, asyncio.subprocess.Process] = {}
107
+ LOG_DIR.mkdir(parents=True, exist_ok=True)
108
+
109
+ def create_job(self, skill_name: str, iterations: int) -> EvolutionJob:
110
+ job_id = f"{skill_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:6]}"
111
+ job = EvolutionJob(
112
+ id=job_id,
113
+ skill_name=skill_name,
114
+ iterations=iterations,
115
+ started_at=datetime.now().isoformat(),
116
+ )
117
+ self._jobs[job_id] = job
118
+ return job
119
+
120
+ def get_job(self, job_id: str) -> Optional[EvolutionJob]:
121
+ return self._jobs.get(job_id)
122
+
123
+ def get_active_jobs(self) -> list[EvolutionJob]:
124
+ return [
125
+ j for j in self._jobs.values()
126
+ if j.status not in (JobStatus.COMPLETED, JobStatus.FAILED)
127
+ ]
128
+
129
+ def get_all_jobs(self, limit: int = 50) -> list[EvolutionJob]:
130
+ sorted_jobs = sorted(
131
+ self._jobs.values(),
132
+ key=lambda j: j.started_at,
133
+ reverse=True,
134
+ )
135
+ return sorted_jobs[:limit]
136
+
137
+ def set_process(self, job_id: str, process: asyncio.subprocess.Process):
138
+ self._processes[job_id] = process
139
+
140
+ def get_process(self, job_id: str) -> Optional[asyncio.subprocess.Process]:
141
+ return self._processes.get(job_id)
142
+
143
+ def cleanup_process(self, job_id: str):
144
+ self._processes.pop(job_id, None)
145
+
146
+ # ── Log parsing ─────────────────────────────────────────────────
147
+
148
+ # Patterns to detect phase changes from Rich output
149
+ PHASE_PATTERNS = [
150
+ (r"Loaded:.*\.md", JobStatus.LOADING_SKILL),
151
+ (r"Building evaluation dataset", JobStatus.BUILDING_DATASET),
152
+ (r"Generated.*synthetic examples", JobStatus.BUILDING_DATASET),
153
+ (r"Mined.*examples from session", JobStatus.BUILDING_DATASET),
154
+ (r"Loaded golden dataset", JobStatus.BUILDING_DATASET),
155
+ (r"Validating baseline constraints", JobStatus.VALIDATING),
156
+ (r"Configuring optimizer", JobStatus.CONFIGURING),
157
+ (r"Running GEPA optimization", JobStatus.OPTIMIZING),
158
+ (r"Running MIPROv2", JobStatus.OPTIMIZING),
159
+ (r"Optimization completed", JobStatus.OPTIMIZING),
160
+ (r"Validating evolved skill", JobStatus.EVALUATING),
161
+ (r"Evaluating on holdout", JobStatus.EVALUATING),
162
+ (r"Evolution Results", JobStatus.SAVING),
163
+ (r"Saved.*to output", JobStatus.SAVING),
164
+ (r"✓ Skill evolved", JobStatus.COMPLETED),
165
+ ]
166
+
167
+ # Pattern to extract scores
168
+ SCORE_PATTERN = re.compile(r"baseline[=_:\s]+(\d+\.?\d*)|evolved[=_:\s]+(\d+\.?\d*)|score[=_:\s]+(\d+\.?\d*)|improvement[=_:\s]+([+-]?\d+\.?\d*)", re.IGNORECASE)
169
+
170
+ # Pattern to extract iteration number
171
+ ITER_PATTERN = re.compile(r"iteration[=:\s]+(\d+)|eval[=:\s#]+(\d+)/(\d+)", re.IGNORECASE)
172
+
173
+ def parse_line(self, job: EvolutionJob, line: str):
174
+ """Parse a log line and update job state."""
175
+ # Strip ANSI codes
176
+ clean = re.sub(r"\x1b\[[0-9;]*m", "", line).strip()
177
+ if not clean:
178
+ return
179
+
180
+ job.add_log(clean)
181
+
182
+ # Check phase transitions
183
+ for pattern, phase in self.PHASE_PATTERNS:
184
+ if re.search(pattern, clean, re.IGNORECASE):
185
+ if phase != job.status:
186
+ job.status = phase
187
+
188
+ # Check for optimization iteration progress
189
+ iter_match = self.ITER_PATTERN.search(clean)
190
+ if iter_match:
191
+ num = iter_match.group(1) or iter_match.group(2)
192
+ if num:
193
+ job.current_iteration = int(num)
194
+ total = iter_match.group(3)
195
+ if total:
196
+ job.iterations = int(total)
197
+
198
+ # Check for scores
199
+ score_match = self.SCORE_PATTERN.search(clean)
200
+ if score_match:
201
+ val = score_match.group(1) or score_match.group(2) or score_match.group(3) or score_match.group(4)
202
+ if val:
203
+ try:
204
+ score = float(val)
205
+ if "baseline" in clean.lower():
206
+ job.baseline_score = score
207
+ elif "evolved" in clean.lower() or "best" in clean.lower():
208
+ job.current_best_score = score
209
+ elif "improvement" in clean.lower():
210
+ job.improvement = score
211
+ except ValueError:
212
+ pass
213
+
214
+ # Check for completion
215
+ if "evolved_skill.md" in clean and "Saved" in clean:
216
+ job.status = JobStatus.COMPLETED
217
+ job.completed_at = datetime.now().isoformat()
218
+
219
+ # Check for failure
220
+ if "FAILED" in clean or "not found" in clean.lower():
221
+ if "✗" in clean or "Error" in clean or "error" in clean:
222
+ job.error = clean
223
+ job.status = JobStatus.FAILED
224
+ job.completed_at = datetime.now().isoformat()
225
+
226
+ # Persist periodically
227
+ if len(job.logs) % 10 == 0:
228
+ job.save_log()
229
+
230
+
231
+ # Global tracker instance
232
+ tracker = JobTracker()