tribunal-kit 6.0.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. package/.agent/.manifest.json +78 -0
  2. package/.agent/ARCHITECTURE.md +19 -241
  3. package/.agent/agents/accessibility-reviewer.md +23 -16
  4. package/.agent/agents/ai-code-reviewer.md +25 -21
  5. package/.agent/agents/anti-pattern-reviewer.md +12 -7
  6. package/.agent/agents/api-architect.md +1 -0
  7. package/.agent/agents/backend-specialist.md +23 -22
  8. package/.agent/agents/cloud-engineer.md +1 -0
  9. package/.agent/agents/code-archaeologist.md +1 -0
  10. package/.agent/agents/complexity-reviewer.md +10 -7
  11. package/.agent/agents/database-architect.md +3 -2
  12. package/.agent/agents/db-latency-auditor.md +6 -2
  13. package/.agent/agents/debugger.md +3 -2
  14. package/.agent/agents/dependency-reviewer.md +1 -0
  15. package/.agent/agents/devops-engineer.md +9 -8
  16. package/.agent/agents/documentation-writer.md +6 -5
  17. package/.agent/agents/explorer-agent.md +1 -0
  18. package/.agent/agents/frontend-reviewer.md +21 -17
  19. package/.agent/agents/frontend-specialist.md +23 -20
  20. package/.agent/agents/game-developer.md +1 -0
  21. package/.agent/agents/interaction-reviewer.md +10 -5
  22. package/.agent/agents/logic-reviewer.md +3 -0
  23. package/.agent/agents/minimalist-reviewer.md +6 -0
  24. package/.agent/agents/mobile-developer.md +7 -6
  25. package/.agent/agents/mobile-reviewer.md +14 -13
  26. package/.agent/agents/orchestrator.md +3 -0
  27. package/.agent/agents/penetration-tester.md +1 -0
  28. package/.agent/agents/performance-optimizer.md +6 -5
  29. package/.agent/agents/performance-reviewer.md +6 -6
  30. package/.agent/agents/pipeline-reviewer.md +144 -0
  31. package/.agent/agents/precedence-reviewer.md +1 -0
  32. package/.agent/agents/product-manager.md +1 -0
  33. package/.agent/agents/product-owner.md +1 -0
  34. package/.agent/agents/product-reviewer.md +12 -7
  35. package/.agent/agents/project-planner.md +3 -0
  36. package/.agent/agents/qa-automation-engineer.md +50 -43
  37. package/.agent/agents/resilience-reviewer.md +1 -0
  38. package/.agent/agents/schema-reviewer.md +1 -0
  39. package/.agent/agents/security-auditor.md +24 -24
  40. package/.agent/agents/seo-specialist.md +33 -23
  41. package/.agent/agents/sql-reviewer.md +5 -4
  42. package/.agent/agents/supervisor-agent.md +12 -2
  43. package/.agent/agents/swarm-worker-contracts.md +13 -13
  44. package/.agent/agents/swarm-worker-registry.md +51 -51
  45. package/.agent/agents/system-architect.md +1 -0
  46. package/.agent/agents/test-coverage-reviewer.md +25 -22
  47. package/.agent/agents/test-engineer.md +12 -11
  48. package/.agent/agents/throughput-optimizer.md +45 -40
  49. package/.agent/agents/type-safety-reviewer.md +5 -4
  50. package/.agent/agents/ui-ux-auditor.md +6 -4
  51. package/.agent/agents/ui-visual-auditor.md +3 -0
  52. package/.agent/agents/ux-reviewer.md +11 -6
  53. package/.agent/agents/visual-reviewer.md +11 -6
  54. package/.agent/agents/vitals-reviewer.md +5 -4
  55. package/.agent/history/memory/.memory.idx +3716 -1
  56. package/.agent/history/memory/MEMORY.md +246 -1
  57. package/.agent/mcp_config.json +1 -6
  58. package/.agent/routing_index.json +2034 -263
  59. package/.agent/rules/GEMINI.md +12 -10
  60. package/.agent/rules/GEMINI_PLANNER.md +19 -21
  61. package/.agent/scripts/_colors.js +52 -54
  62. package/.agent/scripts/_utils.js +52 -53
  63. package/.agent/scripts/auto_preview.js +39 -43
  64. package/.agent/scripts/bundle_analyzer.js +47 -60
  65. package/.agent/scripts/case_law_manager.js +200 -294
  66. package/.agent/scripts/checklist.js +73 -94
  67. package/.agent/scripts/cicd_validator.js +305 -0
  68. package/.agent/scripts/compile_router.py +4 -111
  69. package/.agent/scripts/context_broker.js +317 -412
  70. package/.agent/scripts/contract_engine.js +402 -0
  71. package/.agent/scripts/dependency_analyzer.js +112 -124
  72. package/.agent/scripts/graph_builder.js +75 -103
  73. package/.agent/scripts/graph_visualizer.js +10 -12
  74. package/.agent/scripts/graph_zoom.js +38 -55
  75. package/.agent/scripts/guardrail_engine.js +195 -145
  76. package/.agent/scripts/impact_classifier.js +55 -30
  77. package/.agent/scripts/inner_loop_validator.js +108 -159
  78. package/.agent/scripts/integrity_manifest.js +59 -67
  79. package/.agent/scripts/lint_runner.js +65 -75
  80. package/.agent/scripts/marathon_harness.js +131 -208
  81. package/.agent/scripts/migrate_skills_frontmatter.py +4 -63
  82. package/.agent/scripts/minify_context.js +29 -33
  83. package/.agent/scripts/minimal_change_engine.js +95 -87
  84. package/.agent/scripts/mutation_runner.js +46 -62
  85. package/.agent/scripts/pipeline_engine.js +320 -209
  86. package/.agent/scripts/prompt_compiler.js +118 -93
  87. package/.agent/scripts/schema_validator.js +73 -121
  88. package/.agent/scripts/security_scan.js +88 -117
  89. package/.agent/scripts/session_manager.js +52 -69
  90. package/.agent/scripts/signal_detector.js +24 -22
  91. package/.agent/scripts/skill_evolution.js +184 -245
  92. package/.agent/scripts/skill_integrator.js +35 -48
  93. package/.agent/scripts/socratic_gate_policy.js +15 -12
  94. package/.agent/scripts/strengthen_skills.js +29 -33
  95. package/.agent/scripts/swarm_dispatcher.js +120 -151
  96. package/.agent/scripts/test_runner.js +54 -56
  97. package/.agent/scripts/token_budget_broker.js +9 -7
  98. package/.agent/scripts/trace_engine.js +126 -0
  99. package/.agent/scripts/verify_all.js +76 -93
  100. package/.agent/scripts/visual_audit.js +16 -21
  101. package/.agent/skill_topic_map.json +237 -0
  102. package/.agent/skills/12-principles-of-animation/SKILL.md +7 -0
  103. package/.agent/skills/60fps-animation/SKILL.md +7 -0
  104. package/.agent/skills/accessible-animation/SKILL.md +5 -1
  105. package/.agent/skills/adapt/SKILL.md +7 -1
  106. package/.agent/skills/advanced-rag-pipelines/SKILL.md +1 -0
  107. package/.agent/skills/agent-organizer/SKILL.md +1 -0
  108. package/.agent/skills/agentic-patterns/SKILL.md +33 -25
  109. package/.agent/skills/agentic-workflows-2026/SKILL.md +80 -0
  110. package/.agent/skills/ai-app-hardening/SKILL.md +59 -0
  111. package/.agent/skills/ai-prompt-injection-defense/SKILL.md +7 -6
  112. package/.agent/skills/animation-on-scroll/SKILL.md +24 -15
  113. package/.agent/skills/animation-systems/SKILL.md +11 -10
  114. package/.agent/skills/antfu-conventions/SKILL.md +7 -2
  115. package/.agent/skills/api-patterns/SKILL.md +14 -10
  116. package/.agent/skills/api-security-auditor/SKILL.md +15 -14
  117. package/.agent/skills/app-builder/SKILL.md +1 -0
  118. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +2 -2
  119. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
  120. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +12 -12
  121. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +3 -3
  122. package/.agent/skills/apple-design/SKILL.md +8 -7
  123. package/.agent/skills/architecture/SKILL.md +3 -2
  124. package/.agent/skills/audit-and-fix/SKILL.md +8 -5
  125. package/.agent/skills/authentication-best-practices/SKILL.md +9 -8
  126. package/.agent/skills/backend-security-expert/SKILL.md +1 -0
  127. package/.agent/skills/baseline-ui/SKILL.md +8 -7
  128. package/.agent/skills/bash-linux/SKILL.md +1 -0
  129. package/.agent/skills/behavioral-modes/SKILL.md +1 -0
  130. package/.agent/skills/better-colors/SKILL.md +11 -7
  131. package/.agent/skills/better-typography/SKILL.md +30 -16
  132. package/.agent/skills/better-ui/SKILL.md +17 -10
  133. package/.agent/skills/bolder/SKILL.md +6 -0
  134. package/.agent/skills/brainstorming/SKILL.md +6 -4
  135. package/.agent/skills/browser-native-ai/SKILL.md +5 -4
  136. package/.agent/skills/build-primitive/SKILL.md +5 -0
  137. package/.agent/skills/building-native-ui/SKILL.md +1 -0
  138. package/.agent/skills/cicd-pro/SKILL.md +2 -1
  139. package/.agent/skills/clarify/SKILL.md +19 -14
  140. package/.agent/skills/clean-code/SKILL.md +16 -15
  141. package/.agent/skills/cloud-architect/SKILL.md +1 -0
  142. package/.agent/skills/cobejs/SKILL.md +7 -9
  143. package/.agent/skills/code-review-checklist/SKILL.md +1 -0
  144. package/.agent/skills/codebase-design/SKILL.md +7 -2
  145. package/.agent/skills/colorize/SKILL.md +8 -3
  146. package/.agent/skills/compact-landing/SKILL.md +8 -3
  147. package/.agent/skills/company-logos/SKILL.md +6 -0
  148. package/.agent/skills/config-validator/SKILL.md +10 -9
  149. package/.agent/skills/containerization-pro/SKILL.md +6 -5
  150. package/.agent/skills/context-engineering-pro/SKILL.md +70 -0
  151. package/.agent/skills/create-design-md/SKILL.md +13 -5
  152. package/.agent/skills/critique/SKILL.md +10 -8
  153. package/.agent/skills/csharp-developer/SKILL.md +1 -0
  154. package/.agent/skills/data-validation-schemas/SKILL.md +28 -23
  155. package/.agent/skills/database-design/SKILL.md +2 -1
  156. package/.agent/skills/delight/SKILL.md +6 -0
  157. package/.agent/skills/deployment-procedures/SKILL.md +2 -1
  158. package/.agent/skills/design-lab/SKILL.md +5 -0
  159. package/.agent/skills/devops-engineer/SKILL.md +3 -2
  160. package/.agent/skills/devops-incident-responder/SKILL.md +2 -1
  161. package/.agent/skills/diagnosing-bugs/SKILL.md +12 -2
  162. package/.agent/skills/distill/SKILL.md +7 -2
  163. package/.agent/skills/documentation-templates/SKILL.md +3 -2
  164. package/.agent/skills/domain-modeling/SKILL.md +12 -4
  165. package/.agent/skills/duckdb-analytical-sql/SKILL.md +59 -0
  166. package/.agent/skills/edge-ai-mobile/SKILL.md +50 -0
  167. package/.agent/skills/edge-computing/SKILL.md +9 -8
  168. package/.agent/skills/emil-design-eng/SKILL.md +43 -27
  169. package/.agent/skills/error-resilience/SKILL.md +34 -16
  170. package/.agent/skills/expo-router-v4/SKILL.md +81 -0
  171. package/.agent/skills/extract-design-system/SKILL.md +12 -11
  172. package/.agent/skills/fabel-protocol/SKILL.md +24 -17
  173. package/.agent/skills/fixing-accessibility/SKILL.md +23 -16
  174. package/.agent/skills/fixing-metadata/SKILL.md +24 -13
  175. package/.agent/skills/fixing-motion-performance/SKILL.md +7 -5
  176. package/.agent/skills/framer-motion-expert/SKILL.md +29 -15
  177. package/.agent/skills/frontend-design/SKILL.md +21 -13
  178. package/.agent/skills/frontend-security-expert/SKILL.md +1 -0
  179. package/.agent/skills/game-design-expert/SKILL.md +1 -0
  180. package/.agent/skills/game-engineering-expert/SKILL.md +1 -0
  181. package/.agent/skills/generative-ui-expert/SKILL.md +3 -2
  182. package/.agent/skills/geo-fundamentals/SKILL.md +2 -1
  183. package/.agent/skills/git-pro/SKILL.md +10 -9
  184. package/.agent/skills/github-operations/SKILL.md +2 -1
  185. package/.agent/skills/gpt-taste/SKILL.md +7 -0
  186. package/.agent/skills/gsap-core/SKILL.md +26 -22
  187. package/.agent/skills/gsap-frameworks/SKILL.md +6 -5
  188. package/.agent/skills/gsap-performance/SKILL.md +4 -3
  189. package/.agent/skills/gsap-plugins/SKILL.md +34 -33
  190. package/.agent/skills/gsap-react/SKILL.md +9 -8
  191. package/.agent/skills/gsap-scrolltrigger/SKILL.md +34 -33
  192. package/.agent/skills/gsap-timeline/SKILL.md +18 -15
  193. package/.agent/skills/gsap-utils/SKILL.md +25 -24
  194. package/.agent/skills/harden/SKILL.md +9 -3
  195. package/.agent/skills/harness-protocol/SKILL.md +1 -0
  196. package/.agent/skills/i18n-localization/SKILL.md +10 -9
  197. package/.agent/skills/impeccable/SKILL.md +5 -0
  198. package/.agent/skills/improve-codebase-architecture/SKILL.md +10 -5
  199. package/.agent/skills/improve-ui/SKILL.md +12 -5
  200. package/.agent/skills/intelligent-routing/SKILL.md +7 -6
  201. package/.agent/skills/knowledge-graph/SKILL.md +1 -0
  202. package/.agent/skills/landing-page/SKILL.md +1 -0
  203. package/.agent/skills/lint-and-validate/SKILL.md +9 -4
  204. package/.agent/skills/llm-engineering/SKILL.md +55 -54
  205. package/.agent/skills/local-first/SKILL.md +20 -19
  206. package/.agent/skills/local-first-architecture/SKILL.md +6 -1
  207. package/.agent/skills/lottie-animation/SKILL.md +7 -3
  208. package/.agent/skills/marquee-loop/SKILL.md +1 -0
  209. package/.agent/skills/masked-reveal/SKILL.md +17 -4
  210. package/.agent/skills/mcp-builder/SKILL.md +13 -10
  211. package/.agent/skills/micro-interaction/SKILL.md +20 -5
  212. package/.agent/skills/mobile-design/SKILL.md +26 -15
  213. package/.agent/skills/monorepo-management/SKILL.md +3 -2
  214. package/.agent/skills/morphing-icons/SKILL.md +16 -6
  215. package/.agent/skills/motion-engineering/SKILL.md +19 -15
  216. package/.agent/skills/nextjs-react-expert/SKILL.md +26 -21
  217. package/.agent/skills/nodejs-best-practices/SKILL.md +89 -76
  218. package/.agent/skills/observability/SKILL.md +45 -44
  219. package/.agent/skills/opentelemetry-observability/SKILL.md +59 -0
  220. package/.agent/skills/page-transition-animation/SKILL.md +6 -3
  221. package/.agent/skills/parallel-agents/SKILL.md +7 -2
  222. package/.agent/skills/performance-profiling/SKILL.md +24 -13
  223. package/.agent/skills/plan-writing/SKILL.md +1 -0
  224. package/.agent/skills/platform-engineer/SKILL.md +3 -2
  225. package/.agent/skills/platform-engineering-opentofu/SKILL.md +68 -0
  226. package/.agent/skills/playwright-ai-e2e/SKILL.md +60 -0
  227. package/.agent/skills/playwright-best-practices/SKILL.md +29 -28
  228. package/.agent/skills/polish/SKILL.md +13 -12
  229. package/.agent/skills/powershell-windows/SKILL.md +1 -0
  230. package/.agent/skills/pricing-page/SKILL.md +8 -3
  231. package/.agent/skills/product-aware-heuristics/SKILL.md +122 -72
  232. package/.agent/skills/progressive-blur/SKILL.md +9 -4
  233. package/.agent/skills/project-idioms/SKILL.md +1 -0
  234. package/.agent/skills/property-based-testing/SKILL.md +58 -0
  235. package/.agent/skills/python-patterns/SKILL.md +1 -0
  236. package/.agent/skills/python-pro/SKILL.md +1 -0
  237. package/.agent/skills/quieter/SKILL.md +6 -0
  238. package/.agent/skills/react-doctor/SKILL.md +6 -0
  239. package/.agent/skills/react-specialist/SKILL.md +32 -28
  240. package/.agent/skills/readme-builder/SKILL.md +1 -0
  241. package/.agent/skills/realtime-patterns/SKILL.md +34 -33
  242. package/.agent/skills/red-team-tactics/SKILL.md +1 -0
  243. package/.agent/skills/redesign-skill/SKILL.md +6 -0
  244. package/.agent/skills/review-animations/SKILL.md +5 -2
  245. package/.agent/skills/review-animations/STANDARDS.md +37 -23
  246. package/.agent/skills/rust-pro/SKILL.md +1 -0
  247. package/.agent/skills/seo-fundamentals/SKILL.md +4 -3
  248. package/.agent/skills/server-management/SKILL.md +1 -0
  249. package/.agent/skills/shadcn-ui-expert/SKILL.md +28 -22
  250. package/.agent/skills/shape/SKILL.md +9 -2
  251. package/.agent/skills/skill-creator/SKILL.md +1 -0
  252. package/.agent/skills/soft-skill/SKILL.md +6 -0
  253. package/.agent/skills/sounds-on-the-web/SKILL.md +1 -0
  254. package/.agent/skills/sql-pro/SKILL.md +1 -0
  255. package/.agent/skills/supabase-postgres-best-practices/SKILL.md +1 -0
  256. package/.agent/skills/svg-animation/SKILL.md +16 -7
  257. package/.agent/skills/swiftui-expert/SKILL.md +1 -0
  258. package/.agent/skills/swiss-design/SKILL.md +5 -0
  259. package/.agent/skills/system-design-pro/SKILL.md +1 -0
  260. package/.agent/skills/systematic-debugging/SKILL.md +1 -0
  261. package/.agent/skills/tailwind-patterns/SKILL.md +25 -11
  262. package/.agent/skills/taste-skill/SKILL.md +6 -0
  263. package/.agent/skills/tdd-workflow/SKILL.md +5 -0
  264. package/.agent/skills/test-result-analyzer/SKILL.md +1 -0
  265. package/.agent/skills/testing-patterns/SKILL.md +123 -115
  266. package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +5 -0
  267. package/.agent/skills/thinking-protocol/SKILL.md +3 -0
  268. package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +9 -8
  269. package/.agent/skills/transitions-dev/SKILL.md +19 -6
  270. package/.agent/skills/trend-researcher/SKILL.md +1 -0
  271. package/.agent/skills/typescript-advanced/SKILL.md +23 -18
  272. package/.agent/skills/typeset/SKILL.md +10 -1
  273. package/.agent/skills/ui-reasoning-engine/SKILL.md +67 -48
  274. package/.agent/skills/ui-skill-packs/SKILL.md +6 -1
  275. package/.agent/skills/ui-skills-root/SKILL.md +39 -38
  276. package/.agent/skills/ui-ux-pro-max/SKILL.md +34 -26
  277. package/.agent/skills/ui-ux-researcher/SKILL.md +1 -0
  278. package/.agent/skills/vector-search-pgvector/SKILL.md +78 -0
  279. package/.agent/skills/vue-expert/SKILL.md +22 -19
  280. package/.agent/skills/vulnerability-scanner/SKILL.md +22 -21
  281. package/.agent/skills/web-accessibility-auditor/SKILL.md +2 -1
  282. package/.agent/skills/web-design-guidelines/SKILL.md +16 -10
  283. package/.agent/skills/web-quality-audit/SKILL.md +5 -0
  284. package/.agent/skills/webapp-testing/SKILL.md +14 -13
  285. package/.agent/skills/webgpu-performance/SKILL.md +1 -0
  286. package/.agent/skills/whimsy-injector/SKILL.md +9 -5
  287. package/.agent/skills/workflow-optimizer/SKILL.md +1 -0
  288. package/.agent/skills/zero-trust-passkeys/SKILL.md +90 -0
  289. package/.agent/templates/DESIGN.md +119 -110
  290. package/.agent/templates/design-tokens.json +9 -6
  291. package/.agent/workflows/acf.md +1 -0
  292. package/.agent/workflows/api-tester.md +1 -0
  293. package/.agent/workflows/audit.md +1 -0
  294. package/.agent/workflows/brainstorm.md +1 -0
  295. package/.agent/workflows/changelog.md +1 -0
  296. package/.agent/workflows/contract.md +60 -0
  297. package/.agent/workflows/create.md +1 -0
  298. package/.agent/workflows/debug.md +1 -0
  299. package/.agent/workflows/deploy.md +1 -0
  300. package/.agent/workflows/enhance.md +1 -0
  301. package/.agent/workflows/fix-ci.md +89 -0
  302. package/.agent/workflows/fix.md +1 -0
  303. package/.agent/workflows/generate.md +1 -0
  304. package/.agent/workflows/marathon.md +1 -0
  305. package/.agent/workflows/migrate.md +1 -0
  306. package/.agent/workflows/minimal.md +9 -7
  307. package/.agent/workflows/orchestrate.md +1 -0
  308. package/.agent/workflows/performance-benchmarker.md +1 -0
  309. package/.agent/workflows/pipeline.md +26 -21
  310. package/.agent/workflows/plan.md +1 -0
  311. package/.agent/workflows/preview.md +1 -0
  312. package/.agent/workflows/refactor.md +3 -2
  313. package/.agent/workflows/review-ai.md +4 -3
  314. package/.agent/workflows/review.md +1 -0
  315. package/.agent/workflows/session.md +1 -0
  316. package/.agent/workflows/status.md +1 -0
  317. package/.agent/workflows/strengthen-skills.md +1 -0
  318. package/.agent/workflows/super-prompt.md +1 -0
  319. package/.agent/workflows/swarm.md +15 -3
  320. package/.agent/workflows/test.md +8 -7
  321. package/.agent/workflows/tribunal-backend.md +3 -2
  322. package/.agent/workflows/tribunal-cicd.md +104 -0
  323. package/.agent/workflows/tribunal-database.md +1 -0
  324. package/.agent/workflows/tribunal-frontend.md +8 -6
  325. package/.agent/workflows/tribunal-full.md +15 -14
  326. package/.agent/workflows/tribunal-mobile.md +6 -5
  327. package/.agent/workflows/tribunal-performance.md +1 -0
  328. package/.agent/workflows/tribunal-speed.md +1 -0
  329. package/.agent/workflows/tribunal-ui.md +29 -21
  330. package/.agent/workflows/ui-ux-pro-max.md +19 -15
  331. package/CONTRIBUTING.md +3 -3
  332. package/README.md +160 -88
  333. package/SECURITY.md +11 -11
  334. package/bin/mcp-server.js +512 -233
  335. package/bin/tribunal-kit.js +29 -30
  336. package/bin/wrapper.js +45 -48
  337. package/dist/cli.js +26 -0
  338. package/dist/commands/case.js +2 -0
  339. package/dist/commands/contract.js +440 -0
  340. package/dist/commands/memory.js +3 -2
  341. package/dist/commands/native.js +36 -0
  342. package/dist/commands/status.js +6 -0
  343. package/dist/esm/index.mjs +32 -0
  344. package/dist/index.d.ts +58 -3
  345. package/package.json +20 -16
  346. package/scripts/benchmark.js +62 -86
  347. package/scripts/changelog.js +67 -73
  348. package/scripts/fix-vbc.js +13 -15
  349. package/scripts/fix-vbc.ps1 +2 -118
  350. package/scripts/stress_benchmark.js +358 -0
  351. package/scripts/sync-version.js +71 -41
  352. package/scripts/validate-payload.js +23 -30
  353. 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,228 +85,393 @@ 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
 
114
+ function getAgentDir() {
115
+ const fs = require('fs');
116
+ const local = path.join(process.cwd(), '.agent');
117
+ if (fs.existsSync(local)) return local;
118
+ return path.resolve(__dirname, '../.agent');
119
+ }
120
+
113
121
  function handleRequest(req) {
114
- if (req.method === "notifications/initialized" || req.method === "notifications/cancelled") {
122
+ const fs = require('fs');
123
+ if (req.method === 'notifications/initialized' || req.method === 'notifications/cancelled') {
115
124
  return null;
116
125
  }
117
- if (req.method === "ping") {
126
+ if (req.method === 'ping') {
118
127
  return {};
119
128
  }
120
- if (req.method === "resources/list") {
121
- return { resources: [] };
122
- }
123
- if (req.method === "prompts/list") {
124
- return { prompts: [] };
125
- }
126
129
 
127
130
  // MCP spec: method names follow path-style convention
128
- if (req.method === "initialize") {
131
+ if (req.method === 'initialize') {
129
132
  return {
130
- protocolVersion: "2024-11-05",
133
+ protocolVersion: '2025-03-26',
131
134
  capabilities: {
132
135
  tools: {},
133
136
  resources: { subscribe: false, listChanged: false },
134
137
  prompts: { listChanged: false },
135
138
  },
136
139
  serverInfo: {
137
- name: "tribunal-kit-mcp",
140
+ name: 'tribunal-kit-mcp',
138
141
  version: PKG.version,
139
142
  },
140
143
  };
141
144
  }
142
145
 
143
- if (req.method === "tools/list") {
146
+ if (req.method === 'resources/list') {
147
+ const agentDir = getAgentDir();
148
+ const resources = [];
149
+
150
+ // Agents
151
+ const agentsDir = path.join(agentDir, 'agents');
152
+ if (fs.existsSync(agentsDir)) {
153
+ const files = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
154
+ for (const f of files) {
155
+ const name = path.basename(f, '.md');
156
+ resources.push({
157
+ uri: `tribunal://agent/${name}`,
158
+ name: `Agent: ${name}`,
159
+ description: `Tribunal Specialist Agent rule file for ${name}`,
160
+ mimeType: 'text/markdown',
161
+ });
162
+ }
163
+ }
164
+
165
+ // Skills
166
+ const skillsDir = path.join(agentDir, 'skills');
167
+ if (fs.existsSync(skillsDir)) {
168
+ const dirs = fs.readdirSync(skillsDir, { withFileTypes: true });
169
+ for (const d of dirs) {
170
+ if (d.isDirectory()) {
171
+ const skillFile = path.join(skillsDir, d.name, 'SKILL.md');
172
+ if (fs.existsSync(skillFile)) {
173
+ resources.push({
174
+ uri: `tribunal://skill/${d.name}`,
175
+ name: `Skill: ${d.name}`,
176
+ description: `Tribunal Skill instruction file for ${d.name}`,
177
+ mimeType: 'text/markdown',
178
+ });
179
+ }
180
+ }
181
+ }
182
+ }
183
+
184
+ // Workflows
185
+ const workflowsDir = path.join(agentDir, 'workflows');
186
+ if (fs.existsSync(workflowsDir)) {
187
+ const files = fs.readdirSync(workflowsDir).filter(f => f.endsWith('.md'));
188
+ for (const f of files) {
189
+ const name = path.basename(f, '.md');
190
+ resources.push({
191
+ uri: `tribunal://workflow/${name}`,
192
+ name: `Workflow: ${name}`,
193
+ description: `Tribunal Workflow guide for ${name}`,
194
+ mimeType: 'text/markdown',
195
+ });
196
+ }
197
+ }
198
+
199
+ return { resources };
200
+ }
201
+
202
+ if (req.method === 'resources/read') {
203
+ const uri = req.params && req.params.uri;
204
+ if (!uri) throw new Error('Missing uri parameter');
205
+ const agentDir = getAgentDir();
206
+ let filePath = null;
207
+
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`);
217
+ }
218
+
219
+ if (!filePath || !fs.existsSync(filePath)) {
220
+ throw new Error(`Resource not found: ${uri}`);
221
+ }
222
+
223
+ const text = fs.readFileSync(filePath, 'utf8');
224
+ return {
225
+ contents: [
226
+ {
227
+ uri,
228
+ mimeType: 'text/markdown',
229
+ text,
230
+ },
231
+ ],
232
+ };
233
+ }
234
+
235
+ if (req.method === 'prompts/list') {
236
+ const agentDir = getAgentDir();
237
+ const prompts = [];
238
+ const workflowsDir = path.join(agentDir, 'workflows');
239
+
240
+ if (fs.existsSync(workflowsDir)) {
241
+ const files = fs.readdirSync(workflowsDir).filter(f => f.endsWith('.md'));
242
+ for (const f of files) {
243
+ const name = path.basename(f, '.md');
244
+ prompts.push({
245
+ name,
246
+ description: `Execute tribunal workflow /${name}`,
247
+ arguments: [
248
+ {
249
+ name: 'task',
250
+ description: 'The task or target file to execute the workflow against',
251
+ required: false,
252
+ },
253
+ ],
254
+ });
255
+ }
256
+ }
257
+
258
+ return { prompts };
259
+ }
260
+
261
+ if (req.method === 'prompts/get') {
262
+ const name = req.params && req.params.name;
263
+ const task = (req.params && req.params.arguments && req.params.arguments.task) || '';
264
+ if (!name) throw new Error('Missing prompt name parameter');
265
+
266
+ const agentDir = getAgentDir();
267
+ const workflowPath = path.join(agentDir, 'workflows', `${name}.md`);
268
+ if (!fs.existsSync(workflowPath)) {
269
+ throw new Error(`Prompt workflow not found: ${name}`);
270
+ }
271
+
272
+ const content = fs.readFileSync(workflowPath, 'utf8');
273
+ const promptText = task ? `${content}\n\nTarget Task/File: ${task}` : content;
274
+
275
+ return {
276
+ messages: [
277
+ {
278
+ role: 'user',
279
+ content: {
280
+ type: 'text',
281
+ text: promptText,
282
+ },
283
+ },
284
+ ],
285
+ };
286
+ }
287
+
288
+ if (req.method === 'tools/list') {
144
289
  return {
145
290
  tools: [
146
291
  {
147
- name: "run_tribunal_audit",
148
- description:
149
- "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.',
150
294
  inputSchema: {
151
- type: "object",
295
+ type: 'object',
152
296
  properties: {},
153
297
  additionalProperties: false,
154
298
  },
155
299
  },
156
300
  {
157
- name: "sync_ide_bridges",
158
- description:
159
- "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.',
160
303
  inputSchema: {
161
- type: "object",
304
+ type: 'object',
162
305
  properties: {},
163
306
  additionalProperties: false,
164
307
  },
165
308
  },
166
309
  {
167
- name: "search_case_law",
310
+ name: 'search_case_law',
168
311
  description:
169
- "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.',
170
313
  inputSchema: {
171
- type: "object",
314
+ type: 'object',
172
315
  properties: {
173
316
  query: {
174
- type: "string",
317
+ type: 'string',
175
318
  description: "Search query (e.g. 'useEffect state')",
176
319
  },
177
320
  },
178
- required: ["query"],
321
+ required: ['query'],
179
322
  additionalProperties: false,
180
323
  },
181
324
  },
182
325
  {
183
- name: "list_tribunal_agents",
184
- description: "List all available Tribunal Kit agents.",
326
+ name: 'list_tribunal_agents',
327
+ description: 'List all available Tribunal Kit agents.',
185
328
  inputSchema: {
186
- type: "object",
329
+ type: 'object',
187
330
  properties: {},
188
331
  additionalProperties: false,
189
332
  },
190
333
  },
191
334
  {
192
- name: "get_tribunal_agent",
193
- 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.',
194
337
  inputSchema: {
195
- type: "object",
338
+ type: 'object',
196
339
  properties: {
197
- name: { type: "string", description: "The agent name (e.g. 'frontend-specialist')" },
340
+ name: { type: 'string', description: "The agent name (e.g. 'frontend-specialist')" },
198
341
  },
199
- required: ["name"],
342
+ required: ['name'],
200
343
  additionalProperties: false,
201
344
  },
202
345
  },
203
346
  {
204
- name: "list_tribunal_skills",
205
- description: "List all available Tribunal Kit skills.",
347
+ name: 'list_tribunal_skills',
348
+ description: 'List all available Tribunal Kit skills.',
206
349
  inputSchema: {
207
- type: "object",
350
+ type: 'object',
208
351
  properties: {},
209
352
  additionalProperties: false,
210
353
  },
211
354
  },
212
355
  {
213
- name: "get_tribunal_skill",
214
- 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.',
215
358
  inputSchema: {
216
- type: "object",
359
+ type: 'object',
217
360
  properties: {
218
- name: { type: "string", description: "The skill name (e.g. 'react-specialist')" },
361
+ name: { type: 'string', description: "The skill name (e.g. 'react-specialist')" },
219
362
  },
220
- required: ["name"],
363
+ required: ['name'],
221
364
  additionalProperties: false,
222
365
  },
223
366
  },
224
367
  {
225
- name: "recall_memory",
226
- 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.',
227
371
  inputSchema: {
228
- type: "object",
372
+ type: 'object',
229
373
  properties: {
230
374
  query: {
231
- type: "string",
375
+ type: 'string',
232
376
  description: "Search query (e.g. 'database', 'auth', 'deploy')",
233
377
  },
234
378
  budget: {
235
- type: "number",
236
- 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.',
237
382
  },
238
383
  },
239
- required: ["query"],
384
+ required: ['query'],
240
385
  additionalProperties: false,
241
386
  },
242
387
  },
243
388
  {
244
- name: "store_memory",
245
- 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).',
246
392
  inputSchema: {
247
- type: "object",
393
+ type: 'object',
248
394
  properties: {
249
395
  type: {
250
- type: "string",
251
- enum: ["semantic", "procedural", "episodic", "working"],
252
- 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)',
253
400
  },
254
401
  content: {
255
- type: "string",
256
- description: "The memory content to store",
402
+ type: 'string',
403
+ description: 'The memory content to store',
257
404
  },
258
405
  tags: {
259
- type: "array",
260
- items: { type: "string" },
261
- description: "Searchable tags for this memory",
406
+ type: 'array',
407
+ items: { type: 'string' },
408
+ description: 'Searchable tags for this memory',
262
409
  },
263
410
  },
264
- required: ["type", "content"],
411
+ required: ['type', 'content'],
265
412
  additionalProperties: false,
266
413
  },
267
414
  },
268
415
  {
269
- name: "get_sparse_context",
270
- 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.',
271
419
  inputSchema: {
272
- type: "object",
420
+ type: 'object',
273
421
  properties: {
274
422
  task: {
275
- type: "string",
423
+ type: 'string',
276
424
  description: "The user task description (e.g. 'JWT auth API')",
277
425
  },
278
426
  files: {
279
- type: "array",
280
- items: { type: "string" },
427
+ type: 'array',
428
+ items: { type: 'string' },
281
429
  description: "List of files being touched (e.g. ['src/auth.js'])",
282
430
  },
283
431
  model: {
284
- type: "string",
285
- enum: ["large", "small"],
286
- 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)',
287
436
  },
288
437
  },
289
- required: ["task"],
438
+ required: ['task'],
290
439
  additionalProperties: false,
291
440
  },
292
441
  },
293
442
  {
294
- name: "align_output",
295
- 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).',
296
446
  inputSchema: {
297
- type: "object",
447
+ type: 'object',
298
448
  properties: {
299
449
  text: {
300
- type: "string",
301
- 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.',
452
+ },
453
+ },
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',
302
472
  },
303
473
  },
304
- required: ["text"],
474
+ required: ['file', 'content'],
305
475
  additionalProperties: false,
306
476
  },
307
477
  },
@@ -309,217 +479,325 @@ function handleRequest(req) {
309
479
  };
310
480
  }
311
481
 
312
- if (req.method === "tools/call") {
482
+ if (req.method === 'tools/call') {
313
483
  const toolName = req.params && req.params.name;
314
484
  if (!toolName) {
315
- throw {
316
- code: -32602,
317
- message: "Missing required parameter: params.name",
318
- };
485
+ throw new RpcError(-32602, 'Missing required parameter: params.name');
319
486
  }
320
487
 
321
- if (toolName === "run_tribunal_audit") {
488
+ if (toolName === 'run_tribunal_audit') {
322
489
  const text = runTribunalAudit();
323
- return { content: [{ type: "text", text }] };
490
+ return { content: [{ type: 'text', text }] };
324
491
  }
325
492
 
326
- if (toolName === "sync_ide_bridges") {
327
- const fs = require("fs");
493
+ if (toolName === 'sync_ide_bridges') {
494
+ const fs = require('fs');
328
495
  const cwd = process.cwd();
329
- const agentDest = path.join(cwd, ".agent");
496
+ const agentDest = path.join(cwd, '.agent');
330
497
  if (!fs.existsSync(agentDest)) {
331
498
  return {
332
499
  content: [
333
500
  {
334
- type: "text",
335
- text: "Error: .agent/ directory not found. Run `tk init` first.",
501
+ type: 'text',
502
+ text: 'Error: .agent/ directory not found. Run `tk init` first.',
503
+ },
504
+ ],
505
+ };
506
+ }
507
+ try {
508
+ const { generateIDEBridges } = require(path.resolve(__dirname, '../dist/commands/init.js'));
509
+ // generateIDEBridges is async — execute synchronously in MCP context
510
+ generateIDEBridges(cwd, agentDest, true)
511
+ .then(() => {})
512
+ .catch(() => {});
513
+ return {
514
+ content: [
515
+ {
516
+ type: 'text',
517
+ text: 'Sync complete',
518
+ },
519
+ ],
520
+ };
521
+ } catch (e) {
522
+ return {
523
+ content: [
524
+ {
525
+ type: 'text',
526
+ text: `Sync failed: ${e.message}`,
336
527
  },
337
528
  ],
338
529
  };
339
530
  }
340
- // Run synchronously by spawning a minimal script
341
- const result = spawnSync(
342
- process.execPath,
343
- [
344
- "-e",
345
- `
346
- const { generateIDEBridges } = require('${path.resolve(__dirname, "../dist/commands/init.js").replace(/\\/g, "\\\\")}');
347
- generateIDEBridges('${cwd.replace(/\\/g, "\\\\")}', '${agentDest.replace(/\\/g, "\\\\")}', false).then(() => console.log('Sync complete'));
348
- `,
349
- ],
350
- { encoding: "utf8", timeout: SPAWN_TIMEOUT_MS },
351
- );
352
- return {
353
- content: [
354
- {
355
- type: "text",
356
- text: result.stdout || result.stderr || "Sync complete",
357
- },
358
- ],
359
- };
360
531
  }
361
532
 
362
- if (toolName === "search_case_law") {
363
- const query =
364
- req.params && req.params.arguments && req.params.arguments.query;
365
- if (!query || typeof query !== "string") {
366
- throw {
367
- code: -32602,
368
- message: "Missing or invalid required argument: query (string)",
369
- };
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)');
370
537
  }
371
538
  const text = searchCaseLaw(query);
372
- return { content: [{ type: "text", text }] };
539
+ return { content: [{ type: 'text', text }] };
373
540
  }
374
541
 
375
- if (toolName === "list_tribunal_agents") {
376
- const fs = require("fs");
377
- const agentDir = path.join(process.cwd(), ".agent", "agents");
378
- if (!fs.existsSync(agentDir)) return { content: [{ type: "text", text: "No agents found or .agent directory missing." }] };
379
- const agents = fs.readdirSync(agentDir).filter(f => f.endsWith('.md')).map(f => f.replace('.md', ''));
380
- 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- ') }] };
381
554
  }
382
555
 
383
- if (toolName === "get_tribunal_agent") {
384
- const fs = require("fs");
556
+ if (toolName === 'get_tribunal_agent') {
557
+ const fs = require('fs');
385
558
  const name = req.params?.arguments?.name;
386
- 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)');
387
561
  const sanitizedName = path.basename(name);
388
- const agentsDir = path.resolve(process.cwd(), ".agent", "agents");
562
+ const agentsDir = path.resolve(getAgentDir(), 'agents');
389
563
  const agentPath = path.resolve(agentsDir, `${sanitizedName}.md`);
390
564
  // Path containment: ensure resolved path stays within agents directory
391
- if (!agentPath.startsWith(agentsDir)) throw { code: -32602, message: "Invalid agent name: path traversal detected" };
392
- if (!fs.existsSync(agentPath)) return { content: [{ type: "text", text: `Agent '${sanitizedName}' not found.` }] };
393
- const text = fs.readFileSync(agentPath, "utf8");
394
- 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) }] };
395
571
  }
396
572
 
397
- if (toolName === "list_tribunal_skills") {
398
- const fs = require("fs");
399
- const skillsDir = path.join(process.cwd(), ".agent", "skills");
400
- if (!fs.existsSync(skillsDir)) return { content: [{ type: "text", text: "No skills found or .agent directory missing." }] };
401
- const skills = fs.readdirSync(skillsDir, { withFileTypes: true }).filter(d => d.isDirectory()).map(d => d.name);
402
- 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- ') }] };
403
585
  }
404
586
 
405
- if (toolName === "get_tribunal_skill") {
406
- const fs = require("fs");
587
+ if (toolName === 'get_tribunal_skill') {
588
+ const fs = require('fs');
407
589
  const name = req.params?.arguments?.name;
408
- 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)');
409
592
  const sanitizedName = path.basename(name);
410
- const skillsDir = path.resolve(process.cwd(), ".agent", "skills");
411
- const skillPath = path.resolve(skillsDir, sanitizedName, "SKILL.md");
593
+ const skillsDir = path.resolve(getAgentDir(), 'skills');
594
+ const skillPath = path.resolve(skillsDir, sanitizedName, 'SKILL.md');
412
595
  // Path containment: ensure resolved path stays within skills directory
413
- if (!skillPath.startsWith(skillsDir)) throw { code: -32602, message: "Invalid skill name: path traversal detected" };
414
- if (!fs.existsSync(skillPath)) return { content: [{ type: "text", text: `Skill '${sanitizedName}' not found.` }] };
415
- const text = fs.readFileSync(skillPath, "utf8");
416
- 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) }] };
417
602
  }
418
603
 
419
- if (toolName === "get_sparse_context") {
604
+ if (toolName === 'get_sparse_context') {
420
605
  const task = req.params?.arguments?.task;
421
606
  const files = req.params?.arguments?.files || [];
422
- const model = req.params?.arguments?.model || "large";
607
+ const model = req.params?.arguments?.model || 'large';
423
608
 
424
- if (!task) throw { code: -32602, message: "Missing required argument: task" };
609
+ if (!task) throw new RpcError(-32602, 'Missing required argument: task');
425
610
 
426
- const agentDest = path.join(process.cwd(), ".agent");
427
- const fs = require("fs");
611
+ const agentDest = getAgentDir();
612
+ const fs = require('fs');
428
613
  if (!fs.existsSync(agentDest)) {
429
- 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
+ };
430
619
  }
431
620
 
432
621
  try {
433
- const brokerScript = path.join(agentDest, "scripts", "context_broker.js");
622
+ const brokerScript = path.join(agentDest, 'scripts', 'context_broker.js');
434
623
  const { broker } = require(brokerScript);
435
624
  const brokerResult = broker(task, files, model, agentDest);
436
- return { content: [{ type: "text", text: stripBoilerplate(brokerResult.promptText) }] };
625
+ return { content: [{ type: 'text', text: stripBoilerplate(brokerResult.promptText) }] };
437
626
  } catch (e) {
438
- 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
+ };
439
630
  }
440
631
  }
441
632
 
442
- if (toolName === "recall_memory") {
633
+ if (toolName === 'recall_memory') {
443
634
  const query = req.params?.arguments?.query;
444
- if (!query || typeof query !== "string") {
445
- 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)');
446
637
  }
447
638
  const budget = req.params?.arguments?.budget || 2000;
448
- const agentDest = path.join(process.cwd(), ".agent");
449
- const fs = require("fs");
639
+ const agentDest = getAgentDir();
640
+ const fs = require('fs');
450
641
  if (!fs.existsSync(agentDest)) {
451
- 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
+ };
452
647
  }
453
648
  try {
454
- const { _memoryRecall } = require("../dist/commands/memory.js");
649
+ const { _memoryRecall } = require('../dist/commands/memory.js');
455
650
  const { results, tokens_used } = _memoryRecall(agentDest, query, budget);
456
651
  if (results.length === 0) {
457
- return { content: [{ type: "text", text: `No memories match query: "${query}"` }] };
652
+ return { content: [{ type: 'text', text: `No memories match query: "${query}"` }] };
458
653
  }
459
654
  let text = `## Memory Recall (${results.length} results, ~${tokens_used}/${budget} tokens)\n\n`;
460
655
  for (const entry of results) {
461
656
  text += `- **[${entry.memory_type.toUpperCase()}]** #${entry.id}: ${entry.content}`;
462
- if (entry.tags.length > 0) text += ` _(${entry.tags.join(", ")})_`;
657
+ if (entry.tags.length > 0) text += ` _(${entry.tags.join(', ')})_`;
463
658
  text += `\n`;
464
659
  }
465
- return { content: [{ type: "text", text }] };
660
+ return { content: [{ type: 'text', text }] };
466
661
  } catch (e) {
467
- return { content: [{ type: "text", text: `Memory recall failed: ${e.message}` }] };
662
+ return { content: [{ type: 'text', text: `Memory recall failed: ${e.message}` }] };
468
663
  }
469
664
  }
470
665
 
471
- if (toolName === "store_memory") {
666
+ if (toolName === 'store_memory') {
472
667
  const memType = req.params?.arguments?.type;
473
668
  const content = req.params?.arguments?.content;
474
669
  const tags = req.params?.arguments?.tags || [];
475
670
  if (!memType || !content) {
476
- throw { code: -32602, message: "Missing required arguments: type (string), content (string)" };
671
+ throw new RpcError(-32602, 'Missing required arguments: type (string), content (string)');
477
672
  }
478
- const validTypes = ["semantic", "procedural", "episodic", "working"];
673
+ const validTypes = ['semantic', 'procedural', 'episodic', 'working'];
479
674
  if (!validTypes.includes(memType)) {
480
- 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
+ );
481
679
  }
482
- const agentDest = path.join(process.cwd(), ".agent");
483
- const fs = require("fs");
680
+ const agentDest = getAgentDir();
681
+ const fs = require('fs');
484
682
  if (!fs.existsSync(agentDest)) {
485
- 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
+ };
486
688
  }
487
689
  try {
488
- const { _memoryStore } = require("../dist/commands/memory.js");
690
+ const { _memoryStore } = require('../dist/commands/memory.js');
489
691
  const result = _memoryStore(agentDest, memType, content, tags, null);
490
- 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
+ };
491
700
  } catch (e) {
492
- return { content: [{ type: "text", text: `Memory store failed: ${e.message}` }] };
701
+ return { content: [{ type: 'text', text: `Memory store failed: ${e.message}` }] };
493
702
  }
494
703
  }
495
704
 
496
- if (toolName === "align_output") {
705
+ if (toolName === 'align_output') {
497
706
  const text = req.params?.arguments?.text;
498
- if (typeof text !== "string") {
499
- 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)');
500
709
  }
501
710
  try {
502
- const { alignText, validateCodeContent } = require("../dist/commands/align.js");
711
+ const { alignText, validateCodeContent } = require('../dist/commands/align.js');
503
712
  const aligned = alignText(text);
504
713
  const warnings = validateCodeContent(aligned);
505
-
714
+
506
715
  let outputText = aligned;
507
716
  if (warnings.length > 0) {
508
- outputText += "\n\n⚠️ OCAE Alignment Validator Warnings:\n";
717
+ outputText += '\n\n⚠️ OCAE Alignment Validator Warnings:\n';
509
718
  for (const warnMsg of warnings) {
510
719
  outputText += `● ${warnMsg}\n`;
511
720
  }
512
721
  }
513
- 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 }] };
514
792
  } catch (e) {
515
- return { content: [{ type: "text", text: `Alignment failed: ${e.message}` }] };
793
+ return { content: [{ type: 'text', text: `Contract verification failed: ${e.message}` }] };
516
794
  }
517
795
  }
518
796
 
519
- throw { code: -32601, message: `Unknown tool: ${toolName}` };
797
+ throw new RpcError(-32601, `Unknown tool: ${toolName}`);
520
798
  }
521
799
 
522
- throw { code: -32601, message: `Unknown method: ${req.method}` };
800
+ throw new RpcError(-32601, `Unknown method: ${req.method}`);
523
801
  }
524
802
 
525
803
  function processSingleRequest(req) {
@@ -529,31 +807,32 @@ function processSingleRequest(req) {
529
807
  if (req.id === undefined || req.id === null) {
530
808
  return null;
531
809
  }
532
- return { jsonrpc: "2.0", id: req.id, result };
810
+ return { jsonrpc: '2.0', id: req.id, result };
533
811
  } catch (e) {
534
- const code = e && typeof e.code === "number" ? e.code : -32603;
535
- 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';
536
814
  if (req.id === undefined || req.id === null) {
537
815
  return {
538
- jsonrpc: "2.0",
816
+ jsonrpc: '2.0',
539
817
  id: null,
540
818
  error: { code, message },
541
819
  };
542
820
  }
543
821
  return {
544
- jsonrpc: "2.0",
822
+ jsonrpc: '2.0',
545
823
  id: req.id,
546
824
  error: { code, message },
547
825
  };
548
826
  }
549
827
  }
550
828
 
551
- rl.on("line", (line) => {
552
- if (line.length > 1048576) { // 1MB limit
829
+ rl.on('line', line => {
830
+ if (line.length > 1048576) {
831
+ // 1MB limit
553
832
  const errorRes = {
554
- jsonrpc: "2.0",
833
+ jsonrpc: '2.0',
555
834
  id: null,
556
- 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)' },
557
836
  };
558
837
  console.log(JSON.stringify(errorRes));
559
838
  return;
@@ -566,9 +845,9 @@ rl.on("line", (line) => {
566
845
  } catch (parseErr) {
567
846
  // Invalid JSON — send a parse error
568
847
  const errorRes = {
569
- jsonrpc: "2.0",
848
+ jsonrpc: '2.0',
570
849
  id: null,
571
- error: { code: -32700, message: "Parse error: " + parseErr.message },
850
+ error: { code: -32700, message: 'Parse error: ' + parseErr.message },
572
851
  };
573
852
  console.log(JSON.stringify(errorRes));
574
853
  return;
@@ -593,7 +872,7 @@ rl.on("line", (line) => {
593
872
  }
594
873
  });
595
874
 
596
- if (process.env.NODE_ENV === "test") {
875
+ if (process.env.NODE_ENV === 'test') {
597
876
  module.exports = {
598
877
  handleRequest,
599
878
  stripBoilerplate,