tribunal-kit 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/.manifest.json +78 -0
- package/.agent/ARCHITECTURE.md +19 -241
- package/.agent/agents/accessibility-reviewer.md +23 -16
- package/.agent/agents/ai-code-reviewer.md +25 -21
- package/.agent/agents/anti-pattern-reviewer.md +12 -7
- package/.agent/agents/api-architect.md +1 -0
- package/.agent/agents/backend-specialist.md +23 -22
- package/.agent/agents/cloud-engineer.md +1 -0
- package/.agent/agents/code-archaeologist.md +1 -0
- package/.agent/agents/complexity-reviewer.md +10 -7
- package/.agent/agents/database-architect.md +3 -2
- package/.agent/agents/db-latency-auditor.md +6 -2
- package/.agent/agents/debugger.md +3 -2
- package/.agent/agents/dependency-reviewer.md +1 -0
- package/.agent/agents/devops-engineer.md +9 -8
- package/.agent/agents/documentation-writer.md +6 -5
- package/.agent/agents/explorer-agent.md +1 -0
- package/.agent/agents/frontend-reviewer.md +21 -17
- package/.agent/agents/frontend-specialist.md +23 -20
- package/.agent/agents/game-developer.md +1 -0
- package/.agent/agents/interaction-reviewer.md +10 -5
- package/.agent/agents/logic-reviewer.md +3 -0
- package/.agent/agents/minimalist-reviewer.md +6 -0
- package/.agent/agents/mobile-developer.md +7 -6
- package/.agent/agents/mobile-reviewer.md +14 -13
- package/.agent/agents/orchestrator.md +3 -0
- package/.agent/agents/penetration-tester.md +1 -0
- package/.agent/agents/performance-optimizer.md +6 -5
- package/.agent/agents/performance-reviewer.md +6 -6
- package/.agent/agents/pipeline-reviewer.md +144 -0
- package/.agent/agents/precedence-reviewer.md +1 -0
- package/.agent/agents/product-manager.md +1 -0
- package/.agent/agents/product-owner.md +1 -0
- package/.agent/agents/product-reviewer.md +12 -7
- package/.agent/agents/project-planner.md +3 -0
- package/.agent/agents/qa-automation-engineer.md +50 -43
- package/.agent/agents/resilience-reviewer.md +1 -0
- package/.agent/agents/schema-reviewer.md +1 -0
- package/.agent/agents/security-auditor.md +24 -24
- package/.agent/agents/seo-specialist.md +33 -23
- package/.agent/agents/sql-reviewer.md +5 -4
- package/.agent/agents/supervisor-agent.md +12 -2
- package/.agent/agents/swarm-worker-contracts.md +13 -13
- package/.agent/agents/swarm-worker-registry.md +51 -51
- package/.agent/agents/system-architect.md +1 -0
- package/.agent/agents/test-coverage-reviewer.md +25 -22
- package/.agent/agents/test-engineer.md +12 -11
- package/.agent/agents/throughput-optimizer.md +45 -40
- package/.agent/agents/type-safety-reviewer.md +5 -4
- package/.agent/agents/ui-ux-auditor.md +6 -4
- package/.agent/agents/ui-visual-auditor.md +3 -0
- package/.agent/agents/ux-reviewer.md +11 -6
- package/.agent/agents/visual-reviewer.md +11 -6
- package/.agent/agents/vitals-reviewer.md +5 -4
- package/.agent/history/memory/.memory.idx +3716 -1
- package/.agent/history/memory/MEMORY.md +246 -1
- package/.agent/mcp_config.json +1 -6
- package/.agent/routing_index.json +2034 -263
- package/.agent/rules/GEMINI.md +12 -10
- package/.agent/rules/GEMINI_PLANNER.md +19 -21
- package/.agent/scripts/_colors.js +52 -54
- package/.agent/scripts/_utils.js +52 -53
- package/.agent/scripts/auto_preview.js +39 -43
- package/.agent/scripts/bundle_analyzer.js +47 -60
- package/.agent/scripts/case_law_manager.js +200 -294
- package/.agent/scripts/checklist.js +73 -94
- package/.agent/scripts/cicd_validator.js +305 -0
- package/.agent/scripts/compile_router.py +4 -111
- package/.agent/scripts/context_broker.js +317 -412
- package/.agent/scripts/contract_engine.js +402 -0
- package/.agent/scripts/dependency_analyzer.js +112 -124
- package/.agent/scripts/graph_builder.js +75 -103
- package/.agent/scripts/graph_visualizer.js +10 -12
- package/.agent/scripts/graph_zoom.js +38 -55
- package/.agent/scripts/guardrail_engine.js +195 -145
- package/.agent/scripts/impact_classifier.js +55 -30
- package/.agent/scripts/inner_loop_validator.js +108 -159
- package/.agent/scripts/integrity_manifest.js +59 -67
- package/.agent/scripts/lint_runner.js +65 -75
- package/.agent/scripts/marathon_harness.js +131 -208
- package/.agent/scripts/migrate_skills_frontmatter.py +4 -63
- package/.agent/scripts/minify_context.js +29 -33
- package/.agent/scripts/minimal_change_engine.js +95 -87
- package/.agent/scripts/mutation_runner.js +46 -62
- package/.agent/scripts/pipeline_engine.js +320 -209
- package/.agent/scripts/prompt_compiler.js +118 -93
- package/.agent/scripts/schema_validator.js +73 -121
- package/.agent/scripts/security_scan.js +88 -117
- package/.agent/scripts/session_manager.js +52 -69
- package/.agent/scripts/signal_detector.js +24 -22
- package/.agent/scripts/skill_evolution.js +184 -245
- package/.agent/scripts/skill_integrator.js +35 -48
- package/.agent/scripts/socratic_gate_policy.js +15 -12
- package/.agent/scripts/strengthen_skills.js +29 -33
- package/.agent/scripts/swarm_dispatcher.js +120 -151
- package/.agent/scripts/test_runner.js +54 -56
- package/.agent/scripts/token_budget_broker.js +9 -7
- package/.agent/scripts/trace_engine.js +126 -0
- package/.agent/scripts/verify_all.js +76 -93
- package/.agent/scripts/visual_audit.js +16 -21
- package/.agent/skill_topic_map.json +237 -0
- package/.agent/skills/12-principles-of-animation/SKILL.md +7 -0
- package/.agent/skills/60fps-animation/SKILL.md +7 -0
- package/.agent/skills/accessible-animation/SKILL.md +5 -1
- package/.agent/skills/adapt/SKILL.md +7 -1
- package/.agent/skills/advanced-rag-pipelines/SKILL.md +1 -0
- package/.agent/skills/agent-organizer/SKILL.md +1 -0
- package/.agent/skills/agentic-patterns/SKILL.md +33 -25
- package/.agent/skills/agentic-workflows-2026/SKILL.md +80 -0
- package/.agent/skills/ai-app-hardening/SKILL.md +59 -0
- package/.agent/skills/ai-prompt-injection-defense/SKILL.md +7 -6
- package/.agent/skills/animation-on-scroll/SKILL.md +24 -15
- package/.agent/skills/animation-systems/SKILL.md +11 -10
- package/.agent/skills/antfu-conventions/SKILL.md +7 -2
- package/.agent/skills/api-patterns/SKILL.md +14 -10
- package/.agent/skills/api-security-auditor/SKILL.md +15 -14
- package/.agent/skills/app-builder/SKILL.md +1 -0
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +2 -2
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +12 -12
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +3 -3
- package/.agent/skills/apple-design/SKILL.md +8 -7
- package/.agent/skills/architecture/SKILL.md +3 -2
- package/.agent/skills/audit-and-fix/SKILL.md +8 -5
- package/.agent/skills/authentication-best-practices/SKILL.md +9 -8
- package/.agent/skills/backend-security-expert/SKILL.md +1 -0
- package/.agent/skills/baseline-ui/SKILL.md +8 -7
- package/.agent/skills/bash-linux/SKILL.md +1 -0
- package/.agent/skills/behavioral-modes/SKILL.md +1 -0
- package/.agent/skills/better-colors/SKILL.md +11 -7
- package/.agent/skills/better-typography/SKILL.md +30 -16
- package/.agent/skills/better-ui/SKILL.md +17 -10
- package/.agent/skills/bolder/SKILL.md +6 -0
- package/.agent/skills/brainstorming/SKILL.md +6 -4
- package/.agent/skills/browser-native-ai/SKILL.md +5 -4
- package/.agent/skills/build-primitive/SKILL.md +5 -0
- package/.agent/skills/building-native-ui/SKILL.md +1 -0
- package/.agent/skills/cicd-pro/SKILL.md +2 -1
- package/.agent/skills/clarify/SKILL.md +19 -14
- package/.agent/skills/clean-code/SKILL.md +16 -15
- package/.agent/skills/cloud-architect/SKILL.md +1 -0
- package/.agent/skills/cobejs/SKILL.md +7 -9
- package/.agent/skills/code-review-checklist/SKILL.md +1 -0
- package/.agent/skills/codebase-design/SKILL.md +7 -2
- package/.agent/skills/colorize/SKILL.md +8 -3
- package/.agent/skills/compact-landing/SKILL.md +8 -3
- package/.agent/skills/company-logos/SKILL.md +6 -0
- package/.agent/skills/config-validator/SKILL.md +10 -9
- package/.agent/skills/containerization-pro/SKILL.md +6 -5
- package/.agent/skills/context-engineering-pro/SKILL.md +70 -0
- package/.agent/skills/create-design-md/SKILL.md +13 -5
- package/.agent/skills/critique/SKILL.md +10 -8
- package/.agent/skills/csharp-developer/SKILL.md +1 -0
- package/.agent/skills/data-validation-schemas/SKILL.md +28 -23
- package/.agent/skills/database-design/SKILL.md +2 -1
- package/.agent/skills/delight/SKILL.md +6 -0
- package/.agent/skills/deployment-procedures/SKILL.md +2 -1
- package/.agent/skills/design-lab/SKILL.md +5 -0
- package/.agent/skills/devops-engineer/SKILL.md +3 -2
- package/.agent/skills/devops-incident-responder/SKILL.md +2 -1
- package/.agent/skills/diagnosing-bugs/SKILL.md +12 -2
- package/.agent/skills/distill/SKILL.md +7 -2
- package/.agent/skills/documentation-templates/SKILL.md +3 -2
- package/.agent/skills/domain-modeling/SKILL.md +12 -4
- package/.agent/skills/duckdb-analytical-sql/SKILL.md +59 -0
- package/.agent/skills/edge-ai-mobile/SKILL.md +50 -0
- package/.agent/skills/edge-computing/SKILL.md +9 -8
- package/.agent/skills/emil-design-eng/SKILL.md +43 -27
- package/.agent/skills/error-resilience/SKILL.md +34 -16
- package/.agent/skills/expo-router-v4/SKILL.md +81 -0
- package/.agent/skills/extract-design-system/SKILL.md +12 -11
- package/.agent/skills/fabel-protocol/SKILL.md +24 -17
- package/.agent/skills/fixing-accessibility/SKILL.md +23 -16
- package/.agent/skills/fixing-metadata/SKILL.md +24 -13
- package/.agent/skills/fixing-motion-performance/SKILL.md +7 -5
- package/.agent/skills/framer-motion-expert/SKILL.md +29 -15
- package/.agent/skills/frontend-design/SKILL.md +21 -13
- package/.agent/skills/frontend-security-expert/SKILL.md +1 -0
- package/.agent/skills/game-design-expert/SKILL.md +1 -0
- package/.agent/skills/game-engineering-expert/SKILL.md +1 -0
- package/.agent/skills/generative-ui-expert/SKILL.md +3 -2
- package/.agent/skills/geo-fundamentals/SKILL.md +2 -1
- package/.agent/skills/git-pro/SKILL.md +10 -9
- package/.agent/skills/github-operations/SKILL.md +2 -1
- package/.agent/skills/gpt-taste/SKILL.md +7 -0
- package/.agent/skills/gsap-core/SKILL.md +26 -22
- package/.agent/skills/gsap-frameworks/SKILL.md +6 -5
- package/.agent/skills/gsap-performance/SKILL.md +4 -3
- package/.agent/skills/gsap-plugins/SKILL.md +34 -33
- package/.agent/skills/gsap-react/SKILL.md +9 -8
- package/.agent/skills/gsap-scrolltrigger/SKILL.md +34 -33
- package/.agent/skills/gsap-timeline/SKILL.md +18 -15
- package/.agent/skills/gsap-utils/SKILL.md +25 -24
- package/.agent/skills/harden/SKILL.md +9 -3
- package/.agent/skills/harness-protocol/SKILL.md +1 -0
- package/.agent/skills/i18n-localization/SKILL.md +10 -9
- package/.agent/skills/impeccable/SKILL.md +5 -0
- package/.agent/skills/improve-codebase-architecture/SKILL.md +10 -5
- package/.agent/skills/improve-ui/SKILL.md +12 -5
- package/.agent/skills/intelligent-routing/SKILL.md +7 -6
- package/.agent/skills/knowledge-graph/SKILL.md +1 -0
- package/.agent/skills/landing-page/SKILL.md +1 -0
- package/.agent/skills/lint-and-validate/SKILL.md +9 -4
- package/.agent/skills/llm-engineering/SKILL.md +55 -54
- package/.agent/skills/local-first/SKILL.md +20 -19
- package/.agent/skills/local-first-architecture/SKILL.md +6 -1
- package/.agent/skills/lottie-animation/SKILL.md +7 -3
- package/.agent/skills/marquee-loop/SKILL.md +1 -0
- package/.agent/skills/masked-reveal/SKILL.md +17 -4
- package/.agent/skills/mcp-builder/SKILL.md +13 -10
- package/.agent/skills/micro-interaction/SKILL.md +20 -5
- package/.agent/skills/mobile-design/SKILL.md +26 -15
- package/.agent/skills/monorepo-management/SKILL.md +3 -2
- package/.agent/skills/morphing-icons/SKILL.md +16 -6
- package/.agent/skills/motion-engineering/SKILL.md +19 -15
- package/.agent/skills/nextjs-react-expert/SKILL.md +26 -21
- package/.agent/skills/nodejs-best-practices/SKILL.md +89 -76
- package/.agent/skills/observability/SKILL.md +45 -44
- package/.agent/skills/opentelemetry-observability/SKILL.md +59 -0
- package/.agent/skills/page-transition-animation/SKILL.md +6 -3
- package/.agent/skills/parallel-agents/SKILL.md +7 -2
- package/.agent/skills/performance-profiling/SKILL.md +24 -13
- package/.agent/skills/plan-writing/SKILL.md +1 -0
- package/.agent/skills/platform-engineer/SKILL.md +3 -2
- package/.agent/skills/platform-engineering-opentofu/SKILL.md +68 -0
- package/.agent/skills/playwright-ai-e2e/SKILL.md +60 -0
- package/.agent/skills/playwright-best-practices/SKILL.md +29 -28
- package/.agent/skills/polish/SKILL.md +13 -12
- package/.agent/skills/powershell-windows/SKILL.md +1 -0
- package/.agent/skills/pricing-page/SKILL.md +8 -3
- package/.agent/skills/product-aware-heuristics/SKILL.md +122 -72
- package/.agent/skills/progressive-blur/SKILL.md +9 -4
- package/.agent/skills/project-idioms/SKILL.md +1 -0
- package/.agent/skills/property-based-testing/SKILL.md +58 -0
- package/.agent/skills/python-patterns/SKILL.md +1 -0
- package/.agent/skills/python-pro/SKILL.md +1 -0
- package/.agent/skills/quieter/SKILL.md +6 -0
- package/.agent/skills/react-doctor/SKILL.md +6 -0
- package/.agent/skills/react-specialist/SKILL.md +32 -28
- package/.agent/skills/readme-builder/SKILL.md +1 -0
- package/.agent/skills/realtime-patterns/SKILL.md +34 -33
- package/.agent/skills/red-team-tactics/SKILL.md +1 -0
- package/.agent/skills/redesign-skill/SKILL.md +6 -0
- package/.agent/skills/review-animations/SKILL.md +5 -2
- package/.agent/skills/review-animations/STANDARDS.md +37 -23
- package/.agent/skills/rust-pro/SKILL.md +1 -0
- package/.agent/skills/seo-fundamentals/SKILL.md +4 -3
- package/.agent/skills/server-management/SKILL.md +1 -0
- package/.agent/skills/shadcn-ui-expert/SKILL.md +28 -22
- package/.agent/skills/shape/SKILL.md +9 -2
- package/.agent/skills/skill-creator/SKILL.md +1 -0
- package/.agent/skills/soft-skill/SKILL.md +6 -0
- package/.agent/skills/sounds-on-the-web/SKILL.md +1 -0
- package/.agent/skills/sql-pro/SKILL.md +1 -0
- package/.agent/skills/supabase-postgres-best-practices/SKILL.md +1 -0
- package/.agent/skills/svg-animation/SKILL.md +16 -7
- package/.agent/skills/swiftui-expert/SKILL.md +1 -0
- package/.agent/skills/swiss-design/SKILL.md +5 -0
- package/.agent/skills/system-design-pro/SKILL.md +1 -0
- package/.agent/skills/systematic-debugging/SKILL.md +1 -0
- package/.agent/skills/tailwind-patterns/SKILL.md +25 -11
- package/.agent/skills/taste-skill/SKILL.md +6 -0
- package/.agent/skills/tdd-workflow/SKILL.md +5 -0
- package/.agent/skills/test-result-analyzer/SKILL.md +1 -0
- package/.agent/skills/testing-patterns/SKILL.md +123 -115
- package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +5 -0
- package/.agent/skills/thinking-protocol/SKILL.md +3 -0
- package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +9 -8
- package/.agent/skills/transitions-dev/SKILL.md +19 -6
- package/.agent/skills/trend-researcher/SKILL.md +1 -0
- package/.agent/skills/typescript-advanced/SKILL.md +23 -18
- package/.agent/skills/typeset/SKILL.md +10 -1
- package/.agent/skills/ui-reasoning-engine/SKILL.md +67 -48
- package/.agent/skills/ui-skill-packs/SKILL.md +6 -1
- package/.agent/skills/ui-skills-root/SKILL.md +39 -38
- package/.agent/skills/ui-ux-pro-max/SKILL.md +34 -26
- package/.agent/skills/ui-ux-researcher/SKILL.md +1 -0
- package/.agent/skills/vector-search-pgvector/SKILL.md +78 -0
- package/.agent/skills/vue-expert/SKILL.md +22 -19
- package/.agent/skills/vulnerability-scanner/SKILL.md +22 -21
- package/.agent/skills/web-accessibility-auditor/SKILL.md +2 -1
- package/.agent/skills/web-design-guidelines/SKILL.md +16 -10
- package/.agent/skills/web-quality-audit/SKILL.md +5 -0
- package/.agent/skills/webapp-testing/SKILL.md +14 -13
- package/.agent/skills/webgpu-performance/SKILL.md +1 -0
- package/.agent/skills/whimsy-injector/SKILL.md +9 -5
- package/.agent/skills/workflow-optimizer/SKILL.md +1 -0
- package/.agent/skills/zero-trust-passkeys/SKILL.md +90 -0
- package/.agent/templates/DESIGN.md +119 -110
- package/.agent/templates/design-tokens.json +9 -6
- package/.agent/workflows/acf.md +1 -0
- package/.agent/workflows/api-tester.md +1 -0
- package/.agent/workflows/audit.md +1 -0
- package/.agent/workflows/brainstorm.md +1 -0
- package/.agent/workflows/changelog.md +1 -0
- package/.agent/workflows/contract.md +60 -0
- package/.agent/workflows/create.md +1 -0
- package/.agent/workflows/debug.md +1 -0
- package/.agent/workflows/deploy.md +1 -0
- package/.agent/workflows/enhance.md +1 -0
- package/.agent/workflows/fix-ci.md +89 -0
- package/.agent/workflows/fix.md +1 -0
- package/.agent/workflows/generate.md +1 -0
- package/.agent/workflows/marathon.md +1 -0
- package/.agent/workflows/migrate.md +1 -0
- package/.agent/workflows/minimal.md +9 -7
- package/.agent/workflows/orchestrate.md +1 -0
- package/.agent/workflows/performance-benchmarker.md +1 -0
- package/.agent/workflows/pipeline.md +26 -21
- package/.agent/workflows/plan.md +1 -0
- package/.agent/workflows/preview.md +1 -0
- package/.agent/workflows/refactor.md +3 -2
- package/.agent/workflows/review-ai.md +4 -3
- package/.agent/workflows/review.md +1 -0
- package/.agent/workflows/session.md +1 -0
- package/.agent/workflows/status.md +1 -0
- package/.agent/workflows/strengthen-skills.md +1 -0
- package/.agent/workflows/super-prompt.md +1 -0
- package/.agent/workflows/swarm.md +15 -3
- package/.agent/workflows/test.md +8 -7
- package/.agent/workflows/tribunal-backend.md +3 -2
- package/.agent/workflows/tribunal-cicd.md +104 -0
- package/.agent/workflows/tribunal-database.md +1 -0
- package/.agent/workflows/tribunal-frontend.md +8 -6
- package/.agent/workflows/tribunal-full.md +15 -14
- package/.agent/workflows/tribunal-mobile.md +6 -5
- package/.agent/workflows/tribunal-performance.md +1 -0
- package/.agent/workflows/tribunal-speed.md +1 -0
- package/.agent/workflows/tribunal-ui.md +29 -21
- package/.agent/workflows/ui-ux-pro-max.md +19 -15
- package/CONTRIBUTING.md +3 -3
- package/README.md +160 -88
- package/SECURITY.md +11 -11
- package/bin/mcp-server.js +512 -233
- package/bin/tribunal-kit.js +29 -30
- package/bin/wrapper.js +45 -48
- package/dist/cli.js +26 -0
- package/dist/commands/case.js +2 -0
- package/dist/commands/contract.js +440 -0
- package/dist/commands/memory.js +3 -2
- package/dist/commands/native.js +36 -0
- package/dist/commands/status.js +6 -0
- package/dist/esm/index.mjs +32 -0
- package/dist/index.d.ts +58 -3
- package/package.json +20 -16
- package/scripts/benchmark.js +62 -86
- package/scripts/changelog.js +67 -73
- package/scripts/fix-vbc.js +13 -15
- package/scripts/fix-vbc.ps1 +2 -118
- package/scripts/stress_benchmark.js +358 -0
- package/scripts/sync-version.js +71 -41
- package/scripts/validate-payload.js +23 -30
- package/scripts/visual_audit.js +23 -13
|
@@ -26,20 +26,32 @@
|
|
|
26
26
|
* const { planPhase, buildPhase, validatePhase, fullPipeline } = require('./pipeline_engine');
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
'use strict';
|
|
30
30
|
|
|
31
|
-
const fs = require(
|
|
32
|
-
const path = require(
|
|
31
|
+
const fs = require('fs');
|
|
32
|
+
const path = require('path');
|
|
33
33
|
|
|
34
34
|
// ── Shared Utilities ────────────────────────────────────────────────────────
|
|
35
|
-
const {
|
|
36
|
-
|
|
35
|
+
const {
|
|
36
|
+
GREEN,
|
|
37
|
+
YELLOW,
|
|
38
|
+
CYAN,
|
|
39
|
+
RED,
|
|
40
|
+
BLUE,
|
|
41
|
+
BOLD,
|
|
42
|
+
DIM,
|
|
43
|
+
RESET,
|
|
44
|
+
banner,
|
|
45
|
+
sectionHeader,
|
|
46
|
+
timer,
|
|
47
|
+
} = require('./_colors');
|
|
48
|
+
const { findAgentDir, parseArgs, loadJson } = require('./_utils');
|
|
37
49
|
|
|
38
50
|
// ── Lazy-load sibling scripts (avoid circular deps) ─────────────────────────
|
|
39
51
|
let _contextBroker = null;
|
|
40
52
|
function getContextBroker() {
|
|
41
53
|
if (!_contextBroker) {
|
|
42
|
-
_contextBroker = require(path.join(__dirname,
|
|
54
|
+
_contextBroker = require(path.join(__dirname, 'context_broker.js'));
|
|
43
55
|
}
|
|
44
56
|
return _contextBroker;
|
|
45
57
|
}
|
|
@@ -48,7 +60,7 @@ let _innerLoopValidator = null;
|
|
|
48
60
|
function getInnerLoopValidator() {
|
|
49
61
|
if (!_innerLoopValidator) {
|
|
50
62
|
try {
|
|
51
|
-
_innerLoopValidator = require(path.join(__dirname,
|
|
63
|
+
_innerLoopValidator = require(path.join(__dirname, 'inner_loop_validator.js'));
|
|
52
64
|
} catch {
|
|
53
65
|
_innerLoopValidator = null;
|
|
54
66
|
}
|
|
@@ -60,7 +72,7 @@ let _guardrailEngine = null;
|
|
|
60
72
|
function _getGuardrailEngine() {
|
|
61
73
|
if (!_guardrailEngine) {
|
|
62
74
|
try {
|
|
63
|
-
_guardrailEngine = require(path.join(__dirname,
|
|
75
|
+
_guardrailEngine = require(path.join(__dirname, 'guardrail_engine.js'));
|
|
64
76
|
} catch {
|
|
65
77
|
_guardrailEngine = null;
|
|
66
78
|
}
|
|
@@ -72,7 +84,7 @@ let _minimalChangeEngine = null;
|
|
|
72
84
|
function getMinimalChangeEngine() {
|
|
73
85
|
if (!_minimalChangeEngine) {
|
|
74
86
|
try {
|
|
75
|
-
_minimalChangeEngine = require(path.join(__dirname,
|
|
87
|
+
_minimalChangeEngine = require(path.join(__dirname, 'minimal_change_engine.js'));
|
|
76
88
|
} catch {
|
|
77
89
|
_minimalChangeEngine = null;
|
|
78
90
|
}
|
|
@@ -80,42 +92,83 @@ function getMinimalChangeEngine() {
|
|
|
80
92
|
return _minimalChangeEngine;
|
|
81
93
|
}
|
|
82
94
|
|
|
83
|
-
|
|
84
95
|
// ── Task Classification ─────────────────────────────────────────────────────
|
|
85
96
|
// Lightweight intent detection — no LLM call needed.
|
|
86
97
|
|
|
87
98
|
const TASK_TYPES = {
|
|
88
99
|
frontend_component: {
|
|
89
|
-
keywords: [
|
|
90
|
-
|
|
100
|
+
keywords: [
|
|
101
|
+
'component',
|
|
102
|
+
'page',
|
|
103
|
+
'layout',
|
|
104
|
+
'ui',
|
|
105
|
+
'form',
|
|
106
|
+
'modal',
|
|
107
|
+
'dialog',
|
|
108
|
+
'card',
|
|
109
|
+
'hero',
|
|
110
|
+
'nav',
|
|
111
|
+
'sidebar',
|
|
112
|
+
'dashboard',
|
|
113
|
+
'landing',
|
|
114
|
+
],
|
|
115
|
+
stack_hint: ['react', 'vue', 'svelte', 'html', 'css'],
|
|
91
116
|
},
|
|
92
117
|
frontend_page: {
|
|
93
|
-
keywords: [
|
|
94
|
-
stack_hint: [
|
|
118
|
+
keywords: ['page', 'landing', 'dashboard', 'home', 'about', 'pricing', 'settings'],
|
|
119
|
+
stack_hint: ['react', 'next', 'vue', 'nuxt'],
|
|
95
120
|
},
|
|
96
121
|
api_endpoint: {
|
|
97
|
-
keywords: [
|
|
98
|
-
|
|
122
|
+
keywords: [
|
|
123
|
+
'api',
|
|
124
|
+
'endpoint',
|
|
125
|
+
'route',
|
|
126
|
+
'handler',
|
|
127
|
+
'middleware',
|
|
128
|
+
'controller',
|
|
129
|
+
'rest',
|
|
130
|
+
'graphql',
|
|
131
|
+
],
|
|
132
|
+
stack_hint: ['express', 'fastapi', 'hono', 'node'],
|
|
99
133
|
},
|
|
100
134
|
database_query: {
|
|
101
|
-
keywords: [
|
|
102
|
-
stack_hint: [
|
|
135
|
+
keywords: ['query', 'sql', 'migration', 'schema', 'prisma', 'drizzle', 'orm', 'table', 'index'],
|
|
136
|
+
stack_hint: ['prisma', 'drizzle', 'postgres', 'mysql', 'sql'],
|
|
103
137
|
},
|
|
104
138
|
auth_flow: {
|
|
105
|
-
keywords: [
|
|
106
|
-
|
|
139
|
+
keywords: [
|
|
140
|
+
'auth',
|
|
141
|
+
'login',
|
|
142
|
+
'signup',
|
|
143
|
+
'jwt',
|
|
144
|
+
'oauth',
|
|
145
|
+
'session',
|
|
146
|
+
'password',
|
|
147
|
+
'rbac',
|
|
148
|
+
'permission',
|
|
149
|
+
],
|
|
150
|
+
stack_hint: ['jwt', 'oauth', 'next-auth'],
|
|
107
151
|
},
|
|
108
152
|
test_suite: {
|
|
109
|
-
keywords: [
|
|
110
|
-
stack_hint: [
|
|
153
|
+
keywords: ['test', 'spec', 'jest', 'vitest', 'playwright', 'e2e', 'unit', 'mock'],
|
|
154
|
+
stack_hint: ['jest', 'vitest', 'playwright'],
|
|
111
155
|
},
|
|
112
156
|
refactor: {
|
|
113
|
-
keywords: [
|
|
157
|
+
keywords: ['refactor', 'clean', 'extract', 'rename', 'move', 'split', 'merge', 'deduplicate'],
|
|
114
158
|
stack_hint: [],
|
|
115
159
|
},
|
|
116
160
|
animation: {
|
|
117
|
-
keywords: [
|
|
118
|
-
|
|
161
|
+
keywords: [
|
|
162
|
+
'animation',
|
|
163
|
+
'motion',
|
|
164
|
+
'gsap',
|
|
165
|
+
'framer',
|
|
166
|
+
'transition',
|
|
167
|
+
'scroll',
|
|
168
|
+
'parallax',
|
|
169
|
+
'hover',
|
|
170
|
+
],
|
|
171
|
+
stack_hint: ['gsap', 'framer-motion', 'css'],
|
|
119
172
|
},
|
|
120
173
|
general: {
|
|
121
174
|
keywords: [],
|
|
@@ -125,18 +178,17 @@ const TASK_TYPES = {
|
|
|
125
178
|
|
|
126
179
|
// Stack detection keywords
|
|
127
180
|
const STACK_KEYWORDS = {
|
|
128
|
-
react: [
|
|
129
|
-
nextjs: [
|
|
130
|
-
vue: [
|
|
131
|
-
typescript: [
|
|
132
|
-
python: [
|
|
133
|
-
node: [
|
|
134
|
-
css: [
|
|
135
|
-
sql: [
|
|
136
|
-
rust: [
|
|
181
|
+
react: ['react', 'jsx', 'tsx', 'useState', 'useEffect', 'component'],
|
|
182
|
+
nextjs: ['next', 'nextjs', 'server component', 'server action', 'app router'],
|
|
183
|
+
vue: ['vue', 'nuxt', 'composition api', 'ref(', 'computed('],
|
|
184
|
+
typescript: ['typescript', 'ts', 'interface', 'type ', 'generic'],
|
|
185
|
+
python: ['python', 'fastapi', 'django', 'flask', 'pydantic'],
|
|
186
|
+
node: ['node', 'express', 'hono', 'koa'],
|
|
187
|
+
css: ['css', 'tailwind', 'style', 'responsive', 'dark mode'],
|
|
188
|
+
sql: ['sql', 'postgres', 'mysql', 'prisma', 'drizzle', 'query'],
|
|
189
|
+
rust: ['rust', 'cargo', 'tokio', 'axum'],
|
|
137
190
|
};
|
|
138
191
|
|
|
139
|
-
|
|
140
192
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
141
193
|
// PASS 1 — PLANNER
|
|
142
194
|
// Classify the task, detect stack, select minimal skills, emit structured spec.
|
|
@@ -152,11 +204,22 @@ const STACK_KEYWORDS = {
|
|
|
152
204
|
* @returns {object} Structured spec JSON
|
|
153
205
|
*/
|
|
154
206
|
function planPhase(task, files = [], agentDir = null) {
|
|
207
|
+
let taskStr = task;
|
|
208
|
+
let fileList = files;
|
|
209
|
+
|
|
210
|
+
if (typeof task === 'object' && task !== null) {
|
|
211
|
+
taskStr = task.task || task.spec || '';
|
|
212
|
+
if (task.files) fileList = task.files;
|
|
213
|
+
if (task.file) fileList = [task.file];
|
|
214
|
+
if (task.agentDir) agentDir = task.agentDir;
|
|
215
|
+
}
|
|
216
|
+
if (typeof taskStr !== 'string') taskStr = String(taskStr || '');
|
|
155
217
|
const resolvedAgentDir = agentDir || findAgentDir();
|
|
156
|
-
const taskLower =
|
|
218
|
+
const taskLower = taskStr.toLowerCase();
|
|
219
|
+
files = Array.isArray(fileList) ? fileList : [fileList];
|
|
157
220
|
|
|
158
221
|
// 1. Classify task type
|
|
159
|
-
let bestType =
|
|
222
|
+
let bestType = 'general';
|
|
160
223
|
let bestScore = 0;
|
|
161
224
|
for (const [type, config] of Object.entries(TASK_TYPES)) {
|
|
162
225
|
let score = 0;
|
|
@@ -182,11 +245,15 @@ function planPhase(task, files = [], agentDir = null) {
|
|
|
182
245
|
|
|
183
246
|
// Infer stack from file extensions
|
|
184
247
|
const extToStack = {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
248
|
+
'.tsx': 'react',
|
|
249
|
+
'.jsx': 'react',
|
|
250
|
+
'.ts': 'typescript',
|
|
251
|
+
'.js': 'node',
|
|
252
|
+
'.vue': 'vue',
|
|
253
|
+
'.py': 'python',
|
|
254
|
+
'.rs': 'rust',
|
|
255
|
+
'.sql': 'sql',
|
|
256
|
+
'.css': 'css',
|
|
190
257
|
};
|
|
191
258
|
for (const f of files) {
|
|
192
259
|
const ext = path.extname(f).toLowerCase();
|
|
@@ -201,8 +268,8 @@ function planPhase(task, files = [], agentDir = null) {
|
|
|
201
268
|
const selection = broker.selectSkills(
|
|
202
269
|
task,
|
|
203
270
|
files,
|
|
204
|
-
|
|
205
|
-
broker.loadSkills(resolvedAgentDir)
|
|
271
|
+
'small', // Use small-model tier for aggressive pruning
|
|
272
|
+
broker.loadSkills(resolvedAgentDir),
|
|
206
273
|
);
|
|
207
274
|
|
|
208
275
|
// Take only top 3 essential skills for Pass 2
|
|
@@ -213,22 +280,30 @@ function planPhase(task, files = [], agentDir = null) {
|
|
|
213
280
|
|
|
214
281
|
// 4. Extract constraints from task text
|
|
215
282
|
const constraints = {};
|
|
216
|
-
if (
|
|
283
|
+
if (
|
|
284
|
+
taskLower.includes('accessible') ||
|
|
285
|
+
taskLower.includes('a11y') ||
|
|
286
|
+
taskLower.includes('aria')
|
|
287
|
+
) {
|
|
217
288
|
constraints.accessibility = true;
|
|
218
289
|
}
|
|
219
|
-
if (taskLower.includes(
|
|
290
|
+
if (taskLower.includes('responsive') || taskLower.includes('mobile')) {
|
|
220
291
|
constraints.responsive = true;
|
|
221
292
|
}
|
|
222
|
-
if (taskLower.includes(
|
|
293
|
+
if (taskLower.includes('dark mode') || taskLower.includes('theme')) {
|
|
223
294
|
constraints.dark_mode = true;
|
|
224
295
|
}
|
|
225
|
-
if (
|
|
296
|
+
if (
|
|
297
|
+
taskLower.includes('animation') ||
|
|
298
|
+
taskLower.includes('motion') ||
|
|
299
|
+
taskLower.includes('gsap')
|
|
300
|
+
) {
|
|
226
301
|
constraints.animation = true;
|
|
227
302
|
}
|
|
228
|
-
if (taskLower.includes(
|
|
303
|
+
if (taskLower.includes('test') || taskLower.includes('spec')) {
|
|
229
304
|
constraints.tests_required = true;
|
|
230
305
|
}
|
|
231
|
-
if (taskLower.includes(
|
|
306
|
+
if (taskLower.includes('typescript') || taskLower.includes('type-safe')) {
|
|
232
307
|
constraints.type_safe = true;
|
|
233
308
|
}
|
|
234
309
|
|
|
@@ -240,15 +315,24 @@ function planPhase(task, files = [], agentDir = null) {
|
|
|
240
315
|
let socraticGatePolicy = null;
|
|
241
316
|
let tokenBudget = null;
|
|
242
317
|
try {
|
|
243
|
-
const { classifyImpact } = require(
|
|
244
|
-
const { evaluateSocraticGate } = require(
|
|
245
|
-
const { getTokenBudget } = require(
|
|
318
|
+
const { classifyImpact } = require('./impact_classifier.js');
|
|
319
|
+
const { evaluateSocraticGate } = require('./socratic_gate_policy.js');
|
|
320
|
+
const { getTokenBudget } = require('./token_budget_broker.js');
|
|
246
321
|
impactClassification = classifyImpact({ files, task });
|
|
247
|
-
socraticGatePolicy = evaluateSocraticGate({
|
|
322
|
+
socraticGatePolicy = evaluateSocraticGate({
|
|
323
|
+
tier: impactClassification.tier,
|
|
324
|
+
ambiguityScore: 0.2,
|
|
325
|
+
});
|
|
248
326
|
tokenBudget = getTokenBudget(impactClassification.tier);
|
|
249
327
|
} catch {
|
|
250
|
-
impactClassification = {
|
|
251
|
-
|
|
328
|
+
impactClassification = {
|
|
329
|
+
tier: 1,
|
|
330
|
+
score: 0.2,
|
|
331
|
+
maxReviewers: 1,
|
|
332
|
+
requireGate: false,
|
|
333
|
+
fastPass: false,
|
|
334
|
+
};
|
|
335
|
+
socraticGatePolicy = { shouldBlock: false, reason: 'Fallback evaluation' };
|
|
252
336
|
tokenBudget = { tier: 1, maxTokens: 2000, maxReviewers: 1 };
|
|
253
337
|
}
|
|
254
338
|
|
|
@@ -289,7 +373,6 @@ function planPhase(task, files = [], agentDir = null) {
|
|
|
289
373
|
};
|
|
290
374
|
}
|
|
291
375
|
|
|
292
|
-
|
|
293
376
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
294
377
|
// PASS 2 — BUILDER
|
|
295
378
|
// Assemble a minimal, focused prompt for code generation.
|
|
@@ -315,37 +398,37 @@ function buildPhase(spec, agentDir = null, opts = {}) {
|
|
|
315
398
|
const skillsLoaded = [];
|
|
316
399
|
|
|
317
400
|
// ── Section 1: Task Specification (compact) ────────────────────────────────
|
|
318
|
-
lines.push(
|
|
319
|
-
lines.push(
|
|
401
|
+
lines.push('# Code Generation Task');
|
|
402
|
+
lines.push('');
|
|
320
403
|
lines.push(`Type: ${spec.task_type}`);
|
|
321
|
-
lines.push(`Stack: ${spec.stack.join(
|
|
404
|
+
lines.push(`Stack: ${spec.stack.join(', ') || 'detect from context'}`);
|
|
322
405
|
if (spec.target_file) {
|
|
323
406
|
lines.push(`Target: ${spec.target_file}`);
|
|
324
407
|
}
|
|
325
|
-
lines.push(
|
|
326
|
-
lines.push(
|
|
327
|
-
lines.push(
|
|
408
|
+
lines.push('');
|
|
409
|
+
lines.push('## Requirements');
|
|
410
|
+
lines.push('');
|
|
328
411
|
lines.push(spec.spec);
|
|
329
|
-
lines.push(
|
|
412
|
+
lines.push('');
|
|
330
413
|
|
|
331
414
|
// Constraints
|
|
332
415
|
const constraintEntries = Object.entries(spec.constraints || {});
|
|
333
416
|
if (constraintEntries.length > 0) {
|
|
334
|
-
lines.push(
|
|
335
|
-
lines.push(
|
|
417
|
+
lines.push('## Constraints');
|
|
418
|
+
lines.push('');
|
|
336
419
|
for (const [key, val] of constraintEntries) {
|
|
337
|
-
lines.push(`- ${key.replace(/_/g,
|
|
420
|
+
lines.push(`- ${key.replace(/_/g, ' ')}: ${val}`);
|
|
338
421
|
}
|
|
339
|
-
lines.push(
|
|
422
|
+
lines.push('');
|
|
340
423
|
}
|
|
341
424
|
|
|
342
425
|
// ── Section 2: Essential Skill Key-Rules (max 3 skills) ────────────────────
|
|
343
426
|
const skillNames = (spec.essential_skills || []).map(s => s.name);
|
|
344
427
|
if (skillNames.length > 0) {
|
|
345
|
-
lines.push(
|
|
346
|
-
lines.push(
|
|
347
|
-
lines.push(
|
|
348
|
-
lines.push(
|
|
428
|
+
lines.push('## Design & Implementation Guidelines');
|
|
429
|
+
lines.push('');
|
|
430
|
+
lines.push('Follow these rules strictly:');
|
|
431
|
+
lines.push('');
|
|
349
432
|
|
|
350
433
|
for (const skillName of skillNames.slice(0, 3)) {
|
|
351
434
|
const skill = allSkills.find(s => s.name === skillName);
|
|
@@ -353,39 +436,39 @@ function buildPhase(spec, agentDir = null, opts = {}) {
|
|
|
353
436
|
|
|
354
437
|
skillsLoaded.push(skillName);
|
|
355
438
|
lines.push(`### ${skillName}`);
|
|
356
|
-
lines.push(
|
|
439
|
+
lines.push('');
|
|
357
440
|
// Use condensed key-rules only — not full SKILL.md
|
|
358
|
-
lines.push(skill.keyRules ||
|
|
359
|
-
lines.push(
|
|
441
|
+
lines.push(skill.keyRules || '');
|
|
442
|
+
lines.push('');
|
|
360
443
|
}
|
|
361
444
|
}
|
|
362
445
|
|
|
363
446
|
// ── Section 3: Target File Context (if modifying existing code) ────────────
|
|
364
447
|
if (opts.targetFileContent) {
|
|
365
|
-
lines.push(
|
|
366
|
-
lines.push(
|
|
367
|
-
lines.push(
|
|
448
|
+
lines.push('## Current File Content');
|
|
449
|
+
lines.push('');
|
|
450
|
+
lines.push('```');
|
|
368
451
|
// Truncate to ~200 lines to stay within budget
|
|
369
|
-
const fileLines = opts.targetFileContent.split(
|
|
452
|
+
const fileLines = opts.targetFileContent.split('\n');
|
|
370
453
|
if (fileLines.length > 200) {
|
|
371
|
-
lines.push(fileLines.slice(0, 200).join(
|
|
454
|
+
lines.push(fileLines.slice(0, 200).join('\n'));
|
|
372
455
|
lines.push(`\n... (${fileLines.length - 200} more lines truncated)`);
|
|
373
456
|
} else {
|
|
374
457
|
lines.push(opts.targetFileContent);
|
|
375
458
|
}
|
|
376
|
-
lines.push(
|
|
377
|
-
lines.push(
|
|
459
|
+
lines.push('```');
|
|
460
|
+
lines.push('');
|
|
378
461
|
}
|
|
379
462
|
|
|
380
463
|
// ── Section 4: Output Format Instruction ───────────────────────────────────
|
|
381
|
-
lines.push(
|
|
382
|
-
lines.push(
|
|
383
|
-
lines.push(
|
|
384
|
-
lines.push(
|
|
385
|
-
lines.push(
|
|
386
|
-
lines.push(
|
|
464
|
+
lines.push('## Output Instructions');
|
|
465
|
+
lines.push('');
|
|
466
|
+
lines.push('Generate ONLY the code. No explanations, no preamble, no markdown fences.');
|
|
467
|
+
lines.push('Use self-documenting names. Add error handling on async functions.');
|
|
468
|
+
lines.push('Mark any uncertain API calls with // VERIFY: [reason].');
|
|
469
|
+
lines.push('');
|
|
387
470
|
|
|
388
|
-
const prompt = lines.join(
|
|
471
|
+
const prompt = lines.join('\n');
|
|
389
472
|
|
|
390
473
|
// Rough token estimate: ~4 chars per token for English text
|
|
391
474
|
const tokenEstimate = Math.ceil(prompt.length / 4);
|
|
@@ -393,7 +476,6 @@ function buildPhase(spec, agentDir = null, opts = {}) {
|
|
|
393
476
|
return { prompt, tokenEstimate, skillsLoaded };
|
|
394
477
|
}
|
|
395
478
|
|
|
396
|
-
|
|
397
479
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
398
480
|
// PASS 3 — VALIDATOR
|
|
399
481
|
// Run deterministic checks on generated code (zero LLM calls).
|
|
@@ -412,21 +494,21 @@ function buildPhase(spec, agentDir = null, opts = {}) {
|
|
|
412
494
|
*/
|
|
413
495
|
function validatePhase(code, spec, opts = {}) {
|
|
414
496
|
const issues = [];
|
|
415
|
-
let verdict =
|
|
497
|
+
let verdict = 'APPROVED';
|
|
416
498
|
|
|
417
499
|
// ── Inner Loop Validator (security patterns + syntax) ──────────────────────
|
|
418
500
|
const innerLoop = getInnerLoopValidator();
|
|
419
|
-
if (innerLoop && typeof innerLoop.validateSnippet ===
|
|
501
|
+
if (innerLoop && typeof innerLoop.validateSnippet === 'function') {
|
|
420
502
|
try {
|
|
421
503
|
const ilResult = innerLoop.validateSnippet(code, opts.lang || detectLang(spec));
|
|
422
504
|
if (ilResult && ilResult.issues) {
|
|
423
505
|
for (const issue of ilResult.issues) {
|
|
424
506
|
issues.push({
|
|
425
|
-
source:
|
|
426
|
-
severity: issue.severity ||
|
|
427
|
-
category: issue.category ||
|
|
507
|
+
source: 'inner_loop_validator',
|
|
508
|
+
severity: issue.severity || 'medium',
|
|
509
|
+
category: issue.category || 'unknown',
|
|
428
510
|
line: issue.line || null,
|
|
429
|
-
message: issue.message ||
|
|
511
|
+
message: issue.message || 'Unnamed issue',
|
|
430
512
|
fix: issue.fix || null,
|
|
431
513
|
});
|
|
432
514
|
}
|
|
@@ -441,37 +523,38 @@ function validatePhase(code, spec, opts = {}) {
|
|
|
441
523
|
issues.push(...manualIssues);
|
|
442
524
|
|
|
443
525
|
// ── Classify verdict ───────────────────────────────────────────────────────
|
|
444
|
-
const criticalCount = issues.filter(i => i.severity ===
|
|
445
|
-
const highCount = issues.filter(i => i.severity ===
|
|
526
|
+
const criticalCount = issues.filter(i => i.severity === 'critical').length;
|
|
527
|
+
const highCount = issues.filter(i => i.severity === 'high').length;
|
|
446
528
|
|
|
447
529
|
if (criticalCount > 0) {
|
|
448
|
-
verdict =
|
|
530
|
+
verdict = 'REJECTED';
|
|
449
531
|
} else if (highCount > 0) {
|
|
450
|
-
verdict =
|
|
532
|
+
verdict = 'WARNING';
|
|
451
533
|
} else {
|
|
452
|
-
verdict =
|
|
534
|
+
verdict = 'APPROVED';
|
|
453
535
|
}
|
|
454
536
|
|
|
455
537
|
// ── Build self-healing feedback for retry ──────────────────────────────────
|
|
456
538
|
let feedback = null;
|
|
457
|
-
if (verdict !==
|
|
458
|
-
const feedbackLines = [
|
|
539
|
+
if (verdict !== 'APPROVED' && issues.length > 0) {
|
|
540
|
+
const feedbackLines = ['The following issues were found in the generated code:'];
|
|
459
541
|
for (const issue of issues.slice(0, 5)) {
|
|
460
542
|
feedbackLines.push(`- [${issue.severity.toUpperCase()}] ${issue.message}`);
|
|
461
543
|
if (issue.fix) feedbackLines.push(` Fix: ${issue.fix}`);
|
|
462
544
|
}
|
|
463
|
-
feedbackLines.push(
|
|
464
|
-
feedbackLines.push(
|
|
465
|
-
feedback = feedbackLines.join(
|
|
545
|
+
feedbackLines.push('');
|
|
546
|
+
feedbackLines.push('Please regenerate the code addressing these issues.');
|
|
547
|
+
feedback = feedbackLines.join('\n');
|
|
466
548
|
}
|
|
467
549
|
|
|
468
|
-
const summary =
|
|
469
|
-
|
|
470
|
-
|
|
550
|
+
const summary =
|
|
551
|
+
verdict === 'APPROVED'
|
|
552
|
+
? `✅ Code passed validation (${issues.length} issues found, none blocking)`
|
|
553
|
+
: `${verdict === 'REJECTED' ? '❌' : '⚠️'} Code ${verdict.toLowerCase()}: ${criticalCount} critical, ${highCount} high severity issues`;
|
|
471
554
|
|
|
472
555
|
return {
|
|
473
556
|
verdict,
|
|
474
|
-
passed: verdict ===
|
|
557
|
+
passed: verdict === 'APPROVED',
|
|
475
558
|
issues,
|
|
476
559
|
summary,
|
|
477
560
|
feedback,
|
|
@@ -482,14 +565,21 @@ function validatePhase(code, spec, opts = {}) {
|
|
|
482
565
|
* Detect language from spec for validation context.
|
|
483
566
|
*/
|
|
484
567
|
function detectLang(spec) {
|
|
485
|
-
if (!spec || !spec.target_file) return
|
|
568
|
+
if (!spec || !spec.target_file) return 'js';
|
|
486
569
|
const ext = path.extname(spec.target_file).toLowerCase();
|
|
487
570
|
const map = {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
571
|
+
'.ts': 'ts',
|
|
572
|
+
'.tsx': 'tsx',
|
|
573
|
+
'.js': 'js',
|
|
574
|
+
'.jsx': 'jsx',
|
|
575
|
+
'.py': 'py',
|
|
576
|
+
'.rs': 'rs',
|
|
577
|
+
'.sql': 'sql',
|
|
578
|
+
'.vue': 'vue',
|
|
579
|
+
'.css': 'css',
|
|
580
|
+
'.html': 'html',
|
|
491
581
|
};
|
|
492
|
-
return map[ext] ||
|
|
582
|
+
return map[ext] || 'js';
|
|
493
583
|
}
|
|
494
584
|
|
|
495
585
|
/**
|
|
@@ -498,54 +588,56 @@ function detectLang(spec) {
|
|
|
498
588
|
*/
|
|
499
589
|
function runManualChecks(code, spec) {
|
|
500
590
|
const issues = [];
|
|
501
|
-
const lines = code.split(
|
|
591
|
+
const lines = code.split('\n');
|
|
502
592
|
|
|
503
593
|
// Check 1: eval() usage
|
|
504
594
|
if (/\beval\s*\(/.test(code)) {
|
|
505
595
|
issues.push({
|
|
506
|
-
source:
|
|
507
|
-
severity:
|
|
508
|
-
category:
|
|
596
|
+
source: 'pipeline_validator',
|
|
597
|
+
severity: 'critical',
|
|
598
|
+
category: 'Code Injection',
|
|
509
599
|
line: findLineNumber(lines, /\beval\s*\(/),
|
|
510
|
-
message:
|
|
511
|
-
fix:
|
|
600
|
+
message: 'eval() is a code injection vector — never use in production',
|
|
601
|
+
fix: 'Use JSON.parse(), new Function(), or a proper parser instead',
|
|
512
602
|
});
|
|
513
603
|
}
|
|
514
604
|
|
|
515
605
|
// Check 2: Hardcoded secrets
|
|
516
606
|
if (/(?:password|secret|api[_-]?key)\s*[:=]\s*["'][^"']{4,}["']/i.test(code)) {
|
|
517
607
|
issues.push({
|
|
518
|
-
source:
|
|
519
|
-
severity:
|
|
520
|
-
category:
|
|
608
|
+
source: 'pipeline_validator',
|
|
609
|
+
severity: 'critical',
|
|
610
|
+
category: 'Hardcoded Secret',
|
|
521
611
|
line: findLineNumber(lines, /(?:password|secret|api[_-]?key)\s*[:=]\s*["']/i),
|
|
522
|
-
message:
|
|
523
|
-
fix:
|
|
612
|
+
message: 'Hardcoded secret detected — use environment variables',
|
|
613
|
+
fix: 'Replace with process.env.SECRET_NAME or equivalent',
|
|
524
614
|
});
|
|
525
615
|
}
|
|
526
616
|
|
|
527
617
|
// Check 3: innerHTML XSS
|
|
528
|
-
if (/\.innerHTML\s*=/.test(code) && !code.includes(
|
|
618
|
+
if (/\.innerHTML\s*=/.test(code) && !code.includes('DOMPurify')) {
|
|
529
619
|
issues.push({
|
|
530
|
-
source:
|
|
531
|
-
severity:
|
|
532
|
-
category:
|
|
620
|
+
source: 'pipeline_validator',
|
|
621
|
+
severity: 'high',
|
|
622
|
+
category: 'XSS',
|
|
533
623
|
line: findLineNumber(lines, /\.innerHTML\s*=/),
|
|
534
|
-
message:
|
|
624
|
+
message: 'Direct innerHTML assignment without sanitization',
|
|
535
625
|
fix: "Use textContent, DOMPurify.sanitize(), or React's JSX instead",
|
|
536
626
|
});
|
|
537
627
|
}
|
|
538
628
|
|
|
539
629
|
// Check 4: SQL injection (string interpolation in queries)
|
|
540
|
-
if (
|
|
541
|
-
|
|
630
|
+
if (
|
|
631
|
+
/\$\{.*\}.*(?:SELECT|INSERT|UPDATE|DELETE|WHERE)/i.test(code) ||
|
|
632
|
+
/['"].*\+.*(?:SELECT|INSERT|UPDATE|DELETE|WHERE)/i.test(code)
|
|
633
|
+
) {
|
|
542
634
|
issues.push({
|
|
543
|
-
source:
|
|
544
|
-
severity:
|
|
545
|
-
category:
|
|
635
|
+
source: 'pipeline_validator',
|
|
636
|
+
severity: 'critical',
|
|
637
|
+
category: 'SQL Injection',
|
|
546
638
|
line: null,
|
|
547
|
-
message:
|
|
548
|
-
fix:
|
|
639
|
+
message: 'Possible SQL injection — string interpolation in SQL query',
|
|
640
|
+
fix: 'Use parameterized queries ($1, ?) or an ORM',
|
|
549
641
|
});
|
|
550
642
|
}
|
|
551
643
|
|
|
@@ -553,36 +645,36 @@ function runManualChecks(code, spec) {
|
|
|
553
645
|
const consoleCount = (code.match(/console\.(log|debug|info)\(/g) || []).length;
|
|
554
646
|
if (consoleCount > 3) {
|
|
555
647
|
issues.push({
|
|
556
|
-
source:
|
|
557
|
-
severity:
|
|
558
|
-
category:
|
|
648
|
+
source: 'pipeline_validator',
|
|
649
|
+
severity: 'low',
|
|
650
|
+
category: 'Code Quality',
|
|
559
651
|
line: null,
|
|
560
652
|
message: `${consoleCount} console.log statements found — remove before production`,
|
|
561
|
-
fix:
|
|
653
|
+
fix: 'Use a proper logger (winston, pino) or remove debug logs',
|
|
562
654
|
});
|
|
563
655
|
}
|
|
564
656
|
|
|
565
657
|
// Check 6: Empty catch blocks
|
|
566
658
|
if (/catch\s*\([^)]*\)\s*\{[\s\n]*\}/.test(code)) {
|
|
567
659
|
issues.push({
|
|
568
|
-
source:
|
|
569
|
-
severity:
|
|
570
|
-
category:
|
|
660
|
+
source: 'pipeline_validator',
|
|
661
|
+
severity: 'medium',
|
|
662
|
+
category: 'Error Handling',
|
|
571
663
|
line: findLineNumber(lines, /catch\s*\([^)]*\)\s*\{[\s\n]*\}/),
|
|
572
|
-
message:
|
|
573
|
-
fix:
|
|
664
|
+
message: 'Empty catch block swallows errors silently',
|
|
665
|
+
fix: 'At minimum, log the error: catch(err) { console.error(err); }',
|
|
574
666
|
});
|
|
575
667
|
}
|
|
576
668
|
|
|
577
669
|
// Check 7: TypeScript `any` usage (if TS file)
|
|
578
670
|
const lang = detectLang(spec);
|
|
579
|
-
if ((lang ===
|
|
671
|
+
if ((lang === 'ts' || lang === 'tsx') && /:\s*any\b/.test(code)) {
|
|
580
672
|
const anyCount = (code.match(/:\s*any\b/g) || []).length;
|
|
581
673
|
if (anyCount > 2) {
|
|
582
674
|
issues.push({
|
|
583
|
-
source:
|
|
584
|
-
severity:
|
|
585
|
-
category:
|
|
675
|
+
source: 'pipeline_validator',
|
|
676
|
+
severity: 'medium',
|
|
677
|
+
category: 'Type Safety',
|
|
586
678
|
line: null,
|
|
587
679
|
message: `${anyCount} uses of 'any' type — reduces type safety`,
|
|
588
680
|
fix: "Replace with specific types or use 'unknown' with type guards",
|
|
@@ -603,7 +695,6 @@ function findLineNumber(lines, pattern) {
|
|
|
603
695
|
return null;
|
|
604
696
|
}
|
|
605
697
|
|
|
606
|
-
|
|
607
698
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
608
699
|
// FULL PIPELINE — Orchestrate all 3 passes
|
|
609
700
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
@@ -632,7 +723,7 @@ function fullPipeline(task, files = [], opts = {}) {
|
|
|
632
723
|
|
|
633
724
|
// Pass 3: Return validator as a callable
|
|
634
725
|
// The caller invokes validate(code) after the LLM generates the code
|
|
635
|
-
const validate =
|
|
726
|
+
const validate = code => validatePhase(code, spec, { lang: detectLang(spec) });
|
|
636
727
|
|
|
637
728
|
return {
|
|
638
729
|
spec,
|
|
@@ -643,7 +734,6 @@ function fullPipeline(task, files = [], opts = {}) {
|
|
|
643
734
|
};
|
|
644
735
|
}
|
|
645
736
|
|
|
646
|
-
|
|
647
737
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
648
738
|
// PUBLIC API
|
|
649
739
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
@@ -658,23 +748,22 @@ module.exports = {
|
|
|
658
748
|
STACK_KEYWORDS,
|
|
659
749
|
};
|
|
660
750
|
|
|
661
|
-
|
|
662
751
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
663
752
|
// CLI ENTRY POINT
|
|
664
753
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
665
754
|
|
|
666
755
|
if (require.main === module) {
|
|
667
756
|
const { flags, positional } = parseArgs(process.argv.slice(2), {
|
|
668
|
-
task: { type:
|
|
669
|
-
file: { type:
|
|
670
|
-
phase: { type:
|
|
671
|
-
output: { type:
|
|
672
|
-
spec: { type:
|
|
673
|
-
code: { type:
|
|
674
|
-
|
|
757
|
+
task: { type: 'string', default: null },
|
|
758
|
+
file: { type: 'string', default: null },
|
|
759
|
+
phase: { type: 'string', default: 'full' },
|
|
760
|
+
output: { type: 'string', default: 'report' },
|
|
761
|
+
spec: { type: 'string', default: null },
|
|
762
|
+
code: { type: 'string', default: null },
|
|
763
|
+
'dry-run': { type: 'boolean', default: false },
|
|
675
764
|
});
|
|
676
765
|
|
|
677
|
-
if (flags.help || (!flags.task && positional[0] !==
|
|
766
|
+
if (flags.help || (!flags.task && positional[0] !== 'demo')) {
|
|
678
767
|
console.log(`
|
|
679
768
|
${BOLD}pipeline_engine.js${RESET} — Tribunal Hybrid Pipeline Engine
|
|
680
769
|
|
|
@@ -708,15 +797,15 @@ ${BOLD}Examples:${RESET}
|
|
|
708
797
|
const agentDir = findAgentDir();
|
|
709
798
|
|
|
710
799
|
// ── Demo Mode ──────────────────────────────────────────────────────────────
|
|
711
|
-
if (positional[0] ===
|
|
800
|
+
if (positional[0] === 'demo') {
|
|
712
801
|
const scenarios = [
|
|
713
|
-
{ task:
|
|
714
|
-
{ task:
|
|
715
|
-
{ task:
|
|
716
|
-
{ task:
|
|
802
|
+
{ task: 'Build a React dashboard with charts and dark mode', file: 'Dashboard.tsx' },
|
|
803
|
+
{ task: 'Create an Express JWT authentication middleware', file: 'auth.ts' },
|
|
804
|
+
{ task: 'Write a Prisma query for paginated user search', file: 'users.ts' },
|
|
805
|
+
{ task: 'Design a premium SaaS landing page with scroll animations', file: 'Hero.tsx' },
|
|
717
806
|
];
|
|
718
807
|
|
|
719
|
-
console.log(banner(
|
|
808
|
+
console.log(banner('Pipeline Engine — Demo Mode'));
|
|
720
809
|
|
|
721
810
|
for (const scenario of scenarios) {
|
|
722
811
|
const t = timer();
|
|
@@ -725,59 +814,71 @@ ${BOLD}Examples:${RESET}
|
|
|
725
814
|
|
|
726
815
|
console.log(`\n ${BOLD}Task:${RESET} "${scenario.task}"`);
|
|
727
816
|
console.log(` ${DIM}Type:${RESET} ${result.spec.task_type}`);
|
|
728
|
-
console.log(` ${DIM}Stack:${RESET} ${result.spec.stack.join(
|
|
729
|
-
console.log(
|
|
817
|
+
console.log(` ${DIM}Stack:${RESET} ${result.spec.stack.join(', ')}`);
|
|
818
|
+
console.log(
|
|
819
|
+
` ${GREEN}Skills:${RESET} ${result.skillsLoaded.join(', ') || '(none matched)'}`,
|
|
820
|
+
);
|
|
730
821
|
console.log(` ${CYAN}Tokens:${RESET} ~${result.tokenEstimate} (vs ~12,000 monolithic)`);
|
|
731
822
|
console.log(` ${DIM}Time:${RESET} ${elapsed}ms`);
|
|
732
823
|
}
|
|
733
824
|
|
|
734
|
-
console.log(`\n${CYAN}${
|
|
825
|
+
console.log(`\n${CYAN}${'━'.repeat(56)}${RESET}\n`);
|
|
735
826
|
process.exit(0);
|
|
736
827
|
}
|
|
737
828
|
|
|
738
829
|
// ── Phase Execution ────────────────────────────────────────────────────────
|
|
739
830
|
const files = flags.file ? [flags.file] : [];
|
|
740
831
|
|
|
741
|
-
if (flags.phase ===
|
|
832
|
+
if (flags.phase === 'plan' || flags.phase === 'full') {
|
|
742
833
|
const t = timer();
|
|
743
834
|
const spec = planPhase(flags.task, files, agentDir);
|
|
744
835
|
const elapsed = t().toFixed(1);
|
|
745
836
|
|
|
746
|
-
if (flags.output ===
|
|
837
|
+
if (flags.output === 'json') {
|
|
747
838
|
console.log(JSON.stringify(spec, null, 2));
|
|
748
839
|
} else {
|
|
749
|
-
console.log(banner(
|
|
840
|
+
console.log(banner('Pipeline — Pass 1: Planner'));
|
|
750
841
|
console.log(` ${BOLD}Task Type:${RESET} ${spec.task_type}`);
|
|
751
|
-
console.log(` ${BOLD}Stack:${RESET} ${spec.stack.join(
|
|
752
|
-
console.log(
|
|
842
|
+
console.log(` ${BOLD}Stack:${RESET} ${spec.stack.join(', ') || '(auto-detect)'}`);
|
|
843
|
+
console.log(
|
|
844
|
+
` ${BOLD}Skills:${RESET} ${spec.essential_skills.map(s => s.name).join(', ')}`,
|
|
845
|
+
);
|
|
753
846
|
if (Object.keys(spec.constraints).length > 0) {
|
|
754
|
-
console.log(` ${BOLD}Constraints:${RESET} ${Object.keys(spec.constraints).join(
|
|
847
|
+
console.log(` ${BOLD}Constraints:${RESET} ${Object.keys(spec.constraints).join(', ')}`);
|
|
755
848
|
}
|
|
756
849
|
console.log(` ${DIM}Time: ${elapsed}ms${RESET}`);
|
|
757
850
|
}
|
|
758
851
|
|
|
759
|
-
if (flags.phase ===
|
|
852
|
+
if (flags.phase === 'full' && !flags['dry-run']) {
|
|
760
853
|
const builderResult = buildPhase(spec, agentDir);
|
|
761
854
|
|
|
762
|
-
if (flags.output ===
|
|
763
|
-
console.log(
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
855
|
+
if (flags.output === 'json') {
|
|
856
|
+
console.log(
|
|
857
|
+
JSON.stringify(
|
|
858
|
+
{
|
|
859
|
+
spec,
|
|
860
|
+
tokenEstimate: builderResult.tokenEstimate,
|
|
861
|
+
skillsLoaded: builderResult.skillsLoaded,
|
|
862
|
+
},
|
|
863
|
+
null,
|
|
864
|
+
2,
|
|
865
|
+
),
|
|
866
|
+
);
|
|
867
|
+
} else if (flags.output === 'prompt') {
|
|
769
868
|
console.log(builderResult.prompt);
|
|
770
869
|
} else {
|
|
771
|
-
console.log(sectionHeader(
|
|
870
|
+
console.log(sectionHeader('Pass 2: Builder Prompt', 2));
|
|
772
871
|
console.log(` ${BOLD}Token Estimate:${RESET} ~${builderResult.tokenEstimate}`);
|
|
773
|
-
console.log(` ${BOLD}Skills Loaded:${RESET} ${builderResult.skillsLoaded.join(
|
|
774
|
-
console.log(
|
|
872
|
+
console.log(` ${BOLD}Skills Loaded:${RESET} ${builderResult.skillsLoaded.join(', ')}`);
|
|
873
|
+
console.log(
|
|
874
|
+
` ${GREEN}Savings:${RESET} ~${Math.round((1 - builderResult.tokenEstimate / 14000) * 100)}% vs monolithic prompt`,
|
|
875
|
+
);
|
|
775
876
|
console.log(`\n ${DIM}Use --output prompt to see the full builder prompt${RESET}`);
|
|
776
877
|
}
|
|
777
878
|
}
|
|
778
879
|
}
|
|
779
880
|
|
|
780
|
-
if (flags.phase ===
|
|
881
|
+
if (flags.phase === 'build') {
|
|
781
882
|
let spec;
|
|
782
883
|
if (flags.spec) {
|
|
783
884
|
spec = loadJson(flags.spec);
|
|
@@ -794,26 +895,32 @@ ${BOLD}Examples:${RESET}
|
|
|
794
895
|
|
|
795
896
|
const result = buildPhase(spec, agentDir);
|
|
796
897
|
|
|
797
|
-
if (flags.output ===
|
|
898
|
+
if (flags.output === 'prompt') {
|
|
798
899
|
console.log(result.prompt);
|
|
799
|
-
} else if (flags.output ===
|
|
800
|
-
console.log(
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
900
|
+
} else if (flags.output === 'json') {
|
|
901
|
+
console.log(
|
|
902
|
+
JSON.stringify(
|
|
903
|
+
{
|
|
904
|
+
tokenEstimate: result.tokenEstimate,
|
|
905
|
+
skillsLoaded: result.skillsLoaded,
|
|
906
|
+
},
|
|
907
|
+
null,
|
|
908
|
+
2,
|
|
909
|
+
),
|
|
910
|
+
);
|
|
804
911
|
} else {
|
|
805
|
-
console.log(banner(
|
|
912
|
+
console.log(banner('Pipeline — Pass 2: Builder'));
|
|
806
913
|
console.log(` Token Estimate: ~${result.tokenEstimate}`);
|
|
807
|
-
console.log(` Skills Loaded: ${result.skillsLoaded.join(
|
|
914
|
+
console.log(` Skills Loaded: ${result.skillsLoaded.join(', ')}`);
|
|
808
915
|
console.log(`\n Use --output prompt to see the full builder prompt`);
|
|
809
916
|
}
|
|
810
917
|
}
|
|
811
918
|
|
|
812
|
-
if (flags.phase ===
|
|
919
|
+
if (flags.phase === 'validate') {
|
|
813
920
|
let codeContent;
|
|
814
921
|
if (flags.code) {
|
|
815
922
|
try {
|
|
816
|
-
codeContent = fs.readFileSync(flags.code,
|
|
923
|
+
codeContent = fs.readFileSync(flags.code, 'utf8');
|
|
817
924
|
} catch (_err) {
|
|
818
925
|
console.error(`${RED}✖ Could not read code file: ${flags.code}${RESET}`);
|
|
819
926
|
process.exit(1);
|
|
@@ -826,28 +933,32 @@ ${BOLD}Examples:${RESET}
|
|
|
826
933
|
const spec = flags.task ? planPhase(flags.task, files, agentDir) : { target_file: flags.code };
|
|
827
934
|
const result = validatePhase(codeContent, spec);
|
|
828
935
|
|
|
829
|
-
if (flags.output ===
|
|
936
|
+
if (flags.output === 'json') {
|
|
830
937
|
console.log(JSON.stringify(result, null, 2));
|
|
831
938
|
} else {
|
|
832
|
-
console.log(banner(
|
|
833
|
-
const icon =
|
|
834
|
-
|
|
939
|
+
console.log(banner('Pipeline — Pass 3: Validator'));
|
|
940
|
+
const icon =
|
|
941
|
+
result.verdict === 'APPROVED'
|
|
942
|
+
? `${GREEN}✅`
|
|
943
|
+
: result.verdict === 'WARNING'
|
|
944
|
+
? `${YELLOW}⚠️`
|
|
945
|
+
: `${RED}❌`;
|
|
835
946
|
console.log(` ${BOLD}Verdict:${RESET} ${icon} ${result.verdict}${RESET}`);
|
|
836
947
|
console.log(` ${BOLD}Issues:${RESET} ${result.issues.length}`);
|
|
837
948
|
|
|
838
949
|
if (result.issues.length > 0) {
|
|
839
|
-
console.log(
|
|
950
|
+
console.log('');
|
|
840
951
|
for (const issue of result.issues) {
|
|
841
|
-
const sev =
|
|
842
|
-
|
|
843
|
-
const loc = issue.line ? ` (line ${issue.line})` :
|
|
952
|
+
const sev =
|
|
953
|
+
issue.severity === 'critical' ? RED : issue.severity === 'high' ? YELLOW : DIM;
|
|
954
|
+
const loc = issue.line ? ` (line ${issue.line})` : '';
|
|
844
955
|
console.log(` ${sev}[${issue.severity.toUpperCase()}]${RESET} ${issue.message}${loc}`);
|
|
845
956
|
}
|
|
846
957
|
}
|
|
847
958
|
|
|
848
959
|
if (result.feedback) {
|
|
849
960
|
console.log(`\n ${BLUE}Self-Healing Feedback:${RESET}`);
|
|
850
|
-
console.log(` ${DIM}${result.feedback.split(
|
|
961
|
+
console.log(` ${DIM}${result.feedback.split('\n').join('\n ')}${RESET}`);
|
|
851
962
|
}
|
|
852
963
|
}
|
|
853
964
|
|