tribunal-kit 9.2.4 → 9.2.5
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/.agent/.manifest.json +78 -78
- package/.agent/.shared/ui-ux-pro-max/README.md +4 -4
- package/.agent/.tribunal/session.jsonl +15 -15
- package/.agent/ADRs/ADR-001-system-architecture-intelligence.md +49 -0
- package/.agent/ARCHITECTURE.md +63 -63
- package/.agent/agents/accessibility-reviewer.md +109 -109
- package/.agent/agents/agent-shield-auditor.md +18 -18
- package/.agent/agents/ai-code-reviewer.md +223 -223
- package/.agent/agents/anti-pattern-reviewer.md +104 -104
- package/.agent/agents/api-architect.md +89 -89
- package/.agent/agents/architecture-auditor.md +195 -0
- package/.agent/agents/backend-specialist.md +242 -242
- package/.agent/agents/cloud-engineer.md +120 -120
- package/.agent/agents/code-archaeologist.md +186 -186
- package/.agent/agents/complexity-reviewer.md +76 -76
- package/.agent/agents/database-architect.md +206 -206
- package/.agent/agents/db-latency-auditor.md +237 -237
- package/.agent/agents/debugger.md +215 -215
- package/.agent/agents/dependency-reviewer.md +124 -124
- package/.agent/agents/devops-engineer.md +240 -240
- package/.agent/agents/documentation-writer.md +228 -228
- package/.agent/agents/explorer-agent.md +186 -186
- package/.agent/agents/frontend-reviewer.md +195 -195
- package/.agent/agents/frontend-specialist.md +122 -122
- package/.agent/agents/game-developer.md +68 -68
- package/.agent/agents/harness-manager.md +49 -49
- package/.agent/agents/human-gate-negotiator.md +22 -22
- package/.agent/agents/interaction-reviewer.md +123 -123
- package/.agent/agents/kernel-scheduler.md +56 -56
- package/.agent/agents/logic-reviewer.md +147 -147
- package/.agent/agents/memory-archivist.md +37 -37
- package/.agent/agents/minimalist-reviewer.md +104 -104
- package/.agent/agents/mobile-developer.md +216 -216
- package/.agent/agents/mobile-reviewer.md +180 -180
- package/.agent/agents/orchestrator.md +268 -268
- package/.agent/agents/penetration-tester.md +180 -180
- package/.agent/agents/performance-optimizer.md +202 -202
- package/.agent/agents/performance-reviewer.md +180 -180
- package/.agent/agents/pipeline-reviewer.md +144 -144
- package/.agent/agents/precedence-reviewer.md +266 -266
- package/.agent/agents/product-manager.md +167 -167
- package/.agent/agents/product-owner.md +103 -103
- package/.agent/agents/product-reviewer.md +103 -103
- package/.agent/agents/project-planner.md +181 -181
- package/.agent/agents/qa-automation-engineer.md +244 -244
- package/.agent/agents/resilience-reviewer.md +108 -108
- package/.agent/agents/schema-reviewer.md +87 -87
- package/.agent/agents/security-auditor.md +204 -204
- package/.agent/agents/seo-specialist.md +213 -213
- package/.agent/agents/sql-reviewer.md +180 -180
- package/.agent/agents/supervisor-agent.md +202 -202
- package/.agent/agents/swarm-worker-contracts.md +170 -170
- package/.agent/agents/swarm-worker-registry.md +99 -99
- package/.agent/agents/system-architect.md +260 -105
- package/.agent/agents/test-coverage-reviewer.md +181 -181
- package/.agent/agents/test-engineer.md +138 -138
- package/.agent/agents/throughput-optimizer.md +316 -316
- package/.agent/agents/type-safety-reviewer.md +202 -202
- package/.agent/agents/ui-ux-auditor.md +80 -80
- package/.agent/agents/ui-visual-auditor.md +102 -102
- package/.agent/agents/ux-reviewer.md +109 -109
- package/.agent/agents/visual-reviewer.md +103 -103
- package/.agent/agents/vitals-reviewer.md +245 -245
- package/.agent/config/claude.json +18 -18
- package/.agent/config/plugin.json +102 -102
- package/.agent/config/slash-commands.json +115 -115
- package/.agent/config/specialist-registry.json +415 -415
- package/.agent/config/system-prompt.md +258 -258
- package/.agent/history/arch-mapper-cache.json +6712 -0
- package/.agent/history/architecture.idx.json +5746 -0
- package/.agent/mcp_config.json +32 -32
- package/.agent/patterns/generator.md +11 -11
- package/.agent/patterns/inversion.md +14 -14
- package/.agent/patterns/pipeline.md +11 -11
- package/.agent/patterns/reviewer.md +15 -15
- package/.agent/patterns/tool-wrapper.md +11 -11
- package/.agent/plans/implementation_plan.md +48 -0
- package/.agent/plans/task.md +35 -0
- package/.agent/routing_index.json +2060 -2060
- package/.agent/rules/GEMINI.md +437 -437
- package/.agent/rules/GEMINI_PLANNER.md +82 -82
- package/.agent/rules/kernel.md +86 -86
- package/.agent/scripts/_colors.js +210 -210
- package/.agent/scripts/_utils.js +373 -377
- package/.agent/scripts/architecture_mapper.js +625 -0
- package/.agent/scripts/ast_context_loader.js +137 -137
- package/.agent/scripts/auto_preview.js +203 -203
- package/.agent/scripts/browser_audit.js +102 -102
- package/.agent/scripts/bundle_analyzer.js +287 -287
- package/.agent/scripts/case_law_manager.js +887 -887
- package/.agent/scripts/checklist.js +300 -300
- package/.agent/scripts/cicd_validator.js +305 -305
- package/.agent/scripts/context_broker.js +962 -962
- package/.agent/scripts/context_compiler.js +1143 -1112
- package/.agent/scripts/contract_engine.js +402 -402
- package/.agent/scripts/dependency_analyzer.js +313 -313
- package/.agent/scripts/graph_builder.js +384 -384
- package/.agent/scripts/graph_visualizer.js +390 -390
- package/.agent/scripts/graph_zoom.js +181 -181
- package/.agent/scripts/guardrail_engine.js +785 -785
- package/.agent/scripts/harness_manager.js +60 -60
- package/.agent/scripts/impact_classifier.js +192 -192
- package/.agent/scripts/inner_loop_validator.js +472 -472
- package/.agent/scripts/integrity_manifest.js +484 -484
- package/.agent/scripts/lint_runner.js +218 -218
- package/.agent/scripts/marathon_harness.js +986 -986
- package/.agent/scripts/mcp_server.js +181 -181
- package/.agent/scripts/memory_archivist.js +97 -97
- package/.agent/scripts/memory_consolidator.js +37 -37
- package/.agent/scripts/memory_engine.js +782 -782
- package/.agent/scripts/minify_context.js +111 -111
- package/.agent/scripts/minimal_change_engine.js +445 -445
- package/.agent/scripts/mutation_runner.js +307 -305
- package/.agent/scripts/payload_schemas.js +164 -164
- package/.agent/scripts/pipeline_engine.js +906 -906
- package/.agent/scripts/prompt_compiler.js +272 -272
- package/.agent/scripts/schema_validator.js +326 -326
- package/.agent/scripts/security_scan.js +390 -390
- package/.agent/scripts/session_logger.js +115 -115
- package/.agent/scripts/session_manager.js +299 -299
- package/.agent/scripts/signal_detector.js +175 -175
- package/.agent/scripts/skill_evolution.js +997 -997
- package/.agent/scripts/skill_integrator.js +304 -304
- package/.agent/scripts/socratic_gate_policy.js +63 -63
- package/.agent/scripts/strengthen_skills.js +199 -199
- package/.agent/scripts/swarm_dispatcher.js +983 -979
- package/.agent/scripts/syscall_registry.js +105 -105
- package/.agent/scripts/test_runner.js +209 -209
- package/.agent/scripts/token_budget_broker.js +165 -165
- package/.agent/scripts/trace_engine.js +126 -126
- package/.agent/scripts/verify_all.js +276 -276
- package/.agent/scripts/visual_audit.js +87 -87
- package/.agent/skill_topic_map.json +314 -314
- package/.agent/skills/12-principles-of-animation/SKILL.md +51 -51
- package/.agent/skills/60fps-animation/SKILL.md +91 -91
- package/.agent/skills/accessible-animation/SKILL.md +189 -189
- package/.agent/skills/adapt/SKILL.md +56 -56
- package/.agent/skills/adr-generation/SKILL.md +57 -0
- package/.agent/skills/advanced-rag-pipelines/SKILL.md +94 -94
- package/.agent/skills/agent-organizer/SKILL.md +117 -117
- package/.agent/skills/agent-syscall-guidelines/SKILL.md +25 -25
- package/.agent/skills/agentic-patterns/SKILL.md +281 -281
- package/.agent/skills/agentic-workflows-2026/SKILL.md +91 -91
- package/.agent/skills/agentshield-security/SKILL.md +26 -26
- package/.agent/skills/ai-app-hardening/SKILL.md +51 -51
- package/.agent/skills/ai-prompt-injection-defense/SKILL.md +162 -162
- package/.agent/skills/animation-on-scroll/SKILL.md +196 -196
- package/.agent/skills/animation-systems/SKILL.md +198 -198
- package/.agent/skills/antfu-conventions/SKILL.md +54 -54
- package/.agent/skills/api-patterns/SKILL.md +218 -218
- package/.agent/skills/api-security-auditor/SKILL.md +155 -155
- package/.agent/skills/app-builder/SKILL.md +535 -535
- package/.agent/skills/app-builder/templates/SKILL.md +108 -108
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -76
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -92
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -88
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -88
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -83
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -90
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -90
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +126 -126
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +127 -127
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +172 -172
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +139 -139
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -83
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +122 -122
- package/.agent/skills/appflow-wireframe/SKILL.md +96 -96
- package/.agent/skills/apple-design/SKILL.md +89 -89
- package/.agent/skills/architecture/SKILL.md +188 -188
- package/.agent/skills/architecture-drift/SKILL.md +45 -0
- package/.agent/skills/audit-and-fix/SKILL.md +100 -100
- package/.agent/skills/authentication-best-practices/SKILL.md +157 -157
- package/.agent/skills/autonomous-execution/SKILL.md +76 -0
- package/.agent/skills/backend-security-expert/SKILL.md +73 -73
- package/.agent/skills/baseline-ui/SKILL.md +55 -55
- package/.agent/skills/bash-linux/SKILL.md +139 -139
- package/.agent/skills/behavioral-modes/SKILL.md +200 -200
- package/.agent/skills/better-colors/SKILL.md +116 -116
- package/.agent/skills/better-typography/SKILL.md +90 -90
- package/.agent/skills/better-ui/SKILL.md +130 -130
- package/.agent/skills/bolder/SKILL.md +49 -49
- package/.agent/skills/brainstorming/SKILL.md +460 -460
- package/.agent/skills/browser-audit/SKILL.md +102 -102
- package/.agent/skills/browser-native-ai/SKILL.md +72 -72
- package/.agent/skills/build-primitive/SKILL.md +50 -50
- package/.agent/skills/building-native-ui/SKILL.md +162 -162
- package/.agent/skills/cicd-pro/SKILL.md +412 -412
- package/.agent/skills/clarify/SKILL.md +55 -55
- package/.agent/skills/clean-code/SKILL.md +367 -367
- package/.agent/skills/cloud-architect/SKILL.md +409 -409
- package/.agent/skills/cobejs/SKILL.md +70 -70
- package/.agent/skills/code-review-checklist/SKILL.md +163 -163
- package/.agent/skills/codebase-design/SKILL.md +76 -76
- package/.agent/skills/colorize/SKILL.md +57 -57
- package/.agent/skills/compact-landing/SKILL.md +50 -50
- package/.agent/skills/company-logos/SKILL.md +54 -54
- package/.agent/skills/config-validator/SKILL.md +125 -125
- package/.agent/skills/containerization-pro/SKILL.md +422 -422
- package/.agent/skills/context-engineering-pro/SKILL.md +69 -69
- package/.agent/skills/create-design-md/SKILL.md +92 -92
- package/.agent/skills/critique/SKILL.md +79 -79
- package/.agent/skills/csharp-developer/SKILL.md +478 -478
- package/.agent/skills/data-validation-schemas/SKILL.md +297 -297
- package/.agent/skills/database-design/SKILL.md +219 -219
- package/.agent/skills/delight/SKILL.md +46 -46
- package/.agent/skills/deployment-procedures/SKILL.md +132 -132
- package/.agent/skills/design-lab/SKILL.md +42 -42
- package/.agent/skills/devops-engineer/SKILL.md +305 -305
- package/.agent/skills/devops-incident-responder/SKILL.md +103 -103
- package/.agent/skills/diagnosing-bugs/SKILL.md +172 -172
- package/.agent/skills/distill/SKILL.md +45 -45
- package/.agent/skills/documentation-templates/SKILL.md +251 -251
- package/.agent/skills/domain-modeling/SKILL.md +61 -61
- package/.agent/skills/duckdb-analytical-sql/SKILL.md +51 -51
- package/.agent/skills/edge-ai-mobile/SKILL.md +42 -42
- package/.agent/skills/edge-computing/SKILL.md +143 -143
- package/.agent/skills/emil-design-eng/SKILL.md +134 -134
- package/.agent/skills/error-resilience/SKILL.md +403 -403
- package/.agent/skills/expo-router-v4/SKILL.md +72 -72
- package/.agent/skills/extract-design-system/SKILL.md +120 -120
- package/.agent/skills/fabel-protocol/SKILL.md +282 -282
- package/.agent/skills/failure-mode-analysis/SKILL.md +48 -0
- package/.agent/skills/fixing-accessibility/SKILL.md +87 -87
- package/.agent/skills/fixing-metadata/SKILL.md +83 -83
- package/.agent/skills/fixing-motion-performance/SKILL.md +78 -78
- package/.agent/skills/framer-motion-expert/SKILL.md +237 -237
- package/.agent/skills/frontend-design/SKILL.md +103 -103
- package/.agent/skills/frontend-security-expert/SKILL.md +56 -56
- package/.agent/skills/game-design-expert/SKILL.md +92 -92
- package/.agent/skills/game-engineering-expert/SKILL.md +108 -108
- package/.agent/skills/generative-ui-expert/SKILL.md +100 -100
- package/.agent/skills/geo-fundamentals/SKILL.md +108 -108
- package/.agent/skills/git-pro/SKILL.md +401 -401
- package/.agent/skills/github-operations/SKILL.md +295 -295
- package/.agent/skills/gpt-taste/SKILL.md +50 -50
- package/.agent/skills/graph-engineering/SKILL.md +28 -28
- package/.agent/skills/gsap-core/SKILL.md +277 -277
- package/.agent/skills/gsap-frameworks/SKILL.md +168 -168
- package/.agent/skills/gsap-performance/SKILL.md +94 -94
- package/.agent/skills/gsap-plugins/SKILL.md +441 -441
- package/.agent/skills/gsap-react/SKILL.md +213 -213
- package/.agent/skills/gsap-scrolltrigger/SKILL.md +312 -312
- package/.agent/skills/gsap-timeline/SKILL.md +122 -122
- package/.agent/skills/gsap-utils/SKILL.md +299 -299
- package/.agent/skills/harden/SKILL.md +55 -55
- package/.agent/skills/harness-protocol/SKILL.md +48 -48
- package/.agent/skills/huggingface-spaces/SKILL.md +1 -1
- package/.agent/skills/human-gate-negotiation/SKILL.md +30 -30
- package/.agent/skills/i18n-localization/SKILL.md +134 -134
- package/.agent/skills/impeccable/SKILL.md +52 -52
- package/.agent/skills/improve-codebase-architecture/SKILL.md +48 -48
- package/.agent/skills/improve-ui/SKILL.md +70 -70
- package/.agent/skills/intelligent-routing/SKILL.md +204 -204
- package/.agent/skills/knowledge-graph/SKILL.md +71 -71
- package/.agent/skills/landing-page/SKILL.md +65 -65
- package/.agent/skills/lint-and-validate/SKILL.md +224 -224
- package/.agent/skills/llm-engineering/SKILL.md +360 -360
- package/.agent/skills/local-first/SKILL.md +138 -138
- package/.agent/skills/local-first-architecture/SKILL.md +62 -62
- package/.agent/skills/lottie-animation/SKILL.md +62 -62
- package/.agent/skills/marquee-loop/SKILL.md +72 -72
- package/.agent/skills/masked-reveal/SKILL.md +230 -230
- package/.agent/skills/mcp-builder/SKILL.md +105 -105
- package/.agent/skills/micro-interaction/SKILL.md +253 -253
- package/.agent/skills/mobile-design/SKILL.md +245 -245
- package/.agent/skills/monorepo-management/SKILL.md +295 -295
- package/.agent/skills/morphing-icons/SKILL.md +348 -348
- package/.agent/skills/motion-engineering/SKILL.md +197 -197
- package/.agent/skills/nextjs-react-expert/SKILL.md +218 -218
- package/.agent/skills/nodejs-best-practices/SKILL.md +542 -542
- package/.agent/skills/observability/SKILL.md +303 -303
- package/.agent/skills/opentelemetry-observability/SKILL.md +51 -51
- package/.agent/skills/page-transition-animation/SKILL.md +86 -86
- package/.agent/skills/parallel-agents/SKILL.md +110 -110
- package/.agent/skills/performance-profiling/SKILL.md +230 -230
- package/.agent/skills/plan-writing/SKILL.md +127 -127
- package/.agent/skills/platform-engineer/SKILL.md +108 -108
- package/.agent/skills/platform-engineering-opentofu/SKILL.md +59 -59
- package/.agent/skills/playwright-ai-e2e/SKILL.md +52 -52
- package/.agent/skills/playwright-best-practices/SKILL.md +149 -149
- package/.agent/skills/polish/SKILL.md +39 -39
- package/.agent/skills/powershell-windows/SKILL.md +122 -122
- package/.agent/skills/pricing-page/SKILL.md +48 -48
- package/.agent/skills/product-aware-heuristics/SKILL.md +390 -390
- package/.agent/skills/progressive-blur/SKILL.md +80 -80
- package/.agent/skills/project-idioms/SKILL.md +91 -91
- package/.agent/skills/property-based-testing/SKILL.md +50 -50
- package/.agent/skills/python-patterns/SKILL.md +220 -220
- package/.agent/skills/python-pro/SKILL.md +305 -305
- package/.agent/skills/quieter/SKILL.md +49 -49
- package/.agent/skills/react-doctor/SKILL.md +51 -51
- package/.agent/skills/react-specialist/SKILL.md +280 -280
- package/.agent/skills/readme-builder/SKILL.md +270 -270
- package/.agent/skills/realtime-patterns/SKILL.md +283 -283
- package/.agent/skills/red-team-tactics/SKILL.md +191 -191
- package/.agent/skills/redesign-skill/SKILL.md +46 -46
- package/.agent/skills/review-animations/SKILL.md +45 -45
- package/.agent/skills/review-animations/STANDARDS.md +87 -87
- package/.agent/skills/rust-pro/SKILL.md +652 -652
- package/.agent/skills/semantic-filesystem-navigation/SKILL.md +24 -24
- package/.agent/skills/seo-fundamentals/SKILL.md +139 -139
- package/.agent/skills/server-management/SKILL.md +178 -178
- package/.agent/skills/session-log-interrogation/SKILL.md +29 -29
- package/.agent/skills/shadcn-ui-expert/SKILL.md +196 -196
- package/.agent/skills/shape/SKILL.md +56 -56
- package/.agent/skills/skill-creator/SKILL.md +177 -177
- package/.agent/skills/soft-skill/SKILL.md +53 -53
- package/.agent/skills/sounds-on-the-web/SKILL.md +76 -76
- package/.agent/skills/sql-pro/SKILL.md +624 -624
- package/.agent/skills/subagent-driven-development/SKILL.md +32 -32
- package/.agent/skills/supabase-postgres-best-practices/SKILL.md +57 -57
- package/.agent/skills/svg-animation/SKILL.md +356 -356
- package/.agent/skills/swiftui-expert/SKILL.md +164 -164
- package/.agent/skills/swiss-design/SKILL.md +44 -44
- package/.agent/skills/system-design-pro/SKILL.md +188 -318
- package/.agent/skills/systematic-debugging/SKILL.md +129 -129
- package/.agent/skills/systematic-debugging/condition-based-waiting.md +120 -120
- package/.agent/skills/systematic-debugging/defense-in-depth.md +128 -128
- package/.agent/skills/systematic-debugging/root-cause-tracing.md +183 -183
- package/.agent/skills/tailwind-patterns/SKILL.md +583 -583
- package/.agent/skills/taste-skill/SKILL.md +52 -52
- package/.agent/skills/tdd-workflow/SKILL.md +105 -105
- package/.agent/skills/test-result-analyzer/SKILL.md +270 -270
- package/.agent/skills/testing-patterns/SKILL.md +534 -534
- package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +62 -62
- package/.agent/skills/thinking-protocol/SKILL.md +21 -21
- package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +43 -43
- package/.agent/skills/transformers-js/references/CONFIGURATION.md +1 -1
- package/.agent/skills/transitions-dev/SKILL.md +90 -90
- package/.agent/skills/trend-researcher/SKILL.md +198 -198
- package/.agent/skills/tribunal-instincts-memory/SKILL.md +31 -31
- package/.agent/skills/typescript-advanced/SKILL.md +306 -306
- package/.agent/skills/typeset/SKILL.md +60 -60
- package/.agent/skills/ui-reasoning-engine/SKILL.md +155 -155
- package/.agent/skills/ui-skill-packs/SKILL.md +57 -57
- package/.agent/skills/ui-skills-root/SKILL.md +69 -69
- package/.agent/skills/ui-ux-pro-max/SKILL.md +110 -110
- package/.agent/skills/ui-ux-researcher/SKILL.md +199 -199
- package/.agent/skills/vector-search-pgvector/SKILL.md +70 -70
- package/.agent/skills/verification-before-completion/SKILL.md +107 -107
- package/.agent/skills/vue-expert/SKILL.md +259 -259
- package/.agent/skills/vulnerability-scanner/SKILL.md +378 -378
- package/.agent/skills/web-accessibility-auditor/SKILL.md +179 -179
- package/.agent/skills/web-design-guidelines/SKILL.md +49 -49
- package/.agent/skills/web-quality-audit/SKILL.md +47 -47
- package/.agent/skills/webapp-testing/SKILL.md +128 -128
- package/.agent/skills/webgpu-performance/SKILL.md +88 -88
- package/.agent/skills/whimsy-injector/SKILL.md +305 -305
- package/.agent/skills/workflow-optimizer/SKILL.md +188 -188
- package/.agent/skills/zero-trust-passkeys/SKILL.md +82 -82
- package/.agent/templates/DESIGN.md +843 -843
- package/.agent/templates/design-tokens.json +140 -140
- package/.agent/templates/sdd/implementer-prompt.md +62 -62
- package/.agent/templates/sdd/re-review-prompt.md +36 -36
- package/.agent/templates/sdd/task-reviewer-prompt.md +78 -78
- package/.agent/workflows/acf.md +153 -153
- package/.agent/workflows/api-tester.md +189 -189
- package/.agent/workflows/assimilate.md +21 -21
- package/.agent/workflows/audit-live.md +53 -53
- package/.agent/workflows/audit.md +172 -172
- package/.agent/workflows/brainstorm.md +157 -157
- package/.agent/workflows/changelog.md +152 -152
- package/.agent/workflows/compare-web.md +35 -35
- package/.agent/workflows/context.md +102 -102
- package/.agent/workflows/contract.md +79 -79
- package/.agent/workflows/create.md +182 -182
- package/.agent/workflows/debug.md +201 -201
- package/.agent/workflows/deploy.md +215 -215
- package/.agent/workflows/enhance.md +165 -165
- package/.agent/workflows/fix-ci.md +94 -94
- package/.agent/workflows/fix.md +149 -149
- package/.agent/workflows/generate.md +216 -216
- package/.agent/workflows/htop.md +22 -22
- package/.agent/workflows/marathon.md +291 -291
- package/.agent/workflows/migrate.md +198 -198
- package/.agent/workflows/minimal.md +101 -101
- package/.agent/workflows/orchestrate.md +205 -205
- package/.agent/workflows/performance-benchmarker.md +148 -148
- package/.agent/workflows/pipeline.md +165 -165
- package/.agent/workflows/plan.md +206 -206
- package/.agent/workflows/preview.md +116 -116
- package/.agent/workflows/refactor.md +207 -207
- package/.agent/workflows/resume.md +20 -20
- package/.agent/workflows/review-ai.md +139 -139
- package/.agent/workflows/review.md +155 -155
- package/.agent/workflows/sdd.md +137 -137
- package/.agent/workflows/session.md +135 -135
- package/.agent/workflows/skill-enhancement-engine.md +84 -84
- package/.agent/workflows/status.md +112 -112
- package/.agent/workflows/strengthen-skills.md +174 -174
- package/.agent/workflows/super-prompt.md +146 -146
- package/.agent/workflows/swarm.md +218 -218
- package/.agent/workflows/team-mode.md +22 -22
- package/.agent/workflows/test.md +224 -224
- package/.agent/workflows/tribunal-backend.md +149 -149
- package/.agent/workflows/tribunal-cicd.md +109 -109
- package/.agent/workflows/tribunal-database.md +142 -142
- package/.agent/workflows/tribunal-frontend.md +157 -157
- package/.agent/workflows/tribunal-full.md +156 -156
- package/.agent/workflows/tribunal-mobile.md +142 -142
- package/.agent/workflows/tribunal-performance.md +149 -149
- package/.agent/workflows/tribunal-speed.md +222 -222
- package/.agent/workflows/tribunal-ui.md +97 -97
- package/.agent/workflows/ui-ux-pro-max.md +103 -103
- package/.agents/skills/12-principles-of-animation/SKILL.md +51 -51
- package/.agents/skills/60fps-animation/SKILL.md +91 -91
- package/.agents/skills/accessible-animation/SKILL.md +189 -189
- package/.agents/skills/adapt/SKILL.md +56 -56
- package/.agents/skills/adr-generation/SKILL.md +57 -0
- package/.agents/skills/advanced-rag-pipelines/SKILL.md +94 -94
- package/.agents/skills/agent-organizer/SKILL.md +117 -117
- package/.agents/skills/agent-syscall-guidelines/SKILL.md +25 -25
- package/.agents/skills/agentic-patterns/SKILL.md +281 -281
- package/.agents/skills/agentic-workflows-2026/SKILL.md +91 -91
- package/.agents/skills/agentshield-security/SKILL.md +26 -26
- package/.agents/skills/ai-app-hardening/SKILL.md +51 -51
- package/.agents/skills/ai-prompt-injection-defense/SKILL.md +162 -162
- package/.agents/skills/animation-on-scroll/SKILL.md +196 -196
- package/.agents/skills/animation-systems/SKILL.md +198 -198
- package/.agents/skills/antfu-conventions/SKILL.md +54 -54
- package/.agents/skills/api-patterns/SKILL.md +218 -218
- package/.agents/skills/api-security-auditor/SKILL.md +155 -155
- package/.agents/skills/app-builder/SKILL.md +535 -535
- package/.agents/skills/app-builder/templates/SKILL.md +108 -108
- package/.agents/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -76
- package/.agents/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -92
- package/.agents/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -88
- package/.agents/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -88
- package/.agents/skills/app-builder/templates/express-api/TEMPLATE.md +83 -83
- package/.agents/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -90
- package/.agents/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -90
- package/.agents/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +126 -126
- package/.agents/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +127 -127
- package/.agents/skills/app-builder/templates/nextjs-static/TEMPLATE.md +172 -172
- package/.agents/skills/app-builder/templates/nuxt-app/TEMPLATE.md +139 -139
- package/.agents/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -83
- package/.agents/skills/app-builder/templates/react-native-app/TEMPLATE.md +122 -122
- package/.agents/skills/appflow-wireframe/SKILL.md +96 -96
- package/.agents/skills/apple-design/SKILL.md +89 -89
- package/.agents/skills/architecture/SKILL.md +188 -188
- package/.agents/skills/architecture-drift/SKILL.md +45 -0
- package/.agents/skills/audit-and-fix/SKILL.md +100 -100
- package/.agents/skills/authentication-best-practices/SKILL.md +157 -157
- package/.agents/skills/autonomous-execution/SKILL.md +76 -0
- package/.agents/skills/backend-security-expert/SKILL.md +73 -73
- package/.agents/skills/baseline-ui/SKILL.md +55 -55
- package/.agents/skills/bash-linux/SKILL.md +139 -139
- package/.agents/skills/behavioral-modes/SKILL.md +200 -200
- package/.agents/skills/better-colors/SKILL.md +116 -116
- package/.agents/skills/better-typography/SKILL.md +90 -90
- package/.agents/skills/better-ui/SKILL.md +130 -130
- package/.agents/skills/bolder/SKILL.md +49 -49
- package/.agents/skills/brainstorming/SKILL.md +460 -460
- package/.agents/skills/browser-audit/SKILL.md +102 -102
- package/.agents/skills/browser-native-ai/SKILL.md +72 -72
- package/.agents/skills/build-primitive/SKILL.md +50 -50
- package/.agents/skills/building-native-ui/SKILL.md +162 -162
- package/.agents/skills/cicd-pro/SKILL.md +412 -412
- package/.agents/skills/clarify/SKILL.md +55 -55
- package/.agents/skills/clean-code/SKILL.md +367 -367
- package/.agents/skills/cloud-architect/SKILL.md +409 -409
- package/.agents/skills/cobejs/SKILL.md +70 -70
- package/.agents/skills/code-review-checklist/SKILL.md +163 -163
- package/.agents/skills/codebase-design/SKILL.md +76 -76
- package/.agents/skills/colorize/SKILL.md +57 -57
- package/.agents/skills/compact-landing/SKILL.md +50 -50
- package/.agents/skills/company-logos/SKILL.md +54 -54
- package/.agents/skills/config-validator/SKILL.md +125 -125
- package/.agents/skills/containerization-pro/SKILL.md +422 -422
- package/.agents/skills/context-engineering-pro/SKILL.md +69 -69
- package/.agents/skills/create-design-md/SKILL.md +92 -92
- package/.agents/skills/critique/SKILL.md +79 -79
- package/.agents/skills/csharp-developer/SKILL.md +478 -478
- package/.agents/skills/data-validation-schemas/SKILL.md +297 -297
- package/.agents/skills/database-design/SKILL.md +219 -219
- package/.agents/skills/delight/SKILL.md +46 -46
- package/.agents/skills/deployment-procedures/SKILL.md +132 -132
- package/.agents/skills/design-lab/SKILL.md +42 -42
- package/.agents/skills/devops-engineer/SKILL.md +305 -305
- package/.agents/skills/devops-incident-responder/SKILL.md +103 -103
- package/.agents/skills/diagnosing-bugs/SKILL.md +172 -172
- package/.agents/skills/distill/SKILL.md +45 -45
- package/.agents/skills/documentation-templates/SKILL.md +251 -251
- package/.agents/skills/domain-modeling/SKILL.md +61 -61
- package/.agents/skills/duckdb-analytical-sql/SKILL.md +51 -51
- package/.agents/skills/edge-ai-mobile/SKILL.md +42 -42
- package/.agents/skills/edge-computing/SKILL.md +143 -143
- package/.agents/skills/emil-design-eng/SKILL.md +134 -134
- package/.agents/skills/error-resilience/SKILL.md +403 -403
- package/.agents/skills/expo-router-v4/SKILL.md +72 -72
- package/.agents/skills/extract-design-system/SKILL.md +120 -120
- package/.agents/skills/fabel-protocol/SKILL.md +282 -282
- package/.agents/skills/failure-mode-analysis/SKILL.md +48 -0
- package/.agents/skills/fixing-accessibility/SKILL.md +87 -87
- package/.agents/skills/fixing-metadata/SKILL.md +83 -83
- package/.agents/skills/fixing-motion-performance/SKILL.md +78 -78
- package/.agents/skills/framer-motion-expert/SKILL.md +237 -237
- package/.agents/skills/frontend-design/SKILL.md +103 -103
- package/.agents/skills/frontend-security-expert/SKILL.md +56 -56
- package/.agents/skills/game-design-expert/SKILL.md +92 -92
- package/.agents/skills/game-engineering-expert/SKILL.md +108 -108
- package/.agents/skills/generative-ui-expert/SKILL.md +100 -100
- package/.agents/skills/geo-fundamentals/SKILL.md +108 -108
- package/.agents/skills/git-pro/SKILL.md +401 -401
- package/.agents/skills/github-operations/SKILL.md +295 -295
- package/.agents/skills/gpt-taste/SKILL.md +50 -50
- package/.agents/skills/graph-engineering/SKILL.md +28 -28
- package/.agents/skills/gsap-core/SKILL.md +277 -277
- package/.agents/skills/gsap-frameworks/SKILL.md +168 -168
- package/.agents/skills/gsap-performance/SKILL.md +94 -94
- package/.agents/skills/gsap-plugins/SKILL.md +441 -441
- package/.agents/skills/gsap-react/SKILL.md +213 -213
- package/.agents/skills/gsap-scrolltrigger/SKILL.md +312 -312
- package/.agents/skills/gsap-timeline/SKILL.md +122 -122
- package/.agents/skills/gsap-utils/SKILL.md +299 -299
- package/.agents/skills/harden/SKILL.md +55 -55
- package/.agents/skills/harness-protocol/SKILL.md +48 -48
- package/.agents/skills/huggingface-spaces/SKILL.md +1 -1
- package/.agents/skills/human-gate-negotiation/SKILL.md +30 -30
- package/.agents/skills/i18n-localization/SKILL.md +134 -134
- package/.agents/skills/impeccable/SKILL.md +52 -52
- package/.agents/skills/improve-codebase-architecture/SKILL.md +48 -48
- package/.agents/skills/improve-ui/SKILL.md +70 -70
- package/.agents/skills/intelligent-routing/SKILL.md +204 -204
- package/.agents/skills/knowledge-graph/SKILL.md +71 -71
- package/.agents/skills/landing-page/SKILL.md +65 -65
- package/.agents/skills/lint-and-validate/SKILL.md +224 -224
- package/.agents/skills/llm-engineering/SKILL.md +360 -360
- package/.agents/skills/local-first/SKILL.md +138 -138
- package/.agents/skills/local-first-architecture/SKILL.md +62 -62
- package/.agents/skills/lottie-animation/SKILL.md +62 -62
- package/.agents/skills/marquee-loop/SKILL.md +72 -72
- package/.agents/skills/masked-reveal/SKILL.md +230 -230
- package/.agents/skills/mcp-builder/SKILL.md +105 -105
- package/.agents/skills/micro-interaction/SKILL.md +253 -253
- package/.agents/skills/mobile-design/SKILL.md +245 -245
- package/.agents/skills/monorepo-management/SKILL.md +295 -295
- package/.agents/skills/morphing-icons/SKILL.md +348 -348
- package/.agents/skills/motion-engineering/SKILL.md +197 -197
- package/.agents/skills/nextjs-react-expert/SKILL.md +218 -218
- package/.agents/skills/nodejs-best-practices/SKILL.md +542 -542
- package/.agents/skills/observability/SKILL.md +303 -303
- package/.agents/skills/opentelemetry-observability/SKILL.md +51 -51
- package/.agents/skills/page-transition-animation/SKILL.md +86 -86
- package/.agents/skills/parallel-agents/SKILL.md +110 -110
- package/.agents/skills/performance-profiling/SKILL.md +230 -230
- package/.agents/skills/plan-writing/SKILL.md +127 -127
- package/.agents/skills/platform-engineer/SKILL.md +108 -108
- package/.agents/skills/platform-engineering-opentofu/SKILL.md +59 -59
- package/.agents/skills/playwright-ai-e2e/SKILL.md +52 -52
- package/.agents/skills/playwright-best-practices/SKILL.md +149 -149
- package/.agents/skills/polish/SKILL.md +39 -39
- package/.agents/skills/powershell-windows/SKILL.md +122 -122
- package/.agents/skills/pricing-page/SKILL.md +48 -48
- package/.agents/skills/product-aware-heuristics/SKILL.md +390 -390
- package/.agents/skills/progressive-blur/SKILL.md +80 -80
- package/.agents/skills/project-idioms/SKILL.md +91 -91
- package/.agents/skills/property-based-testing/SKILL.md +50 -50
- package/.agents/skills/python-patterns/SKILL.md +220 -220
- package/.agents/skills/python-pro/SKILL.md +305 -305
- package/.agents/skills/quieter/SKILL.md +49 -49
- package/.agents/skills/react-doctor/SKILL.md +51 -51
- package/.agents/skills/react-specialist/SKILL.md +280 -280
- package/.agents/skills/readme-builder/SKILL.md +270 -270
- package/.agents/skills/realtime-patterns/SKILL.md +283 -283
- package/.agents/skills/red-team-tactics/SKILL.md +191 -191
- package/.agents/skills/redesign-skill/SKILL.md +46 -46
- package/.agents/skills/review-animations/SKILL.md +45 -45
- package/.agents/skills/review-animations/STANDARDS.md +87 -87
- package/.agents/skills/rust-pro/SKILL.md +652 -652
- package/.agents/skills/semantic-filesystem-navigation/SKILL.md +24 -24
- package/.agents/skills/seo-fundamentals/SKILL.md +139 -139
- package/.agents/skills/server-management/SKILL.md +178 -178
- package/.agents/skills/session-log-interrogation/SKILL.md +29 -29
- package/.agents/skills/shadcn-ui-expert/SKILL.md +196 -196
- package/.agents/skills/shape/SKILL.md +56 -56
- package/.agents/skills/skill-creator/SKILL.md +177 -177
- package/.agents/skills/soft-skill/SKILL.md +53 -53
- package/.agents/skills/sounds-on-the-web/SKILL.md +76 -76
- package/.agents/skills/sql-pro/SKILL.md +624 -624
- package/.agents/skills/subagent-driven-development/SKILL.md +32 -32
- package/.agents/skills/supabase-postgres-best-practices/SKILL.md +57 -57
- package/.agents/skills/svg-animation/SKILL.md +356 -356
- package/.agents/skills/swiftui-expert/SKILL.md +164 -164
- package/.agents/skills/swiss-design/SKILL.md +44 -44
- package/.agents/skills/system-design-pro/SKILL.md +188 -318
- package/.agents/skills/systematic-debugging/SKILL.md +129 -129
- package/.agents/skills/systematic-debugging/condition-based-waiting.md +120 -120
- package/.agents/skills/systematic-debugging/defense-in-depth.md +128 -128
- package/.agents/skills/systematic-debugging/root-cause-tracing.md +183 -183
- package/.agents/skills/tailwind-patterns/SKILL.md +583 -583
- package/.agents/skills/taste-skill/SKILL.md +52 -52
- package/.agents/skills/tdd-workflow/SKILL.md +105 -105
- package/.agents/skills/test-result-analyzer/SKILL.md +270 -270
- package/.agents/skills/testing-patterns/SKILL.md +534 -534
- package/.agents/skills/thermo-nuclear-code-quality-review/SKILL.md +62 -62
- package/.agents/skills/thinking-protocol/SKILL.md +21 -21
- package/.agents/skills/to-spring-or-not-to-spring/SKILL.md +43 -43
- package/.agents/skills/transformers-js/references/CONFIGURATION.md +1 -1
- package/.agents/skills/transitions-dev/SKILL.md +90 -90
- package/.agents/skills/trend-researcher/SKILL.md +198 -198
- package/.agents/skills/tribunal-instincts-memory/SKILL.md +31 -31
- package/.agents/skills/typescript-advanced/SKILL.md +306 -306
- package/.agents/skills/typeset/SKILL.md +60 -60
- package/.agents/skills/ui-reasoning-engine/SKILL.md +155 -155
- package/.agents/skills/ui-skill-packs/SKILL.md +57 -57
- package/.agents/skills/ui-skills-root/SKILL.md +69 -69
- package/.agents/skills/ui-ux-pro-max/SKILL.md +110 -110
- package/.agents/skills/ui-ux-researcher/SKILL.md +199 -199
- package/.agents/skills/vector-search-pgvector/SKILL.md +70 -70
- package/.agents/skills/verification-before-completion/SKILL.md +107 -107
- package/.agents/skills/vue-expert/SKILL.md +259 -259
- package/.agents/skills/vulnerability-scanner/SKILL.md +378 -378
- package/.agents/skills/web-accessibility-auditor/SKILL.md +179 -179
- package/.agents/skills/web-design-guidelines/SKILL.md +49 -49
- package/.agents/skills/web-quality-audit/SKILL.md +47 -47
- package/.agents/skills/webapp-testing/SKILL.md +128 -128
- package/.agents/skills/webgpu-performance/SKILL.md +88 -88
- package/.agents/skills/whimsy-injector/SKILL.md +305 -305
- package/.agents/skills/workflow-optimizer/SKILL.md +188 -188
- package/.agents/skills/zero-trust-passkeys/SKILL.md +82 -82
- package/AGENTS.md +93 -93
- package/CLAUDE.md +444 -444
- package/CONTRIBUTING.md +134 -134
- package/README.md +242 -242
- package/SECURITY.md +58 -52
- package/bin/adapter-install.js +264 -264
- package/bin/global-store.js +48 -48
- package/bin/mcp-server.js +1653 -1653
- package/bin/proxy-server.js +122 -122
- package/bin/spawn-agent.js +45 -45
- package/bin/tk-proxy.js +34 -34
- package/bin/tribunal-kit.js +113 -113
- package/bin/wrapper.js +209 -211
- package/hooks/hooks-cursor.json +10 -10
- package/hooks/hooks.json +10 -10
- package/hooks/session-start.js +77 -77
- package/mcp_config.json +18 -18
- package/package.json +169 -179
- package/{.claude-plugin → plugins/claude}/marketplace.json +14 -14
- package/{.claude-plugin → plugins/claude}/plugin.json +26 -26
- package/{.codex-plugin → plugins/codex}/plugin.json +41 -41
- package/{plugin.json → plugins/core-plugin.json} +26 -26
- package/{.cursor-plugin → plugins/cursor}/plugin.json +26 -26
- package/{.devin-plugin → plugins/devin}/plugin.json +14 -14
- package/{gemini-extension.json → plugins/gemini/extension.json} +6 -6
- package/{.hermes-plugin → plugins/hermes}/__init__.py +102 -102
- package/{.hermes-plugin → plugins/hermes}/plugin.yaml +6 -6
- package/{.kimi-plugin → plugins/kimi}/plugin.json +34 -34
- package/{marketplace.json → plugins/marketplace.json} +14 -14
- package/{.opencode → plugins/opencode}/INSTALL.md +42 -42
- package/{.opencode → plugins/opencode}/plugins/tribunal.js +110 -110
- package/{.opencode → plugins/opencode}/rules.md +258 -258
- package/{.pi → plugins/pi}/extensions/tribunal.ts +130 -130
- package/scripts/apply-version.js +57 -57
- package/scripts/audit_skill_sdo.js +89 -89
- package/scripts/benchmark.js +231 -231
- package/scripts/build-graph.js +71 -71
- package/scripts/changelog.js +190 -190
- package/scripts/clean-pycache.js +42 -42
- package/scripts/context_compiler.js +1143 -1117
- package/scripts/fix-vbc.js +96 -96
- package/scripts/fix-vbc.ps1 +3 -3
- package/scripts/modernize_skills.js +268 -268
- package/scripts/package-cores.js +116 -116
- package/scripts/skill_enhancement_engine.js +608 -608
- package/scripts/stress_benchmark.js +358 -358
- package/scripts/sync-skills.js +61 -61
- package/scripts/sync-version.js +177 -177
- package/scripts/telemetry_gc.js +156 -156
- package/scripts/validate-payload.js +73 -73
- package/scripts/visual_audit.js +136 -136
- package/skills/12-principles-of-animation/SKILL.md +51 -51
- package/skills/60fps-animation/SKILL.md +91 -91
- package/skills/accessible-animation/SKILL.md +189 -189
- package/skills/adapt/SKILL.md +56 -56
- package/skills/adr-generation/SKILL.md +57 -0
- package/skills/advanced-rag-pipelines/SKILL.md +94 -94
- package/skills/agent-organizer/SKILL.md +117 -117
- package/skills/agent-syscall-guidelines/SKILL.md +25 -25
- package/skills/agentic-patterns/SKILL.md +281 -281
- package/skills/agentic-workflows-2026/SKILL.md +91 -91
- package/skills/agentshield-security/SKILL.md +26 -26
- package/skills/ai-app-hardening/SKILL.md +51 -51
- package/skills/ai-prompt-injection-defense/SKILL.md +162 -162
- package/skills/animation-on-scroll/SKILL.md +196 -196
- package/skills/animation-systems/SKILL.md +198 -198
- package/skills/antfu-conventions/SKILL.md +54 -54
- package/skills/api-patterns/SKILL.md +218 -218
- package/skills/api-security-auditor/SKILL.md +155 -155
- package/skills/app-builder/SKILL.md +535 -535
- package/skills/app-builder/templates/SKILL.md +108 -108
- package/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -76
- package/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -92
- package/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -88
- package/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -88
- package/skills/app-builder/templates/express-api/TEMPLATE.md +83 -83
- package/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -90
- package/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -90
- package/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +126 -126
- package/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +127 -127
- package/skills/app-builder/templates/nextjs-static/TEMPLATE.md +172 -172
- package/skills/app-builder/templates/nuxt-app/TEMPLATE.md +139 -139
- package/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -83
- package/skills/app-builder/templates/react-native-app/TEMPLATE.md +122 -122
- package/skills/appflow-wireframe/SKILL.md +96 -96
- package/skills/apple-design/SKILL.md +89 -89
- package/skills/architecture/SKILL.md +188 -188
- package/skills/architecture-drift/SKILL.md +45 -0
- package/skills/audit-and-fix/SKILL.md +100 -100
- package/skills/authentication-best-practices/SKILL.md +157 -157
- package/skills/autonomous-execution/SKILL.md +76 -0
- package/skills/backend-security-expert/SKILL.md +73 -73
- package/skills/baseline-ui/SKILL.md +55 -55
- package/skills/bash-linux/SKILL.md +139 -139
- package/skills/behavioral-modes/SKILL.md +200 -200
- package/skills/better-colors/SKILL.md +116 -116
- package/skills/better-typography/SKILL.md +90 -90
- package/skills/better-ui/SKILL.md +130 -130
- package/skills/bolder/SKILL.md +49 -49
- package/skills/brainstorming/SKILL.md +460 -460
- package/skills/browser-audit/SKILL.md +102 -102
- package/skills/browser-native-ai/SKILL.md +72 -72
- package/skills/build-primitive/SKILL.md +50 -50
- package/skills/building-native-ui/SKILL.md +162 -162
- package/skills/cicd-pro/SKILL.md +412 -412
- package/skills/clarify/SKILL.md +55 -55
- package/skills/clean-code/SKILL.md +367 -367
- package/skills/cloud-architect/SKILL.md +409 -409
- package/skills/cobejs/SKILL.md +70 -70
- package/skills/code-review-checklist/SKILL.md +163 -163
- package/skills/codebase-design/SKILL.md +76 -76
- package/skills/colorize/SKILL.md +57 -57
- package/skills/compact-landing/SKILL.md +50 -50
- package/skills/company-logos/SKILL.md +54 -54
- package/skills/config-validator/SKILL.md +125 -125
- package/skills/containerization-pro/SKILL.md +422 -422
- package/skills/context-engineering-pro/SKILL.md +69 -69
- package/skills/create-design-md/SKILL.md +92 -92
- package/skills/critique/SKILL.md +79 -79
- package/skills/csharp-developer/SKILL.md +478 -478
- package/skills/data-validation-schemas/SKILL.md +297 -297
- package/skills/database-design/SKILL.md +219 -219
- package/skills/delight/SKILL.md +46 -46
- package/skills/deployment-procedures/SKILL.md +132 -132
- package/skills/design-lab/SKILL.md +42 -42
- package/skills/devops-engineer/SKILL.md +305 -305
- package/skills/devops-incident-responder/SKILL.md +103 -103
- package/skills/diagnosing-bugs/SKILL.md +172 -172
- package/skills/distill/SKILL.md +45 -45
- package/skills/documentation-templates/SKILL.md +251 -251
- package/skills/domain-modeling/SKILL.md +61 -61
- package/skills/duckdb-analytical-sql/SKILL.md +51 -51
- package/skills/edge-ai-mobile/SKILL.md +42 -42
- package/skills/edge-computing/SKILL.md +143 -143
- package/skills/emil-design-eng/SKILL.md +134 -134
- package/skills/error-resilience/SKILL.md +403 -403
- package/skills/expo-router-v4/SKILL.md +72 -72
- package/skills/extract-design-system/SKILL.md +120 -120
- package/skills/fabel-protocol/SKILL.md +282 -282
- package/skills/failure-mode-analysis/SKILL.md +48 -0
- package/skills/fixing-accessibility/SKILL.md +87 -87
- package/skills/fixing-metadata/SKILL.md +83 -83
- package/skills/fixing-motion-performance/SKILL.md +78 -78
- package/skills/framer-motion-expert/SKILL.md +237 -237
- package/skills/frontend-design/SKILL.md +103 -103
- package/skills/frontend-security-expert/SKILL.md +56 -56
- package/skills/game-design-expert/SKILL.md +92 -92
- package/skills/game-engineering-expert/SKILL.md +108 -108
- package/skills/generative-ui-expert/SKILL.md +100 -100
- package/skills/geo-fundamentals/SKILL.md +108 -108
- package/skills/git-pro/SKILL.md +401 -401
- package/skills/github-operations/SKILL.md +295 -295
- package/skills/gpt-taste/SKILL.md +50 -50
- package/skills/graph-engineering/SKILL.md +28 -28
- package/skills/gsap-core/SKILL.md +277 -277
- package/skills/gsap-frameworks/SKILL.md +168 -168
- package/skills/gsap-performance/SKILL.md +94 -94
- package/skills/gsap-plugins/SKILL.md +441 -441
- package/skills/gsap-react/SKILL.md +213 -213
- package/skills/gsap-scrolltrigger/SKILL.md +312 -312
- package/skills/gsap-timeline/SKILL.md +122 -122
- package/skills/gsap-utils/SKILL.md +299 -299
- package/skills/harden/SKILL.md +55 -55
- package/skills/harness-protocol/SKILL.md +48 -48
- package/skills/huggingface-spaces/SKILL.md +1 -1
- package/skills/human-gate-negotiation/SKILL.md +30 -30
- package/skills/i18n-localization/SKILL.md +134 -134
- package/skills/impeccable/SKILL.md +52 -52
- package/skills/improve-codebase-architecture/SKILL.md +48 -48
- package/skills/improve-ui/SKILL.md +70 -70
- package/skills/intelligent-routing/SKILL.md +204 -204
- package/skills/knowledge-graph/SKILL.md +71 -71
- package/skills/landing-page/SKILL.md +65 -65
- package/skills/lint-and-validate/SKILL.md +224 -224
- package/skills/llm-engineering/SKILL.md +360 -360
- package/skills/local-first/SKILL.md +138 -138
- package/skills/local-first-architecture/SKILL.md +62 -62
- package/skills/lottie-animation/SKILL.md +62 -62
- package/skills/marquee-loop/SKILL.md +72 -72
- package/skills/masked-reveal/SKILL.md +230 -230
- package/skills/mcp-builder/SKILL.md +105 -105
- package/skills/micro-interaction/SKILL.md +253 -253
- package/skills/mobile-design/SKILL.md +245 -245
- package/skills/monorepo-management/SKILL.md +295 -295
- package/skills/morphing-icons/SKILL.md +348 -348
- package/skills/motion-engineering/SKILL.md +197 -197
- package/skills/nextjs-react-expert/SKILL.md +218 -218
- package/skills/nodejs-best-practices/SKILL.md +542 -542
- package/skills/observability/SKILL.md +303 -303
- package/skills/opentelemetry-observability/SKILL.md +51 -51
- package/skills/page-transition-animation/SKILL.md +86 -86
- package/skills/parallel-agents/SKILL.md +110 -110
- package/skills/performance-profiling/SKILL.md +230 -230
- package/skills/plan-writing/SKILL.md +127 -127
- package/skills/platform-engineer/SKILL.md +108 -108
- package/skills/platform-engineering-opentofu/SKILL.md +59 -59
- package/skills/playwright-ai-e2e/SKILL.md +52 -52
- package/skills/playwright-best-practices/SKILL.md +149 -149
- package/skills/polish/SKILL.md +39 -39
- package/skills/powershell-windows/SKILL.md +122 -122
- package/skills/pricing-page/SKILL.md +48 -48
- package/skills/product-aware-heuristics/SKILL.md +390 -390
- package/skills/progressive-blur/SKILL.md +80 -80
- package/skills/project-idioms/SKILL.md +91 -91
- package/skills/property-based-testing/SKILL.md +50 -50
- package/skills/python-patterns/SKILL.md +220 -220
- package/skills/python-pro/SKILL.md +305 -305
- package/skills/quieter/SKILL.md +49 -49
- package/skills/react-doctor/SKILL.md +51 -51
- package/skills/react-specialist/SKILL.md +280 -280
- package/skills/readme-builder/SKILL.md +270 -270
- package/skills/realtime-patterns/SKILL.md +283 -283
- package/skills/red-team-tactics/SKILL.md +191 -191
- package/skills/redesign-skill/SKILL.md +46 -46
- package/skills/review-animations/SKILL.md +45 -45
- package/skills/review-animations/STANDARDS.md +87 -87
- package/skills/rust-pro/SKILL.md +652 -652
- package/skills/semantic-filesystem-navigation/SKILL.md +24 -24
- package/skills/seo-fundamentals/SKILL.md +139 -139
- package/skills/server-management/SKILL.md +178 -178
- package/skills/session-log-interrogation/SKILL.md +29 -29
- package/skills/shadcn-ui-expert/SKILL.md +196 -196
- package/skills/shape/SKILL.md +56 -56
- package/skills/skill-creator/SKILL.md +177 -177
- package/skills/soft-skill/SKILL.md +53 -53
- package/skills/sounds-on-the-web/SKILL.md +76 -76
- package/skills/sql-pro/SKILL.md +624 -624
- package/skills/subagent-driven-development/SKILL.md +32 -32
- package/skills/supabase-postgres-best-practices/SKILL.md +57 -57
- package/skills/svg-animation/SKILL.md +356 -356
- package/skills/swiftui-expert/SKILL.md +164 -164
- package/skills/swiss-design/SKILL.md +44 -44
- package/skills/system-design-pro/SKILL.md +188 -318
- package/skills/systematic-debugging/SKILL.md +129 -129
- package/skills/systematic-debugging/condition-based-waiting.md +120 -120
- package/skills/systematic-debugging/defense-in-depth.md +128 -128
- package/skills/systematic-debugging/root-cause-tracing.md +183 -183
- package/skills/tailwind-patterns/SKILL.md +583 -583
- package/skills/taste-skill/SKILL.md +52 -52
- package/skills/tdd-workflow/SKILL.md +105 -105
- package/skills/test-result-analyzer/SKILL.md +270 -270
- package/skills/testing-patterns/SKILL.md +534 -534
- package/skills/thermo-nuclear-code-quality-review/SKILL.md +62 -62
- package/skills/thinking-protocol/SKILL.md +21 -21
- package/skills/to-spring-or-not-to-spring/SKILL.md +43 -43
- package/skills/transformers-js/references/CONFIGURATION.md +1 -1
- package/skills/transitions-dev/SKILL.md +90 -90
- package/skills/trend-researcher/SKILL.md +198 -198
- package/skills/tribunal-instincts-memory/SKILL.md +31 -31
- package/skills/typescript-advanced/SKILL.md +306 -306
- package/skills/typeset/SKILL.md +60 -60
- package/skills/ui-reasoning-engine/SKILL.md +155 -155
- package/skills/ui-skill-packs/SKILL.md +57 -57
- package/skills/ui-skills-root/SKILL.md +69 -69
- package/skills/ui-ux-pro-max/SKILL.md +110 -110
- package/skills/ui-ux-researcher/SKILL.md +199 -199
- package/skills/vector-search-pgvector/SKILL.md +70 -70
- package/skills/verification-before-completion/SKILL.md +107 -107
- package/skills/vue-expert/SKILL.md +259 -259
- package/skills/vulnerability-scanner/SKILL.md +378 -378
- package/skills/web-accessibility-auditor/SKILL.md +179 -179
- package/skills/web-design-guidelines/SKILL.md +49 -49
- package/skills/web-quality-audit/SKILL.md +47 -47
- package/skills/webapp-testing/SKILL.md +128 -128
- package/skills/webgpu-performance/SKILL.md +88 -88
- package/skills/whimsy-injector/SKILL.md +305 -305
- package/skills/workflow-optimizer/SKILL.md +188 -188
- package/skills/zero-trust-passkeys/SKILL.md +82 -82
- package/{dist → src}/browser/audit.js +229 -229
- package/{dist → src}/browser/case_bridge.js +189 -189
- package/{dist → src}/browser/cdp.js +513 -513
- package/{dist → src}/browser/compare.js +110 -110
- package/{dist → src}/browser/discovery.js +140 -140
- package/{dist → src}/browser/idpi.js +142 -142
- package/{dist → src}/browser/index.js +89 -89
- package/{dist → src}/browser/launcher.js +154 -154
- package/{dist → src}/browser/sentinel.js +202 -202
- package/{dist → src}/browser/synapse.js +251 -251
- package/{dist → src}/browser/trimmer.js +210 -210
- package/{dist → src}/commands/align.js +201 -201
- package/{dist → src}/commands/audit-web.js +112 -112
- package/{dist → src}/commands/browse.js +56 -56
- package/{dist → src}/commands/case.js +71 -73
- package/{dist → src}/commands/compare-web.js +61 -61
- package/{dist → src}/commands/compile.js +91 -91
- package/{dist → src}/commands/context.js +71 -71
- package/{dist → src}/commands/contract.js +440 -440
- package/{dist → src}/commands/deconstruct.js +58 -58
- package/{dist → src}/commands/graph.js +44 -44
- package/{dist → src}/commands/guardrail.js +275 -275
- package/{dist → src}/commands/heal.js +99 -99
- package/{dist → src}/commands/hook.js +28 -28
- package/{dist → src}/commands/init.js +393 -393
- package/{dist → src}/commands/learn.js +119 -117
- package/{dist → src}/commands/marathon.js +45 -45
- package/{dist → src}/commands/memory.js +508 -508
- package/{dist → src}/commands/minimal.js +71 -71
- package/{dist → src}/commands/mutate.js +30 -30
- package/{dist → src}/commands/native.js +264 -264
- package/{dist → src}/commands/optimize.js +332 -328
- package/{dist → src}/commands/sdd.js +265 -229
- package/{dist → src}/commands/status.js +66 -66
- package/{dist → src}/commands/sync.js +25 -25
- package/{dist → src}/commands/uninstall.js +54 -54
- package/{dist → src}/commands/update.js +37 -37
- package/{dist → src}/commands/validate.js +58 -58
- package/{dist → src}/esm/index.mjs +1 -1
- package/{dist → src}/mcp/server.js +8 -8
- package/{dist → src}/tui/banner.js +1 -1
- package/{dist → src}/tui/index.js +21 -21
- package/{dist → src}/tui/reviewer-grid.js +90 -90
- package/{dist → src}/tui/shimmer.js +91 -91
- package/{dist → src}/tui/theme.js +130 -130
- package/{dist → src}/tui/tree.js +93 -93
- package/{dist → src}/tui/wizard.js +148 -148
- package/{dist → src}/types.js +8 -8
- package/{dist → src}/utils/fs.js +102 -102
- package/{dist → src}/utils/hasher.js +142 -142
- package/{dist → src}/utils/helpers.js +53 -53
- package/{dist → src}/utils/logger.js +54 -54
- package/{dist → src}/utils/version.js +157 -157
- package/.agent/history/README.md +0 -53
- package/.agent/history/architecture-explorer.html +0 -352
- package/.agent/history/architecture-graph.yaml +0 -619
- package/.agent/history/case-law/cases/template-case.json +0 -19
- package/.agent/history/graph-cache.json +0 -1042
- package/.agent/history/integrity_manifest.json +0 -4694
- package/.agent/history/memory/.memory.idx +0 -7596
- package/.agent/history/memory/MEMORY.md +0 -512
- package/.agent/history/memory.db +0 -0
- package/.agent/history/snapshots/.opencode__plugins__tribunal.js.json +0 -12
- package/.agent/history/snapshots/.pi__extensions__tribunal.ts.json +0 -12
- package/.agent/history/snapshots/bin__adapter-install.js.json +0 -13
- package/.agent/history/snapshots/bin__global-store.js.json +0 -15
- package/.agent/history/snapshots/bin__mcp-server.js.json +0 -21
- package/.agent/history/snapshots/bin__proxy-server.js.json +0 -20
- package/.agent/history/snapshots/bin__spawn-agent.js.json +0 -12
- package/.agent/history/snapshots/bin__tk-proxy.js.json +0 -21
- package/.agent/history/snapshots/bin__tribunal-kit.js.json +0 -21
- package/.agent/history/snapshots/bin__wrapper.js.json +0 -14
- package/.agent/history/snapshots/eslint.config.js.json +0 -8
- package/.agent/history/snapshots/hooks__session-start.js.json +0 -11
- package/.agent/history/snapshots/scripts__apply-version.js.json +0 -11
- package/.agent/history/snapshots/scripts__audit_skill_sdo.js.json +0 -11
- package/.agent/history/snapshots/scripts__benchmark.js.json +0 -14
- package/.agent/history/snapshots/scripts__changelog.js.json +0 -12
- package/.agent/history/snapshots/scripts__clean-pycache.js.json +0 -11
- package/.agent/history/snapshots/scripts__context_compiler.js.json +0 -17
- package/.agent/history/snapshots/scripts__fix-vbc.js.json +0 -11
- package/.agent/history/snapshots/scripts__modernize_skills.js.json +0 -11
- package/.agent/history/snapshots/scripts__package-cores.js.json +0 -12
- package/.agent/history/snapshots/scripts__skill_enhancement_engine.js.json +0 -11
- package/.agent/history/snapshots/scripts__stress_benchmark.js.json +0 -15
- package/.agent/history/snapshots/scripts__sync-skills.js.json +0 -11
- package/.agent/history/snapshots/scripts__sync-version.js.json +0 -11
- package/.agent/history/snapshots/scripts__telemetry_gc.js.json +0 -11
- package/.agent/history/snapshots/scripts__validate-payload.js.json +0 -11
- package/.agent/history/snapshots/scripts__visual_audit.js.json +0 -11
- package/.agent/history/snapshots/test__integration__bridges.test.js.json +0 -13
- package/.agent/history/snapshots/test__integration__browser_cli.test.js.json +0 -12
- package/.agent/history/snapshots/test__integration__graceful_degradation.test.js.json +0 -12
- package/.agent/history/snapshots/test__integration__init.test.js.json +0 -13
- package/.agent/history/snapshots/test__integration__minimal_change_pipeline.test.js.json +0 -13
- package/.agent/history/snapshots/test__integration__parallel_tribunal.test.js.json +0 -12
- package/.agent/history/snapshots/test__integration__routing.test.js.json +0 -11
- package/.agent/history/snapshots/test__integration__swarm_dispatcher.test.js.json +0 -13
- package/.agent/history/snapshots/test__integration__sync_status.test.js.json +0 -13
- package/.agent/history/snapshots/test__integration__wave2.test.js.json +0 -13
- package/.agent/history/snapshots/test__integration__wrapper.test.js.json +0 -13
- package/.agent/history/snapshots/test__unit__align.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__args.test.js.json +0 -20
- package/.agent/history/snapshots/test__unit__ast_context_loader.test.js.json +0 -12
- package/.agent/history/snapshots/test__unit__audit_release.test.js.json +0 -16
- package/.agent/history/snapshots/test__unit__browser_case_bridge.test.js.json +0 -11
- package/.agent/history/snapshots/test__unit__browser_discovery.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__browser_idpi.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__browser_sentinel.test.js.json +0 -11
- package/.agent/history/snapshots/test__unit__browser_synapse.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__browser_trimmer.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__case_law_manager.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__cicd_validator.test.js.json +0 -12
- package/.agent/history/snapshots/test__unit__compile.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__context_broker.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__context_compiler.test.js.json +0 -26
- package/.agent/history/snapshots/test__unit__contract_engine.test.js.json +0 -13
- package/.agent/history/snapshots/test__unit__copyDir.test.js.json +0 -23
- package/.agent/history/snapshots/test__unit__graph_tools.test.js.json +0 -11
- package/.agent/history/snapshots/test__unit__guardrail_engine.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__impact_classifier.test.js.json +0 -12
- package/.agent/history/snapshots/test__unit__init.test.js.json +0 -14
- package/.agent/history/snapshots/test__unit__inner_loop_validator.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__integrity_manifest.test.js.json +0 -13
- package/.agent/history/snapshots/test__unit__learn.test.js.json +0 -11
- package/.agent/history/snapshots/test__unit__marathon.test.js.json +0 -22
- package/.agent/history/snapshots/test__unit__mcp_server.test.js.json +0 -16
- package/.agent/history/snapshots/test__unit__memory.test.js.json +0 -13
- package/.agent/history/snapshots/test__unit__minimal_change.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__native.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__optimize.test.js.json +0 -13
- package/.agent/history/snapshots/test__unit__path_resolution.test.js.json +0 -14
- package/.agent/history/snapshots/test__unit__platform_download_audit.test.js.json +0 -11
- package/.agent/history/snapshots/test__unit__production_readiness_evidence.test.js.json +0 -21
- package/.agent/history/snapshots/test__unit__prompt_compiler.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__sdd_integration.test.js.json +0 -12
- package/.agent/history/snapshots/test__unit__selfInstall.test.js.json +0 -23
- package/.agent/history/snapshots/test__unit__semver.test.js.json +0 -20
- package/.agent/history/snapshots/test__unit__skill_evolution.test.js.json +0 -11
- package/.agent/history/snapshots/test__unit__stress.test.js.json +0 -15
- package/.agent/history/snapshots/test__unit__swarm_dispatcher.test.js.json +0 -12
- package/.agent/history/snapshots/test__unit__token_budget_broker.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__tui.test.js.json +0 -10
- package/.agent/history/snapshots/test__unit__utils.test.js.json +0 -10
- package/.agents/plugins/marketplace.json +0 -20
- package/.claude/CLAUDE.md +0 -442
- /package/{dist → src}/cli.js +0 -0
- /package/{dist → src}/index.d.ts +0 -0
|
@@ -1,997 +1,997 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* skill_evolution.js — Tribunal Kit Skill Evolution Forge
|
|
4
|
-
* =========================================================
|
|
5
|
-
* Analyzes the delta between what the AI proposed and what the developer
|
|
6
|
-
* actually committed, then distills those decisions into evolving
|
|
7
|
-
* project-specific SKILL idioms — WITHOUT sending full files to any LLM.
|
|
8
|
-
*
|
|
9
|
-
* Core Strategy: Semantic Delta Extraction
|
|
10
|
-
* 1. Read the raw git diff of staged/recent changes
|
|
11
|
-
* 2. Strip trivial noise (whitespace, comments, import renames)
|
|
12
|
-
* 3. Score remaining lines for "Architectural Weight"
|
|
13
|
-
* 4. Only high-weight deltas reach the LLM reflection prompt
|
|
14
|
-
* 5. LLM returns structured YAML idiom entries (not prose)
|
|
15
|
-
* 6. Idioms are merged into .agent/skills/project-idioms/SKILL.md
|
|
16
|
-
*
|
|
17
|
-
* Usage:
|
|
18
|
-
* node .agent/scripts/skill_evolution.js digest
|
|
19
|
-
* node .agent/scripts/skill_evolution.js digest --dry-run
|
|
20
|
-
* node .agent/scripts/skill_evolution.js show
|
|
21
|
-
* node .agent/scripts/skill_evolution.js reset
|
|
22
|
-
* node .agent/scripts/skill_evolution.js status
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
'use strict';
|
|
26
|
-
|
|
27
|
-
const fs = require('fs');
|
|
28
|
-
const path = require('path');
|
|
29
|
-
const https = require('https');
|
|
30
|
-
const {
|
|
31
|
-
const readline = require('readline');
|
|
32
|
-
|
|
33
|
-
// ── Colours ──────────────────────────────────────────────────────────────────
|
|
34
|
-
const { GREEN, YELLOW, CYAN, RED, BLUE, BOLD, DIM, RESET } = require('./_colors');
|
|
35
|
-
|
|
36
|
-
// ── Shared Utilities ──────────────────────────────────────────────────────────
|
|
37
|
-
const { findAgentDir } = require('./_utils');
|
|
38
|
-
|
|
39
|
-
function getPaths(startDir = process.cwd()) {
|
|
40
|
-
const agentDir = findAgentDir(startDir);
|
|
41
|
-
const skillDir = path.join(agentDir, 'skills', 'project-idioms');
|
|
42
|
-
const historyDir = path.join(agentDir, 'history', 'skill-evolution');
|
|
43
|
-
return {
|
|
44
|
-
agentDir,
|
|
45
|
-
skillDir,
|
|
46
|
-
skillFile: path.join(skillDir, 'SKILL.md'),
|
|
47
|
-
historyDir,
|
|
48
|
-
logFile: path.join(historyDir, 'digest-log.json'),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ── Architectural Weight Patterns ────────────────────────────────────────────
|
|
53
|
-
const HIGH_WEIGHT_PATTERNS = [
|
|
54
|
-
/\bclass\b/,
|
|
55
|
-
/\binterface\b/,
|
|
56
|
-
/\btype\s+\w+\s*=/,
|
|
57
|
-
/\bextends\b/,
|
|
58
|
-
/\bimplements\b/,
|
|
59
|
-
/\bthrow\b/,
|
|
60
|
-
/\bcatch\b/,
|
|
61
|
-
/\btry\b/,
|
|
62
|
-
/\bprisma\.\w+\(/,
|
|
63
|
-
/\bsupabase\./,
|
|
64
|
-
/\bfetch\(/,
|
|
65
|
-
/\baxios\./,
|
|
66
|
-
/\bReturnType\b/,
|
|
67
|
-
/\bPromise</,
|
|
68
|
-
/\basync\s+function/,
|
|
69
|
-
/\bawait\b/,
|
|
70
|
-
/\bexport\s+(default\s+)?(class|function|const)/,
|
|
71
|
-
/\bmodule\.exports\b/,
|
|
72
|
-
/\bRouter\b|\bapp\.(get|post|put|delete|patch)\(/,
|
|
73
|
-
/\buse[A-Z]\w+\(/,
|
|
74
|
-
/\bcreateContext\(/,
|
|
75
|
-
/\bz\.object\(/,
|
|
76
|
-
/\bPrisma\b|\bdrizzle\b/,
|
|
77
|
-
/\benv\.\w+/,
|
|
78
|
-
/\bprocess\.env\./,
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
const NOISE_PATTERNS = [
|
|
82
|
-
/^\s*$/,
|
|
83
|
-
/^\s*(\/\/|#|\/\*).*$/,
|
|
84
|
-
/^\s*\*/,
|
|
85
|
-
/^\s*import\s+\{[^}]+\}\s+from\s+['"](?!\.)/,
|
|
86
|
-
/^\s*(console\.(log|warn|error)|print\()/,
|
|
87
|
-
/^\s*\w+\s*[:,]?\s*$/,
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
function architecturalWeight(line) {
|
|
91
|
-
const code = line.replace(/^[+-]/, '').trim();
|
|
92
|
-
for (const p of NOISE_PATTERNS) {
|
|
93
|
-
if (p.test(code)) return 0;
|
|
94
|
-
}
|
|
95
|
-
for (const p of HIGH_WEIGHT_PATTERNS) {
|
|
96
|
-
if (p.test(code)) return 2;
|
|
97
|
-
}
|
|
98
|
-
return 1;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// ── Levenshtein Semantic Deduplication ───────────────────────────────────────
|
|
102
|
-
// FIX: Replaces over-aggressive substring matching (.includes) with normalised
|
|
103
|
-
// edit-distance similarity. A new idiom must differ by >= 20% from all existing
|
|
104
|
-
// ones to be accepted. Threshold 0.80 = 80% similar → considered a duplicate.
|
|
105
|
-
|
|
106
|
-
function levenshtein(a, b) {
|
|
107
|
-
const m = a.length,
|
|
108
|
-
n = b.length;
|
|
109
|
-
// Allocate DP table with base cases pre-filled
|
|
110
|
-
const dp = Array.from({ length: m + 1 }, (_, i) =>
|
|
111
|
-
Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),
|
|
112
|
-
);
|
|
113
|
-
for (let i = 1; i <= m; i++) {
|
|
114
|
-
for (let j = 1; j <= n; j++) {
|
|
115
|
-
dp[i][j] =
|
|
116
|
-
a[i - 1] === b[j - 1]
|
|
117
|
-
? dp[i - 1][j - 1]
|
|
118
|
-
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return dp[m][n];
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function normalizedSimilarity(a, b) {
|
|
125
|
-
if (!a.length && !b.length) return 1.0;
|
|
126
|
-
const maxLen = Math.max(a.length, b.length);
|
|
127
|
-
if (maxLen === 0) return 1.0;
|
|
128
|
-
return 1 - levenshtein(a, b) / maxLen;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Returns true if newPattern is semantically similar to any existing idiom.
|
|
133
|
-
* Uses Levenshtein normalised similarity with a configurable threshold.
|
|
134
|
-
* @param {string} newPattern
|
|
135
|
-
* @param {object[]} existingIdioms - array of { pattern } objects
|
|
136
|
-
* @param {number} threshold - 0.0–1.0 (default 0.80 = 80% similar = duplicate)
|
|
137
|
-
*/
|
|
138
|
-
function isDuplicateIdiom(newPattern, existingIdioms, threshold = 0.8) {
|
|
139
|
-
const newLow = newPattern.toLowerCase();
|
|
140
|
-
return existingIdioms.some(ex => {
|
|
141
|
-
const exLow = (ex.pattern || '').toLowerCase();
|
|
142
|
-
return normalizedSimilarity(newLow, exLow) >= threshold;
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function semanticDelta(diffText, minWeight = 2) {
|
|
147
|
-
const lines = diffText.split('\n');
|
|
148
|
-
const kept = [];
|
|
149
|
-
let currentHunkHasHigh = false;
|
|
150
|
-
let hunkLines = [];
|
|
151
|
-
|
|
152
|
-
for (const line of lines) {
|
|
153
|
-
if (line.startsWith('---') || line.startsWith('+++') || line.startsWith('diff --git')) {
|
|
154
|
-
kept.push(line);
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
if (line.startsWith('@@')) {
|
|
158
|
-
if (currentHunkHasHigh) kept.push(...hunkLines);
|
|
159
|
-
currentHunkHasHigh = false;
|
|
160
|
-
hunkLines = [line];
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
if (line.startsWith('+') || line.startsWith('-')) {
|
|
164
|
-
const w = architecturalWeight(line);
|
|
165
|
-
hunkLines.push(line);
|
|
166
|
-
if (w >= minWeight) currentHunkHasHigh = true;
|
|
167
|
-
} else {
|
|
168
|
-
hunkLines.push(line);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
if (currentHunkHasHigh) kept.push(...hunkLines);
|
|
172
|
-
|
|
173
|
-
let result = kept.join('\n');
|
|
174
|
-
result = result.replace(/\n( ?\n){3,}/g, '\n\n');
|
|
175
|
-
return result.trim();
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// ── Git helpers ────────────────────────────────────────────────────────────────
|
|
179
|
-
function getGitDiff(mode = 'staged') {
|
|
180
|
-
try {
|
|
181
|
-
let
|
|
182
|
-
if (mode === 'staged')
|
|
183
|
-
else if (mode === 'head')
|
|
184
|
-
else
|
|
185
|
-
return
|
|
186
|
-
encoding: 'utf8',
|
|
187
|
-
timeout: 10000,
|
|
188
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
189
|
-
});
|
|
190
|
-
} catch {
|
|
191
|
-
return '';
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function countTokensEstimate(text) {
|
|
196
|
-
return Math.max(1, Math.floor(text.length / 4));
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// ── Idiom management ──────────────────────────────────────────────────────────
|
|
200
|
-
function loadExistingIdioms() {
|
|
201
|
-
const { skillFile } = getPaths();
|
|
202
|
-
if (!fs.existsSync(skillFile)) return [];
|
|
203
|
-
const content = fs.readFileSync(skillFile, 'utf8');
|
|
204
|
-
const idioms = [];
|
|
205
|
-
const pattern = /\|\s*(\d+)\s*\|\s*`([^`]+)`\s*\|\s*([^|]+)\|\s*([^|]+)\|\s*([^|]+)\|/g;
|
|
206
|
-
let m;
|
|
207
|
-
while ((m = pattern.exec(content)) !== null) {
|
|
208
|
-
idioms.push({
|
|
209
|
-
id: parseInt(m[1], 10),
|
|
210
|
-
pattern: m[2].trim(),
|
|
211
|
-
reason: m[3].trim(),
|
|
212
|
-
domain: m[4].trim(),
|
|
213
|
-
since: m[5].trim(),
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
return idioms;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function nextIdiomId(idioms) {
|
|
220
|
-
if (!idioms.length) return 1;
|
|
221
|
-
return Math.max(...idioms.map(i => i.id)) + 1;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function renderSkillMd(idioms, digestCount) {
|
|
225
|
-
const now = new Date().toISOString().slice(0, 10);
|
|
226
|
-
const rows = idioms.map(
|
|
227
|
-
i => `| ${i.id} | \`${i.pattern}\` | ${i.reason} | ${i.domain} | ${i.since} |`,
|
|
228
|
-
);
|
|
229
|
-
const table = rows.length ? rows.join('\n') : '_No idioms recorded yet._';
|
|
230
|
-
|
|
231
|
-
return `---
|
|
232
|
-
name: project-idioms
|
|
233
|
-
description: >
|
|
234
|
-
Auto-evolved skill containing project-specific architectural idioms.
|
|
235
|
-
Generated by skill_evolution.js — do not edit manually. Commit this
|
|
236
|
-
file to share your Engineering Culture across the team.
|
|
237
|
-
version: auto
|
|
238
|
-
last-updated: ${now}
|
|
239
|
-
digest-cycles: ${digestCount}
|
|
240
|
-
pattern: generator
|
|
241
|
-
---
|
|
242
|
-
|
|
243
|
-
# Project Idioms — Auto-Evolved Skill
|
|
244
|
-
|
|
245
|
-
> **Authority Level: ABSOLUTE**
|
|
246
|
-
> These idioms were extracted from the developer's own code decisions.
|
|
247
|
-
> They override generic agent defaults. Every agent MUST respect them.
|
|
248
|
-
|
|
249
|
-
---
|
|
250
|
-
|
|
251
|
-
## How Idioms Are Born
|
|
252
|
-
|
|
253
|
-
1. Developer commits code that differs from the AI proposal.
|
|
254
|
-
2. \`skill_evolution.js digest\` extracts architectural deltas only.
|
|
255
|
-
3. A minimal LLM reflection prompt (< 500 tokens) identifies the "WHY."
|
|
256
|
-
4. The idiom is recorded here with a stable pattern + reason pair.
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
## Recorded Idioms
|
|
261
|
-
|
|
262
|
-
| ID | Pattern | Why This Project Uses It | Domain | Since |
|
|
263
|
-
|:---|:--------|:-------------------------|:-------|:------|
|
|
264
|
-
${table}
|
|
265
|
-
|
|
266
|
-
---
|
|
267
|
-
|
|
268
|
-
## Enforcement Rules for All Agents
|
|
269
|
-
|
|
270
|
-
\`\`\`
|
|
271
|
-
□ Before proposing code: scan this skill's idiom table
|
|
272
|
-
□ If your proposal contradicts an idiom → flag it explicitly
|
|
273
|
-
□ Never override an idiom silently — always ask the developer first
|
|
274
|
-
□ When citing an idiom: "Per Project Idiom #N: [pattern] — [reason]"
|
|
275
|
-
\`\`\`
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
## Digest History
|
|
280
|
-
|
|
281
|
-
Last digest: \`${now}\`
|
|
282
|
-
Total cycles: \`${digestCount}\`
|
|
283
|
-
|
|
284
|
-
Run \`node .agent/scripts/skill_evolution.js status\` to see the full log.
|
|
285
|
-
`;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function generateReflectionPrompt(delta) {
|
|
289
|
-
return `You are analyzing a code delta from a developer who changed an AI-proposed solution.
|
|
290
|
-
Your only job: identify the ARCHITECTURAL IDIOM this change reveals about their project.
|
|
291
|
-
|
|
292
|
-
Rules:
|
|
293
|
-
- Return ONLY a YAML list of idioms. No prose. No explanation outside YAML.
|
|
294
|
-
- Each idiom: pattern (code signature), reason (1 sentence WHY), domain (backend/frontend/database/general)
|
|
295
|
-
- Ignore whitespace, comment, import changes — only architectural choices
|
|
296
|
-
- If no meaningful idiom can be extracted, return: "idioms: []"
|
|
297
|
-
- Maximum 3 idioms per delta.
|
|
298
|
-
|
|
299
|
-
Delta:
|
|
300
|
-
\`\`\`
|
|
301
|
-
${delta.slice(0, 1500)}
|
|
302
|
-
\`\`\`
|
|
303
|
-
|
|
304
|
-
Output format (YAML only):
|
|
305
|
-
idioms:
|
|
306
|
-
- pattern: "<code pattern or convention>"
|
|
307
|
-
reason: "<why this project uses this pattern>"
|
|
308
|
-
domain: "<backend|frontend|database|security|performance|general>"
|
|
309
|
-
`;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function parseLlmYamlResponse(response) {
|
|
313
|
-
const idioms = [];
|
|
314
|
-
let inIdioms = false;
|
|
315
|
-
let current = {};
|
|
316
|
-
|
|
317
|
-
for (const line of response.split('\n')) {
|
|
318
|
-
const stripped = line.trim();
|
|
319
|
-
if (stripped === 'idioms:') {
|
|
320
|
-
inIdioms = true;
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
if (!inIdioms) continue;
|
|
324
|
-
if (stripped.startsWith('- pattern:')) {
|
|
325
|
-
if (current.pattern) idioms.push(current);
|
|
326
|
-
current = {
|
|
327
|
-
pattern: stripped.split(':', 2)[1].trim().replace(/^"|"$/g, ''),
|
|
328
|
-
};
|
|
329
|
-
} else if (stripped.startsWith('reason:') && current.pattern) {
|
|
330
|
-
current.reason = stripped.split(':', 2)[1].trim().replace(/^"|"$/g, '');
|
|
331
|
-
} else if (stripped.startsWith('domain:') && current.pattern) {
|
|
332
|
-
current.domain = stripped.split(':', 2)[1].trim().replace(/^"|"$/g, '');
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
if (current.pattern) idioms.push(current);
|
|
336
|
-
return idioms;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// ── Log helpers ────────────────────────────────────────────────────────────────
|
|
340
|
-
function loadLog() {
|
|
341
|
-
const { historyDir, logFile } = getPaths();
|
|
342
|
-
fs.mkdirSync(historyDir, { recursive: true });
|
|
343
|
-
if (fs.existsSync(logFile)) {
|
|
344
|
-
try {
|
|
345
|
-
return JSON.parse(fs.readFileSync(logFile, 'utf8'));
|
|
346
|
-
} catch {
|
|
347
|
-
/* fallthrough */
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
return { cycles: [], total_tokens_saved: 0, total_idioms: 0 };
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function saveLog(log) {
|
|
354
|
-
const { historyDir, logFile } = getPaths();
|
|
355
|
-
fs.mkdirSync(historyDir, { recursive: true });
|
|
356
|
-
fs.writeFileSync(logFile, JSON.stringify(log, null, 2), 'utf8');
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// ── Auto-LLM API Integration ─────────────────────────────────────────────────
|
|
360
|
-
// GENERATE: Eliminates the manual copy-paste loop by auto-detecting an API key
|
|
361
|
-
// and calling the LLM directly. Falls back to manual mode if no key is found.
|
|
362
|
-
// Supported providers (checked in order): Anthropic → OpenAI → Gemini.
|
|
363
|
-
|
|
364
|
-
function detectLlmProvider() {
|
|
365
|
-
if (process.env.ANTHROPIC_API_KEY)
|
|
366
|
-
return { provider: 'anthropic', key: process.env.ANTHROPIC_API_KEY };
|
|
367
|
-
if (process.env.OPENAI_API_KEY) return { provider: 'openai', key: process.env.OPENAI_API_KEY };
|
|
368
|
-
if (process.env.GEMINI_API_KEY) return { provider: 'gemini', key: process.env.GEMINI_API_KEY };
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Call an LLM API with the reflection prompt. Returns the raw text response.
|
|
374
|
-
* Uses only built-in Node.js `https` — zero external dependencies.
|
|
375
|
-
*
|
|
376
|
-
* @param {string} prompt - The reflection prompt to send
|
|
377
|
-
* @param {string} provider - 'anthropic' | 'openai' | 'gemini'
|
|
378
|
-
* @param {string} apiKey - The API key
|
|
379
|
-
* @returns {Promise<string|null>} LLM response text or null on failure
|
|
380
|
-
*/
|
|
381
|
-
async function callLlmApi(prompt, provider, apiKey) {
|
|
382
|
-
const timeout = 30000; // 30s max — skill evolution is non-blocking
|
|
383
|
-
|
|
384
|
-
function httpsPost(hostname, path, headers, body) {
|
|
385
|
-
return new Promise((resolve, reject) => {
|
|
386
|
-
const data = JSON.stringify(body);
|
|
387
|
-
const req = https.request(
|
|
388
|
-
{
|
|
389
|
-
method: 'POST',
|
|
390
|
-
hostname,
|
|
391
|
-
path,
|
|
392
|
-
headers: { ...headers, 'Content-Length': Buffer.byteLength(data) },
|
|
393
|
-
},
|
|
394
|
-
res => {
|
|
395
|
-
let raw = '';
|
|
396
|
-
res.on('data', c => {
|
|
397
|
-
raw += c;
|
|
398
|
-
});
|
|
399
|
-
res.on('end', () => resolve(raw));
|
|
400
|
-
res.on('error', reject);
|
|
401
|
-
},
|
|
402
|
-
);
|
|
403
|
-
req.on('error', reject);
|
|
404
|
-
req.setTimeout(timeout, () => {
|
|
405
|
-
req.destroy(new Error('LLM API timeout'));
|
|
406
|
-
});
|
|
407
|
-
req.write(data);
|
|
408
|
-
req.end();
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
try {
|
|
413
|
-
if (provider === 'anthropic') {
|
|
414
|
-
const raw = await httpsPost(
|
|
415
|
-
'api.anthropic.com',
|
|
416
|
-
'/v1/messages',
|
|
417
|
-
{
|
|
418
|
-
'Content-Type': 'application/json',
|
|
419
|
-
'x-api-key': apiKey,
|
|
420
|
-
'anthropic-version': '2023-06-01',
|
|
421
|
-
},
|
|
422
|
-
{
|
|
423
|
-
model: 'claude-3-haiku-20240307', // Fastest/cheapest — idiom extraction
|
|
424
|
-
max_tokens: 512,
|
|
425
|
-
messages: [{ role: 'user', content: prompt }],
|
|
426
|
-
},
|
|
427
|
-
);
|
|
428
|
-
const json = JSON.parse(raw);
|
|
429
|
-
return json?.content?.[0]?.text ?? null;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (provider === 'openai') {
|
|
433
|
-
const raw = await httpsPost(
|
|
434
|
-
'api.openai.com',
|
|
435
|
-
'/v1/chat/completions',
|
|
436
|
-
{
|
|
437
|
-
'Content-Type': 'application/json',
|
|
438
|
-
Authorization: `Bearer ${apiKey}`,
|
|
439
|
-
},
|
|
440
|
-
{
|
|
441
|
-
model: 'gpt-4o-mini', // Cheapest capable model for YAML extraction
|
|
442
|
-
max_tokens: 512,
|
|
443
|
-
messages: [{ role: 'user', content: prompt }],
|
|
444
|
-
temperature: 0.1,
|
|
445
|
-
},
|
|
446
|
-
);
|
|
447
|
-
const json = JSON.parse(raw);
|
|
448
|
-
return json?.choices?.[0]?.message?.content ?? null;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
if (provider === 'gemini') {
|
|
452
|
-
const raw = await httpsPost(
|
|
453
|
-
'generativelanguage.googleapis.com',
|
|
454
|
-
`/v1beta/models/gemini-1.5-flash:generateContent?key=${apiKey}`,
|
|
455
|
-
{ 'Content-Type': 'application/json' },
|
|
456
|
-
{
|
|
457
|
-
contents: [{ parts: [{ text: prompt }] }],
|
|
458
|
-
generationConfig: { maxOutputTokens: 512, temperature: 0.1 },
|
|
459
|
-
},
|
|
460
|
-
);
|
|
461
|
-
const json = JSON.parse(raw);
|
|
462
|
-
return json?.candidates?.[0]?.content?.parts?.[0]?.text ?? null;
|
|
463
|
-
}
|
|
464
|
-
} catch {
|
|
465
|
-
return null; // Network/parse failure — caller falls back to manual mode
|
|
466
|
-
}
|
|
467
|
-
return null;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// ── Commands ──────────────────────────────────────────────────────────────────
|
|
471
|
-
// ── Strategy Filtering ────────────────────────────────────────────────────────
|
|
472
|
-
function applyStrategyFilter(signals, strategy) {
|
|
473
|
-
if (strategy === 'repair-only') {
|
|
474
|
-
return signals.filter(s => s.type === 'log_error');
|
|
475
|
-
}
|
|
476
|
-
return signals;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// ── Log Reflection Prompt ─────────────────────────────────────────────────────
|
|
480
|
-
function generateLogReflectionPrompt(delta) {
|
|
481
|
-
return `You are analyzing runtime log signals (errors, tracebacks, and warnings) from an AI agent's execution.
|
|
482
|
-
Your job is to identify systemic coding issues and extract evolution assets:
|
|
483
|
-
1. **Idioms (Genes)**: Coding rules/conventions to prevent the AI from generating this mistake again.
|
|
484
|
-
2. **Cases (Capsules)**: Rejection precedents (offending code pattern and why it failed) to block reviewers from approving it.
|
|
485
|
-
|
|
486
|
-
Rules:
|
|
487
|
-
- Return ONLY a YAML structure containing 'idioms:' and 'cases:'. No markdown boxes, no conversational prose.
|
|
488
|
-
- Maximum 3 idioms and 3 cases.
|
|
489
|
-
- If an asset category is not applicable, leave it empty (e.g., 'idioms: []').
|
|
490
|
-
|
|
491
|
-
Log Signals:
|
|
492
|
-
\`\`\`
|
|
493
|
-
${delta.slice(0, 1800)}
|
|
494
|
-
\`\`\`
|
|
495
|
-
|
|
496
|
-
Output format (YAML only):
|
|
497
|
-
idioms:
|
|
498
|
-
- pattern: "<code convention or rule to avoid this error>"
|
|
499
|
-
reason: "<why it is needed based on the error>"
|
|
500
|
-
domain: "<backend|frontend|database|security|performance|general>"
|
|
501
|
-
cases:
|
|
502
|
-
- pattern: "<offending code snippet or error-triggering pattern>"
|
|
503
|
-
reason: "<specific runtime error / traceback reason>"
|
|
504
|
-
domain: "<backend|frontend|database|security|performance|general>"
|
|
505
|
-
verdict: "REJECTED"
|
|
506
|
-
`;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
// ── Combined YAML Parser ──────────────────────────────────────────────────────
|
|
510
|
-
function parseEvolutionYaml(response) {
|
|
511
|
-
const idioms = [];
|
|
512
|
-
const cases = [];
|
|
513
|
-
let currentSection = null; // 'idioms' | 'cases'
|
|
514
|
-
let current = null;
|
|
515
|
-
|
|
516
|
-
const lines = response.split('\n');
|
|
517
|
-
for (const line of lines) {
|
|
518
|
-
const trimmed = line.trim();
|
|
519
|
-
if (trimmed === 'idioms:') {
|
|
520
|
-
if (current) {
|
|
521
|
-
if (currentSection === 'idioms') idioms.push(current);
|
|
522
|
-
if (currentSection === 'cases') cases.push(current);
|
|
523
|
-
}
|
|
524
|
-
currentSection = 'idioms';
|
|
525
|
-
current = null;
|
|
526
|
-
continue;
|
|
527
|
-
}
|
|
528
|
-
if (trimmed === 'cases:') {
|
|
529
|
-
if (current) {
|
|
530
|
-
if (currentSection === 'idioms') idioms.push(current);
|
|
531
|
-
if (currentSection === 'cases') cases.push(current);
|
|
532
|
-
}
|
|
533
|
-
currentSection = 'cases';
|
|
534
|
-
current = null;
|
|
535
|
-
continue;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (
|
|
539
|
-
trimmed.startsWith('- pattern:') ||
|
|
540
|
-
(trimmed.startsWith('- ') && trimmed.includes('pattern:'))
|
|
541
|
-
) {
|
|
542
|
-
if (current) {
|
|
543
|
-
if (currentSection === 'idioms') idioms.push(current);
|
|
544
|
-
if (currentSection === 'cases') cases.push(current);
|
|
545
|
-
}
|
|
546
|
-
let pat = '';
|
|
547
|
-
if (trimmed.startsWith('- pattern:')) {
|
|
548
|
-
pat = trimmed.substring('- pattern:'.length).trim();
|
|
549
|
-
} else {
|
|
550
|
-
pat = trimmed.split('pattern:', 2)[1].trim();
|
|
551
|
-
}
|
|
552
|
-
current = { pattern: pat.replace(/^['"]|['"]$/g, '') };
|
|
553
|
-
} else if (trimmed.startsWith('reason:') && current) {
|
|
554
|
-
current.reason = trimmed
|
|
555
|
-
.substring('reason:'.length)
|
|
556
|
-
.trim()
|
|
557
|
-
.replace(/^['"]|['"]$/g, '');
|
|
558
|
-
} else if (trimmed.startsWith('domain:') && current) {
|
|
559
|
-
current.domain = trimmed
|
|
560
|
-
.substring('domain:'.length)
|
|
561
|
-
.trim()
|
|
562
|
-
.replace(/^['"]|['"]$/g, '');
|
|
563
|
-
} else if (trimmed.startsWith('verdict:') && current) {
|
|
564
|
-
current.verdict = trimmed
|
|
565
|
-
.substring('verdict:'.length)
|
|
566
|
-
.trim()
|
|
567
|
-
.replace(/^['"]|['"]$/g, '');
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
if (current) {
|
|
572
|
-
if (currentSection === 'idioms') idioms.push(current);
|
|
573
|
-
if (currentSection === 'cases') cases.push(current);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
return { idioms, cases };
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
// ── Commands ──────────────────────────────────────────────────────────────────
|
|
580
|
-
async function cmdDigest(args) {
|
|
581
|
-
const dryRun = args.includes('--dry-run');
|
|
582
|
-
const diffMode = args.includes('--head') ? 'head' : 'staged';
|
|
583
|
-
|
|
584
|
-
const logArg = args.find(a => a.startsWith('--log='));
|
|
585
|
-
const logFile = logArg ? logArg.split('=').slice(1).join('=') : null;
|
|
586
|
-
|
|
587
|
-
const strategyArg = args.find(a => a.startsWith('--strategy='));
|
|
588
|
-
const strategy = strategyArg ? strategyArg.split('=').slice(1).join('=') : 'balanced';
|
|
589
|
-
|
|
590
|
-
console.log(`\n${BOLD}${CYAN}━━━ Skill Evolution — Digest Cycle ━━━━━━━━━━━━━━━━${RESET}`);
|
|
591
|
-
if (dryRun) console.log(` ${YELLOW}DRY RUN — no files will be written${RESET}\n`);
|
|
592
|
-
|
|
593
|
-
let rawDiff = '';
|
|
594
|
-
let delta = '';
|
|
595
|
-
let rawTokens = 0;
|
|
596
|
-
let deltaTokens = 0;
|
|
597
|
-
let logSignals = [];
|
|
598
|
-
const isLogMode = !!logFile;
|
|
599
|
-
|
|
600
|
-
if (isLogMode) {
|
|
601
|
-
console.log(` ${DIM}[1/5] Reading log file: ${logFile}...${RESET}`);
|
|
602
|
-
if (!fs.existsSync(logFile)) {
|
|
603
|
-
console.log(` ${RED}✖ Log file not found: ${logFile}${RESET}\n`);
|
|
604
|
-
return;
|
|
605
|
-
}
|
|
606
|
-
const logText = fs.readFileSync(logFile, 'utf8');
|
|
607
|
-
rawTokens = countTokensEstimate(logText);
|
|
608
|
-
|
|
609
|
-
console.log(` ${DIM}[2/5] Extracting signals from log (Signal Detector)...${RESET}`);
|
|
610
|
-
const { detectSignals } = require('./signal_detector');
|
|
611
|
-
const signals = detectSignals(logText);
|
|
612
|
-
|
|
613
|
-
if (signals.length === 0) {
|
|
614
|
-
console.log(` ${GREEN}✔ No errors or performance signals found in logs.${RESET}`);
|
|
615
|
-
console.log(` ${DIM} No self-evolution reflection needed.${RESET}\n`);
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
logSignals = applyStrategyFilter(signals, strategy);
|
|
620
|
-
if (logSignals.length === 0) {
|
|
621
|
-
console.log(` ${YELLOW}⚠ Strategy filter [${strategy}] filtered out all signals.${RESET}\n`);
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
console.log(
|
|
626
|
-
` ${GREEN}✔ Filtered to ${logSignals.length} signal(s) using [${strategy}] strategy.${RESET}`,
|
|
627
|
-
);
|
|
628
|
-
|
|
629
|
-
delta = logSignals
|
|
630
|
-
.map(s => {
|
|
631
|
-
let chunk = `--- SIGNAL: ${s.type} ---\n`;
|
|
632
|
-
if (s.file) chunk += `File: ${s.file}${s.line ? `:${s.line}` : ''}\n`;
|
|
633
|
-
chunk += `Message: ${s.message}\n`;
|
|
634
|
-
chunk += `Context:\n${s.context}\n`;
|
|
635
|
-
return chunk;
|
|
636
|
-
})
|
|
637
|
-
.join('\n\n');
|
|
638
|
-
|
|
639
|
-
deltaTokens = countTokensEstimate(delta);
|
|
640
|
-
} else {
|
|
641
|
-
console.log(` ${DIM}[1/5] Fetching git diff (${diffMode})...${RESET}`);
|
|
642
|
-
rawDiff = getGitDiff(diffMode);
|
|
643
|
-
if (!rawDiff.trim()) {
|
|
644
|
-
console.log(` ${YELLOW}⚠ No diff found. Commit or stage changes first.${RESET}`);
|
|
645
|
-
console.log(` ${DIM}Tip: Use --head to diff against the last commit.${RESET}\n`);
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
rawTokens = countTokensEstimate(rawDiff);
|
|
650
|
-
console.log(` ${DIM} Raw diff: ~${rawTokens} tokens (${rawDiff.length} chars)${RESET}`);
|
|
651
|
-
|
|
652
|
-
console.log(` ${DIM}[2/5] Extracting architectural delta (Semantic Filter)...${RESET}`);
|
|
653
|
-
delta = semanticDelta(rawDiff, 2);
|
|
654
|
-
if (!delta.trim()) {
|
|
655
|
-
console.log(` ${GREEN}✔ Delta is 100% trivial (whitespace/comments/imports only).${RESET}`);
|
|
656
|
-
console.log(` ${DIM} No LLM call needed. Zero tokens consumed.${RESET}\n`);
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
deltaTokens = countTokensEstimate(delta);
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
const savedTokens = Math.max(0, rawTokens - deltaTokens);
|
|
664
|
-
const savedPct = Math.floor((savedTokens / Math.max(rawTokens, 1)) * 100);
|
|
665
|
-
console.log(
|
|
666
|
-
` ${GREEN}✔ Filtered to ~${deltaTokens} tokens (${savedPct}% reduction, saved ~${savedTokens} tokens)${RESET}`,
|
|
667
|
-
);
|
|
668
|
-
|
|
669
|
-
console.log(`\n ${BOLD}Architectural Delta Preview:${RESET}`);
|
|
670
|
-
const previewLines = delta.split('\n').slice(0, 20);
|
|
671
|
-
for (const line of previewLines) {
|
|
672
|
-
if (line.startsWith('+')) console.log(` ${GREEN}${line}${RESET}`);
|
|
673
|
-
else if (line.startsWith('-')) console.log(` ${RED}${line}${RESET}`);
|
|
674
|
-
else if (line.startsWith('@@')) console.log(` ${BLUE}${line}${RESET}`);
|
|
675
|
-
else console.log(` ${DIM}${line}${RESET}`);
|
|
676
|
-
}
|
|
677
|
-
if (delta.split('\n').length > 20)
|
|
678
|
-
console.log(` ... (${delta.split('\n').length - 20} more lines)`);
|
|
679
|
-
|
|
680
|
-
if (dryRun) {
|
|
681
|
-
console.log(
|
|
682
|
-
`\n ${YELLOW}[DRY RUN] Would send ${deltaTokens} tokens to LLM for reflection.${RESET}`,
|
|
683
|
-
);
|
|
684
|
-
console.log(` ${DIM}Run without --dry-run to complete the digest.${RESET}\n`);
|
|
685
|
-
return;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
// GENERATE: Auto-LLM call.
|
|
689
|
-
const reflectionPrompt = isLogMode
|
|
690
|
-
? generateLogReflectionPrompt(delta)
|
|
691
|
-
: generateReflectionPrompt(delta);
|
|
692
|
-
let llmResponse = '';
|
|
693
|
-
|
|
694
|
-
let llmCreds = detectLlmProvider();
|
|
695
|
-
if (llmCreds) {
|
|
696
|
-
console.log(` ${DIM}[3/5] LLM Reflection — auto-calling ${llmCreds.provider} API...${RESET}`);
|
|
697
|
-
const autoResponse = await callLlmApi(reflectionPrompt, llmCreds.provider, llmCreds.key);
|
|
698
|
-
if (autoResponse) {
|
|
699
|
-
llmResponse = autoResponse;
|
|
700
|
-
console.log(
|
|
701
|
-
` ${GREEN}✔ Auto-response received (${llmCreds.provider}) — ${llmResponse.split('\n').length} lines${RESET}`,
|
|
702
|
-
);
|
|
703
|
-
} else {
|
|
704
|
-
console.log(` ${YELLOW}⚠ API call failed — falling back to manual mode${RESET}`);
|
|
705
|
-
llmCreds = null;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
if (!llmCreds || !llmResponse) {
|
|
710
|
-
// Manual fallback: copy-paste mode
|
|
711
|
-
console.log(
|
|
712
|
-
`\n ${DIM}[3/5] LLM Reflection — copy the prompt below and paste the response${RESET}`,
|
|
713
|
-
);
|
|
714
|
-
console.log(
|
|
715
|
-
` ${DIM} Tip: Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY to automate this step.${RESET}`,
|
|
716
|
-
);
|
|
717
|
-
console.log(`\n ${BOLD}${'─'.repeat(60)}${RESET}`);
|
|
718
|
-
console.log(reflectionPrompt);
|
|
719
|
-
console.log(` ${BOLD}${'─'.repeat(60)}${RESET}`);
|
|
720
|
-
console.log(`\n ${BOLD}Paste LLM response below (type END_RESPONSE when done):${RESET}`);
|
|
721
|
-
|
|
722
|
-
const rl = readline.createInterface({
|
|
723
|
-
input: process.stdin,
|
|
724
|
-
output: process.stdout,
|
|
725
|
-
});
|
|
726
|
-
const responseLines = [];
|
|
727
|
-
await new Promise(resolve => {
|
|
728
|
-
const listener = line => {
|
|
729
|
-
if (line.trim() === 'END_RESPONSE') {
|
|
730
|
-
rl.removeListener('line', listener);
|
|
731
|
-
resolve();
|
|
732
|
-
} else responseLines.push(line);
|
|
733
|
-
};
|
|
734
|
-
rl.on('line', listener);
|
|
735
|
-
});
|
|
736
|
-
rl.close();
|
|
737
|
-
llmResponse = responseLines.join('\n');
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
console.log(`\n ${DIM}[4/5] Parsing idioms/cases...${RESET}`);
|
|
741
|
-
let newIdioms = [];
|
|
742
|
-
let newCases = [];
|
|
743
|
-
|
|
744
|
-
if (isLogMode) {
|
|
745
|
-
const parsed = parseEvolutionYaml(llmResponse);
|
|
746
|
-
newIdioms = parsed.idioms;
|
|
747
|
-
newCases = parsed.cases;
|
|
748
|
-
} else {
|
|
749
|
-
newIdioms = parseLlmYamlResponse(llmResponse);
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
if (!newIdioms.length && !newCases.length) {
|
|
753
|
-
console.log(` ${YELLOW}⚠ No idioms or cases extracted from LLM response.${RESET}`);
|
|
754
|
-
console.log(`\n`);
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
if (newIdioms.length > 0) {
|
|
759
|
-
console.log(` ${GREEN}✔ Extracted ${newIdioms.length} idiom(s)${RESET}`);
|
|
760
|
-
for (const idiom of newIdioms) {
|
|
761
|
-
console.log(` ${CYAN}• ${idiom.pattern || '?'}${RESET} — ${idiom.reason || ''}`);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
if (newCases.length > 0) {
|
|
766
|
-
console.log(` ${GREEN}✔ Extracted ${newCases.length} case precedent(s)${RESET}`);
|
|
767
|
-
for (const c of newCases) {
|
|
768
|
-
console.log(` ${RED}• ${c.pattern || '?'}${RESET} — ${c.reason || ''}`);
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
console.log(`\n ${DIM}[5/5] Merging into project-idioms/SKILL.md...${RESET}`);
|
|
773
|
-
const existing = loadExistingIdioms();
|
|
774
|
-
const log = loadLog();
|
|
775
|
-
let nextId = nextIdiomId(existing);
|
|
776
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
777
|
-
const merged = [...existing];
|
|
778
|
-
let added = 0;
|
|
779
|
-
|
|
780
|
-
for (const idiom of newIdioms) {
|
|
781
|
-
if (isDuplicateIdiom(idiom.pattern || '', existing)) {
|
|
782
|
-
console.log(` ${DIM} Skipped near-duplicate idiom: ${idiom.pattern}${RESET}`);
|
|
783
|
-
continue;
|
|
784
|
-
}
|
|
785
|
-
merged.push({
|
|
786
|
-
id: nextId,
|
|
787
|
-
pattern: idiom.pattern || '?',
|
|
788
|
-
reason: idiom.reason || 'No reason provided.',
|
|
789
|
-
domain: idiom.domain || 'general',
|
|
790
|
-
since: today,
|
|
791
|
-
});
|
|
792
|
-
nextId++;
|
|
793
|
-
added++;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
if (added > 0) {
|
|
797
|
-
log.total_idioms = merged.length;
|
|
798
|
-
const skillMd = renderSkillMd(merged, (log.cycles || []).length + 1);
|
|
799
|
-
const { skillDir, skillFile } = getPaths();
|
|
800
|
-
fs.mkdirSync(skillDir, { recursive: true });
|
|
801
|
-
fs.writeFileSync(skillFile, skillMd, 'utf8');
|
|
802
|
-
console.log(` ${GREEN}✔ ${added} new idiom(s) added to SKILL.md${RESET}`);
|
|
803
|
-
} else {
|
|
804
|
-
console.log(` ${DIM} No new unique idioms added to SKILL.md.${RESET}`);
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
// Record Case Precedents if present
|
|
808
|
-
if (newCases && newCases.length > 0) {
|
|
809
|
-
console.log(`\n ${DIM}Merging into Case Law precedents...${RESET}`);
|
|
810
|
-
const caseLawManager = require('./case_law_manager');
|
|
811
|
-
const clIndex = caseLawManager.loadIndex();
|
|
812
|
-
let clNextId = clIndex.next_id;
|
|
813
|
-
let clAdded = 0;
|
|
814
|
-
|
|
815
|
-
for (const c of newCases) {
|
|
816
|
-
const diffText = c.pattern || '';
|
|
817
|
-
const reason = c.reason || '';
|
|
818
|
-
const domain = c.domain || 'general';
|
|
819
|
-
const verdict = c.verdict || 'REJECTED';
|
|
820
|
-
const fingerprint = caseLawManager.contentHash(diffText);
|
|
821
|
-
|
|
822
|
-
let isDup = false;
|
|
823
|
-
for (const existing of clIndex.cases) {
|
|
824
|
-
if (existing.fingerprint === fingerprint) {
|
|
825
|
-
isDup = true;
|
|
826
|
-
break;
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
if (isDup) {
|
|
830
|
-
console.log(` ${DIM} Skipped duplicate case: ${reason.slice(0, 50)}...${RESET}`);
|
|
831
|
-
continue;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
const deltaCase = caseLawManager.semanticDelta(diffText);
|
|
835
|
-
const tags = caseLawManager.extractTags(diffText + ' ' + reason);
|
|
836
|
-
const caseRecord = {
|
|
837
|
-
id: clNextId,
|
|
838
|
-
fingerprint,
|
|
839
|
-
timestamp: new Date().toISOString().slice(0, 19),
|
|
840
|
-
domain,
|
|
841
|
-
verdict,
|
|
842
|
-
reason: reason.trim(),
|
|
843
|
-
pr_ref: 'auto-evolution',
|
|
844
|
-
reviewer: 'skill-evolution',
|
|
845
|
-
tags,
|
|
846
|
-
stack_version: null,
|
|
847
|
-
diff_raw: diffText.trim(),
|
|
848
|
-
diff_delta: deltaCase,
|
|
849
|
-
auto_recorded: true,
|
|
850
|
-
};
|
|
851
|
-
|
|
852
|
-
caseLawManager.saveCase(caseRecord);
|
|
853
|
-
clIndex.cases.push({
|
|
854
|
-
id: clNextId,
|
|
855
|
-
fingerprint,
|
|
856
|
-
domain,
|
|
857
|
-
verdict,
|
|
858
|
-
tags,
|
|
859
|
-
timestamp: caseRecord.timestamp,
|
|
860
|
-
reason_summary: reason.trim().slice(0, 120),
|
|
861
|
-
stack_version: null,
|
|
862
|
-
});
|
|
863
|
-
clNextId++;
|
|
864
|
-
clAdded++;
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
if (clAdded > 0) {
|
|
868
|
-
clIndex.next_id = clNextId;
|
|
869
|
-
caseLawManager.saveIndex(clIndex);
|
|
870
|
-
console.log(` ${GREEN}✔ ${clAdded} new Case Law precedent(s) recorded.${RESET}`);
|
|
871
|
-
} else {
|
|
872
|
-
console.log(` ${DIM} No new unique Case Law precedents recorded.${RESET}`);
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
log.cycles = log.cycles || [];
|
|
877
|
-
log.cycles.push({
|
|
878
|
-
timestamp: new Date().toISOString().slice(0, 19),
|
|
879
|
-
raw_tokens: rawTokens,
|
|
880
|
-
delta_tokens: deltaTokens,
|
|
881
|
-
tokens_saved: savedTokens,
|
|
882
|
-
idioms_added: added,
|
|
883
|
-
});
|
|
884
|
-
log.total_tokens_saved = (log.total_tokens_saved || 0) + savedTokens;
|
|
885
|
-
saveLog(log);
|
|
886
|
-
|
|
887
|
-
console.log(`\n ${GREEN}✔ Learn cycle complete.${RESET}`);
|
|
888
|
-
console.log(` ${DIM} Total idioms: ${merged.length}${RESET}`);
|
|
889
|
-
console.log(` ${DIM} Lifetime tokens saved: ${log.total_tokens_saved}${RESET}\n`);
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
function cmdShow() {
|
|
893
|
-
const { skillFile } = getPaths();
|
|
894
|
-
if (!fs.existsSync(skillFile)) {
|
|
895
|
-
console.log(`${YELLOW}No project-idioms skill found. Run 'digest' first.${RESET}`);
|
|
896
|
-
return;
|
|
897
|
-
}
|
|
898
|
-
console.log(fs.readFileSync(skillFile, 'utf8'));
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
function cmdReset() {
|
|
902
|
-
const { skillFile, logFile } = getPaths();
|
|
903
|
-
if (fs.existsSync(skillFile)) {
|
|
904
|
-
fs.unlinkSync(skillFile);
|
|
905
|
-
console.log(`${GREEN}✔ project-idioms/SKILL.md deleted.${RESET}`);
|
|
906
|
-
}
|
|
907
|
-
if (fs.existsSync(logFile)) {
|
|
908
|
-
fs.unlinkSync(logFile);
|
|
909
|
-
console.log(`${GREEN}✔ Digest log cleared.${RESET}`);
|
|
910
|
-
}
|
|
911
|
-
console.log(`${DIM}Run 'digest' to start a fresh evolution cycle.${RESET}`);
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
function cmdStatus() {
|
|
915
|
-
const log = loadLog();
|
|
916
|
-
const cycles = log.cycles || [];
|
|
917
|
-
const totalSaved = log.total_tokens_saved || 0;
|
|
918
|
-
const totalIdioms = log.total_idioms || 0;
|
|
919
|
-
const { skillFile } = getPaths();
|
|
920
|
-
const idiomsExist = fs.existsSync(skillFile);
|
|
921
|
-
|
|
922
|
-
console.log(`\n${BOLD}${CYAN}━━━ Skill Evolution Status ━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
923
|
-
console.log(` Digest cycles : ${BOLD}${cycles.length}${RESET}`);
|
|
924
|
-
console.log(` Total idioms : ${BOLD}${totalIdioms}${RESET}`);
|
|
925
|
-
console.log(
|
|
926
|
-
` Tokens saved : ${GREEN}${totalSaved.toLocaleString()} tokens${RESET} (≈ $${((totalSaved / 1_000_000) * 3).toFixed(4)} at $3/M)`,
|
|
927
|
-
);
|
|
928
|
-
console.log(` SKILL.md exists : ${idiomsExist ? '✔' : '✗'}`);
|
|
929
|
-
|
|
930
|
-
if (cycles.length) {
|
|
931
|
-
console.log(`\n ${BOLD}Last 5 digest cycles:${RESET}`);
|
|
932
|
-
for (const cycle of cycles.slice(-5).reverse()) {
|
|
933
|
-
const ts = (cycle.timestamp || '?').slice(0, 16);
|
|
934
|
-
const deltaT = cycle.delta_tokens || 0;
|
|
935
|
-
const saved = cycle.tokens_saved || 0;
|
|
936
|
-
const addedCount = cycle.idioms_added || 0;
|
|
937
|
-
const pct = Math.floor((saved / Math.max(cycle.raw_tokens || 1, 1)) * 100);
|
|
938
|
-
console.log(
|
|
939
|
-
` ${DIM}${ts}${RESET} delta=${deltaT}tok saved=${saved}tok (${pct}%) idioms+=${addedCount}`,
|
|
940
|
-
);
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
console.log(`${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n`);
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
947
|
-
const COMMANDS = {
|
|
948
|
-
digest: cmdDigest,
|
|
949
|
-
show: cmdShow,
|
|
950
|
-
reset: cmdReset,
|
|
951
|
-
status: cmdStatus,
|
|
952
|
-
};
|
|
953
|
-
|
|
954
|
-
async function main() {
|
|
955
|
-
const argv = process.argv.slice(2);
|
|
956
|
-
if (!argv.length || ['-h', '--help', 'help'].includes(argv[0])) {
|
|
957
|
-
console.log(`
|
|
958
|
-
${BOLD}skill_evolution.js${RESET} — Tribunal Skill Evolution Forge
|
|
959
|
-
|
|
960
|
-
${BOLD}Commands:${RESET}
|
|
961
|
-
digest [--dry-run] [--head] Analyze latest git diff and evolve SKILL.md
|
|
962
|
-
--dry-run : preview without writing
|
|
963
|
-
--head : diff last commit instead of staged
|
|
964
|
-
show Print current project-idioms/SKILL.md
|
|
965
|
-
status Show digest history and token savings
|
|
966
|
-
reset Clear all idioms and start fresh
|
|
967
|
-
|
|
968
|
-
${BOLD}Token Budget:${RESET}
|
|
969
|
-
Raw diff -> Semantic Filter -> Only architectural lines -> LLM
|
|
970
|
-
Typical savings: 70–90% of tokens. Most trivial commits = 0 tokens.
|
|
971
|
-
`);
|
|
972
|
-
return;
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
const cmd = argv[0];
|
|
976
|
-
const rest = argv.slice(1);
|
|
977
|
-
if (!COMMANDS[cmd]) {
|
|
978
|
-
console.log(`${RED}✖ Unknown command: '${cmd}'${RESET}`);
|
|
979
|
-
process.exit(1);
|
|
980
|
-
}
|
|
981
|
-
await COMMANDS[cmd](rest);
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
module.exports = {
|
|
985
|
-
semanticDelta,
|
|
986
|
-
architecturalWeight,
|
|
987
|
-
parseLlmYamlResponse,
|
|
988
|
-
loadExistingIdioms,
|
|
989
|
-
getPaths,
|
|
990
|
-
};
|
|
991
|
-
|
|
992
|
-
if (require.main === module) {
|
|
993
|
-
main().catch(err => {
|
|
994
|
-
console.error(err);
|
|
995
|
-
process.exit(1);
|
|
996
|
-
});
|
|
997
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* skill_evolution.js — Tribunal Kit Skill Evolution Forge
|
|
4
|
+
* =========================================================
|
|
5
|
+
* Analyzes the delta between what the AI proposed and what the developer
|
|
6
|
+
* actually committed, then distills those decisions into evolving
|
|
7
|
+
* project-specific SKILL idioms — WITHOUT sending full files to any LLM.
|
|
8
|
+
*
|
|
9
|
+
* Core Strategy: Semantic Delta Extraction
|
|
10
|
+
* 1. Read the raw git diff of staged/recent changes
|
|
11
|
+
* 2. Strip trivial noise (whitespace, comments, import renames)
|
|
12
|
+
* 3. Score remaining lines for "Architectural Weight"
|
|
13
|
+
* 4. Only high-weight deltas reach the LLM reflection prompt
|
|
14
|
+
* 5. LLM returns structured YAML idiom entries (not prose)
|
|
15
|
+
* 6. Idioms are merged into .agent/skills/project-idioms/SKILL.md
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* node .agent/scripts/skill_evolution.js digest
|
|
19
|
+
* node .agent/scripts/skill_evolution.js digest --dry-run
|
|
20
|
+
* node .agent/scripts/skill_evolution.js show
|
|
21
|
+
* node .agent/scripts/skill_evolution.js reset
|
|
22
|
+
* node .agent/scripts/skill_evolution.js status
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
const fs = require('fs');
|
|
28
|
+
const path = require('path');
|
|
29
|
+
const https = require('https');
|
|
30
|
+
const { execFileSync } = require('child_process');
|
|
31
|
+
const readline = require('readline');
|
|
32
|
+
|
|
33
|
+
// ── Colours ──────────────────────────────────────────────────────────────────
|
|
34
|
+
const { GREEN, YELLOW, CYAN, RED, BLUE, BOLD, DIM, RESET } = require('./_colors');
|
|
35
|
+
|
|
36
|
+
// ── Shared Utilities ──────────────────────────────────────────────────────────
|
|
37
|
+
const { findAgentDir } = require('./_utils');
|
|
38
|
+
|
|
39
|
+
function getPaths(startDir = process.cwd()) {
|
|
40
|
+
const agentDir = findAgentDir(startDir);
|
|
41
|
+
const skillDir = path.join(agentDir, 'skills', 'project-idioms');
|
|
42
|
+
const historyDir = path.join(agentDir, 'history', 'skill-evolution');
|
|
43
|
+
return {
|
|
44
|
+
agentDir,
|
|
45
|
+
skillDir,
|
|
46
|
+
skillFile: path.join(skillDir, 'SKILL.md'),
|
|
47
|
+
historyDir,
|
|
48
|
+
logFile: path.join(historyDir, 'digest-log.json'),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ── Architectural Weight Patterns ────────────────────────────────────────────
|
|
53
|
+
const HIGH_WEIGHT_PATTERNS = [
|
|
54
|
+
/\bclass\b/,
|
|
55
|
+
/\binterface\b/,
|
|
56
|
+
/\btype\s+\w+\s*=/,
|
|
57
|
+
/\bextends\b/,
|
|
58
|
+
/\bimplements\b/,
|
|
59
|
+
/\bthrow\b/,
|
|
60
|
+
/\bcatch\b/,
|
|
61
|
+
/\btry\b/,
|
|
62
|
+
/\bprisma\.\w+\(/,
|
|
63
|
+
/\bsupabase\./,
|
|
64
|
+
/\bfetch\(/,
|
|
65
|
+
/\baxios\./,
|
|
66
|
+
/\bReturnType\b/,
|
|
67
|
+
/\bPromise</,
|
|
68
|
+
/\basync\s+function/,
|
|
69
|
+
/\bawait\b/,
|
|
70
|
+
/\bexport\s+(default\s+)?(class|function|const)/,
|
|
71
|
+
/\bmodule\.exports\b/,
|
|
72
|
+
/\bRouter\b|\bapp\.(get|post|put|delete|patch)\(/,
|
|
73
|
+
/\buse[A-Z]\w+\(/,
|
|
74
|
+
/\bcreateContext\(/,
|
|
75
|
+
/\bz\.object\(/,
|
|
76
|
+
/\bPrisma\b|\bdrizzle\b/,
|
|
77
|
+
/\benv\.\w+/,
|
|
78
|
+
/\bprocess\.env\./,
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
const NOISE_PATTERNS = [
|
|
82
|
+
/^\s*$/,
|
|
83
|
+
/^\s*(\/\/|#|\/\*).*$/,
|
|
84
|
+
/^\s*\*/,
|
|
85
|
+
/^\s*import\s+\{[^}]+\}\s+from\s+['"](?!\.)/,
|
|
86
|
+
/^\s*(console\.(log|warn|error)|print\()/,
|
|
87
|
+
/^\s*\w+\s*[:,]?\s*$/,
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
function architecturalWeight(line) {
|
|
91
|
+
const code = line.replace(/^[+-]/, '').trim();
|
|
92
|
+
for (const p of NOISE_PATTERNS) {
|
|
93
|
+
if (p.test(code)) return 0;
|
|
94
|
+
}
|
|
95
|
+
for (const p of HIGH_WEIGHT_PATTERNS) {
|
|
96
|
+
if (p.test(code)) return 2;
|
|
97
|
+
}
|
|
98
|
+
return 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── Levenshtein Semantic Deduplication ───────────────────────────────────────
|
|
102
|
+
// FIX: Replaces over-aggressive substring matching (.includes) with normalised
|
|
103
|
+
// edit-distance similarity. A new idiom must differ by >= 20% from all existing
|
|
104
|
+
// ones to be accepted. Threshold 0.80 = 80% similar → considered a duplicate.
|
|
105
|
+
|
|
106
|
+
function levenshtein(a, b) {
|
|
107
|
+
const m = a.length,
|
|
108
|
+
n = b.length;
|
|
109
|
+
// Allocate DP table with base cases pre-filled
|
|
110
|
+
const dp = Array.from({ length: m + 1 }, (_, i) =>
|
|
111
|
+
Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),
|
|
112
|
+
);
|
|
113
|
+
for (let i = 1; i <= m; i++) {
|
|
114
|
+
for (let j = 1; j <= n; j++) {
|
|
115
|
+
dp[i][j] =
|
|
116
|
+
a[i - 1] === b[j - 1]
|
|
117
|
+
? dp[i - 1][j - 1]
|
|
118
|
+
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return dp[m][n];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function normalizedSimilarity(a, b) {
|
|
125
|
+
if (!a.length && !b.length) return 1.0;
|
|
126
|
+
const maxLen = Math.max(a.length, b.length);
|
|
127
|
+
if (maxLen === 0) return 1.0;
|
|
128
|
+
return 1 - levenshtein(a, b) / maxLen;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Returns true if newPattern is semantically similar to any existing idiom.
|
|
133
|
+
* Uses Levenshtein normalised similarity with a configurable threshold.
|
|
134
|
+
* @param {string} newPattern
|
|
135
|
+
* @param {object[]} existingIdioms - array of { pattern } objects
|
|
136
|
+
* @param {number} threshold - 0.0–1.0 (default 0.80 = 80% similar = duplicate)
|
|
137
|
+
*/
|
|
138
|
+
function isDuplicateIdiom(newPattern, existingIdioms, threshold = 0.8) {
|
|
139
|
+
const newLow = newPattern.toLowerCase();
|
|
140
|
+
return existingIdioms.some(ex => {
|
|
141
|
+
const exLow = (ex.pattern || '').toLowerCase();
|
|
142
|
+
return normalizedSimilarity(newLow, exLow) >= threshold;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function semanticDelta(diffText, minWeight = 2) {
|
|
147
|
+
const lines = diffText.split('\n');
|
|
148
|
+
const kept = [];
|
|
149
|
+
let currentHunkHasHigh = false;
|
|
150
|
+
let hunkLines = [];
|
|
151
|
+
|
|
152
|
+
for (const line of lines) {
|
|
153
|
+
if (line.startsWith('---') || line.startsWith('+++') || line.startsWith('diff --git')) {
|
|
154
|
+
kept.push(line);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (line.startsWith('@@')) {
|
|
158
|
+
if (currentHunkHasHigh) kept.push(...hunkLines);
|
|
159
|
+
currentHunkHasHigh = false;
|
|
160
|
+
hunkLines = [line];
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (line.startsWith('+') || line.startsWith('-')) {
|
|
164
|
+
const w = architecturalWeight(line);
|
|
165
|
+
hunkLines.push(line);
|
|
166
|
+
if (w >= minWeight) currentHunkHasHigh = true;
|
|
167
|
+
} else {
|
|
168
|
+
hunkLines.push(line);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (currentHunkHasHigh) kept.push(...hunkLines);
|
|
172
|
+
|
|
173
|
+
let result = kept.join('\n');
|
|
174
|
+
result = result.replace(/\n( ?\n){3,}/g, '\n\n');
|
|
175
|
+
return result.trim();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── Git helpers ────────────────────────────────────────────────────────────────
|
|
179
|
+
function getGitDiff(mode = 'staged') {
|
|
180
|
+
try {
|
|
181
|
+
let args = [];
|
|
182
|
+
if (mode === 'staged') args = ['diff', '--cached', '--unified=3'];
|
|
183
|
+
else if (mode === 'head') args = ['diff', 'HEAD~1', 'HEAD', '--unified=3'];
|
|
184
|
+
else args = ['diff', '--unified=3'];
|
|
185
|
+
return execFileSync('git', args, {
|
|
186
|
+
encoding: 'utf8',
|
|
187
|
+
timeout: 10000,
|
|
188
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
189
|
+
});
|
|
190
|
+
} catch {
|
|
191
|
+
return '';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function countTokensEstimate(text) {
|
|
196
|
+
return Math.max(1, Math.floor(text.length / 4));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ── Idiom management ──────────────────────────────────────────────────────────
|
|
200
|
+
function loadExistingIdioms() {
|
|
201
|
+
const { skillFile } = getPaths();
|
|
202
|
+
if (!fs.existsSync(skillFile)) return [];
|
|
203
|
+
const content = fs.readFileSync(skillFile, 'utf8');
|
|
204
|
+
const idioms = [];
|
|
205
|
+
const pattern = /\|\s*(\d+)\s*\|\s*`([^`]+)`\s*\|\s*([^|]+)\|\s*([^|]+)\|\s*([^|]+)\|/g;
|
|
206
|
+
let m;
|
|
207
|
+
while ((m = pattern.exec(content)) !== null) {
|
|
208
|
+
idioms.push({
|
|
209
|
+
id: parseInt(m[1], 10),
|
|
210
|
+
pattern: m[2].trim(),
|
|
211
|
+
reason: m[3].trim(),
|
|
212
|
+
domain: m[4].trim(),
|
|
213
|
+
since: m[5].trim(),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return idioms;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function nextIdiomId(idioms) {
|
|
220
|
+
if (!idioms.length) return 1;
|
|
221
|
+
return Math.max(...idioms.map(i => i.id)) + 1;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function renderSkillMd(idioms, digestCount) {
|
|
225
|
+
const now = new Date().toISOString().slice(0, 10);
|
|
226
|
+
const rows = idioms.map(
|
|
227
|
+
i => `| ${i.id} | \`${i.pattern}\` | ${i.reason} | ${i.domain} | ${i.since} |`,
|
|
228
|
+
);
|
|
229
|
+
const table = rows.length ? rows.join('\n') : '_No idioms recorded yet._';
|
|
230
|
+
|
|
231
|
+
return `---
|
|
232
|
+
name: project-idioms
|
|
233
|
+
description: >
|
|
234
|
+
Auto-evolved skill containing project-specific architectural idioms.
|
|
235
|
+
Generated by skill_evolution.js — do not edit manually. Commit this
|
|
236
|
+
file to share your Engineering Culture across the team.
|
|
237
|
+
version: auto
|
|
238
|
+
last-updated: ${now}
|
|
239
|
+
digest-cycles: ${digestCount}
|
|
240
|
+
pattern: generator
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
# Project Idioms — Auto-Evolved Skill
|
|
244
|
+
|
|
245
|
+
> **Authority Level: ABSOLUTE**
|
|
246
|
+
> These idioms were extracted from the developer's own code decisions.
|
|
247
|
+
> They override generic agent defaults. Every agent MUST respect them.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## How Idioms Are Born
|
|
252
|
+
|
|
253
|
+
1. Developer commits code that differs from the AI proposal.
|
|
254
|
+
2. \`skill_evolution.js digest\` extracts architectural deltas only.
|
|
255
|
+
3. A minimal LLM reflection prompt (< 500 tokens) identifies the "WHY."
|
|
256
|
+
4. The idiom is recorded here with a stable pattern + reason pair.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Recorded Idioms
|
|
261
|
+
|
|
262
|
+
| ID | Pattern | Why This Project Uses It | Domain | Since |
|
|
263
|
+
|:---|:--------|:-------------------------|:-------|:------|
|
|
264
|
+
${table}
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Enforcement Rules for All Agents
|
|
269
|
+
|
|
270
|
+
\`\`\`
|
|
271
|
+
□ Before proposing code: scan this skill's idiom table
|
|
272
|
+
□ If your proposal contradicts an idiom → flag it explicitly
|
|
273
|
+
□ Never override an idiom silently — always ask the developer first
|
|
274
|
+
□ When citing an idiom: "Per Project Idiom #N: [pattern] — [reason]"
|
|
275
|
+
\`\`\`
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Digest History
|
|
280
|
+
|
|
281
|
+
Last digest: \`${now}\`
|
|
282
|
+
Total cycles: \`${digestCount}\`
|
|
283
|
+
|
|
284
|
+
Run \`node .agent/scripts/skill_evolution.js status\` to see the full log.
|
|
285
|
+
`;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function generateReflectionPrompt(delta) {
|
|
289
|
+
return `You are analyzing a code delta from a developer who changed an AI-proposed solution.
|
|
290
|
+
Your only job: identify the ARCHITECTURAL IDIOM this change reveals about their project.
|
|
291
|
+
|
|
292
|
+
Rules:
|
|
293
|
+
- Return ONLY a YAML list of idioms. No prose. No explanation outside YAML.
|
|
294
|
+
- Each idiom: pattern (code signature), reason (1 sentence WHY), domain (backend/frontend/database/general)
|
|
295
|
+
- Ignore whitespace, comment, import changes — only architectural choices
|
|
296
|
+
- If no meaningful idiom can be extracted, return: "idioms: []"
|
|
297
|
+
- Maximum 3 idioms per delta.
|
|
298
|
+
|
|
299
|
+
Delta:
|
|
300
|
+
\`\`\`
|
|
301
|
+
${delta.slice(0, 1500)}
|
|
302
|
+
\`\`\`
|
|
303
|
+
|
|
304
|
+
Output format (YAML only):
|
|
305
|
+
idioms:
|
|
306
|
+
- pattern: "<code pattern or convention>"
|
|
307
|
+
reason: "<why this project uses this pattern>"
|
|
308
|
+
domain: "<backend|frontend|database|security|performance|general>"
|
|
309
|
+
`;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function parseLlmYamlResponse(response) {
|
|
313
|
+
const idioms = [];
|
|
314
|
+
let inIdioms = false;
|
|
315
|
+
let current = {};
|
|
316
|
+
|
|
317
|
+
for (const line of response.split('\n')) {
|
|
318
|
+
const stripped = line.trim();
|
|
319
|
+
if (stripped === 'idioms:') {
|
|
320
|
+
inIdioms = true;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (!inIdioms) continue;
|
|
324
|
+
if (stripped.startsWith('- pattern:')) {
|
|
325
|
+
if (current.pattern) idioms.push(current);
|
|
326
|
+
current = {
|
|
327
|
+
pattern: stripped.split(':', 2)[1].trim().replace(/^"|"$/g, ''),
|
|
328
|
+
};
|
|
329
|
+
} else if (stripped.startsWith('reason:') && current.pattern) {
|
|
330
|
+
current.reason = stripped.split(':', 2)[1].trim().replace(/^"|"$/g, '');
|
|
331
|
+
} else if (stripped.startsWith('domain:') && current.pattern) {
|
|
332
|
+
current.domain = stripped.split(':', 2)[1].trim().replace(/^"|"$/g, '');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (current.pattern) idioms.push(current);
|
|
336
|
+
return idioms;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// ── Log helpers ────────────────────────────────────────────────────────────────
|
|
340
|
+
function loadLog() {
|
|
341
|
+
const { historyDir, logFile } = getPaths();
|
|
342
|
+
fs.mkdirSync(historyDir, { recursive: true });
|
|
343
|
+
if (fs.existsSync(logFile)) {
|
|
344
|
+
try {
|
|
345
|
+
return JSON.parse(fs.readFileSync(logFile, 'utf8'));
|
|
346
|
+
} catch {
|
|
347
|
+
/* fallthrough */
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return { cycles: [], total_tokens_saved: 0, total_idioms: 0 };
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function saveLog(log) {
|
|
354
|
+
const { historyDir, logFile } = getPaths();
|
|
355
|
+
fs.mkdirSync(historyDir, { recursive: true });
|
|
356
|
+
fs.writeFileSync(logFile, JSON.stringify(log, null, 2), 'utf8');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// ── Auto-LLM API Integration ─────────────────────────────────────────────────
|
|
360
|
+
// GENERATE: Eliminates the manual copy-paste loop by auto-detecting an API key
|
|
361
|
+
// and calling the LLM directly. Falls back to manual mode if no key is found.
|
|
362
|
+
// Supported providers (checked in order): Anthropic → OpenAI → Gemini.
|
|
363
|
+
|
|
364
|
+
function detectLlmProvider() {
|
|
365
|
+
if (process.env.ANTHROPIC_API_KEY)
|
|
366
|
+
return { provider: 'anthropic', key: process.env.ANTHROPIC_API_KEY };
|
|
367
|
+
if (process.env.OPENAI_API_KEY) return { provider: 'openai', key: process.env.OPENAI_API_KEY };
|
|
368
|
+
if (process.env.GEMINI_API_KEY) return { provider: 'gemini', key: process.env.GEMINI_API_KEY };
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Call an LLM API with the reflection prompt. Returns the raw text response.
|
|
374
|
+
* Uses only built-in Node.js `https` — zero external dependencies.
|
|
375
|
+
*
|
|
376
|
+
* @param {string} prompt - The reflection prompt to send
|
|
377
|
+
* @param {string} provider - 'anthropic' | 'openai' | 'gemini'
|
|
378
|
+
* @param {string} apiKey - The API key
|
|
379
|
+
* @returns {Promise<string|null>} LLM response text or null on failure
|
|
380
|
+
*/
|
|
381
|
+
async function callLlmApi(prompt, provider, apiKey) {
|
|
382
|
+
const timeout = 30000; // 30s max — skill evolution is non-blocking
|
|
383
|
+
|
|
384
|
+
function httpsPost(hostname, path, headers, body) {
|
|
385
|
+
return new Promise((resolve, reject) => {
|
|
386
|
+
const data = JSON.stringify(body);
|
|
387
|
+
const req = https.request(
|
|
388
|
+
{
|
|
389
|
+
method: 'POST',
|
|
390
|
+
hostname,
|
|
391
|
+
path,
|
|
392
|
+
headers: { ...headers, 'Content-Length': Buffer.byteLength(data) },
|
|
393
|
+
},
|
|
394
|
+
res => {
|
|
395
|
+
let raw = '';
|
|
396
|
+
res.on('data', c => {
|
|
397
|
+
raw += c;
|
|
398
|
+
});
|
|
399
|
+
res.on('end', () => resolve(raw));
|
|
400
|
+
res.on('error', reject);
|
|
401
|
+
},
|
|
402
|
+
);
|
|
403
|
+
req.on('error', reject);
|
|
404
|
+
req.setTimeout(timeout, () => {
|
|
405
|
+
req.destroy(new Error('LLM API timeout'));
|
|
406
|
+
});
|
|
407
|
+
req.write(data);
|
|
408
|
+
req.end();
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
try {
|
|
413
|
+
if (provider === 'anthropic') {
|
|
414
|
+
const raw = await httpsPost(
|
|
415
|
+
'api.anthropic.com',
|
|
416
|
+
'/v1/messages',
|
|
417
|
+
{
|
|
418
|
+
'Content-Type': 'application/json',
|
|
419
|
+
'x-api-key': apiKey,
|
|
420
|
+
'anthropic-version': '2023-06-01',
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
model: 'claude-3-haiku-20240307', // Fastest/cheapest — idiom extraction
|
|
424
|
+
max_tokens: 512,
|
|
425
|
+
messages: [{ role: 'user', content: prompt }],
|
|
426
|
+
},
|
|
427
|
+
);
|
|
428
|
+
const json = JSON.parse(raw);
|
|
429
|
+
return json?.content?.[0]?.text ?? null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (provider === 'openai') {
|
|
433
|
+
const raw = await httpsPost(
|
|
434
|
+
'api.openai.com',
|
|
435
|
+
'/v1/chat/completions',
|
|
436
|
+
{
|
|
437
|
+
'Content-Type': 'application/json',
|
|
438
|
+
Authorization: `Bearer ${apiKey}`,
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
model: 'gpt-4o-mini', // Cheapest capable model for YAML extraction
|
|
442
|
+
max_tokens: 512,
|
|
443
|
+
messages: [{ role: 'user', content: prompt }],
|
|
444
|
+
temperature: 0.1,
|
|
445
|
+
},
|
|
446
|
+
);
|
|
447
|
+
const json = JSON.parse(raw);
|
|
448
|
+
return json?.choices?.[0]?.message?.content ?? null;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (provider === 'gemini') {
|
|
452
|
+
const raw = await httpsPost(
|
|
453
|
+
'generativelanguage.googleapis.com',
|
|
454
|
+
`/v1beta/models/gemini-1.5-flash:generateContent?key=${apiKey}`,
|
|
455
|
+
{ 'Content-Type': 'application/json' },
|
|
456
|
+
{
|
|
457
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
458
|
+
generationConfig: { maxOutputTokens: 512, temperature: 0.1 },
|
|
459
|
+
},
|
|
460
|
+
);
|
|
461
|
+
const json = JSON.parse(raw);
|
|
462
|
+
return json?.candidates?.[0]?.content?.parts?.[0]?.text ?? null;
|
|
463
|
+
}
|
|
464
|
+
} catch {
|
|
465
|
+
return null; // Network/parse failure — caller falls back to manual mode
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// ── Commands ──────────────────────────────────────────────────────────────────
|
|
471
|
+
// ── Strategy Filtering ────────────────────────────────────────────────────────
|
|
472
|
+
function applyStrategyFilter(signals, strategy) {
|
|
473
|
+
if (strategy === 'repair-only') {
|
|
474
|
+
return signals.filter(s => s.type === 'log_error');
|
|
475
|
+
}
|
|
476
|
+
return signals;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// ── Log Reflection Prompt ─────────────────────────────────────────────────────
|
|
480
|
+
function generateLogReflectionPrompt(delta) {
|
|
481
|
+
return `You are analyzing runtime log signals (errors, tracebacks, and warnings) from an AI agent's execution.
|
|
482
|
+
Your job is to identify systemic coding issues and extract evolution assets:
|
|
483
|
+
1. **Idioms (Genes)**: Coding rules/conventions to prevent the AI from generating this mistake again.
|
|
484
|
+
2. **Cases (Capsules)**: Rejection precedents (offending code pattern and why it failed) to block reviewers from approving it.
|
|
485
|
+
|
|
486
|
+
Rules:
|
|
487
|
+
- Return ONLY a YAML structure containing 'idioms:' and 'cases:'. No markdown boxes, no conversational prose.
|
|
488
|
+
- Maximum 3 idioms and 3 cases.
|
|
489
|
+
- If an asset category is not applicable, leave it empty (e.g., 'idioms: []').
|
|
490
|
+
|
|
491
|
+
Log Signals:
|
|
492
|
+
\`\`\`
|
|
493
|
+
${delta.slice(0, 1800)}
|
|
494
|
+
\`\`\`
|
|
495
|
+
|
|
496
|
+
Output format (YAML only):
|
|
497
|
+
idioms:
|
|
498
|
+
- pattern: "<code convention or rule to avoid this error>"
|
|
499
|
+
reason: "<why it is needed based on the error>"
|
|
500
|
+
domain: "<backend|frontend|database|security|performance|general>"
|
|
501
|
+
cases:
|
|
502
|
+
- pattern: "<offending code snippet or error-triggering pattern>"
|
|
503
|
+
reason: "<specific runtime error / traceback reason>"
|
|
504
|
+
domain: "<backend|frontend|database|security|performance|general>"
|
|
505
|
+
verdict: "REJECTED"
|
|
506
|
+
`;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// ── Combined YAML Parser ──────────────────────────────────────────────────────
|
|
510
|
+
function parseEvolutionYaml(response) {
|
|
511
|
+
const idioms = [];
|
|
512
|
+
const cases = [];
|
|
513
|
+
let currentSection = null; // 'idioms' | 'cases'
|
|
514
|
+
let current = null;
|
|
515
|
+
|
|
516
|
+
const lines = response.split('\n');
|
|
517
|
+
for (const line of lines) {
|
|
518
|
+
const trimmed = line.trim();
|
|
519
|
+
if (trimmed === 'idioms:') {
|
|
520
|
+
if (current) {
|
|
521
|
+
if (currentSection === 'idioms') idioms.push(current);
|
|
522
|
+
if (currentSection === 'cases') cases.push(current);
|
|
523
|
+
}
|
|
524
|
+
currentSection = 'idioms';
|
|
525
|
+
current = null;
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
if (trimmed === 'cases:') {
|
|
529
|
+
if (current) {
|
|
530
|
+
if (currentSection === 'idioms') idioms.push(current);
|
|
531
|
+
if (currentSection === 'cases') cases.push(current);
|
|
532
|
+
}
|
|
533
|
+
currentSection = 'cases';
|
|
534
|
+
current = null;
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (
|
|
539
|
+
trimmed.startsWith('- pattern:') ||
|
|
540
|
+
(trimmed.startsWith('- ') && trimmed.includes('pattern:'))
|
|
541
|
+
) {
|
|
542
|
+
if (current) {
|
|
543
|
+
if (currentSection === 'idioms') idioms.push(current);
|
|
544
|
+
if (currentSection === 'cases') cases.push(current);
|
|
545
|
+
}
|
|
546
|
+
let pat = '';
|
|
547
|
+
if (trimmed.startsWith('- pattern:')) {
|
|
548
|
+
pat = trimmed.substring('- pattern:'.length).trim();
|
|
549
|
+
} else {
|
|
550
|
+
pat = trimmed.split('pattern:', 2)[1].trim();
|
|
551
|
+
}
|
|
552
|
+
current = { pattern: pat.replace(/^['"]|['"]$/g, '') };
|
|
553
|
+
} else if (trimmed.startsWith('reason:') && current) {
|
|
554
|
+
current.reason = trimmed
|
|
555
|
+
.substring('reason:'.length)
|
|
556
|
+
.trim()
|
|
557
|
+
.replace(/^['"]|['"]$/g, '');
|
|
558
|
+
} else if (trimmed.startsWith('domain:') && current) {
|
|
559
|
+
current.domain = trimmed
|
|
560
|
+
.substring('domain:'.length)
|
|
561
|
+
.trim()
|
|
562
|
+
.replace(/^['"]|['"]$/g, '');
|
|
563
|
+
} else if (trimmed.startsWith('verdict:') && current) {
|
|
564
|
+
current.verdict = trimmed
|
|
565
|
+
.substring('verdict:'.length)
|
|
566
|
+
.trim()
|
|
567
|
+
.replace(/^['"]|['"]$/g, '');
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (current) {
|
|
572
|
+
if (currentSection === 'idioms') idioms.push(current);
|
|
573
|
+
if (currentSection === 'cases') cases.push(current);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return { idioms, cases };
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// ── Commands ──────────────────────────────────────────────────────────────────
|
|
580
|
+
async function cmdDigest(args) {
|
|
581
|
+
const dryRun = args.includes('--dry-run');
|
|
582
|
+
const diffMode = args.includes('--head') ? 'head' : 'staged';
|
|
583
|
+
|
|
584
|
+
const logArg = args.find(a => a.startsWith('--log='));
|
|
585
|
+
const logFile = logArg ? logArg.split('=').slice(1).join('=') : null;
|
|
586
|
+
|
|
587
|
+
const strategyArg = args.find(a => a.startsWith('--strategy='));
|
|
588
|
+
const strategy = strategyArg ? strategyArg.split('=').slice(1).join('=') : 'balanced';
|
|
589
|
+
|
|
590
|
+
console.log(`\n${BOLD}${CYAN}━━━ Skill Evolution — Digest Cycle ━━━━━━━━━━━━━━━━${RESET}`);
|
|
591
|
+
if (dryRun) console.log(` ${YELLOW}DRY RUN — no files will be written${RESET}\n`);
|
|
592
|
+
|
|
593
|
+
let rawDiff = '';
|
|
594
|
+
let delta = '';
|
|
595
|
+
let rawTokens = 0;
|
|
596
|
+
let deltaTokens = 0;
|
|
597
|
+
let logSignals = [];
|
|
598
|
+
const isLogMode = !!logFile;
|
|
599
|
+
|
|
600
|
+
if (isLogMode) {
|
|
601
|
+
console.log(` ${DIM}[1/5] Reading log file: ${logFile}...${RESET}`);
|
|
602
|
+
if (!fs.existsSync(logFile)) {
|
|
603
|
+
console.log(` ${RED}✖ Log file not found: ${logFile}${RESET}\n`);
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
const logText = fs.readFileSync(logFile, 'utf8');
|
|
607
|
+
rawTokens = countTokensEstimate(logText);
|
|
608
|
+
|
|
609
|
+
console.log(` ${DIM}[2/5] Extracting signals from log (Signal Detector)...${RESET}`);
|
|
610
|
+
const { detectSignals } = require('./signal_detector');
|
|
611
|
+
const signals = detectSignals(logText);
|
|
612
|
+
|
|
613
|
+
if (signals.length === 0) {
|
|
614
|
+
console.log(` ${GREEN}✔ No errors or performance signals found in logs.${RESET}`);
|
|
615
|
+
console.log(` ${DIM} No self-evolution reflection needed.${RESET}\n`);
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
logSignals = applyStrategyFilter(signals, strategy);
|
|
620
|
+
if (logSignals.length === 0) {
|
|
621
|
+
console.log(` ${YELLOW}⚠ Strategy filter [${strategy}] filtered out all signals.${RESET}\n`);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
console.log(
|
|
626
|
+
` ${GREEN}✔ Filtered to ${logSignals.length} signal(s) using [${strategy}] strategy.${RESET}`,
|
|
627
|
+
);
|
|
628
|
+
|
|
629
|
+
delta = logSignals
|
|
630
|
+
.map(s => {
|
|
631
|
+
let chunk = `--- SIGNAL: ${s.type} ---\n`;
|
|
632
|
+
if (s.file) chunk += `File: ${s.file}${s.line ? `:${s.line}` : ''}\n`;
|
|
633
|
+
chunk += `Message: ${s.message}\n`;
|
|
634
|
+
chunk += `Context:\n${s.context}\n`;
|
|
635
|
+
return chunk;
|
|
636
|
+
})
|
|
637
|
+
.join('\n\n');
|
|
638
|
+
|
|
639
|
+
deltaTokens = countTokensEstimate(delta);
|
|
640
|
+
} else {
|
|
641
|
+
console.log(` ${DIM}[1/5] Fetching git diff (${diffMode})...${RESET}`);
|
|
642
|
+
rawDiff = getGitDiff(diffMode);
|
|
643
|
+
if (!rawDiff.trim()) {
|
|
644
|
+
console.log(` ${YELLOW}⚠ No diff found. Commit or stage changes first.${RESET}`);
|
|
645
|
+
console.log(` ${DIM}Tip: Use --head to diff against the last commit.${RESET}\n`);
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
rawTokens = countTokensEstimate(rawDiff);
|
|
650
|
+
console.log(` ${DIM} Raw diff: ~${rawTokens} tokens (${rawDiff.length} chars)${RESET}`);
|
|
651
|
+
|
|
652
|
+
console.log(` ${DIM}[2/5] Extracting architectural delta (Semantic Filter)...${RESET}`);
|
|
653
|
+
delta = semanticDelta(rawDiff, 2);
|
|
654
|
+
if (!delta.trim()) {
|
|
655
|
+
console.log(` ${GREEN}✔ Delta is 100% trivial (whitespace/comments/imports only).${RESET}`);
|
|
656
|
+
console.log(` ${DIM} No LLM call needed. Zero tokens consumed.${RESET}\n`);
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
deltaTokens = countTokensEstimate(delta);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const savedTokens = Math.max(0, rawTokens - deltaTokens);
|
|
664
|
+
const savedPct = Math.floor((savedTokens / Math.max(rawTokens, 1)) * 100);
|
|
665
|
+
console.log(
|
|
666
|
+
` ${GREEN}✔ Filtered to ~${deltaTokens} tokens (${savedPct}% reduction, saved ~${savedTokens} tokens)${RESET}`,
|
|
667
|
+
);
|
|
668
|
+
|
|
669
|
+
console.log(`\n ${BOLD}Architectural Delta Preview:${RESET}`);
|
|
670
|
+
const previewLines = delta.split('\n').slice(0, 20);
|
|
671
|
+
for (const line of previewLines) {
|
|
672
|
+
if (line.startsWith('+')) console.log(` ${GREEN}${line}${RESET}`);
|
|
673
|
+
else if (line.startsWith('-')) console.log(` ${RED}${line}${RESET}`);
|
|
674
|
+
else if (line.startsWith('@@')) console.log(` ${BLUE}${line}${RESET}`);
|
|
675
|
+
else console.log(` ${DIM}${line}${RESET}`);
|
|
676
|
+
}
|
|
677
|
+
if (delta.split('\n').length > 20)
|
|
678
|
+
console.log(` ... (${delta.split('\n').length - 20} more lines)`);
|
|
679
|
+
|
|
680
|
+
if (dryRun) {
|
|
681
|
+
console.log(
|
|
682
|
+
`\n ${YELLOW}[DRY RUN] Would send ${deltaTokens} tokens to LLM for reflection.${RESET}`,
|
|
683
|
+
);
|
|
684
|
+
console.log(` ${DIM}Run without --dry-run to complete the digest.${RESET}\n`);
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// GENERATE: Auto-LLM call.
|
|
689
|
+
const reflectionPrompt = isLogMode
|
|
690
|
+
? generateLogReflectionPrompt(delta)
|
|
691
|
+
: generateReflectionPrompt(delta);
|
|
692
|
+
let llmResponse = '';
|
|
693
|
+
|
|
694
|
+
let llmCreds = detectLlmProvider();
|
|
695
|
+
if (llmCreds) {
|
|
696
|
+
console.log(` ${DIM}[3/5] LLM Reflection — auto-calling ${llmCreds.provider} API...${RESET}`);
|
|
697
|
+
const autoResponse = await callLlmApi(reflectionPrompt, llmCreds.provider, llmCreds.key);
|
|
698
|
+
if (autoResponse) {
|
|
699
|
+
llmResponse = autoResponse;
|
|
700
|
+
console.log(
|
|
701
|
+
` ${GREEN}✔ Auto-response received (${llmCreds.provider}) — ${llmResponse.split('\n').length} lines${RESET}`,
|
|
702
|
+
);
|
|
703
|
+
} else {
|
|
704
|
+
console.log(` ${YELLOW}⚠ API call failed — falling back to manual mode${RESET}`);
|
|
705
|
+
llmCreds = null;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
if (!llmCreds || !llmResponse) {
|
|
710
|
+
// Manual fallback: copy-paste mode
|
|
711
|
+
console.log(
|
|
712
|
+
`\n ${DIM}[3/5] LLM Reflection — copy the prompt below and paste the response${RESET}`,
|
|
713
|
+
);
|
|
714
|
+
console.log(
|
|
715
|
+
` ${DIM} Tip: Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY to automate this step.${RESET}`,
|
|
716
|
+
);
|
|
717
|
+
console.log(`\n ${BOLD}${'─'.repeat(60)}${RESET}`);
|
|
718
|
+
console.log(reflectionPrompt);
|
|
719
|
+
console.log(` ${BOLD}${'─'.repeat(60)}${RESET}`);
|
|
720
|
+
console.log(`\n ${BOLD}Paste LLM response below (type END_RESPONSE when done):${RESET}`);
|
|
721
|
+
|
|
722
|
+
const rl = readline.createInterface({
|
|
723
|
+
input: process.stdin,
|
|
724
|
+
output: process.stdout,
|
|
725
|
+
});
|
|
726
|
+
const responseLines = [];
|
|
727
|
+
await new Promise(resolve => {
|
|
728
|
+
const listener = line => {
|
|
729
|
+
if (line.trim() === 'END_RESPONSE') {
|
|
730
|
+
rl.removeListener('line', listener);
|
|
731
|
+
resolve();
|
|
732
|
+
} else responseLines.push(line);
|
|
733
|
+
};
|
|
734
|
+
rl.on('line', listener);
|
|
735
|
+
});
|
|
736
|
+
rl.close();
|
|
737
|
+
llmResponse = responseLines.join('\n');
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
console.log(`\n ${DIM}[4/5] Parsing idioms/cases...${RESET}`);
|
|
741
|
+
let newIdioms = [];
|
|
742
|
+
let newCases = [];
|
|
743
|
+
|
|
744
|
+
if (isLogMode) {
|
|
745
|
+
const parsed = parseEvolutionYaml(llmResponse);
|
|
746
|
+
newIdioms = parsed.idioms;
|
|
747
|
+
newCases = parsed.cases;
|
|
748
|
+
} else {
|
|
749
|
+
newIdioms = parseLlmYamlResponse(llmResponse);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
if (!newIdioms.length && !newCases.length) {
|
|
753
|
+
console.log(` ${YELLOW}⚠ No idioms or cases extracted from LLM response.${RESET}`);
|
|
754
|
+
console.log(`\n`);
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
if (newIdioms.length > 0) {
|
|
759
|
+
console.log(` ${GREEN}✔ Extracted ${newIdioms.length} idiom(s)${RESET}`);
|
|
760
|
+
for (const idiom of newIdioms) {
|
|
761
|
+
console.log(` ${CYAN}• ${idiom.pattern || '?'}${RESET} — ${idiom.reason || ''}`);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (newCases.length > 0) {
|
|
766
|
+
console.log(` ${GREEN}✔ Extracted ${newCases.length} case precedent(s)${RESET}`);
|
|
767
|
+
for (const c of newCases) {
|
|
768
|
+
console.log(` ${RED}• ${c.pattern || '?'}${RESET} — ${c.reason || ''}`);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
console.log(`\n ${DIM}[5/5] Merging into project-idioms/SKILL.md...${RESET}`);
|
|
773
|
+
const existing = loadExistingIdioms();
|
|
774
|
+
const log = loadLog();
|
|
775
|
+
let nextId = nextIdiomId(existing);
|
|
776
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
777
|
+
const merged = [...existing];
|
|
778
|
+
let added = 0;
|
|
779
|
+
|
|
780
|
+
for (const idiom of newIdioms) {
|
|
781
|
+
if (isDuplicateIdiom(idiom.pattern || '', existing)) {
|
|
782
|
+
console.log(` ${DIM} Skipped near-duplicate idiom: ${idiom.pattern}${RESET}`);
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
merged.push({
|
|
786
|
+
id: nextId,
|
|
787
|
+
pattern: idiom.pattern || '?',
|
|
788
|
+
reason: idiom.reason || 'No reason provided.',
|
|
789
|
+
domain: idiom.domain || 'general',
|
|
790
|
+
since: today,
|
|
791
|
+
});
|
|
792
|
+
nextId++;
|
|
793
|
+
added++;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
if (added > 0) {
|
|
797
|
+
log.total_idioms = merged.length;
|
|
798
|
+
const skillMd = renderSkillMd(merged, (log.cycles || []).length + 1);
|
|
799
|
+
const { skillDir, skillFile } = getPaths();
|
|
800
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
801
|
+
fs.writeFileSync(skillFile, skillMd, 'utf8');
|
|
802
|
+
console.log(` ${GREEN}✔ ${added} new idiom(s) added to SKILL.md${RESET}`);
|
|
803
|
+
} else {
|
|
804
|
+
console.log(` ${DIM} No new unique idioms added to SKILL.md.${RESET}`);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// Record Case Precedents if present
|
|
808
|
+
if (newCases && newCases.length > 0) {
|
|
809
|
+
console.log(`\n ${DIM}Merging into Case Law precedents...${RESET}`);
|
|
810
|
+
const caseLawManager = require('./case_law_manager');
|
|
811
|
+
const clIndex = caseLawManager.loadIndex();
|
|
812
|
+
let clNextId = clIndex.next_id;
|
|
813
|
+
let clAdded = 0;
|
|
814
|
+
|
|
815
|
+
for (const c of newCases) {
|
|
816
|
+
const diffText = c.pattern || '';
|
|
817
|
+
const reason = c.reason || '';
|
|
818
|
+
const domain = c.domain || 'general';
|
|
819
|
+
const verdict = c.verdict || 'REJECTED';
|
|
820
|
+
const fingerprint = caseLawManager.contentHash(diffText);
|
|
821
|
+
|
|
822
|
+
let isDup = false;
|
|
823
|
+
for (const existing of clIndex.cases) {
|
|
824
|
+
if (existing.fingerprint === fingerprint) {
|
|
825
|
+
isDup = true;
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
if (isDup) {
|
|
830
|
+
console.log(` ${DIM} Skipped duplicate case: ${reason.slice(0, 50)}...${RESET}`);
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
const deltaCase = caseLawManager.semanticDelta(diffText);
|
|
835
|
+
const tags = caseLawManager.extractTags(diffText + ' ' + reason);
|
|
836
|
+
const caseRecord = {
|
|
837
|
+
id: clNextId,
|
|
838
|
+
fingerprint,
|
|
839
|
+
timestamp: new Date().toISOString().slice(0, 19),
|
|
840
|
+
domain,
|
|
841
|
+
verdict,
|
|
842
|
+
reason: reason.trim(),
|
|
843
|
+
pr_ref: 'auto-evolution',
|
|
844
|
+
reviewer: 'skill-evolution',
|
|
845
|
+
tags,
|
|
846
|
+
stack_version: null,
|
|
847
|
+
diff_raw: diffText.trim(),
|
|
848
|
+
diff_delta: deltaCase,
|
|
849
|
+
auto_recorded: true,
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
caseLawManager.saveCase(caseRecord);
|
|
853
|
+
clIndex.cases.push({
|
|
854
|
+
id: clNextId,
|
|
855
|
+
fingerprint,
|
|
856
|
+
domain,
|
|
857
|
+
verdict,
|
|
858
|
+
tags,
|
|
859
|
+
timestamp: caseRecord.timestamp,
|
|
860
|
+
reason_summary: reason.trim().slice(0, 120),
|
|
861
|
+
stack_version: null,
|
|
862
|
+
});
|
|
863
|
+
clNextId++;
|
|
864
|
+
clAdded++;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
if (clAdded > 0) {
|
|
868
|
+
clIndex.next_id = clNextId;
|
|
869
|
+
caseLawManager.saveIndex(clIndex);
|
|
870
|
+
console.log(` ${GREEN}✔ ${clAdded} new Case Law precedent(s) recorded.${RESET}`);
|
|
871
|
+
} else {
|
|
872
|
+
console.log(` ${DIM} No new unique Case Law precedents recorded.${RESET}`);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
log.cycles = log.cycles || [];
|
|
877
|
+
log.cycles.push({
|
|
878
|
+
timestamp: new Date().toISOString().slice(0, 19),
|
|
879
|
+
raw_tokens: rawTokens,
|
|
880
|
+
delta_tokens: deltaTokens,
|
|
881
|
+
tokens_saved: savedTokens,
|
|
882
|
+
idioms_added: added,
|
|
883
|
+
});
|
|
884
|
+
log.total_tokens_saved = (log.total_tokens_saved || 0) + savedTokens;
|
|
885
|
+
saveLog(log);
|
|
886
|
+
|
|
887
|
+
console.log(`\n ${GREEN}✔ Learn cycle complete.${RESET}`);
|
|
888
|
+
console.log(` ${DIM} Total idioms: ${merged.length}${RESET}`);
|
|
889
|
+
console.log(` ${DIM} Lifetime tokens saved: ${log.total_tokens_saved}${RESET}\n`);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
function cmdShow() {
|
|
893
|
+
const { skillFile } = getPaths();
|
|
894
|
+
if (!fs.existsSync(skillFile)) {
|
|
895
|
+
console.log(`${YELLOW}No project-idioms skill found. Run 'digest' first.${RESET}`);
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
console.log(fs.readFileSync(skillFile, 'utf8'));
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
function cmdReset() {
|
|
902
|
+
const { skillFile, logFile } = getPaths();
|
|
903
|
+
if (fs.existsSync(skillFile)) {
|
|
904
|
+
fs.unlinkSync(skillFile);
|
|
905
|
+
console.log(`${GREEN}✔ project-idioms/SKILL.md deleted.${RESET}`);
|
|
906
|
+
}
|
|
907
|
+
if (fs.existsSync(logFile)) {
|
|
908
|
+
fs.unlinkSync(logFile);
|
|
909
|
+
console.log(`${GREEN}✔ Digest log cleared.${RESET}`);
|
|
910
|
+
}
|
|
911
|
+
console.log(`${DIM}Run 'digest' to start a fresh evolution cycle.${RESET}`);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
function cmdStatus() {
|
|
915
|
+
const log = loadLog();
|
|
916
|
+
const cycles = log.cycles || [];
|
|
917
|
+
const totalSaved = log.total_tokens_saved || 0;
|
|
918
|
+
const totalIdioms = log.total_idioms || 0;
|
|
919
|
+
const { skillFile } = getPaths();
|
|
920
|
+
const idiomsExist = fs.existsSync(skillFile);
|
|
921
|
+
|
|
922
|
+
console.log(`\n${BOLD}${CYAN}━━━ Skill Evolution Status ━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
923
|
+
console.log(` Digest cycles : ${BOLD}${cycles.length}${RESET}`);
|
|
924
|
+
console.log(` Total idioms : ${BOLD}${totalIdioms}${RESET}`);
|
|
925
|
+
console.log(
|
|
926
|
+
` Tokens saved : ${GREEN}${totalSaved.toLocaleString()} tokens${RESET} (≈ $${((totalSaved / 1_000_000) * 3).toFixed(4)} at $3/M)`,
|
|
927
|
+
);
|
|
928
|
+
console.log(` SKILL.md exists : ${idiomsExist ? '✔' : '✗'}`);
|
|
929
|
+
|
|
930
|
+
if (cycles.length) {
|
|
931
|
+
console.log(`\n ${BOLD}Last 5 digest cycles:${RESET}`);
|
|
932
|
+
for (const cycle of cycles.slice(-5).reverse()) {
|
|
933
|
+
const ts = (cycle.timestamp || '?').slice(0, 16);
|
|
934
|
+
const deltaT = cycle.delta_tokens || 0;
|
|
935
|
+
const saved = cycle.tokens_saved || 0;
|
|
936
|
+
const addedCount = cycle.idioms_added || 0;
|
|
937
|
+
const pct = Math.floor((saved / Math.max(cycle.raw_tokens || 1, 1)) * 100);
|
|
938
|
+
console.log(
|
|
939
|
+
` ${DIM}${ts}${RESET} delta=${deltaT}tok saved=${saved}tok (${pct}%) idioms+=${addedCount}`,
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
console.log(`${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n`);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
947
|
+
const COMMANDS = {
|
|
948
|
+
digest: cmdDigest,
|
|
949
|
+
show: cmdShow,
|
|
950
|
+
reset: cmdReset,
|
|
951
|
+
status: cmdStatus,
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
async function main() {
|
|
955
|
+
const argv = process.argv.slice(2);
|
|
956
|
+
if (!argv.length || ['-h', '--help', 'help'].includes(argv[0])) {
|
|
957
|
+
console.log(`
|
|
958
|
+
${BOLD}skill_evolution.js${RESET} — Tribunal Skill Evolution Forge
|
|
959
|
+
|
|
960
|
+
${BOLD}Commands:${RESET}
|
|
961
|
+
digest [--dry-run] [--head] Analyze latest git diff and evolve SKILL.md
|
|
962
|
+
--dry-run : preview without writing
|
|
963
|
+
--head : diff last commit instead of staged
|
|
964
|
+
show Print current project-idioms/SKILL.md
|
|
965
|
+
status Show digest history and token savings
|
|
966
|
+
reset Clear all idioms and start fresh
|
|
967
|
+
|
|
968
|
+
${BOLD}Token Budget:${RESET}
|
|
969
|
+
Raw diff -> Semantic Filter -> Only architectural lines -> LLM
|
|
970
|
+
Typical savings: 70–90% of tokens. Most trivial commits = 0 tokens.
|
|
971
|
+
`);
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
const cmd = argv[0];
|
|
976
|
+
const rest = argv.slice(1);
|
|
977
|
+
if (!COMMANDS[cmd]) {
|
|
978
|
+
console.log(`${RED}✖ Unknown command: '${cmd}'${RESET}`);
|
|
979
|
+
process.exit(1);
|
|
980
|
+
}
|
|
981
|
+
await COMMANDS[cmd](rest);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
module.exports = {
|
|
985
|
+
semanticDelta,
|
|
986
|
+
architecturalWeight,
|
|
987
|
+
parseLlmYamlResponse,
|
|
988
|
+
loadExistingIdioms,
|
|
989
|
+
getPaths,
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
if (require.main === module) {
|
|
993
|
+
main().catch(err => {
|
|
994
|
+
console.error(err);
|
|
995
|
+
process.exit(1);
|
|
996
|
+
});
|
|
997
|
+
}
|