tribunal-kit 5.8.4 → 6.0.0

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