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.
- package/.brv/.obsidian/app.json +1 -0
- package/.brv/.obsidian/appearance.json +1 -0
- package/.brv/.obsidian/core-plugins.json +33 -0
- package/.brv/.obsidian/graph.json +22 -0
- package/.brv/.obsidian/workspace.json +195 -0
- package/.brv/Sin ti/314/201tulo 1.canvas" +1 -0
- package/.brv/Sin ti/314/201tulo 2.canvas" +1 -0
- package/.brv/Sin ti/314/201tulo.canvas" +1 -0
- package/.brv/_queue_status.json +1 -0
- package/.brv/config.json +5 -0
- package/.brv/context-tree/_index.md +60 -0
- package/.brv/context-tree/_manifest.json +165 -0
- package/.brv/context-tree/backend/_index.md +24 -0
- package/.brv/context-tree/backend/backend/_index.md +40 -0
- package/.brv/context-tree/backend/backend/init.abstract.md +0 -0
- package/.brv/context-tree/backend/backend/init.md +27 -0
- package/.brv/context-tree/backend/backend/init.overview.md +29 -0
- package/.brv/context-tree/backend/backend/job_tracker.abstract.md +1 -0
- package/.brv/context-tree/backend/backend/job_tracker.md +273 -0
- package/.brv/context-tree/backend/backend/job_tracker.overview.md +31 -0
- package/.brv/context-tree/backend/backend/main.abstract.md +0 -0
- package/.brv/context-tree/backend/backend/main.md +1292 -0
- package/.brv/context-tree/backend/backend/main.overview.md +30 -0
- package/.brv/context-tree/backend/backend/requirements.abstract.md +1 -0
- package/.brv/context-tree/backend/backend/requirements.md +37 -0
- package/.brv/context-tree/backend/backend/requirements.overview.md +28 -0
- package/.brv/context-tree/docs/_index.md +37 -0
- package/.brv/context-tree/docs/api/_index.md +54 -0
- package/.brv/context-tree/docs/api/context.md +11 -0
- package/.brv/context-tree/docs/api/hermes_api_openapi_specification.abstract.md +0 -0
- package/.brv/context-tree/docs/api/hermes_api_openapi_specification.md +468 -0
- package/.brv/context-tree/docs/api/hermes_api_openapi_specification.overview.md +44 -0
- package/.brv/context-tree/frontend/_index.md +48 -0
- package/.brv/context-tree/frontend/hermes_dashboard/_index.md +31 -0
- package/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.abstract.md +0 -0
- package/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.md +41 -0
- package/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.overview.md +34 -0
- package/.brv/context-tree/frontend/src/_index.md +53 -0
- package/.brv/context-tree/frontend/src/components/_index.md +52 -0
- package/.brv/context-tree/frontend/src/components/sidebar_navigation_component.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/components/sidebar_navigation_component.md +161 -0
- package/.brv/context-tree/frontend/src/components/sidebar_navigation_component.overview.md +32 -0
- package/.brv/context-tree/frontend/src/context.md +10 -0
- package/.brv/context-tree/frontend/src/functioncallingpage.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/functioncallingpage.md +34 -0
- package/.brv/context-tree/frontend/src/functioncallingpage.overview.md +26 -0
- package/.brv/context-tree/frontend/src/lib/_index.md +48 -0
- package/.brv/context-tree/frontend/src/lib/api_client_library.abstract.md +1 -0
- package/.brv/context-tree/frontend/src/lib/api_client_library.md +403 -0
- package/.brv/context-tree/frontend/src/lib/api_client_library.overview.md +69 -0
- package/.brv/context-tree/frontend/src/page.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/page.md +103 -0
- package/.brv/context-tree/frontend/src/page.overview.md +7 -0
- package/.brv/context-tree/frontend/src/settingspage.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/settingspage.md +124 -0
- package/.brv/context-tree/frontend/src/settingspage.overview.md +34 -0
- package/.brv/context-tree/frontend/src/sidebar.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/sidebar.md +170 -0
- package/.brv/context-tree/frontend/src/sidebar.overview.md +25 -0
- package/.brv/context-tree/meta/_index.md +24 -0
- package/.brv/context-tree/meta/curation_context/_index.md +24 -0
- package/.brv/context-tree/meta/curation_context/empty_context.abstract.md +4 -0
- package/.brv/context-tree/meta/curation_context/empty_context.md +35 -0
- package/.brv/context-tree/meta/curation_context/empty_context.overview.md +20 -0
- package/.brv/dream-log/drm-1777341062653.json +33 -0
- package/.brv/dream-state.json +8 -0
- package/.brv/dream.lock +0 -0
- package/.brv/review-backups/docs/api/hermes_api_openapi_specification.md +468 -0
- package/.claude/settings.local.json +7 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/app.json +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/appearance.json +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/core-plugins.json +33 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/graph.json +22 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/workspace.json +195 -0
- package/.claude/worktrees/phase-2-mcp/.brv/Sin t/303/255tulo 1.canvas" +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/Sin t/303/255tulo 2.canvas" +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/Sin t/303/255tulo.canvas" +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/_queue_status.json +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/config.json +5 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/_index.md +60 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/_manifest.json +165 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/_index.md +24 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/_index.md +40 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/init.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/init.md +27 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/init.overview.md +29 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/job_tracker.abstract.md +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/job_tracker.md +273 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/job_tracker.overview.md +31 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/main.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/main.md +1292 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/main.overview.md +30 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/requirements.abstract.md +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/requirements.md +37 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/requirements.overview.md +28 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/_index.md +37 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/_index.md +54 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/context.md +11 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/hermes_api_openapi_specification.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/hermes_api_openapi_specification.md +468 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/hermes_api_openapi_specification.overview.md +44 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/_index.md +48 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/_index.md +31 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.md +41 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.overview.md +34 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/_index.md +53 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/_index.md +52 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/sidebar_navigation_component.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/sidebar_navigation_component.md +161 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/sidebar_navigation_component.overview.md +32 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/context.md +10 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/functioncallingpage.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/functioncallingpage.md +34 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/functioncallingpage.overview.md +26 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/_index.md +48 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/api_client_library.abstract.md +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/api_client_library.md +403 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/api_client_library.overview.md +69 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/page.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/page.md +103 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/page.overview.md +7 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/settingspage.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/settingspage.md +124 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/settingspage.overview.md +34 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/sidebar.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/sidebar.md +170 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/sidebar.overview.md +25 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/_index.md +24 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/_index.md +24 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/empty_context.abstract.md +4 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/empty_context.md +35 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/empty_context.overview.md +20 -0
- package/.claude/worktrees/phase-2-mcp/.brv/dream-log/drm-1777341062653.json +33 -0
- package/.claude/worktrees/phase-2-mcp/.brv/dream-state.json +8 -0
- package/.claude/worktrees/phase-2-mcp/.brv/dream.lock +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/review-backups/docs/api/hermes_api_openapi_specification.md +468 -0
- package/.claude/worktrees/phase-2-mcp/.claude/settings.local.json +13 -0
- package/.claude/worktrees/phase-2-mcp/.kilocode/package-lock.json +378 -0
- package/.claude/worktrees/phase-2-mcp/.kilocode/package.json +5 -0
- package/.claude/worktrees/phase-2-mcp/AGENTS.md +5 -0
- package/.claude/worktrees/phase-2-mcp/CLAUDE.md +29 -0
- package/.claude/worktrees/phase-2-mcp/QA_AUDIT_PLAN.md +156 -0
- package/.claude/worktrees/phase-2-mcp/README.md +316 -0
- package/.claude/worktrees/phase-2-mcp/agent-agnostic-evolution-dashboard.md +405 -0
- package/.claude/worktrees/phase-2-mcp/backend/__init__.py +0 -0
- package/.claude/worktrees/phase-2-mcp/backend/collectors/__init__.py +0 -0
- package/.claude/worktrees/phase-2-mcp/backend/collectors/claude_code_collector.py +277 -0
- package/.claude/worktrees/phase-2-mcp/backend/collectors/hermes_collector.py +68 -0
- package/.claude/worktrees/phase-2-mcp/backend/curator.py +512 -0
- package/.claude/worktrees/phase-2-mcp/backend/eval/__init__.py +19 -0
- package/.claude/worktrees/phase-2-mcp/backend/eval/engine.py +116 -0
- package/.claude/worktrees/phase-2-mcp/backend/eval/scorers.py +201 -0
- package/.claude/worktrees/phase-2-mcp/backend/generate_dataset.py +86 -0
- package/.claude/worktrees/phase-2-mcp/backend/job_tracker.py +232 -0
- package/.claude/worktrees/phase-2-mcp/backend/main.py +1746 -0
- package/.claude/worktrees/phase-2-mcp/backend/mcp_server.py +250 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/__init__.py +24 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/cycle_orchestrator.py +270 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/delta_validator.py +191 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/dspy_compiler.py +315 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/gepa_strategist.py +213 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/models.py +260 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/skill_deployer.py +195 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/trace_ingestion.py +142 -0
- package/.claude/worktrees/phase-2-mcp/backend/requirements.txt +6 -0
- package/.claude/worktrees/phase-2-mcp/backend/sdd_evolve.py +459 -0
- package/.claude/worktrees/phase-2-mcp/backend/skill_detector.py +227 -0
- package/.claude/worktrees/phase-2-mcp/backend/skill_registry.py +289 -0
- package/.claude/worktrees/phase-2-mcp/backend/storage/__init__.py +5 -0
- package/.claude/worktrees/phase-2-mcp/backend/storage/run_store.py +393 -0
- package/.claude/worktrees/phase-2-mcp/backend/storage/schema.sql +99 -0
- package/.claude/worktrees/phase-2-mcp/backend/validate_evolution.py +267 -0
- package/.claude/worktrees/phase-2-mcp/components.json +28 -0
- package/.claude/worktrees/phase-2-mcp/docs/api/hermes-api.openapi.yaml +438 -0
- package/.claude/worktrees/phase-2-mcp/docs/hero.svg +148 -0
- package/.claude/worktrees/phase-2-mcp/eslint.config.mjs +18 -0
- package/.claude/worktrees/phase-2-mcp/install.sh +245 -0
- package/.claude/worktrees/phase-2-mcp/next-env.d.ts +6 -0
- package/.claude/worktrees/phase-2-mcp/next.config.ts +32 -0
- package/.claude/worktrees/phase-2-mcp/package-lock.json +11936 -0
- package/.claude/worktrees/phase-2-mcp/package.json +41 -0
- package/.claude/worktrees/phase-2-mcp/pnpm-workspace.yaml +4 -0
- package/.claude/worktrees/phase-2-mcp/postcss.config.mjs +7 -0
- package/.claude/worktrees/phase-2-mcp/public/file.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Bold.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Heavy.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Medium.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Regular.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Semibold.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Bold.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Heavy.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Medium.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Regular.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Semibold.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/globe.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/public/next.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/public/theme-preview.html +257 -0
- package/.claude/worktrees/phase-2-mcp/public/vercel.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/public/window.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/run.sh +26 -0
- package/.claude/worktrees/phase-2-mcp/skills-lock.json +10 -0
- package/.claude/worktrees/phase-2-mcp/specs/event-schema.md +223 -0
- package/.claude/worktrees/phase-2-mcp/specs/examples/run.jsonl +3 -0
- package/.claude/worktrees/phase-2-mcp/src/app/api/[...path]/route.ts +55 -0
- package/.claude/worktrees/phase-2-mcp/src/app/api/auth/token/route.ts +22 -0
- package/.claude/worktrees/phase-2-mcp/src/app/evolution/page.tsx +589 -0
- package/.claude/worktrees/phase-2-mcp/src/app/favicon.ico +0 -0
- package/.claude/worktrees/phase-2-mcp/src/app/globals.css +321 -0
- package/.claude/worktrees/phase-2-mcp/src/app/layout.tsx +63 -0
- package/.claude/worktrees/phase-2-mcp/src/app/page.tsx +70 -0
- package/.claude/worktrees/phase-2-mcp/src/app/skills/page.tsx +369 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ApiConfigCard.tsx +199 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ColorBends.css +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ColorBends.d.ts +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ColorBends.jsx +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/CoreLoopToggle.tsx +111 -0
- package/.claude/worktrees/phase-2-mcp/src/components/EnvironmentStatus.tsx +176 -0
- package/.claude/worktrees/phase-2-mcp/src/components/EvolutionBackground.tsx +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ReactQueryProvider.tsx +24 -0
- package/.claude/worktrees/phase-2-mcp/src/components/Sidebar.tsx +247 -0
- package/.claude/worktrees/phase-2-mcp/src/components/SkillDiffViewer.tsx +154 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ThemeAwareBackground.tsx +67 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ThemeToggle.tsx +54 -0
- package/.claude/worktrees/phase-2-mcp/src/components/WelcomeHero.tsx +77 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/ClickSpark.tsx +116 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/CountUp.tsx +98 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/DarkSelect.tsx +95 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/DecryptedText.tsx +161 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/ElectricBorder.tsx +184 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/GlitchText.tsx +34 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/ShinyText.tsx +55 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/SpotlightCard.tsx +42 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/TextType.tsx +95 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/index.ts +9 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/CuratorPage.tsx +632 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/DatasetPage.tsx +271 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/EvolutionPage.tsx +676 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/FunctionCallingPage.tsx +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/LogsPage.tsx +272 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/MetricsPage.tsx +246 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/OverviewPage.tsx +420 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/SettingsPage.tsx +88 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/SkillStudioPage.tsx +376 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/animated-theme-toggler.tsx +97 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/button.tsx +67 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/card.tsx +103 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/input.tsx +19 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/separator.tsx +28 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/sheet.tsx +147 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/sidebar.tsx +702 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/skeleton.tsx +13 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/theme-toggle.tsx +272 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/tooltip.tsx +57 -0
- package/.claude/worktrees/phase-2-mcp/src/hooks/use-mobile.ts +19 -0
- package/.claude/worktrees/phase-2-mcp/src/lib/api.ts +455 -0
- package/.claude/worktrees/phase-2-mcp/src/lib/queryClient.ts +12 -0
- package/.claude/worktrees/phase-2-mcp/src/lib/utils.ts +6 -0
- package/.claude/worktrees/phase-2-mcp/stitch/agent_dashboard/DESIGN_SPEC.md +521 -0
- package/.claude/worktrees/phase-2-mcp/stitch/agent_dashboard/prototype.html +676 -0
- package/.claude/worktrees/phase-2-mcp/stitch/curator_workspace/code.html +448 -0
- package/.claude/worktrees/phase-2-mcp/stitch/curator_workspace/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/datasets/code.html +479 -0
- package/.claude/worktrees/phase-2-mcp/stitch/datasets/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/evolution_history/code.html +461 -0
- package/.claude/worktrees/phase-2-mcp/stitch/evolution_history/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/hermes_dashboard/DESIGN.md +192 -0
- package/.claude/worktrees/phase-2-mcp/stitch/hermes_dashboard/DESIGN_SPEC.md +455 -0
- package/.claude/worktrees/phase-2-mcp/stitch/hermes_overview/code.html +399 -0
- package/.claude/worktrees/phase-2-mcp/stitch/hermes_overview/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/live_logs/code.html +324 -0
- package/.claude/worktrees/phase-2-mcp/stitch/live_logs/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/skill_hub/code.html +596 -0
- package/.claude/worktrees/phase-2-mcp/stitch/skill_hub/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/system_metrics/code.html +527 -0
- package/.claude/worktrees/phase-2-mcp/stitch/system_metrics/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/system_settings/code.html +257 -0
- package/.claude/worktrees/phase-2-mcp/stitch/system_settings/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/test_dashboard.py +201 -0
- package/.claude/worktrees/phase-2-mcp/tests/collectors/__init__.py +0 -0
- package/.claude/worktrees/phase-2-mcp/tests/collectors/fixtures/sample_session.jsonl +7 -0
- package/.claude/worktrees/phase-2-mcp/tests/collectors/test_claude_code_collector.py +171 -0
- package/.claude/worktrees/phase-2-mcp/tests/collectors/test_hermes_collector.py +167 -0
- package/.claude/worktrees/phase-2-mcp/tests/eval/test_engine.py +234 -0
- package/.claude/worktrees/phase-2-mcp/tests/eval/test_scorers.py +249 -0
- package/.claude/worktrees/phase-2-mcp/tests/storage/__init__.py +0 -0
- package/.claude/worktrees/phase-2-mcp/tests/storage/test_run_store.py +359 -0
- package/.claude/worktrees/phase-2-mcp/tests/test_curator.py +559 -0
- package/.claude/worktrees/phase-2-mcp/tests/test_mcp_server.py +114 -0
- package/.claude/worktrees/phase-2-mcp/tsconfig.json +34 -0
- package/.env.example +72 -0
- package/.kilocode/package-lock.json +378 -0
- package/.kilocode/package.json +5 -0
- package/AGENTS.md +5 -0
- package/CLAUDE.md +29 -0
- package/QA_AUDIT_PLAN.md +156 -0
- package/README.md +355 -0
- package/agent-agnostic-evolution-dashboard.md +405 -0
- package/backend/__init__.py +0 -0
- package/backend/collectors/__init__.py +0 -0
- package/backend/collectors/claude_code_collector.py +277 -0
- package/backend/collectors/hermes_collector.py +68 -0
- package/backend/curator.py +512 -0
- package/backend/eval/__init__.py +19 -0
- package/backend/eval/engine.py +116 -0
- package/backend/eval/scorers.py +201 -0
- package/backend/generate_dataset.py +86 -0
- package/backend/job_tracker.py +232 -0
- package/backend/main.py +1746 -0
- package/backend/mcp_server.py +250 -0
- package/backend/promethean/__init__.py +24 -0
- package/backend/promethean/cycle_orchestrator.py +270 -0
- package/backend/promethean/delta_validator.py +191 -0
- package/backend/promethean/dspy_compiler.py +315 -0
- package/backend/promethean/gepa_strategist.py +213 -0
- package/backend/promethean/models.py +260 -0
- package/backend/promethean/skill_deployer.py +195 -0
- package/backend/promethean/trace_ingestion.py +142 -0
- package/backend/requirements.txt +6 -0
- package/backend/sdd_evolve.py +459 -0
- package/backend/skill_detector.py +227 -0
- package/backend/skill_registry.py +289 -0
- package/backend/storage/__init__.py +5 -0
- package/backend/storage/run_store.py +393 -0
- package/backend/storage/schema.sql +99 -0
- package/backend/validate_evolution.py +267 -0
- package/bin/genoma.js +250 -0
- package/components.json +28 -0
- package/docs/api/hermes-api.openapi.yaml +438 -0
- package/docs/hero.svg +148 -0
- package/eslint.config.mjs +18 -0
- package/install.sh +245 -0
- package/next-env.d.ts +6 -0
- package/next.config.ts +32 -0
- package/package.json +46 -0
- package/pnpm-workspace.yaml +4 -0
- package/postcss.config.mjs +7 -0
- package/public/file.svg +1 -0
- package/public/fonts/SF-Pro-Display-Bold.otf +0 -0
- package/public/fonts/SF-Pro-Display-Heavy.otf +0 -0
- package/public/fonts/SF-Pro-Display-Medium.otf +0 -0
- package/public/fonts/SF-Pro-Display-Regular.otf +0 -0
- package/public/fonts/SF-Pro-Display-Semibold.otf +0 -0
- package/public/fonts/SF-Pro-Text-Bold.otf +0 -0
- package/public/fonts/SF-Pro-Text-Heavy.otf +0 -0
- package/public/fonts/SF-Pro-Text-Medium.otf +0 -0
- package/public/fonts/SF-Pro-Text-Regular.otf +0 -0
- package/public/fonts/SF-Pro-Text-Semibold.otf +0 -0
- package/public/globe.svg +1 -0
- package/public/next.svg +1 -0
- package/public/theme-preview.html +257 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/run.sh +26 -0
- package/scripts/postinstall.js +50 -0
- package/skills-lock.json +10 -0
- package/specs/event-schema.md +223 -0
- package/specs/examples/run.jsonl +3 -0
- package/src/app/api/[...path]/route.ts +55 -0
- package/src/app/api/auth/token/route.ts +22 -0
- package/src/app/evolution/page.tsx +589 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +321 -0
- package/src/app/layout.tsx +63 -0
- package/src/app/page.tsx +70 -0
- package/src/app/skills/page.tsx +369 -0
- package/src/components/ApiConfigCard.tsx +199 -0
- package/src/components/ColorBends.css +1 -0
- package/src/components/ColorBends.d.ts +1 -0
- package/src/components/ColorBends.jsx +1 -0
- package/src/components/CoreLoopToggle.tsx +111 -0
- package/src/components/EnvironmentStatus.tsx +176 -0
- package/src/components/EvolutionBackground.tsx +1 -0
- package/src/components/ReactQueryProvider.tsx +24 -0
- package/src/components/Sidebar.tsx +247 -0
- package/src/components/SkillDiffViewer.tsx +154 -0
- package/src/components/ThemeAwareBackground.tsx +67 -0
- package/src/components/ThemeToggle.tsx +54 -0
- package/src/components/WelcomeHero.tsx +77 -0
- package/src/components/bits/ClickSpark.tsx +116 -0
- package/src/components/bits/CountUp.tsx +98 -0
- package/src/components/bits/DarkSelect.tsx +95 -0
- package/src/components/bits/DecryptedText.tsx +161 -0
- package/src/components/bits/ElectricBorder.tsx +184 -0
- package/src/components/bits/GlitchText.tsx +34 -0
- package/src/components/bits/ShinyText.tsx +55 -0
- package/src/components/bits/SpotlightCard.tsx +42 -0
- package/src/components/bits/TextType.tsx +95 -0
- package/src/components/bits/index.ts +9 -0
- package/src/components/pages/CuratorPage.tsx +632 -0
- package/src/components/pages/DatasetPage.tsx +271 -0
- package/src/components/pages/EvolutionPage.tsx +676 -0
- package/src/components/pages/FunctionCallingPage.tsx +1 -0
- package/src/components/pages/LogsPage.tsx +272 -0
- package/src/components/pages/MetricsPage.tsx +246 -0
- package/src/components/pages/OverviewPage.tsx +420 -0
- package/src/components/pages/SettingsPage.tsx +88 -0
- package/src/components/pages/SkillStudioPage.tsx +376 -0
- package/src/components/ui/animated-theme-toggler.tsx +97 -0
- package/src/components/ui/button.tsx +67 -0
- package/src/components/ui/card.tsx +103 -0
- package/src/components/ui/input.tsx +19 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +147 -0
- package/src/components/ui/sidebar.tsx +702 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/theme-toggle.tsx +272 -0
- package/src/components/ui/tooltip.tsx +57 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/lib/api.ts +455 -0
- package/src/lib/queryClient.ts +12 -0
- package/src/lib/utils.ts +6 -0
- package/stitch/agent_dashboard/DESIGN_SPEC.md +521 -0
- package/stitch/agent_dashboard/prototype.html +676 -0
- package/stitch/curator_workspace/code.html +448 -0
- package/stitch/curator_workspace/screen.png +0 -0
- package/stitch/datasets/code.html +479 -0
- package/stitch/datasets/screen.png +0 -0
- package/stitch/evolution_history/code.html +461 -0
- package/stitch/evolution_history/screen.png +0 -0
- package/stitch/hermes_dashboard/DESIGN.md +192 -0
- package/stitch/hermes_dashboard/DESIGN_SPEC.md +455 -0
- package/stitch/hermes_overview/code.html +399 -0
- package/stitch/hermes_overview/screen.png +0 -0
- package/stitch/live_logs/code.html +324 -0
- package/stitch/live_logs/screen.png +0 -0
- package/stitch/skill_hub/code.html +596 -0
- package/stitch/skill_hub/screen.png +0 -0
- package/stitch/system_metrics/code.html +527 -0
- package/stitch/system_metrics/screen.png +0 -0
- package/stitch/system_settings/code.html +257 -0
- package/stitch/system_settings/screen.png +0 -0
- package/test_dashboard.py +201 -0
- package/tests/collectors/__init__.py +0 -0
- package/tests/collectors/fixtures/sample_session.jsonl +7 -0
- package/tests/collectors/test_claude_code_collector.py +171 -0
- package/tests/collectors/test_hermes_collector.py +167 -0
- package/tests/eval/test_engine.py +234 -0
- package/tests/eval/test_scorers.py +249 -0
- package/tests/storage/__init__.py +0 -0
- package/tests/storage/test_run_store.py +359 -0
- package/tests/test_curator.py +559 -0
- package/tests/test_e2e_npm.py +621 -0
- package/tests/test_mcp_server.py +114 -0
- package/tsconfig.json +34 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""
|
|
2
|
+
① PERCIBE — Trace Ingestion Module
|
|
3
|
+
|
|
4
|
+
Ingests standardized traces from any AI agent (Claude Code, OpenCode, Codex, Hermes).
|
|
5
|
+
Detects anomalies using statistical methods (isolation forest on error signatures).
|
|
6
|
+
Feeds anomalies into GEPA for diagnosis.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
from collections import Counter
|
|
13
|
+
from datetime import datetime, timedelta
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
from .models import TraceRecord
|
|
18
|
+
|
|
19
|
+
TRACES_DIR = Path.home() / ".hermes" / "traces"
|
|
20
|
+
INGESTED_DIR = TRACES_DIR / "ingested"
|
|
21
|
+
PROCESSED_DIR = TRACES_DIR / "processed"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TraceIngestor:
|
|
25
|
+
"""Ingests and analyzes traces from multiple AI agents."""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
INGESTED_DIR.mkdir(parents=True, exist_ok=True)
|
|
29
|
+
PROCESSED_DIR.mkdir(parents=True, exist_ok=True)
|
|
30
|
+
|
|
31
|
+
# ── Ingestion ──────────────────────────────────────────────────
|
|
32
|
+
def ingest(self, trace: TraceRecord) -> str:
|
|
33
|
+
"""Ingest a single trace. Returns trace_id."""
|
|
34
|
+
filepath = INGESTED_DIR / f"{trace.timestamp[:10]}_{trace.trace_id}.json"
|
|
35
|
+
filepath.write_text(trace.to_json())
|
|
36
|
+
return trace.trace_id
|
|
37
|
+
|
|
38
|
+
def ingest_batch(self, traces: list[dict]) -> list[str]:
|
|
39
|
+
"""Ingest multiple raw traces. Returns list of trace_ids."""
|
|
40
|
+
ids = []
|
|
41
|
+
for raw in traces:
|
|
42
|
+
trace = TraceRecord.from_json(raw)
|
|
43
|
+
ids.append(self.ingest(trace))
|
|
44
|
+
return ids
|
|
45
|
+
|
|
46
|
+
# ── Analysis ───────────────────────────────────────────────────
|
|
47
|
+
def get_recent_failures(self, days: int = 7, min_occurrences: int = 3) -> list[dict]:
|
|
48
|
+
"""Find error signatures that appear frequently in recent traces."""
|
|
49
|
+
from datetime import timezone
|
|
50
|
+
cutoff = datetime.now(timezone.utc) - timedelta(days=days)
|
|
51
|
+
error_counts: Counter = Counter()
|
|
52
|
+
error_examples: dict[str, list[TraceRecord]] = {}
|
|
53
|
+
|
|
54
|
+
for f in INGESTED_DIR.glob("*.json"):
|
|
55
|
+
try:
|
|
56
|
+
trace = TraceRecord.from_json(f.read_text())
|
|
57
|
+
if trace.outcome != "failure":
|
|
58
|
+
continue
|
|
59
|
+
ts = datetime.fromisoformat(trace.timestamp)
|
|
60
|
+
if ts < cutoff:
|
|
61
|
+
continue
|
|
62
|
+
sig = trace.error_signature or "unknown_error"
|
|
63
|
+
error_counts[sig] += 1
|
|
64
|
+
if sig not in error_examples:
|
|
65
|
+
error_examples[sig] = []
|
|
66
|
+
if len(error_examples[sig]) < 5:
|
|
67
|
+
error_examples[sig].append(trace)
|
|
68
|
+
except Exception:
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
# Filter to signatures that meet the minimum occurrence threshold
|
|
72
|
+
anomalies = []
|
|
73
|
+
for sig, count in error_counts.most_common():
|
|
74
|
+
if count >= min_occurrences:
|
|
75
|
+
examples = error_examples.get(sig, [])
|
|
76
|
+
agents = list(set(t.agent for t in examples))
|
|
77
|
+
anomalies.append({
|
|
78
|
+
"error_signature": sig,
|
|
79
|
+
"occurrences": count,
|
|
80
|
+
"agents_affected": agents,
|
|
81
|
+
"sample_traces": [t.to_json() for t in examples[:3]],
|
|
82
|
+
"first_seen": min(t.timestamp for t in examples),
|
|
83
|
+
"last_seen": max(t.timestamp for t in examples),
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
return anomalies
|
|
87
|
+
|
|
88
|
+
def get_agent_health(self) -> dict:
|
|
89
|
+
"""Return health summary per agent."""
|
|
90
|
+
health: dict[str, dict] = {}
|
|
91
|
+
for f in INGESTED_DIR.glob("*.json"):
|
|
92
|
+
try:
|
|
93
|
+
trace = TraceRecord.from_json(f.read_text())
|
|
94
|
+
agent = trace.agent
|
|
95
|
+
if agent not in health:
|
|
96
|
+
health[agent] = {"total": 0, "success": 0, "failure": 0, "partial": 0}
|
|
97
|
+
health[agent]["total"] += 1
|
|
98
|
+
health[agent][trace.outcome] += 1
|
|
99
|
+
except Exception:
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
for agent, stats in health.items():
|
|
103
|
+
total = stats["total"]
|
|
104
|
+
stats["success_rate"] = round(stats["success"] / total, 3) if total > 0 else 0
|
|
105
|
+
|
|
106
|
+
return health
|
|
107
|
+
|
|
108
|
+
def get_trace_count(self) -> int:
|
|
109
|
+
"""Total ingested traces."""
|
|
110
|
+
return len(list(INGESTED_DIR.glob("*.json")))
|
|
111
|
+
|
|
112
|
+
# ── Dataset Extraction ─────────────────────────────────────────
|
|
113
|
+
def extract_dataset(self, error_signature: str, limit: int = 50) -> str:
|
|
114
|
+
"""Extract traces matching an error signature into a JSONL dataset."""
|
|
115
|
+
dataset_path = TRACES_DIR / "datasets" / f"{error_signature.replace('/', '_')}.jsonl"
|
|
116
|
+
TRACES_DIR.joinpath("datasets").mkdir(parents=True, exist_ok=True)
|
|
117
|
+
|
|
118
|
+
count = 0
|
|
119
|
+
with open(dataset_path, "w") as out:
|
|
120
|
+
for f in INGESTED_DIR.glob("*.json"):
|
|
121
|
+
try:
|
|
122
|
+
trace_data = json.loads(f.read_text())
|
|
123
|
+
if trace_data.get("error_signature") == error_signature:
|
|
124
|
+
out.write(json.dumps(trace_data) + "\n")
|
|
125
|
+
count += 1
|
|
126
|
+
if count >= limit:
|
|
127
|
+
break
|
|
128
|
+
except Exception:
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
return str(dataset_path)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# ── Singleton ───────────────────────────────────────────────────────
|
|
135
|
+
_ingestor: Optional[TraceIngestor] = None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def get_ingestor() -> TraceIngestor:
|
|
139
|
+
global _ingestor
|
|
140
|
+
if _ingestor is None:
|
|
141
|
+
_ingestor = TraceIngestor()
|
|
142
|
+
return _ingestor
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SDD Evolution Engine — Skill-Driven Development optimizer.
|
|
3
|
+
|
|
4
|
+
Replaces the legacy DSPy/GEPA + Ollama pipeline with a direct cloud-LLM
|
|
5
|
+
approach that follows the SDD spec:
|
|
6
|
+
|
|
7
|
+
1. Extract variables from skill templates
|
|
8
|
+
2. Iterative refinement (semantic → format → token+edge-cases)
|
|
9
|
+
3. Structured JSON output with system prompt, template, constraints
|
|
10
|
+
4. Save metrics compatible with the dashboard
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
python sdd_evolve.py --skill github-code-review --iterations 3
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import json
|
|
18
|
+
import os
|
|
19
|
+
import re
|
|
20
|
+
import sys
|
|
21
|
+
import textwrap
|
|
22
|
+
import time
|
|
23
|
+
from datetime import datetime
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import List, Optional
|
|
26
|
+
|
|
27
|
+
# ── Configuration ──────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
# Provider selection: explicit env vars > cloud keys > Ollama fallback
|
|
30
|
+
OPENROUTER_KEY = os.getenv("OPENROUTER_API_KEY")
|
|
31
|
+
NOUS_KEY = os.getenv("NOUS_API_KEY")
|
|
32
|
+
ANTHROPIC_KEY = os.getenv("ANTHROPIC_API_KEY")
|
|
33
|
+
OPENAI_KEY = os.getenv("OPENAI_API_KEY")
|
|
34
|
+
OLLAMA_BASE = os.getenv("OLLAMA_API_BASE", "")
|
|
35
|
+
OPENAI_BASE = os.getenv("OPENAI_BASE_URL", "")
|
|
36
|
+
|
|
37
|
+
# Normalize Ollama URLs so they always end with /v1
|
|
38
|
+
def _norm_ollama(url: str) -> str:
|
|
39
|
+
if url and not url.rstrip("/").endswith("/v1"):
|
|
40
|
+
return url.rstrip("/") + "/v1"
|
|
41
|
+
return url
|
|
42
|
+
|
|
43
|
+
# If main.py explicitly set OPENAI_BASE_URL to an Ollama endpoint, respect it.
|
|
44
|
+
_is_ollama_url = "11434" in OPENAI_BASE or "ollama" in OPENAI_BASE.lower() or "11434" in OLLAMA_BASE
|
|
45
|
+
|
|
46
|
+
if _is_ollama_url:
|
|
47
|
+
# Prefer OPENAI_BASE_URL when it points to Ollama (set by main.py)
|
|
48
|
+
API_BASE = _norm_ollama(OPENAI_BASE) if OPENAI_BASE else _norm_ollama(OLLAMA_BASE) or "http://localhost:11434/v1"
|
|
49
|
+
API_KEY = OPENAI_KEY or "ollama"
|
|
50
|
+
DEFAULT_MODEL = os.getenv("SDD_EVOLVE_MODEL", os.getenv("SDD_OLLAMA_MODEL", "gemma4:31b-cloud"))
|
|
51
|
+
print(f"[INFO] Using Ollama local at {API_BASE} with model {DEFAULT_MODEL}", flush=True)
|
|
52
|
+
elif OPENROUTER_KEY:
|
|
53
|
+
API_BASE = OPENAI_BASE or "https://openrouter.ai/api/v1"
|
|
54
|
+
API_KEY = OPENROUTER_KEY
|
|
55
|
+
DEFAULT_MODEL = os.getenv("SDD_EVOLVE_MODEL", "anthropic/claude-sonnet-4")
|
|
56
|
+
print(f"[INFO] Using OpenRouter with model {DEFAULT_MODEL}", flush=True)
|
|
57
|
+
elif NOUS_KEY:
|
|
58
|
+
API_BASE = OPENAI_BASE or "https://inference-api.nousresearch.com/v1"
|
|
59
|
+
API_KEY = NOUS_KEY
|
|
60
|
+
DEFAULT_MODEL = os.getenv("SDD_EVOLVE_MODEL", "moonshotai/kimi-k2.6")
|
|
61
|
+
print(f"[INFO] Using Nous API with model {DEFAULT_MODEL}", flush=True)
|
|
62
|
+
elif ANTHROPIC_KEY:
|
|
63
|
+
API_BASE = OPENAI_BASE or "https://api.anthropic.com/v1"
|
|
64
|
+
API_KEY = ANTHROPIC_KEY
|
|
65
|
+
DEFAULT_MODEL = os.getenv("SDD_EVOLVE_MODEL", "claude-sonnet-4-20250514")
|
|
66
|
+
print(f"[INFO] Using Anthropic API with model {DEFAULT_MODEL}", flush=True)
|
|
67
|
+
else:
|
|
68
|
+
# Ultimate fallback: Ollama local
|
|
69
|
+
API_BASE = "http://localhost:11434/v1"
|
|
70
|
+
API_KEY = "ollama"
|
|
71
|
+
DEFAULT_MODEL = os.getenv("SDD_EVOLVE_MODEL", "gemma4:31b-cloud")
|
|
72
|
+
print(f"[INFO] No cloud keys found — falling back to Ollama local at {API_BASE} with model {DEFAULT_MODEL}", flush=True)
|
|
73
|
+
|
|
74
|
+
SKILL_SEARCH_PATHS = [
|
|
75
|
+
Path.home() / ".hermes" / "global_skills",
|
|
76
|
+
Path.home() / ".hermes" / "skills",
|
|
77
|
+
Path.home() / ".claude" / "skills",
|
|
78
|
+
Path.home() / ".opencode" / "skills",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
# ── Logging helpers (dashboard job-tracker parses these) ───────────
|
|
82
|
+
|
|
83
|
+
class Logger:
|
|
84
|
+
def __init__(self):
|
|
85
|
+
self._phases = []
|
|
86
|
+
|
|
87
|
+
def phase(self, msg: str):
|
|
88
|
+
print(f"[PHASE] {msg}", flush=True)
|
|
89
|
+
|
|
90
|
+
def info(self, msg: str):
|
|
91
|
+
print(f"[INFO] {msg}", flush=True)
|
|
92
|
+
|
|
93
|
+
def ok(self, msg: str):
|
|
94
|
+
print(f"[OK] {msg}", flush=True)
|
|
95
|
+
|
|
96
|
+
def warn(self, msg: str):
|
|
97
|
+
print(f"[WARN] {msg}", flush=True)
|
|
98
|
+
|
|
99
|
+
def err(self, msg: str):
|
|
100
|
+
print(f"[ERROR] {msg}", flush=True)
|
|
101
|
+
|
|
102
|
+
def metric(self, key: str, value):
|
|
103
|
+
print(f"[METRIC] {key}={value}", flush=True)
|
|
104
|
+
|
|
105
|
+
def score(self, label: str, value: float):
|
|
106
|
+
print(f"[SCORE] {label}={value:.4f}", flush=True)
|
|
107
|
+
|
|
108
|
+
log = Logger()
|
|
109
|
+
|
|
110
|
+
# ── LLM client ─────────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
def _get_client():
|
|
113
|
+
try:
|
|
114
|
+
from openai import OpenAI
|
|
115
|
+
except ImportError:
|
|
116
|
+
log.err("openai package not installed. Run: pip install openai")
|
|
117
|
+
sys.exit(1)
|
|
118
|
+
|
|
119
|
+
if not API_KEY:
|
|
120
|
+
log.err("No API key found. Set OPENROUTER_API_KEY or NOUS_API_KEY in ~/.hermes/.env")
|
|
121
|
+
sys.exit(1)
|
|
122
|
+
|
|
123
|
+
return OpenAI(base_url=API_BASE, api_key=API_KEY)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def chat_completion(messages: list, model: str = DEFAULT_MODEL, temperature: float = 0.4, max_tokens: int = 4000) -> str:
|
|
127
|
+
client = _get_client()
|
|
128
|
+
resp = client.chat.completions.create(
|
|
129
|
+
model=model,
|
|
130
|
+
messages=messages,
|
|
131
|
+
temperature=temperature,
|
|
132
|
+
max_tokens=max_tokens,
|
|
133
|
+
)
|
|
134
|
+
return resp.choices[0].message.content or ""
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# ── Skill loader ───────────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
def find_skill(name: str) -> Optional[Path]:
|
|
140
|
+
for base in SKILL_SEARCH_PATHS:
|
|
141
|
+
if not base.exists():
|
|
142
|
+
continue
|
|
143
|
+
# Direct match: base/name/SKILL.md or base/name.md
|
|
144
|
+
direct = base / name / "SKILL.md"
|
|
145
|
+
if direct.exists():
|
|
146
|
+
return direct
|
|
147
|
+
direct2 = base / f"{name}.md"
|
|
148
|
+
if direct2.exists():
|
|
149
|
+
return direct2
|
|
150
|
+
# Search one level deep
|
|
151
|
+
for child in base.iterdir():
|
|
152
|
+
if child.name.lower() == name.lower():
|
|
153
|
+
if child.is_dir():
|
|
154
|
+
for cand in ["SKILL.md", "skill.md", "README.md", "index.md"]:
|
|
155
|
+
p = child / cand
|
|
156
|
+
if p.exists():
|
|
157
|
+
return p
|
|
158
|
+
elif child.suffix == ".md":
|
|
159
|
+
return child
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def load_skill(path: Path) -> dict:
|
|
164
|
+
raw = path.read_text(encoding="utf-8")
|
|
165
|
+
# Parse frontmatter
|
|
166
|
+
frontmatter = {}
|
|
167
|
+
body = raw
|
|
168
|
+
if raw.strip().startswith("---"):
|
|
169
|
+
parts = raw.split("---", 2)
|
|
170
|
+
if len(parts) >= 3:
|
|
171
|
+
try:
|
|
172
|
+
import yaml
|
|
173
|
+
frontmatter = yaml.safe_load(parts[1]) or {}
|
|
174
|
+
except Exception:
|
|
175
|
+
frontmatter = {}
|
|
176
|
+
body = parts[2]
|
|
177
|
+
|
|
178
|
+
# Extract variables {{var}}
|
|
179
|
+
variables = sorted(set(re.findall(r"\{\{\s*(\w+)\s*\}\}", raw)))
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
"path": path,
|
|
183
|
+
"name": path.parent.name if path.name == "SKILL.md" else path.stem,
|
|
184
|
+
"raw": raw,
|
|
185
|
+
"frontmatter": frontmatter,
|
|
186
|
+
"body": body,
|
|
187
|
+
"variables": variables,
|
|
188
|
+
"size": len(raw),
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
# ── Prompt builders ────────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
def build_iter1_prompt(skill: dict) -> str:
|
|
195
|
+
vars_block = "\n".join(f" - {{{{{v}}}}}" for v in skill["variables"]) or " (none detected)"
|
|
196
|
+
return textwrap.dedent(f"""\
|
|
197
|
+
You are an expert Prompt Engineer specializing in Skill-Driven Development (SDD).
|
|
198
|
+
|
|
199
|
+
TASK: Improve the semantic clarity and logical flow of the following skill.
|
|
200
|
+
|
|
201
|
+
RULES:
|
|
202
|
+
- Preserve ALL template variables exactly as {{{{varName}}}} — do not rename or remove them.
|
|
203
|
+
- Keep the same overall purpose and domain.
|
|
204
|
+
- Fix ambiguous instructions, tighten wording, and ensure a clear step-by-step flow.
|
|
205
|
+
- Add a concise "System_Prompt" section at the top if missing.
|
|
206
|
+
- Do NOT change the output format yet (that comes next iteration).
|
|
207
|
+
|
|
208
|
+
DETECTED VARIABLES:
|
|
209
|
+
{vars_block}
|
|
210
|
+
|
|
211
|
+
ORIGINAL SKILL:
|
|
212
|
+
{skill['raw'][:4000]}
|
|
213
|
+
|
|
214
|
+
OUTPUT: Return ONLY the improved skill markdown (with frontmatter). No explanations outside the markdown.
|
|
215
|
+
""")
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def build_iter2_prompt(skill: dict, iter1_text: str) -> str:
|
|
219
|
+
vars_block = "\n".join(f" - {{{{{v}}}}}" for v in skill["variables"]) or " (none detected)"
|
|
220
|
+
return textwrap.dedent(f"""\
|
|
221
|
+
You are an expert Prompt Engineer specializing in Skill-Driven Development (SDD).
|
|
222
|
+
|
|
223
|
+
TASK: Structure the output format of the following skill. Ensure it produces valid, parseable responses.
|
|
224
|
+
|
|
225
|
+
RULES:
|
|
226
|
+
- Preserve ALL template variables exactly as {{{{varName}}}}.
|
|
227
|
+
- Define a clear response format: prefer structured JSON or well-defined Markdown sections.
|
|
228
|
+
- Add Few-Shot examples (input → expected output) when helpful.
|
|
229
|
+
- Include a "Formato de Respuesta" section describing the exact output schema.
|
|
230
|
+
- If JSON output is appropriate, specify the JSON schema inline.
|
|
231
|
+
|
|
232
|
+
DETECTED VARIABLES:
|
|
233
|
+
{vars_block}
|
|
234
|
+
|
|
235
|
+
SKILL AFTER ITERATION 1 (semantic clarity):
|
|
236
|
+
{iter1_text[:4000]}
|
|
237
|
+
|
|
238
|
+
OUTPUT: Return ONLY the improved skill markdown. No explanations outside the markdown.
|
|
239
|
+
""")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def build_iter3_prompt(skill: dict, iter2_text: str) -> str:
|
|
243
|
+
vars_block = "\n".join(f" - {{{{{v}}}}}" for v in skill["variables"]) or " (none detected)"
|
|
244
|
+
return textwrap.dedent(f"""\
|
|
245
|
+
You are an expert Prompt Engineer specializing in Skill-Driven Development (SDD).
|
|
246
|
+
|
|
247
|
+
TASK: Optimize token consumption and add edge-case handling.
|
|
248
|
+
|
|
249
|
+
RULES:
|
|
250
|
+
- Preserve ALL template variables exactly as {{{{varName}}}}.
|
|
251
|
+
- Remove redundant prose. Make every sentence earn its tokens.
|
|
252
|
+
- Add explicit Constraints section with strict rules (e.g., "No respondas con prosa, solo código").
|
|
253
|
+
- Add Error Handling instructions for invalid/ambiguous inputs.
|
|
254
|
+
- Include Validation Rules as a checklist.
|
|
255
|
+
- Add a brief Meta-Data section describing the skill's capabilities and limits.
|
|
256
|
+
|
|
257
|
+
DETECTED VARIABLES:
|
|
258
|
+
{vars_block}
|
|
259
|
+
|
|
260
|
+
SKILL AFTER ITERATION 2 (structured format):
|
|
261
|
+
{iter2_text[:4000]}
|
|
262
|
+
|
|
263
|
+
OUTPUT: Return ONLY the final evolved skill markdown. No explanations outside the markdown.
|
|
264
|
+
""")
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def build_sdd_json_prompt(skill_name: str, final_md: str, iterations: int) -> str:
|
|
268
|
+
return textwrap.dedent(f"""\
|
|
269
|
+
You are an SDD (Skill-Driven Development) architect.
|
|
270
|
+
|
|
271
|
+
TASK: Analyze the evolved skill below and produce a structured SDD analysis JSON.
|
|
272
|
+
|
|
273
|
+
RULES:
|
|
274
|
+
- The "refined_prompt.system" should be the core identity instructions extracted from the skill.
|
|
275
|
+
- The "refined_prompt.template" should be the reusable user-facing template with variable placeholders.
|
|
276
|
+
- "validation_rules" must be a list of specific, testable constraints.
|
|
277
|
+
- "sdd_analysis" should explain why this version is more robust for system integration.
|
|
278
|
+
|
|
279
|
+
EVOLVED SKILL:
|
|
280
|
+
{final_md[:4000]}
|
|
281
|
+
|
|
282
|
+
OUTPUT ONLY valid JSON matching this exact schema (no markdown fences):
|
|
283
|
+
{{
|
|
284
|
+
"skill_name": "{skill_name}",
|
|
285
|
+
"iteration": {iterations},
|
|
286
|
+
"refined_prompt": {{
|
|
287
|
+
"system": "...",
|
|
288
|
+
"template": "...",
|
|
289
|
+
"validation_rules": ["..."]
|
|
290
|
+
}},
|
|
291
|
+
"sdd_analysis": "..."
|
|
292
|
+
}}
|
|
293
|
+
""")
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
# ── Quality scoring ────────────────────────────────────────────────
|
|
297
|
+
|
|
298
|
+
def score_skill(text: str, original: str) -> dict:
|
|
299
|
+
"""Compute heuristic quality metrics."""
|
|
300
|
+
scores = {}
|
|
301
|
+
|
|
302
|
+
# Structure score: has frontmatter, sections, constraints
|
|
303
|
+
has_fm = text.strip().startswith("---")
|
|
304
|
+
has_constraints = "constraint" in text.lower() or "restricción" in text.lower()
|
|
305
|
+
has_examples = "ejemplo" in text.lower() or "example" in text.lower() or "```" in text
|
|
306
|
+
has_json_schema = "json" in text.lower() and ("schema" in text.lower() or "formato" in text.lower())
|
|
307
|
+
scores["structure"] = min(1.0, (0.25 * has_fm + 0.25 * has_constraints + 0.25 * has_examples + 0.25 * has_json_schema))
|
|
308
|
+
|
|
309
|
+
# Length efficiency: not too much longer, not too much shorter
|
|
310
|
+
orig_len = len(original)
|
|
311
|
+
new_len = len(text)
|
|
312
|
+
ratio = new_len / max(orig_len, 1)
|
|
313
|
+
scores["efficiency"] = 1.0 - abs(ratio - 1.0) # peak at 1.0x, drops if diverges
|
|
314
|
+
scores["efficiency"] = max(0.0, min(1.0, scores["efficiency"]))
|
|
315
|
+
|
|
316
|
+
# Variable preservation
|
|
317
|
+
orig_vars = set(re.findall(r"\{\{\s*(\w+)\s*\}\}", original))
|
|
318
|
+
new_vars = set(re.findall(r"\{\{\s*(\w+)\s*\}\}", text))
|
|
319
|
+
if orig_vars:
|
|
320
|
+
scores["variable_preservation"] = len(new_vars & orig_vars) / len(orig_vars)
|
|
321
|
+
else:
|
|
322
|
+
scores["variable_preservation"] = 1.0
|
|
323
|
+
|
|
324
|
+
# Composite evolved score
|
|
325
|
+
scores["evolved_score"] = round(
|
|
326
|
+
0.4 * scores["structure"] + 0.3 * scores["efficiency"] + 0.3 * scores["variable_preservation"],
|
|
327
|
+
4,
|
|
328
|
+
)
|
|
329
|
+
scores["baseline_score"] = 0.5 # heuristic baseline
|
|
330
|
+
scores["improvement"] = round(scores["evolved_score"] - scores["baseline_score"], 4)
|
|
331
|
+
return scores
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
# ── Main evolution loop ────────────────────────────────────────────
|
|
335
|
+
|
|
336
|
+
def evolve_skill(skill_name: str, iterations: int = 3, hermes_repo: Optional[str] = None):
|
|
337
|
+
start_time = time.time()
|
|
338
|
+
log.phase(f"Starting SDD evolution for skill: {skill_name}")
|
|
339
|
+
log.info(f"Iterations: {iterations}, Model: {DEFAULT_MODEL}")
|
|
340
|
+
|
|
341
|
+
# 1. Load skill
|
|
342
|
+
skill_path = find_skill(skill_name)
|
|
343
|
+
if not skill_path:
|
|
344
|
+
log.err(f"Skill '{skill_name}' not found in any search path")
|
|
345
|
+
sys.exit(1)
|
|
346
|
+
|
|
347
|
+
skill = load_skill(skill_path)
|
|
348
|
+
log.ok(f"Loaded skill from {skill_path}")
|
|
349
|
+
log.info(f"Size: {skill['size']} chars | Variables: {skill['variables']}")
|
|
350
|
+
log.metric("baseline_size", skill["size"])
|
|
351
|
+
|
|
352
|
+
# 2. Run iterative refinement
|
|
353
|
+
current_text = skill["raw"]
|
|
354
|
+
|
|
355
|
+
for i in range(1, iterations + 1):
|
|
356
|
+
log.phase(f"Iteration {i}/{iterations}")
|
|
357
|
+
if i == 1:
|
|
358
|
+
prompt = build_iter1_prompt(skill)
|
|
359
|
+
label = "semantic clarity"
|
|
360
|
+
elif i == 2:
|
|
361
|
+
prompt = build_iter2_prompt(skill, current_text)
|
|
362
|
+
label = "format structure"
|
|
363
|
+
else:
|
|
364
|
+
prompt = build_iter3_prompt(skill, current_text)
|
|
365
|
+
label = "token optimization + edge cases"
|
|
366
|
+
|
|
367
|
+
log.info(f"Optimizing for: {label}")
|
|
368
|
+
try:
|
|
369
|
+
messages = [{"role": "system", "content": "You are a world-class prompt engineer."}, {"role": "user", "content": prompt}]
|
|
370
|
+
current_text = chat_completion(messages, temperature=0.3 if i < 3 else 0.2)
|
|
371
|
+
log.ok(f"Iteration {i} complete ({len(current_text)} chars)")
|
|
372
|
+
except Exception as e:
|
|
373
|
+
log.err(f"LLM call failed at iteration {i}: {e}")
|
|
374
|
+
sys.exit(1)
|
|
375
|
+
|
|
376
|
+
# 3. Generate SDD JSON analysis
|
|
377
|
+
log.phase("Generating SDD analysis")
|
|
378
|
+
try:
|
|
379
|
+
sdd_json_text = chat_completion(
|
|
380
|
+
[{"role": "system", "content": "You output only valid JSON."},
|
|
381
|
+
{"role": "user", "content": build_sdd_json_prompt(skill_name, current_text, iterations)}],
|
|
382
|
+
temperature=0.1,
|
|
383
|
+
max_tokens=3000,
|
|
384
|
+
)
|
|
385
|
+
# Clean up potential markdown fences
|
|
386
|
+
sdd_json_text = re.sub(r"^```json\s*|\s*```$", "", sdd_json_text.strip(), flags=re.MULTILINE)
|
|
387
|
+
sdd_data = json.loads(sdd_json_text)
|
|
388
|
+
log.ok("SDD analysis generated")
|
|
389
|
+
except Exception as e:
|
|
390
|
+
log.warn(f"Could not generate structured SDD analysis: {e}")
|
|
391
|
+
sdd_data = {
|
|
392
|
+
"skill_name": skill_name,
|
|
393
|
+
"iteration": iterations,
|
|
394
|
+
"refined_prompt": {"system": "", "template": "", "validation_rules": []},
|
|
395
|
+
"sdd_analysis": "SDD analysis generation failed.",
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
# 4. Score
|
|
399
|
+
log.phase("Evaluating evolved skill")
|
|
400
|
+
scores = score_skill(current_text, skill["raw"])
|
|
401
|
+
for k, v in scores.items():
|
|
402
|
+
log.score(k, v)
|
|
403
|
+
|
|
404
|
+
# 5. Save outputs
|
|
405
|
+
output_base = Path.home() / ".hermes" / "hermes-agent-self-evolution" / "output" / skill_name
|
|
406
|
+
run_id = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
407
|
+
run_dir = output_base / run_id
|
|
408
|
+
run_dir.mkdir(parents=True, exist_ok=True)
|
|
409
|
+
|
|
410
|
+
evolved_path = run_dir / "evolved_skill.md"
|
|
411
|
+
evolved_path.write_text(current_text, encoding="utf-8")
|
|
412
|
+
|
|
413
|
+
baseline_path = run_dir / "baseline_skill.md"
|
|
414
|
+
baseline_path.write_text(skill["raw"], encoding="utf-8")
|
|
415
|
+
|
|
416
|
+
sdd_path = run_dir / "sdd_analysis.json"
|
|
417
|
+
sdd_path.write_text(json.dumps(sdd_data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
418
|
+
|
|
419
|
+
metrics = {
|
|
420
|
+
"skill_name": skill_name,
|
|
421
|
+
"timestamp": datetime.now().isoformat(),
|
|
422
|
+
"baseline_score": scores["baseline_score"],
|
|
423
|
+
"evolved_score": scores["evolved_score"],
|
|
424
|
+
"improvement": scores["improvement"],
|
|
425
|
+
"elapsed_seconds": round(time.time() - start_time, 2),
|
|
426
|
+
"iterations": iterations,
|
|
427
|
+
"optimizer_model": DEFAULT_MODEL,
|
|
428
|
+
"eval_model": DEFAULT_MODEL,
|
|
429
|
+
"constraints_passed": scores["structure"] > 0.6,
|
|
430
|
+
"original_size": skill["size"],
|
|
431
|
+
"evolved_size": len(current_text),
|
|
432
|
+
"diff_lines": len(current_text.splitlines()) - len(skill["raw"].splitlines()),
|
|
433
|
+
"sdd_analysis": sdd_data,
|
|
434
|
+
}
|
|
435
|
+
metrics_path = run_dir / "metrics.json"
|
|
436
|
+
metrics_path.write_text(json.dumps(metrics, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
437
|
+
|
|
438
|
+
log.ok(f"Saved outputs to {run_dir}")
|
|
439
|
+
log.score("final_evolved_score", scores["evolved_score"])
|
|
440
|
+
log.phase("Evolution complete")
|
|
441
|
+
|
|
442
|
+
return metrics
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
# ── CLI entrypoint ─────────────────────────────────────────────────
|
|
446
|
+
|
|
447
|
+
def main():
|
|
448
|
+
parser = argparse.ArgumentParser(description="SDD Skill Evolution Engine")
|
|
449
|
+
parser.add_argument("--skill", required=True, help="Skill name to evolve")
|
|
450
|
+
parser.add_argument("--iterations", type=int, default=3, help="Number of evolution iterations")
|
|
451
|
+
parser.add_argument("--hermes-repo", default=None, help="Path to hermes repo (unused, kept for compat)")
|
|
452
|
+
parser.add_argument("--eval-source", default="synthetic", help="Dataset source (unused, kept for compat)")
|
|
453
|
+
args = parser.parse_args()
|
|
454
|
+
|
|
455
|
+
evolve_skill(args.skill, args.iterations, args.hermes_repo)
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
if __name__ == "__main__":
|
|
459
|
+
main()
|