tribunal-kit 6.0.1 → 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.
Files changed (349) hide show
  1. package/.agent/ARCHITECTURE.md +9 -6
  2. package/.agent/agents/accessibility-reviewer.md +23 -16
  3. package/.agent/agents/ai-code-reviewer.md +25 -21
  4. package/.agent/agents/anti-pattern-reviewer.md +12 -7
  5. package/.agent/agents/api-architect.md +1 -0
  6. package/.agent/agents/backend-specialist.md +23 -22
  7. package/.agent/agents/cloud-engineer.md +1 -0
  8. package/.agent/agents/code-archaeologist.md +1 -0
  9. package/.agent/agents/complexity-reviewer.md +10 -7
  10. package/.agent/agents/database-architect.md +3 -2
  11. package/.agent/agents/db-latency-auditor.md +6 -2
  12. package/.agent/agents/debugger.md +3 -2
  13. package/.agent/agents/dependency-reviewer.md +1 -0
  14. package/.agent/agents/devops-engineer.md +9 -8
  15. package/.agent/agents/documentation-writer.md +6 -5
  16. package/.agent/agents/explorer-agent.md +1 -0
  17. package/.agent/agents/frontend-reviewer.md +21 -17
  18. package/.agent/agents/frontend-specialist.md +23 -20
  19. package/.agent/agents/game-developer.md +1 -0
  20. package/.agent/agents/interaction-reviewer.md +10 -5
  21. package/.agent/agents/logic-reviewer.md +3 -0
  22. package/.agent/agents/minimalist-reviewer.md +6 -0
  23. package/.agent/agents/mobile-developer.md +7 -6
  24. package/.agent/agents/mobile-reviewer.md +14 -13
  25. package/.agent/agents/orchestrator.md +3 -0
  26. package/.agent/agents/penetration-tester.md +1 -0
  27. package/.agent/agents/performance-optimizer.md +6 -5
  28. package/.agent/agents/performance-reviewer.md +6 -6
  29. package/.agent/agents/pipeline-reviewer.md +144 -0
  30. package/.agent/agents/precedence-reviewer.md +1 -0
  31. package/.agent/agents/product-manager.md +1 -0
  32. package/.agent/agents/product-owner.md +1 -0
  33. package/.agent/agents/product-reviewer.md +12 -7
  34. package/.agent/agents/project-planner.md +3 -0
  35. package/.agent/agents/qa-automation-engineer.md +50 -43
  36. package/.agent/agents/resilience-reviewer.md +1 -0
  37. package/.agent/agents/schema-reviewer.md +1 -0
  38. package/.agent/agents/security-auditor.md +24 -24
  39. package/.agent/agents/seo-specialist.md +33 -23
  40. package/.agent/agents/sql-reviewer.md +5 -4
  41. package/.agent/agents/supervisor-agent.md +12 -2
  42. package/.agent/agents/swarm-worker-contracts.md +13 -13
  43. package/.agent/agents/swarm-worker-registry.md +51 -51
  44. package/.agent/agents/system-architect.md +1 -0
  45. package/.agent/agents/test-coverage-reviewer.md +25 -22
  46. package/.agent/agents/test-engineer.md +12 -11
  47. package/.agent/agents/throughput-optimizer.md +45 -40
  48. package/.agent/agents/type-safety-reviewer.md +5 -4
  49. package/.agent/agents/ui-ux-auditor.md +6 -4
  50. package/.agent/agents/ui-visual-auditor.md +3 -0
  51. package/.agent/agents/ux-reviewer.md +11 -6
  52. package/.agent/agents/visual-reviewer.md +11 -6
  53. package/.agent/agents/vitals-reviewer.md +5 -4
  54. package/.agent/history/memory/.memory.idx +1532 -1
  55. package/.agent/history/memory/MEMORY.md +102 -1
  56. package/.agent/mcp_config.json +1 -6
  57. package/.agent/routing_index.json +2033 -263
  58. package/.agent/rules/GEMINI.md +11 -9
  59. package/.agent/rules/GEMINI_PLANNER.md +19 -21
  60. package/.agent/scripts/_colors.js +52 -54
  61. package/.agent/scripts/_utils.js +52 -53
  62. package/.agent/scripts/auto_preview.js +39 -43
  63. package/.agent/scripts/bundle_analyzer.js +47 -60
  64. package/.agent/scripts/case_law_manager.js +200 -294
  65. package/.agent/scripts/checklist.js +73 -94
  66. package/.agent/scripts/cicd_validator.js +305 -0
  67. package/.agent/scripts/compile_router.py +4 -111
  68. package/.agent/scripts/context_broker.js +317 -412
  69. package/.agent/scripts/contract_engine.js +402 -0
  70. package/.agent/scripts/dependency_analyzer.js +112 -124
  71. package/.agent/scripts/graph_builder.js +75 -103
  72. package/.agent/scripts/graph_visualizer.js +10 -12
  73. package/.agent/scripts/graph_zoom.js +38 -55
  74. package/.agent/scripts/guardrail_engine.js +195 -145
  75. package/.agent/scripts/impact_classifier.js +55 -30
  76. package/.agent/scripts/inner_loop_validator.js +108 -159
  77. package/.agent/scripts/integrity_manifest.js +59 -67
  78. package/.agent/scripts/lint_runner.js +65 -75
  79. package/.agent/scripts/marathon_harness.js +131 -208
  80. package/.agent/scripts/migrate_skills_frontmatter.py +4 -63
  81. package/.agent/scripts/minify_context.js +29 -33
  82. package/.agent/scripts/minimal_change_engine.js +95 -87
  83. package/.agent/scripts/mutation_runner.js +46 -62
  84. package/.agent/scripts/pipeline_engine.js +320 -209
  85. package/.agent/scripts/prompt_compiler.js +118 -93
  86. package/.agent/scripts/schema_validator.js +73 -121
  87. package/.agent/scripts/security_scan.js +88 -117
  88. package/.agent/scripts/session_manager.js +52 -69
  89. package/.agent/scripts/signal_detector.js +24 -22
  90. package/.agent/scripts/skill_evolution.js +184 -245
  91. package/.agent/scripts/skill_integrator.js +35 -48
  92. package/.agent/scripts/socratic_gate_policy.js +15 -12
  93. package/.agent/scripts/strengthen_skills.js +29 -33
  94. package/.agent/scripts/swarm_dispatcher.js +120 -151
  95. package/.agent/scripts/test_runner.js +54 -56
  96. package/.agent/scripts/token_budget_broker.js +9 -7
  97. package/.agent/scripts/trace_engine.js +126 -0
  98. package/.agent/scripts/verify_all.js +76 -93
  99. package/.agent/scripts/visual_audit.js +16 -21
  100. package/.agent/skill_topic_map.json +22 -3
  101. package/.agent/skills/12-principles-of-animation/SKILL.md +7 -0
  102. package/.agent/skills/60fps-animation/SKILL.md +7 -0
  103. package/.agent/skills/accessible-animation/SKILL.md +5 -1
  104. package/.agent/skills/adapt/SKILL.md +7 -1
  105. package/.agent/skills/advanced-rag-pipelines/SKILL.md +1 -0
  106. package/.agent/skills/agent-organizer/SKILL.md +1 -0
  107. package/.agent/skills/agentic-patterns/SKILL.md +33 -25
  108. package/.agent/skills/agentic-workflows-2026/SKILL.md +6 -2
  109. package/.agent/skills/ai-app-hardening/SKILL.md +9 -8
  110. package/.agent/skills/ai-prompt-injection-defense/SKILL.md +7 -6
  111. package/.agent/skills/animation-on-scroll/SKILL.md +24 -15
  112. package/.agent/skills/animation-systems/SKILL.md +11 -10
  113. package/.agent/skills/antfu-conventions/SKILL.md +7 -2
  114. package/.agent/skills/api-patterns/SKILL.md +14 -10
  115. package/.agent/skills/api-security-auditor/SKILL.md +15 -14
  116. package/.agent/skills/app-builder/SKILL.md +1 -0
  117. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +2 -2
  118. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
  119. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +12 -12
  120. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +3 -3
  121. package/.agent/skills/apple-design/SKILL.md +8 -7
  122. package/.agent/skills/architecture/SKILL.md +3 -2
  123. package/.agent/skills/audit-and-fix/SKILL.md +8 -5
  124. package/.agent/skills/authentication-best-practices/SKILL.md +9 -8
  125. package/.agent/skills/backend-security-expert/SKILL.md +1 -0
  126. package/.agent/skills/baseline-ui/SKILL.md +8 -7
  127. package/.agent/skills/bash-linux/SKILL.md +1 -0
  128. package/.agent/skills/behavioral-modes/SKILL.md +1 -0
  129. package/.agent/skills/better-colors/SKILL.md +11 -7
  130. package/.agent/skills/better-typography/SKILL.md +30 -16
  131. package/.agent/skills/better-ui/SKILL.md +17 -10
  132. package/.agent/skills/bolder/SKILL.md +6 -0
  133. package/.agent/skills/brainstorming/SKILL.md +6 -4
  134. package/.agent/skills/browser-native-ai/SKILL.md +5 -4
  135. package/.agent/skills/build-primitive/SKILL.md +5 -0
  136. package/.agent/skills/building-native-ui/SKILL.md +1 -0
  137. package/.agent/skills/cicd-pro/SKILL.md +2 -1
  138. package/.agent/skills/clarify/SKILL.md +19 -14
  139. package/.agent/skills/clean-code/SKILL.md +16 -15
  140. package/.agent/skills/cloud-architect/SKILL.md +1 -0
  141. package/.agent/skills/cobejs/SKILL.md +7 -9
  142. package/.agent/skills/code-review-checklist/SKILL.md +1 -0
  143. package/.agent/skills/codebase-design/SKILL.md +7 -2
  144. package/.agent/skills/colorize/SKILL.md +8 -3
  145. package/.agent/skills/compact-landing/SKILL.md +8 -3
  146. package/.agent/skills/company-logos/SKILL.md +6 -0
  147. package/.agent/skills/config-validator/SKILL.md +10 -9
  148. package/.agent/skills/containerization-pro/SKILL.md +6 -5
  149. package/.agent/skills/context-engineering-pro/SKILL.md +5 -4
  150. package/.agent/skills/create-design-md/SKILL.md +13 -5
  151. package/.agent/skills/critique/SKILL.md +10 -8
  152. package/.agent/skills/csharp-developer/SKILL.md +1 -0
  153. package/.agent/skills/data-validation-schemas/SKILL.md +28 -23
  154. package/.agent/skills/database-design/SKILL.md +2 -1
  155. package/.agent/skills/delight/SKILL.md +6 -0
  156. package/.agent/skills/deployment-procedures/SKILL.md +2 -1
  157. package/.agent/skills/design-lab/SKILL.md +5 -0
  158. package/.agent/skills/devops-engineer/SKILL.md +3 -2
  159. package/.agent/skills/devops-incident-responder/SKILL.md +2 -1
  160. package/.agent/skills/diagnosing-bugs/SKILL.md +12 -2
  161. package/.agent/skills/distill/SKILL.md +7 -2
  162. package/.agent/skills/documentation-templates/SKILL.md +3 -2
  163. package/.agent/skills/domain-modeling/SKILL.md +12 -4
  164. package/.agent/skills/duckdb-analytical-sql/SKILL.md +7 -3
  165. package/.agent/skills/edge-ai-mobile/SKILL.md +5 -1
  166. package/.agent/skills/edge-computing/SKILL.md +9 -8
  167. package/.agent/skills/emil-design-eng/SKILL.md +43 -27
  168. package/.agent/skills/error-resilience/SKILL.md +34 -16
  169. package/.agent/skills/expo-router-v4/SKILL.md +2 -1
  170. package/.agent/skills/extract-design-system/SKILL.md +12 -11
  171. package/.agent/skills/fabel-protocol/SKILL.md +24 -17
  172. package/.agent/skills/fixing-accessibility/SKILL.md +23 -16
  173. package/.agent/skills/fixing-metadata/SKILL.md +24 -13
  174. package/.agent/skills/fixing-motion-performance/SKILL.md +7 -5
  175. package/.agent/skills/framer-motion-expert/SKILL.md +29 -15
  176. package/.agent/skills/frontend-design/SKILL.md +21 -13
  177. package/.agent/skills/frontend-security-expert/SKILL.md +1 -0
  178. package/.agent/skills/game-design-expert/SKILL.md +1 -0
  179. package/.agent/skills/game-engineering-expert/SKILL.md +1 -0
  180. package/.agent/skills/generative-ui-expert/SKILL.md +3 -2
  181. package/.agent/skills/geo-fundamentals/SKILL.md +2 -1
  182. package/.agent/skills/git-pro/SKILL.md +10 -9
  183. package/.agent/skills/github-operations/SKILL.md +2 -1
  184. package/.agent/skills/gpt-taste/SKILL.md +7 -0
  185. package/.agent/skills/gsap-core/SKILL.md +26 -22
  186. package/.agent/skills/gsap-frameworks/SKILL.md +6 -5
  187. package/.agent/skills/gsap-performance/SKILL.md +4 -3
  188. package/.agent/skills/gsap-plugins/SKILL.md +34 -33
  189. package/.agent/skills/gsap-react/SKILL.md +9 -8
  190. package/.agent/skills/gsap-scrolltrigger/SKILL.md +34 -33
  191. package/.agent/skills/gsap-timeline/SKILL.md +18 -15
  192. package/.agent/skills/gsap-utils/SKILL.md +25 -24
  193. package/.agent/skills/harden/SKILL.md +9 -3
  194. package/.agent/skills/harness-protocol/SKILL.md +1 -0
  195. package/.agent/skills/i18n-localization/SKILL.md +10 -9
  196. package/.agent/skills/impeccable/SKILL.md +5 -0
  197. package/.agent/skills/improve-codebase-architecture/SKILL.md +10 -5
  198. package/.agent/skills/improve-ui/SKILL.md +12 -5
  199. package/.agent/skills/intelligent-routing/SKILL.md +7 -6
  200. package/.agent/skills/knowledge-graph/SKILL.md +1 -0
  201. package/.agent/skills/landing-page/SKILL.md +1 -0
  202. package/.agent/skills/lint-and-validate/SKILL.md +9 -4
  203. package/.agent/skills/llm-engineering/SKILL.md +55 -54
  204. package/.agent/skills/local-first/SKILL.md +20 -19
  205. package/.agent/skills/local-first-architecture/SKILL.md +6 -1
  206. package/.agent/skills/lottie-animation/SKILL.md +7 -3
  207. package/.agent/skills/marquee-loop/SKILL.md +1 -0
  208. package/.agent/skills/masked-reveal/SKILL.md +17 -4
  209. package/.agent/skills/mcp-builder/SKILL.md +13 -10
  210. package/.agent/skills/micro-interaction/SKILL.md +20 -5
  211. package/.agent/skills/mobile-design/SKILL.md +26 -15
  212. package/.agent/skills/monorepo-management/SKILL.md +3 -2
  213. package/.agent/skills/morphing-icons/SKILL.md +16 -6
  214. package/.agent/skills/motion-engineering/SKILL.md +19 -15
  215. package/.agent/skills/nextjs-react-expert/SKILL.md +26 -21
  216. package/.agent/skills/nodejs-best-practices/SKILL.md +89 -76
  217. package/.agent/skills/observability/SKILL.md +45 -44
  218. package/.agent/skills/opentelemetry-observability/SKILL.md +2 -1
  219. package/.agent/skills/page-transition-animation/SKILL.md +6 -3
  220. package/.agent/skills/parallel-agents/SKILL.md +7 -2
  221. package/.agent/skills/performance-profiling/SKILL.md +24 -13
  222. package/.agent/skills/plan-writing/SKILL.md +1 -0
  223. package/.agent/skills/platform-engineer/SKILL.md +3 -2
  224. package/.agent/skills/platform-engineering-opentofu/SKILL.md +1 -0
  225. package/.agent/skills/playwright-ai-e2e/SKILL.md +3 -2
  226. package/.agent/skills/playwright-best-practices/SKILL.md +29 -28
  227. package/.agent/skills/polish/SKILL.md +13 -12
  228. package/.agent/skills/powershell-windows/SKILL.md +1 -0
  229. package/.agent/skills/pricing-page/SKILL.md +8 -3
  230. package/.agent/skills/product-aware-heuristics/SKILL.md +122 -72
  231. package/.agent/skills/progressive-blur/SKILL.md +9 -4
  232. package/.agent/skills/project-idioms/SKILL.md +1 -0
  233. package/.agent/skills/property-based-testing/SKILL.md +10 -12
  234. package/.agent/skills/python-patterns/SKILL.md +1 -0
  235. package/.agent/skills/python-pro/SKILL.md +1 -0
  236. package/.agent/skills/quieter/SKILL.md +6 -0
  237. package/.agent/skills/react-doctor/SKILL.md +6 -0
  238. package/.agent/skills/react-specialist/SKILL.md +32 -28
  239. package/.agent/skills/readme-builder/SKILL.md +1 -0
  240. package/.agent/skills/realtime-patterns/SKILL.md +34 -33
  241. package/.agent/skills/red-team-tactics/SKILL.md +1 -0
  242. package/.agent/skills/redesign-skill/SKILL.md +6 -0
  243. package/.agent/skills/review-animations/SKILL.md +5 -2
  244. package/.agent/skills/review-animations/STANDARDS.md +37 -23
  245. package/.agent/skills/rust-pro/SKILL.md +1 -0
  246. package/.agent/skills/seo-fundamentals/SKILL.md +4 -3
  247. package/.agent/skills/server-management/SKILL.md +1 -0
  248. package/.agent/skills/shadcn-ui-expert/SKILL.md +28 -22
  249. package/.agent/skills/shape/SKILL.md +9 -2
  250. package/.agent/skills/skill-creator/SKILL.md +1 -0
  251. package/.agent/skills/soft-skill/SKILL.md +6 -0
  252. package/.agent/skills/sounds-on-the-web/SKILL.md +1 -0
  253. package/.agent/skills/sql-pro/SKILL.md +1 -0
  254. package/.agent/skills/supabase-postgres-best-practices/SKILL.md +1 -0
  255. package/.agent/skills/svg-animation/SKILL.md +16 -7
  256. package/.agent/skills/swiftui-expert/SKILL.md +1 -0
  257. package/.agent/skills/swiss-design/SKILL.md +5 -0
  258. package/.agent/skills/system-design-pro/SKILL.md +1 -0
  259. package/.agent/skills/systematic-debugging/SKILL.md +1 -0
  260. package/.agent/skills/tailwind-patterns/SKILL.md +25 -11
  261. package/.agent/skills/taste-skill/SKILL.md +6 -0
  262. package/.agent/skills/tdd-workflow/SKILL.md +5 -0
  263. package/.agent/skills/test-result-analyzer/SKILL.md +1 -0
  264. package/.agent/skills/testing-patterns/SKILL.md +123 -115
  265. package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +5 -0
  266. package/.agent/skills/thinking-protocol/SKILL.md +3 -0
  267. package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +9 -8
  268. package/.agent/skills/transitions-dev/SKILL.md +19 -6
  269. package/.agent/skills/trend-researcher/SKILL.md +1 -0
  270. package/.agent/skills/typescript-advanced/SKILL.md +23 -18
  271. package/.agent/skills/typeset/SKILL.md +10 -1
  272. package/.agent/skills/ui-reasoning-engine/SKILL.md +67 -48
  273. package/.agent/skills/ui-skill-packs/SKILL.md +6 -1
  274. package/.agent/skills/ui-skills-root/SKILL.md +39 -38
  275. package/.agent/skills/ui-ux-pro-max/SKILL.md +34 -26
  276. package/.agent/skills/ui-ux-researcher/SKILL.md +1 -0
  277. package/.agent/skills/vector-search-pgvector/SKILL.md +3 -2
  278. package/.agent/skills/vue-expert/SKILL.md +22 -19
  279. package/.agent/skills/vulnerability-scanner/SKILL.md +22 -21
  280. package/.agent/skills/web-accessibility-auditor/SKILL.md +2 -1
  281. package/.agent/skills/web-design-guidelines/SKILL.md +16 -10
  282. package/.agent/skills/web-quality-audit/SKILL.md +5 -0
  283. package/.agent/skills/webapp-testing/SKILL.md +14 -13
  284. package/.agent/skills/webgpu-performance/SKILL.md +1 -0
  285. package/.agent/skills/whimsy-injector/SKILL.md +9 -5
  286. package/.agent/skills/workflow-optimizer/SKILL.md +1 -0
  287. package/.agent/skills/zero-trust-passkeys/SKILL.md +11 -6
  288. package/.agent/templates/DESIGN.md +119 -110
  289. package/.agent/templates/design-tokens.json +9 -6
  290. package/.agent/workflows/acf.md +1 -0
  291. package/.agent/workflows/api-tester.md +1 -0
  292. package/.agent/workflows/audit.md +1 -0
  293. package/.agent/workflows/brainstorm.md +1 -0
  294. package/.agent/workflows/changelog.md +1 -0
  295. package/.agent/workflows/contract.md +60 -0
  296. package/.agent/workflows/create.md +1 -0
  297. package/.agent/workflows/debug.md +1 -0
  298. package/.agent/workflows/deploy.md +1 -0
  299. package/.agent/workflows/enhance.md +1 -0
  300. package/.agent/workflows/fix-ci.md +89 -0
  301. package/.agent/workflows/fix.md +1 -0
  302. package/.agent/workflows/generate.md +1 -0
  303. package/.agent/workflows/marathon.md +1 -0
  304. package/.agent/workflows/migrate.md +1 -0
  305. package/.agent/workflows/minimal.md +9 -7
  306. package/.agent/workflows/orchestrate.md +1 -0
  307. package/.agent/workflows/performance-benchmarker.md +1 -0
  308. package/.agent/workflows/pipeline.md +26 -21
  309. package/.agent/workflows/plan.md +1 -0
  310. package/.agent/workflows/preview.md +1 -0
  311. package/.agent/workflows/refactor.md +3 -2
  312. package/.agent/workflows/review-ai.md +4 -3
  313. package/.agent/workflows/review.md +1 -0
  314. package/.agent/workflows/session.md +1 -0
  315. package/.agent/workflows/status.md +1 -0
  316. package/.agent/workflows/strengthen-skills.md +1 -0
  317. package/.agent/workflows/super-prompt.md +1 -0
  318. package/.agent/workflows/swarm.md +15 -3
  319. package/.agent/workflows/test.md +8 -7
  320. package/.agent/workflows/tribunal-backend.md +3 -2
  321. package/.agent/workflows/tribunal-cicd.md +104 -0
  322. package/.agent/workflows/tribunal-database.md +1 -0
  323. package/.agent/workflows/tribunal-frontend.md +8 -6
  324. package/.agent/workflows/tribunal-full.md +2 -1
  325. package/.agent/workflows/tribunal-mobile.md +6 -5
  326. package/.agent/workflows/tribunal-performance.md +1 -0
  327. package/.agent/workflows/tribunal-speed.md +1 -0
  328. package/.agent/workflows/tribunal-ui.md +29 -21
  329. package/.agent/workflows/ui-ux-pro-max.md +19 -15
  330. package/CONTRIBUTING.md +3 -3
  331. package/README.md +94 -44
  332. package/SECURITY.md +10 -10
  333. package/bin/mcp-server.js +385 -252
  334. package/bin/tribunal-kit.js +29 -30
  335. package/bin/wrapper.js +40 -46
  336. package/dist/cli.js +6 -0
  337. package/dist/commands/case.js +2 -0
  338. package/dist/commands/contract.js +440 -0
  339. package/dist/commands/status.js +6 -0
  340. package/dist/index.d.ts +8 -1
  341. package/package.json +13 -12
  342. package/scripts/benchmark.js +62 -86
  343. package/scripts/changelog.js +67 -73
  344. package/scripts/fix-vbc.js +13 -15
  345. package/scripts/fix-vbc.ps1 +2 -118
  346. package/scripts/stress_benchmark.js +358 -0
  347. package/scripts/sync-version.js +71 -41
  348. package/scripts/validate-payload.js +23 -30
  349. package/scripts/visual_audit.js +23 -13
package/bin/mcp-server.js CHANGED
@@ -13,16 +13,24 @@
13
13
  * Protocol: MCP 2024-11-05 over JSON-RPC 2.0 / stdio
14
14
  */
15
15
 
16
- const path = require("path");
17
- const { spawnSync } = require("child_process");
16
+ const path = require('path');
17
+ const { spawnSync } = require('child_process');
18
18
 
19
- const PKG = require(path.resolve(__dirname, "../package.json"));
19
+ const PKG = require(path.resolve(__dirname, '../package.json'));
20
20
 
21
21
  // Timeout for intentionally isolated child processes (30 seconds).
22
22
  const SPAWN_TIMEOUT_MS = 30000;
23
23
 
24
+ class RpcError extends Error {
25
+ constructor(code, message) {
26
+ super(message);
27
+ this.code = code;
28
+ this.name = 'RpcError';
29
+ }
30
+ }
31
+
24
32
  // Minimal JSON-RPC 2.0 over stdio
25
- const readline = require("readline");
33
+ const readline = require('readline');
26
34
 
27
35
  const rl = readline.createInterface({
28
36
  input: process.stdin,
@@ -36,17 +44,12 @@ const rl = readline.createInterface({
36
44
  * explicitly supplied payload and schema.
37
45
  */
38
46
  function runTribunalAudit() {
39
- const fs = require("fs");
47
+ const fs = require('fs');
40
48
  const projectRoot = process.cwd();
41
- const manifestScript = path.join(
42
- projectRoot,
43
- ".agent",
44
- "scripts",
45
- "integrity_manifest.js",
46
- );
49
+ const manifestScript = path.join(projectRoot, '.agent', 'scripts', 'integrity_manifest.js');
47
50
 
48
51
  if (!fs.existsSync(manifestScript)) {
49
- return "Error: .agent/scripts/integrity_manifest.js was not found. Run `tk init` first.";
52
+ return 'Error: .agent/scripts/integrity_manifest.js was not found. Run `tk init` first.';
50
53
  }
51
54
 
52
55
  try {
@@ -56,7 +59,7 @@ function runTribunalAudit() {
56
59
 
57
60
  const { integrity } = manifest;
58
61
  const lines = [
59
- "Tribunal audit complete.",
62
+ 'Tribunal audit complete.',
60
63
  `Agents: ${manifest.agents.total} (${manifest.agents.reviewer_count} reviewers)`,
61
64
  `Skills: ${manifest.skills.total}`,
62
65
  `Scripts: ${manifest.scripts.total}`,
@@ -66,11 +69,13 @@ function runTribunalAudit() {
66
69
  ];
67
70
 
68
71
  if (integrity.phantom_references > 0 || integrity.invalid_claims > 0) {
69
- lines.push("Audit found integrity issues; run `tk guardrail --scan` for remediation details.");
72
+ lines.push(
73
+ 'Audit found integrity issues; run `tk guardrail --scan` for remediation details.',
74
+ );
70
75
  } else {
71
- lines.push("All discovered references and global asset-count claims are valid.");
76
+ lines.push('All discovered references and global asset-count claims are valid.');
72
77
  }
73
- return lines.join("\n");
78
+ return lines.join('\n');
74
79
  } catch (error) {
75
80
  return `Audit failed: ${error.message}`;
76
81
  }
@@ -80,100 +85,96 @@ function runTribunalAudit() {
80
85
  * Search case law in an isolated process because its CLI owns persistent state.
81
86
  */
82
87
  function searchCaseLaw(query) {
83
- const caseLawScript = path.resolve(
84
- __dirname,
85
- "../.agent/scripts/case_law_manager.js",
86
- );
88
+ const caseLawScript = path.resolve(__dirname, '../.agent/scripts/case_law_manager.js');
87
89
  // case_law_manager is a standalone stateful CLI, so retain its process boundary.
88
- const result = spawnSync(
89
- process.execPath,
90
- [caseLawScript, "search-cases", "--query", query],
91
- {
92
- encoding: "utf8",
93
- timeout: SPAWN_TIMEOUT_MS,
94
- },
95
- );
90
+ const result = spawnSync(process.execPath, [caseLawScript, 'search-cases', '--query', query], {
91
+ encoding: 'utf8',
92
+ timeout: SPAWN_TIMEOUT_MS,
93
+ });
96
94
  if (result.error) {
97
- if (result.error.code === "ETIMEDOUT") return "Error: Case law search timed out (exceeded 30s limit)";
95
+ if (result.error.code === 'ETIMEDOUT')
96
+ return 'Error: Case law search timed out (exceeded 30s limit)';
98
97
  return `Error executing case law search: ${result.error.message}`;
99
98
  }
100
- return result.stdout || result.stderr || "No results";
99
+ return result.stdout || result.stderr || 'No results';
101
100
  }
102
101
 
103
-
104
102
  function stripBoilerplate(text) {
105
103
  if (!text) return text;
106
- let minified = text.replace(/AI coding assistants often fall into specific bad habits[\s\S]*$/g, "");
107
- minified = minified.replace(/## 🤖 LLM-Specific Traps[\s\S]*$/g, "");
108
- minified = minified.replace(/## 🏛️ Tribunal Integration[\s\S]*$/g, "");
109
- minified = minified.replace(/## Pre-Flight Checklist[\s\S]*$/g, "");
104
+ let minified = text.replace(
105
+ /AI coding assistants often fall into specific bad habits[\s\S]*$/g,
106
+ '',
107
+ );
108
+ minified = minified.replace(/## 🤖 LLM-Specific Traps[\s\S]*$/g, '');
109
+ minified = minified.replace(/## 🏛️ Tribunal Integration[\s\S]*$/g, '');
110
+ minified = minified.replace(/## Pre-Flight Checklist[\s\S]*$/g, '');
110
111
  return minified.trim();
111
112
  }
112
113
 
113
114
  function getAgentDir() {
114
- const fs = require("fs");
115
- const local = path.join(process.cwd(), ".agent");
115
+ const fs = require('fs');
116
+ const local = path.join(process.cwd(), '.agent');
116
117
  if (fs.existsSync(local)) return local;
117
- return path.resolve(__dirname, "../.agent");
118
+ return path.resolve(__dirname, '../.agent');
118
119
  }
119
120
 
120
121
  function handleRequest(req) {
121
- const fs = require("fs");
122
- if (req.method === "notifications/initialized" || req.method === "notifications/cancelled") {
122
+ const fs = require('fs');
123
+ if (req.method === 'notifications/initialized' || req.method === 'notifications/cancelled') {
123
124
  return null;
124
125
  }
125
- if (req.method === "ping") {
126
+ if (req.method === 'ping') {
126
127
  return {};
127
128
  }
128
129
 
129
130
  // MCP spec: method names follow path-style convention
130
- if (req.method === "initialize") {
131
+ if (req.method === 'initialize') {
131
132
  return {
132
- protocolVersion: "2025-03-26",
133
+ protocolVersion: '2025-03-26',
133
134
  capabilities: {
134
135
  tools: {},
135
136
  resources: { subscribe: false, listChanged: false },
136
137
  prompts: { listChanged: false },
137
138
  },
138
139
  serverInfo: {
139
- name: "tribunal-kit-mcp",
140
+ name: 'tribunal-kit-mcp',
140
141
  version: PKG.version,
141
142
  },
142
143
  };
143
144
  }
144
145
 
145
- if (req.method === "resources/list") {
146
+ if (req.method === 'resources/list') {
146
147
  const agentDir = getAgentDir();
147
148
  const resources = [];
148
-
149
+
149
150
  // Agents
150
- const agentsDir = path.join(agentDir, "agents");
151
+ const agentsDir = path.join(agentDir, 'agents');
151
152
  if (fs.existsSync(agentsDir)) {
152
- const files = fs.readdirSync(agentsDir).filter((f) => f.endsWith(".md"));
153
+ const files = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
153
154
  for (const f of files) {
154
- const name = path.basename(f, ".md");
155
+ const name = path.basename(f, '.md');
155
156
  resources.push({
156
157
  uri: `tribunal://agent/${name}`,
157
158
  name: `Agent: ${name}`,
158
159
  description: `Tribunal Specialist Agent rule file for ${name}`,
159
- mimeType: "text/markdown",
160
+ mimeType: 'text/markdown',
160
161
  });
161
162
  }
162
163
  }
163
164
 
164
165
  // Skills
165
- const skillsDir = path.join(agentDir, "skills");
166
+ const skillsDir = path.join(agentDir, 'skills');
166
167
  if (fs.existsSync(skillsDir)) {
167
168
  const dirs = fs.readdirSync(skillsDir, { withFileTypes: true });
168
169
  for (const d of dirs) {
169
170
  if (d.isDirectory()) {
170
- const skillFile = path.join(skillsDir, d.name, "SKILL.md");
171
+ const skillFile = path.join(skillsDir, d.name, 'SKILL.md');
171
172
  if (fs.existsSync(skillFile)) {
172
173
  resources.push({
173
174
  uri: `tribunal://skill/${d.name}`,
174
175
  name: `Skill: ${d.name}`,
175
176
  description: `Tribunal Skill instruction file for ${d.name}`,
176
- mimeType: "text/markdown",
177
+ mimeType: 'text/markdown',
177
178
  });
178
179
  }
179
180
  }
@@ -181,16 +182,16 @@ function handleRequest(req) {
181
182
  }
182
183
 
183
184
  // Workflows
184
- const workflowsDir = path.join(agentDir, "workflows");
185
+ const workflowsDir = path.join(agentDir, 'workflows');
185
186
  if (fs.existsSync(workflowsDir)) {
186
- const files = fs.readdirSync(workflowsDir).filter((f) => f.endsWith(".md"));
187
+ const files = fs.readdirSync(workflowsDir).filter(f => f.endsWith('.md'));
187
188
  for (const f of files) {
188
- const name = path.basename(f, ".md");
189
+ const name = path.basename(f, '.md');
189
190
  resources.push({
190
191
  uri: `tribunal://workflow/${name}`,
191
192
  name: `Workflow: ${name}`,
192
193
  description: `Tribunal Workflow guide for ${name}`,
193
- mimeType: "text/markdown",
194
+ mimeType: 'text/markdown',
194
195
  });
195
196
  }
196
197
  }
@@ -198,55 +199,55 @@ function handleRequest(req) {
198
199
  return { resources };
199
200
  }
200
201
 
201
- if (req.method === "resources/read") {
202
+ if (req.method === 'resources/read') {
202
203
  const uri = req.params && req.params.uri;
203
- if (!uri) throw new Error("Missing uri parameter");
204
+ if (!uri) throw new Error('Missing uri parameter');
204
205
  const agentDir = getAgentDir();
205
206
  let filePath = null;
206
207
 
207
- if (uri.startsWith("tribunal://agent/")) {
208
- const name = uri.replace("tribunal://agent/", "");
209
- filePath = path.join(agentDir, "agents", `${name}.md`);
210
- } else if (uri.startsWith("tribunal://skill/")) {
211
- const name = uri.replace("tribunal://skill/", "");
212
- filePath = path.join(agentDir, "skills", name, "SKILL.md");
213
- } else if (uri.startsWith("tribunal://workflow/")) {
214
- const name = uri.replace("tribunal://workflow/", "");
215
- filePath = path.join(agentDir, "workflows", `${name}.md`);
208
+ if (uri.startsWith('tribunal://agent/')) {
209
+ const name = uri.replace('tribunal://agent/', '');
210
+ filePath = path.join(agentDir, 'agents', `${name}.md`);
211
+ } else if (uri.startsWith('tribunal://skill/')) {
212
+ const name = uri.replace('tribunal://skill/', '');
213
+ filePath = path.join(agentDir, 'skills', name, 'SKILL.md');
214
+ } else if (uri.startsWith('tribunal://workflow/')) {
215
+ const name = uri.replace('tribunal://workflow/', '');
216
+ filePath = path.join(agentDir, 'workflows', `${name}.md`);
216
217
  }
217
218
 
218
219
  if (!filePath || !fs.existsSync(filePath)) {
219
220
  throw new Error(`Resource not found: ${uri}`);
220
221
  }
221
222
 
222
- const text = fs.readFileSync(filePath, "utf8");
223
+ const text = fs.readFileSync(filePath, 'utf8');
223
224
  return {
224
225
  contents: [
225
226
  {
226
227
  uri,
227
- mimeType: "text/markdown",
228
+ mimeType: 'text/markdown',
228
229
  text,
229
230
  },
230
231
  ],
231
232
  };
232
233
  }
233
234
 
234
- if (req.method === "prompts/list") {
235
+ if (req.method === 'prompts/list') {
235
236
  const agentDir = getAgentDir();
236
237
  const prompts = [];
237
- const workflowsDir = path.join(agentDir, "workflows");
238
+ const workflowsDir = path.join(agentDir, 'workflows');
238
239
 
239
240
  if (fs.existsSync(workflowsDir)) {
240
- const files = fs.readdirSync(workflowsDir).filter((f) => f.endsWith(".md"));
241
+ const files = fs.readdirSync(workflowsDir).filter(f => f.endsWith('.md'));
241
242
  for (const f of files) {
242
- const name = path.basename(f, ".md");
243
+ const name = path.basename(f, '.md');
243
244
  prompts.push({
244
245
  name,
245
246
  description: `Execute tribunal workflow /${name}`,
246
247
  arguments: [
247
248
  {
248
- name: "task",
249
- description: "The task or target file to execute the workflow against",
249
+ name: 'task',
250
+ description: 'The task or target file to execute the workflow against',
250
251
  required: false,
251
252
  },
252
253
  ],
@@ -257,26 +258,26 @@ function handleRequest(req) {
257
258
  return { prompts };
258
259
  }
259
260
 
260
- if (req.method === "prompts/get") {
261
+ if (req.method === 'prompts/get') {
261
262
  const name = req.params && req.params.name;
262
- const task = (req.params && req.params.arguments && req.params.arguments.task) || "";
263
- if (!name) throw new Error("Missing prompt name parameter");
263
+ const task = (req.params && req.params.arguments && req.params.arguments.task) || '';
264
+ if (!name) throw new Error('Missing prompt name parameter');
264
265
 
265
266
  const agentDir = getAgentDir();
266
- const workflowPath = path.join(agentDir, "workflows", `${name}.md`);
267
+ const workflowPath = path.join(agentDir, 'workflows', `${name}.md`);
267
268
  if (!fs.existsSync(workflowPath)) {
268
269
  throw new Error(`Prompt workflow not found: ${name}`);
269
270
  }
270
271
 
271
- const content = fs.readFileSync(workflowPath, "utf8");
272
+ const content = fs.readFileSync(workflowPath, 'utf8');
272
273
  const promptText = task ? `${content}\n\nTarget Task/File: ${task}` : content;
273
274
 
274
275
  return {
275
276
  messages: [
276
277
  {
277
- role: "user",
278
+ role: 'user',
278
279
  content: {
279
- type: "text",
280
+ type: 'text',
280
281
  text: promptText,
281
282
  },
282
283
  },
@@ -284,168 +285,193 @@ function handleRequest(req) {
284
285
  };
285
286
  }
286
287
 
287
- if (req.method === "tools/list") {
288
+ if (req.method === 'tools/list') {
288
289
  return {
289
290
  tools: [
290
291
  {
291
- name: "run_tribunal_audit",
292
- description:
293
- "Runs a full anti-hallucination audit across the workspace.",
292
+ name: 'run_tribunal_audit',
293
+ description: 'Runs a full anti-hallucination audit across the workspace.',
294
294
  inputSchema: {
295
- type: "object",
295
+ type: 'object',
296
296
  properties: {},
297
297
  additionalProperties: false,
298
298
  },
299
299
  },
300
300
  {
301
- name: "sync_ide_bridges",
302
- description:
303
- "Synchronize IDE bridge files with the current GEMINI.md rules.",
301
+ name: 'sync_ide_bridges',
302
+ description: 'Synchronize IDE bridge files with the current GEMINI.md rules.',
304
303
  inputSchema: {
305
- type: "object",
304
+ type: 'object',
306
305
  properties: {},
307
306
  additionalProperties: false,
308
307
  },
309
308
  },
310
309
  {
311
- name: "search_case_law",
310
+ name: 'search_case_law',
312
311
  description:
313
- "Search historical code rejections and legal precedent. Use this before writing code to avoid past mistakes.",
312
+ 'Search historical code rejections and legal precedent. Use this before writing code to avoid past mistakes.',
314
313
  inputSchema: {
315
- type: "object",
314
+ type: 'object',
316
315
  properties: {
317
316
  query: {
318
- type: "string",
317
+ type: 'string',
319
318
  description: "Search query (e.g. 'useEffect state')",
320
319
  },
321
320
  },
322
- required: ["query"],
321
+ required: ['query'],
323
322
  additionalProperties: false,
324
323
  },
325
324
  },
326
325
  {
327
- name: "list_tribunal_agents",
328
- description: "List all available Tribunal Kit agents.",
326
+ name: 'list_tribunal_agents',
327
+ description: 'List all available Tribunal Kit agents.',
329
328
  inputSchema: {
330
- type: "object",
329
+ type: 'object',
331
330
  properties: {},
332
331
  additionalProperties: false,
333
332
  },
334
333
  },
335
334
  {
336
- name: "get_tribunal_agent",
337
- description: "Get the full markdown rules for a specific Tribunal agent.",
335
+ name: 'get_tribunal_agent',
336
+ description: 'Get the full markdown rules for a specific Tribunal agent.',
338
337
  inputSchema: {
339
- type: "object",
338
+ type: 'object',
340
339
  properties: {
341
- name: { type: "string", description: "The agent name (e.g. 'frontend-specialist')" },
340
+ name: { type: 'string', description: "The agent name (e.g. 'frontend-specialist')" },
342
341
  },
343
- required: ["name"],
342
+ required: ['name'],
344
343
  additionalProperties: false,
345
344
  },
346
345
  },
347
346
  {
348
- name: "list_tribunal_skills",
349
- description: "List all available Tribunal Kit skills.",
347
+ name: 'list_tribunal_skills',
348
+ description: 'List all available Tribunal Kit skills.',
350
349
  inputSchema: {
351
- type: "object",
350
+ type: 'object',
352
351
  properties: {},
353
352
  additionalProperties: false,
354
353
  },
355
354
  },
356
355
  {
357
- name: "get_tribunal_skill",
358
- description: "Get the full markdown instructions for a specific Tribunal skill.",
356
+ name: 'get_tribunal_skill',
357
+ description: 'Get the full markdown instructions for a specific Tribunal skill.',
359
358
  inputSchema: {
360
- type: "object",
359
+ type: 'object',
361
360
  properties: {
362
- name: { type: "string", description: "The skill name (e.g. 'react-specialist')" },
361
+ name: { type: 'string', description: "The skill name (e.g. 'react-specialist')" },
363
362
  },
364
- required: ["name"],
363
+ required: ['name'],
365
364
  additionalProperties: false,
366
365
  },
367
366
  },
368
367
  {
369
- name: "recall_memory",
370
- description: "Budget-constrained memory recall from the 4-Type Taxonomy Persistent Memory Engine. Returns the most relevant memories that fit within the token budget, ranked by relevance × recency × priority. Use this BEFORE writing code to recall project guidelines without bloating context.",
368
+ name: 'recall_memory',
369
+ description:
370
+ 'Budget-constrained memory recall from the 4-Type Taxonomy Persistent Memory Engine. Returns the most relevant memories that fit within the token budget, ranked by relevance × recency × priority. Use this BEFORE writing code to recall project guidelines without bloating context.',
371
371
  inputSchema: {
372
- type: "object",
372
+ type: 'object',
373
373
  properties: {
374
374
  query: {
375
- type: "string",
375
+ type: 'string',
376
376
  description: "Search query (e.g. 'database', 'auth', 'deploy')",
377
377
  },
378
378
  budget: {
379
- type: "number",
380
- description: "Maximum token budget for recall (default: 2000). Only the top-ranked memories that fit within this budget are returned.",
379
+ type: 'number',
380
+ description:
381
+ 'Maximum token budget for recall (default: 2000). Only the top-ranked memories that fit within this budget are returned.',
381
382
  },
382
383
  },
383
- required: ["query"],
384
+ required: ['query'],
384
385
  additionalProperties: false,
385
386
  },
386
387
  },
387
388
  {
388
- name: "store_memory",
389
- description: "Store a new memory entry in the 4-Type Taxonomy Persistent Memory Engine. Memories are schema-validated and persisted across sessions. Types: semantic (permanent facts), procedural (how-to recipes), episodic (30-day TTL events), working (session scratch).",
389
+ name: 'store_memory',
390
+ description:
391
+ 'Store a new memory entry in the 4-Type Taxonomy Persistent Memory Engine. Memories are schema-validated and persisted across sessions. Types: semantic (permanent facts), procedural (how-to recipes), episodic (30-day TTL events), working (session scratch).',
390
392
  inputSchema: {
391
- type: "object",
393
+ type: 'object',
392
394
  properties: {
393
395
  type: {
394
- type: "string",
395
- enum: ["semantic", "procedural", "episodic", "working"],
396
- description: "Memory type: semantic (facts), procedural (recipes), episodic (events), working (scratch)",
396
+ type: 'string',
397
+ enum: ['semantic', 'procedural', 'episodic', 'working'],
398
+ description:
399
+ 'Memory type: semantic (facts), procedural (recipes), episodic (events), working (scratch)',
397
400
  },
398
401
  content: {
399
- type: "string",
400
- description: "The memory content to store",
402
+ type: 'string',
403
+ description: 'The memory content to store',
401
404
  },
402
405
  tags: {
403
- type: "array",
404
- items: { type: "string" },
405
- description: "Searchable tags for this memory",
406
+ type: 'array',
407
+ items: { type: 'string' },
408
+ description: 'Searchable tags for this memory',
406
409
  },
407
410
  },
408
- required: ["type", "content"],
411
+ required: ['type', 'content'],
409
412
  additionalProperties: false,
410
413
  },
411
414
  },
412
415
  {
413
- name: "get_sparse_context",
414
- description: "Get a JIT, token-optimized context prompt tailored to the active task and files. Uses the Context Density Broker to score and select relevant skills, stripping duplicate boilerplate and saving up to 85% in prompt tokens.",
416
+ name: 'get_sparse_context',
417
+ description:
418
+ 'Get a JIT, token-optimized context prompt tailored to the active task and files. Uses the Context Density Broker to score and select relevant skills, stripping duplicate boilerplate and saving up to 85% in prompt tokens.',
415
419
  inputSchema: {
416
- type: "object",
420
+ type: 'object',
417
421
  properties: {
418
422
  task: {
419
- type: "string",
423
+ type: 'string',
420
424
  description: "The user task description (e.g. 'JWT auth API')",
421
425
  },
422
426
  files: {
423
- type: "array",
424
- items: { type: "string" },
427
+ type: 'array',
428
+ items: { type: 'string' },
425
429
  description: "List of files being touched (e.g. ['src/auth.js'])",
426
430
  },
427
431
  model: {
428
- type: "string",
429
- enum: ["large", "small"],
430
- description: "Model tier: large (default, includes key rules of supplementary skills) or small (essential skills only)",
432
+ type: 'string',
433
+ enum: ['large', 'small'],
434
+ description:
435
+ 'Model tier: large (default, includes key rules of supplementary skills) or small (essential skills only)',
431
436
  },
432
437
  },
433
- required: ["task"],
438
+ required: ['task'],
434
439
  additionalProperties: false,
435
440
  },
436
441
  },
437
442
  {
438
- name: "align_output",
439
- description: "Align model outputs to Fabel-5 constraints: strips conversational introductions and conclusions, collapses single/double bullet items to prose, and checks for code traps (unawaited dynamic functions in Next.js 15, deprecated hooks in React 19, or non-existent models).",
443
+ name: 'align_output',
444
+ description:
445
+ 'Align model outputs to Fabel-5 constraints: strips conversational introductions and conclusions, collapses single/double bullet items to prose, and checks for code traps (unawaited dynamic functions in Next.js 15, deprecated hooks in React 19, or non-existent models).',
440
446
  inputSchema: {
441
- type: "object",
447
+ type: 'object',
442
448
  properties: {
443
449
  text: {
444
- type: "string",
445
- description: "The raw output text generated by the model to be aligned.",
450
+ type: 'string',
451
+ description: 'The raw output text generated by the model to be aligned.',
446
452
  },
447
453
  },
448
- required: ["text"],
454
+ required: ['text'],
455
+ additionalProperties: false,
456
+ },
457
+ },
458
+ {
459
+ name: 'verify_contracts',
460
+ description:
461
+ 'Verify proposed code changes against project behavioral contracts. Use BEFORE writing code to ensure compliance with team conventions.',
462
+ inputSchema: {
463
+ type: 'object',
464
+ properties: {
465
+ file: {
466
+ type: 'string',
467
+ description: "Relative or absolute file path to verify (e.g. 'src/api/user.ts')",
468
+ },
469
+ content: {
470
+ type: 'string',
471
+ description: 'Proposed file content to verify against loaded contracts',
472
+ },
473
+ },
474
+ required: ['file', 'content'],
449
475
  additionalProperties: false,
450
476
  },
451
477
  },
@@ -453,43 +479,42 @@ function handleRequest(req) {
453
479
  };
454
480
  }
455
481
 
456
- if (req.method === "tools/call") {
482
+ if (req.method === 'tools/call') {
457
483
  const toolName = req.params && req.params.name;
458
484
  if (!toolName) {
459
- throw {
460
- code: -32602,
461
- message: "Missing required parameter: params.name",
462
- };
485
+ throw new RpcError(-32602, 'Missing required parameter: params.name');
463
486
  }
464
487
 
465
- if (toolName === "run_tribunal_audit") {
488
+ if (toolName === 'run_tribunal_audit') {
466
489
  const text = runTribunalAudit();
467
- return { content: [{ type: "text", text }] };
490
+ return { content: [{ type: 'text', text }] };
468
491
  }
469
492
 
470
- if (toolName === "sync_ide_bridges") {
471
- const fs = require("fs");
493
+ if (toolName === 'sync_ide_bridges') {
494
+ const fs = require('fs');
472
495
  const cwd = process.cwd();
473
- const agentDest = path.join(cwd, ".agent");
496
+ const agentDest = path.join(cwd, '.agent');
474
497
  if (!fs.existsSync(agentDest)) {
475
498
  return {
476
499
  content: [
477
500
  {
478
- type: "text",
479
- text: "Error: .agent/ directory not found. Run `tk init` first.",
501
+ type: 'text',
502
+ text: 'Error: .agent/ directory not found. Run `tk init` first.',
480
503
  },
481
504
  ],
482
505
  };
483
506
  }
484
507
  try {
485
- const { generateIDEBridges } = require(path.resolve(__dirname, "../dist/commands/init.js"));
508
+ const { generateIDEBridges } = require(path.resolve(__dirname, '../dist/commands/init.js'));
486
509
  // generateIDEBridges is async — execute synchronously in MCP context
487
- generateIDEBridges(cwd, agentDest, true).then(() => {}).catch(() => {});
510
+ generateIDEBridges(cwd, agentDest, true)
511
+ .then(() => {})
512
+ .catch(() => {});
488
513
  return {
489
514
  content: [
490
515
  {
491
- type: "text",
492
- text: "Sync complete",
516
+ type: 'text',
517
+ text: 'Sync complete',
493
518
  },
494
519
  ],
495
520
  };
@@ -497,7 +522,7 @@ function handleRequest(req) {
497
522
  return {
498
523
  content: [
499
524
  {
500
- type: "text",
525
+ type: 'text',
501
526
  text: `Sync failed: ${e.message}`,
502
527
  },
503
528
  ],
@@ -505,167 +530,274 @@ function handleRequest(req) {
505
530
  }
506
531
  }
507
532
 
508
- if (toolName === "search_case_law") {
509
- const query =
510
- req.params && req.params.arguments && req.params.arguments.query;
511
- if (!query || typeof query !== "string") {
512
- throw {
513
- code: -32602,
514
- message: "Missing or invalid required argument: query (string)",
515
- };
533
+ if (toolName === 'search_case_law') {
534
+ const query = req.params && req.params.arguments && req.params.arguments.query;
535
+ if (!query || typeof query !== 'string') {
536
+ throw new RpcError(-32602, 'Missing or invalid required argument: query (string)');
516
537
  }
517
538
  const text = searchCaseLaw(query);
518
- return { content: [{ type: "text", text }] };
539
+ return { content: [{ type: 'text', text }] };
519
540
  }
520
541
 
521
- if (toolName === "list_tribunal_agents") {
522
- const fs = require("fs");
523
- const agentDir = path.join(getAgentDir(), "agents");
524
- if (!fs.existsSync(agentDir)) return { content: [{ type: "text", text: "No agents found or .agent directory missing." }] };
525
- const agents = fs.readdirSync(agentDir).filter(f => f.endsWith('.md')).map(f => f.replace('.md', ''));
526
- return { content: [{ type: "text", text: "Available Agents:\n- " + agents.join("\n- ") }] };
542
+ if (toolName === 'list_tribunal_agents') {
543
+ const fs = require('fs');
544
+ const agentDir = path.join(getAgentDir(), 'agents');
545
+ if (!fs.existsSync(agentDir))
546
+ return {
547
+ content: [{ type: 'text', text: 'No agents found or .agent directory missing.' }],
548
+ };
549
+ const agents = fs
550
+ .readdirSync(agentDir)
551
+ .filter(f => f.endsWith('.md'))
552
+ .map(f => f.replace('.md', ''));
553
+ return { content: [{ type: 'text', text: 'Available Agents:\n- ' + agents.join('\n- ') }] };
527
554
  }
528
555
 
529
- if (toolName === "get_tribunal_agent") {
530
- const fs = require("fs");
556
+ if (toolName === 'get_tribunal_agent') {
557
+ const fs = require('fs');
531
558
  const name = req.params?.arguments?.name;
532
- if (!name || typeof name !== "string") throw { code: -32602, message: "Missing or invalid argument: name (string)" };
559
+ if (!name || typeof name !== 'string')
560
+ throw new RpcError(-32602, 'Missing or invalid argument: name (string)');
533
561
  const sanitizedName = path.basename(name);
534
- const agentsDir = path.resolve(getAgentDir(), "agents");
562
+ const agentsDir = path.resolve(getAgentDir(), 'agents');
535
563
  const agentPath = path.resolve(agentsDir, `${sanitizedName}.md`);
536
564
  // Path containment: ensure resolved path stays within agents directory
537
- if (!agentPath.startsWith(agentsDir)) throw { code: -32602, message: "Invalid agent name: path traversal detected" };
538
- if (!fs.existsSync(agentPath)) return { content: [{ type: "text", text: `Agent '${sanitizedName}' not found.` }] };
539
- const text = fs.readFileSync(agentPath, "utf8");
540
- return { content: [{ type: "text", text: stripBoilerplate(text) }] };
565
+ if (!agentPath.startsWith(agentsDir))
566
+ throw new RpcError(-32602, 'Invalid agent name: path traversal detected');
567
+ if (!fs.existsSync(agentPath))
568
+ return { content: [{ type: 'text', text: `Agent '${sanitizedName}' not found.` }] };
569
+ const text = fs.readFileSync(agentPath, 'utf8');
570
+ return { content: [{ type: 'text', text: stripBoilerplate(text) }] };
541
571
  }
542
572
 
543
- if (toolName === "list_tribunal_skills") {
544
- const fs = require("fs");
545
- const skillsDir = path.join(getAgentDir(), "skills");
546
- if (!fs.existsSync(skillsDir)) return { content: [{ type: "text", text: "No skills found or .agent directory missing." }] };
547
- const skills = fs.readdirSync(skillsDir, { withFileTypes: true }).filter(d => d.isDirectory()).map(d => d.name);
548
- return { content: [{ type: "text", text: "Available Skills:\n- " + skills.join("\n- ") }] };
573
+ if (toolName === 'list_tribunal_skills') {
574
+ const fs = require('fs');
575
+ const skillsDir = path.join(getAgentDir(), 'skills');
576
+ if (!fs.existsSync(skillsDir))
577
+ return {
578
+ content: [{ type: 'text', text: 'No skills found or .agent directory missing.' }],
579
+ };
580
+ const skills = fs
581
+ .readdirSync(skillsDir, { withFileTypes: true })
582
+ .filter(d => d.isDirectory())
583
+ .map(d => d.name);
584
+ return { content: [{ type: 'text', text: 'Available Skills:\n- ' + skills.join('\n- ') }] };
549
585
  }
550
586
 
551
- if (toolName === "get_tribunal_skill") {
552
- const fs = require("fs");
587
+ if (toolName === 'get_tribunal_skill') {
588
+ const fs = require('fs');
553
589
  const name = req.params?.arguments?.name;
554
- if (!name || typeof name !== "string") throw { code: -32602, message: "Missing or invalid argument: name (string)" };
590
+ if (!name || typeof name !== 'string')
591
+ throw new RpcError(-32602, 'Missing or invalid argument: name (string)');
555
592
  const sanitizedName = path.basename(name);
556
- const skillsDir = path.resolve(getAgentDir(), "skills");
557
- const skillPath = path.resolve(skillsDir, sanitizedName, "SKILL.md");
593
+ const skillsDir = path.resolve(getAgentDir(), 'skills');
594
+ const skillPath = path.resolve(skillsDir, sanitizedName, 'SKILL.md');
558
595
  // Path containment: ensure resolved path stays within skills directory
559
- if (!skillPath.startsWith(skillsDir)) throw { code: -32602, message: "Invalid skill name: path traversal detected" };
560
- if (!fs.existsSync(skillPath)) return { content: [{ type: "text", text: `Skill '${sanitizedName}' not found.` }] };
561
- const text = fs.readFileSync(skillPath, "utf8");
562
- return { content: [{ type: "text", text: stripBoilerplate(text) }] };
596
+ if (!skillPath.startsWith(skillsDir))
597
+ throw new RpcError(-32602, 'Invalid skill name: path traversal detected');
598
+ if (!fs.existsSync(skillPath))
599
+ return { content: [{ type: 'text', text: `Skill '${sanitizedName}' not found.` }] };
600
+ const text = fs.readFileSync(skillPath, 'utf8');
601
+ return { content: [{ type: 'text', text: stripBoilerplate(text) }] };
563
602
  }
564
603
 
565
- if (toolName === "get_sparse_context") {
604
+ if (toolName === 'get_sparse_context') {
566
605
  const task = req.params?.arguments?.task;
567
606
  const files = req.params?.arguments?.files || [];
568
- const model = req.params?.arguments?.model || "large";
607
+ const model = req.params?.arguments?.model || 'large';
569
608
 
570
- if (!task) throw { code: -32602, message: "Missing required argument: task" };
609
+ if (!task) throw new RpcError(-32602, 'Missing required argument: task');
571
610
 
572
611
  const agentDest = getAgentDir();
573
- const fs = require("fs");
612
+ const fs = require('fs');
574
613
  if (!fs.existsSync(agentDest)) {
575
- return { content: [{ type: "text", text: "Error: .agent/ directory not found. Run `tk init` first." }] };
614
+ return {
615
+ content: [
616
+ { type: 'text', text: 'Error: .agent/ directory not found. Run `tk init` first.' },
617
+ ],
618
+ };
576
619
  }
577
620
 
578
621
  try {
579
- const brokerScript = path.join(agentDest, "scripts", "context_broker.js");
622
+ const brokerScript = path.join(agentDest, 'scripts', 'context_broker.js');
580
623
  const { broker } = require(brokerScript);
581
624
  const brokerResult = broker(task, files, model, agentDest);
582
- return { content: [{ type: "text", text: stripBoilerplate(brokerResult.promptText) }] };
625
+ return { content: [{ type: 'text', text: stripBoilerplate(brokerResult.promptText) }] };
583
626
  } catch (e) {
584
- return { content: [{ type: "text", text: `Failed to retrieve sparse context: ${e.message}` }] };
627
+ return {
628
+ content: [{ type: 'text', text: `Failed to retrieve sparse context: ${e.message}` }],
629
+ };
585
630
  }
586
631
  }
587
632
 
588
- if (toolName === "recall_memory") {
633
+ if (toolName === 'recall_memory') {
589
634
  const query = req.params?.arguments?.query;
590
- if (!query || typeof query !== "string") {
591
- throw { code: -32602, message: "Missing or invalid required argument: query (string)" };
635
+ if (!query || typeof query !== 'string') {
636
+ throw new RpcError(-32602, 'Missing or invalid required argument: query (string)');
592
637
  }
593
638
  const budget = req.params?.arguments?.budget || 2000;
594
639
  const agentDest = getAgentDir();
595
- const fs = require("fs");
640
+ const fs = require('fs');
596
641
  if (!fs.existsSync(agentDest)) {
597
- return { content: [{ type: "text", text: "Error: .agent/ directory not found. Run `tk init` first." }] };
642
+ return {
643
+ content: [
644
+ { type: 'text', text: 'Error: .agent/ directory not found. Run `tk init` first.' },
645
+ ],
646
+ };
598
647
  }
599
648
  try {
600
- const { _memoryRecall } = require("../dist/commands/memory.js");
649
+ const { _memoryRecall } = require('../dist/commands/memory.js');
601
650
  const { results, tokens_used } = _memoryRecall(agentDest, query, budget);
602
651
  if (results.length === 0) {
603
- return { content: [{ type: "text", text: `No memories match query: "${query}"` }] };
652
+ return { content: [{ type: 'text', text: `No memories match query: "${query}"` }] };
604
653
  }
605
654
  let text = `## Memory Recall (${results.length} results, ~${tokens_used}/${budget} tokens)\n\n`;
606
655
  for (const entry of results) {
607
656
  text += `- **[${entry.memory_type.toUpperCase()}]** #${entry.id}: ${entry.content}`;
608
- if (entry.tags.length > 0) text += ` _(${entry.tags.join(", ")})_`;
657
+ if (entry.tags.length > 0) text += ` _(${entry.tags.join(', ')})_`;
609
658
  text += `\n`;
610
659
  }
611
- return { content: [{ type: "text", text }] };
660
+ return { content: [{ type: 'text', text }] };
612
661
  } catch (e) {
613
- return { content: [{ type: "text", text: `Memory recall failed: ${e.message}` }] };
662
+ return { content: [{ type: 'text', text: `Memory recall failed: ${e.message}` }] };
614
663
  }
615
664
  }
616
665
 
617
- if (toolName === "store_memory") {
666
+ if (toolName === 'store_memory') {
618
667
  const memType = req.params?.arguments?.type;
619
668
  const content = req.params?.arguments?.content;
620
669
  const tags = req.params?.arguments?.tags || [];
621
670
  if (!memType || !content) {
622
- throw { code: -32602, message: "Missing required arguments: type (string), content (string)" };
671
+ throw new RpcError(-32602, 'Missing required arguments: type (string), content (string)');
623
672
  }
624
- const validTypes = ["semantic", "procedural", "episodic", "working"];
673
+ const validTypes = ['semantic', 'procedural', 'episodic', 'working'];
625
674
  if (!validTypes.includes(memType)) {
626
- throw { code: -32602, message: `Invalid memory type: "${memType}". Must be one of: ${validTypes.join(", ")}` };
675
+ throw new RpcError(
676
+ -32602,
677
+ `Invalid memory type: "${memType}". Must be one of: ${validTypes.join(', ')}`,
678
+ );
627
679
  }
628
680
  const agentDest = getAgentDir();
629
- const fs = require("fs");
681
+ const fs = require('fs');
630
682
  if (!fs.existsSync(agentDest)) {
631
- return { content: [{ type: "text", text: "Error: .agent/ directory not found. Run `tk init` first." }] };
683
+ return {
684
+ content: [
685
+ { type: 'text', text: 'Error: .agent/ directory not found. Run `tk init` first.' },
686
+ ],
687
+ };
632
688
  }
633
689
  try {
634
- const { _memoryStore } = require("../dist/commands/memory.js");
690
+ const { _memoryStore } = require('../dist/commands/memory.js');
635
691
  const result = _memoryStore(agentDest, memType, content, tags, null);
636
- return { content: [{ type: "text", text: `Memory stored: #${result.id} (${memType}, ~${result.token_estimate} tokens)` }] };
692
+ return {
693
+ content: [
694
+ {
695
+ type: 'text',
696
+ text: `Memory stored: #${result.id} (${memType}, ~${result.token_estimate} tokens)`,
697
+ },
698
+ ],
699
+ };
637
700
  } catch (e) {
638
- return { content: [{ type: "text", text: `Memory store failed: ${e.message}` }] };
701
+ return { content: [{ type: 'text', text: `Memory store failed: ${e.message}` }] };
639
702
  }
640
703
  }
641
704
 
642
- if (toolName === "align_output") {
705
+ if (toolName === 'align_output') {
643
706
  const text = req.params?.arguments?.text;
644
- if (typeof text !== "string") {
645
- throw { code: -32602, message: "Missing or invalid required argument: text (string)" };
707
+ if (typeof text !== 'string') {
708
+ throw new RpcError(-32602, 'Missing or invalid required argument: text (string)');
646
709
  }
647
710
  try {
648
- const { alignText, validateCodeContent } = require("../dist/commands/align.js");
711
+ const { alignText, validateCodeContent } = require('../dist/commands/align.js');
649
712
  const aligned = alignText(text);
650
713
  const warnings = validateCodeContent(aligned);
651
-
714
+
652
715
  let outputText = aligned;
653
716
  if (warnings.length > 0) {
654
- outputText += "\n\n⚠️ OCAE Alignment Validator Warnings:\n";
717
+ outputText += '\n\n⚠️ OCAE Alignment Validator Warnings:\n';
655
718
  for (const warnMsg of warnings) {
656
719
  outputText += `● ${warnMsg}\n`;
657
720
  }
658
721
  }
659
- return { content: [{ type: "text", text: outputText }] };
722
+ return { content: [{ type: 'text', text: outputText }] };
723
+ } catch (e) {
724
+ return { content: [{ type: 'text', text: `Output alignment failed: ${e.message}` }] };
725
+ }
726
+ }
727
+
728
+ if (toolName === 'verify_contracts') {
729
+ const file = req.params?.arguments?.file;
730
+ const content = req.params?.arguments?.content;
731
+
732
+ if (!file || typeof file !== 'string' || typeof content !== 'string') {
733
+ throw new RpcError(
734
+ -32602,
735
+ 'Missing or invalid required arguments: file (string), content (string)',
736
+ );
737
+ }
738
+
739
+ try {
740
+ const projectRoot = process.cwd();
741
+ const contractEnginePath = path.join(getAgentDir(), 'scripts', 'contract_engine.js');
742
+ if (!require('fs').existsSync(contractEnginePath)) {
743
+ return {
744
+ content: [
745
+ { type: 'text', text: 'Error: contract_engine.js not found. Run `tk init` first.' },
746
+ ],
747
+ };
748
+ }
749
+
750
+ const contractEngine = require(contractEnginePath);
751
+ const contracts = contractEngine.loadContracts(projectRoot);
752
+
753
+ if (contracts.length === 0) {
754
+ return {
755
+ content: [
756
+ {
757
+ type: 'text',
758
+ text: 'No active behavioral contracts found in .tribunal/contracts/.',
759
+ },
760
+ ],
761
+ };
762
+ }
763
+
764
+ const relativePath = path.relative(projectRoot, file).replace(/\\/g, '/');
765
+ const allViolations = [];
766
+
767
+ for (const contract of contracts) {
768
+ const vList = contractEngine.evaluateContract(contract, relativePath, content);
769
+ if (vList.length > 0) {
770
+ allViolations.push(...vList);
771
+ }
772
+ }
773
+
774
+ if (allViolations.length === 0) {
775
+ return {
776
+ content: [
777
+ {
778
+ type: 'text',
779
+ text: '✅ Contract check passed. Zero behavioral violations detected.',
780
+ },
781
+ ],
782
+ };
783
+ }
784
+
785
+ let report = `📜 Contract Verification Results (${allViolations.length} violations):\n`;
786
+ for (const v of allViolations) {
787
+ report += `● [${v.severity.toUpperCase()}] ${v.contract}: ${v.message}\n`;
788
+ if (v.line) report += ` Line ${v.line}: ${v.snippet || ''}\n`;
789
+ }
790
+
791
+ return { content: [{ type: 'text', text: report }] };
660
792
  } catch (e) {
661
- return { content: [{ type: "text", text: `Alignment failed: ${e.message}` }] };
793
+ return { content: [{ type: 'text', text: `Contract verification failed: ${e.message}` }] };
662
794
  }
663
795
  }
664
796
 
665
- throw { code: -32601, message: `Unknown tool: ${toolName}` };
797
+ throw new RpcError(-32601, `Unknown tool: ${toolName}`);
666
798
  }
667
799
 
668
- throw { code: -32601, message: `Unknown method: ${req.method}` };
800
+ throw new RpcError(-32601, `Unknown method: ${req.method}`);
669
801
  }
670
802
 
671
803
  function processSingleRequest(req) {
@@ -675,31 +807,32 @@ function processSingleRequest(req) {
675
807
  if (req.id === undefined || req.id === null) {
676
808
  return null;
677
809
  }
678
- return { jsonrpc: "2.0", id: req.id, result };
810
+ return { jsonrpc: '2.0', id: req.id, result };
679
811
  } catch (e) {
680
- const code = e && typeof e.code === "number" ? e.code : -32603;
681
- const message = e && e.message ? e.message : "Internal server error";
812
+ const code = e && typeof e.code === 'number' ? e.code : -32603;
813
+ const message = e && e.message ? e.message : 'Internal server error';
682
814
  if (req.id === undefined || req.id === null) {
683
815
  return {
684
- jsonrpc: "2.0",
816
+ jsonrpc: '2.0',
685
817
  id: null,
686
818
  error: { code, message },
687
819
  };
688
820
  }
689
821
  return {
690
- jsonrpc: "2.0",
822
+ jsonrpc: '2.0',
691
823
  id: req.id,
692
824
  error: { code, message },
693
825
  };
694
826
  }
695
827
  }
696
828
 
697
- rl.on("line", (line) => {
698
- if (line.length > 1048576) { // 1MB limit
829
+ rl.on('line', line => {
830
+ if (line.length > 1048576) {
831
+ // 1MB limit
699
832
  const errorRes = {
700
- jsonrpc: "2.0",
833
+ jsonrpc: '2.0',
701
834
  id: null,
702
- error: { code: -32700, message: "Parse error: input line too long (exceeds 1MB limit)" },
835
+ error: { code: -32700, message: 'Parse error: input line too long (exceeds 1MB limit)' },
703
836
  };
704
837
  console.log(JSON.stringify(errorRes));
705
838
  return;
@@ -712,9 +845,9 @@ rl.on("line", (line) => {
712
845
  } catch (parseErr) {
713
846
  // Invalid JSON — send a parse error
714
847
  const errorRes = {
715
- jsonrpc: "2.0",
848
+ jsonrpc: '2.0',
716
849
  id: null,
717
- error: { code: -32700, message: "Parse error: " + parseErr.message },
850
+ error: { code: -32700, message: 'Parse error: ' + parseErr.message },
718
851
  };
719
852
  console.log(JSON.stringify(errorRes));
720
853
  return;
@@ -739,7 +872,7 @@ rl.on("line", (line) => {
739
872
  }
740
873
  });
741
874
 
742
- if (process.env.NODE_ENV === "test") {
875
+ if (process.env.NODE_ENV === 'test') {
743
876
  module.exports = {
744
877
  handleRequest,
745
878
  stripBoilerplate,