tribunal-kit 6.0.1 → 8.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 (434) 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/config/claude.json +18 -0
  55. package/.agent/config/plugin.json +102 -0
  56. package/.agent/config/slash-commands.json +103 -0
  57. package/.agent/config/specialist-registry.json +415 -0
  58. package/.agent/config/system-prompt.md +191 -0
  59. package/.agent/history/architecture-graph.yaml +302 -3
  60. package/.agent/history/graph-cache.json +515 -45
  61. package/.agent/history/memory/.memory.idx +1532 -1
  62. package/.agent/history/memory/MEMORY.md +102 -1
  63. package/.agent/history/memory.db +0 -0
  64. package/.agent/history/snapshots/bin__adapter-install.js.json +13 -0
  65. package/.agent/history/snapshots/bin__global-store.js.json +15 -0
  66. package/.agent/history/snapshots/bin__mcp-server.js.json +19 -0
  67. package/.agent/history/snapshots/bin__proxy-server.js.json +20 -0
  68. package/.agent/history/snapshots/bin__spawn-agent.js.json +12 -0
  69. package/.agent/history/snapshots/bin__tk-proxy.js.json +21 -0
  70. package/.agent/history/snapshots/bin__tribunal-kit.js.json +9 -7
  71. package/.agent/history/snapshots/bin__wrapper.js.json +14 -0
  72. package/.agent/history/snapshots/eslint.config.js.json +1 -2
  73. package/.agent/history/snapshots/scripts__benchmark.js.json +14 -0
  74. package/.agent/history/snapshots/scripts__changelog.js.json +1 -2
  75. package/.agent/history/snapshots/scripts__fix-vbc.js.json +11 -0
  76. package/.agent/history/snapshots/scripts__stress_benchmark.js.json +15 -0
  77. package/.agent/history/snapshots/scripts__sync-version.js.json +1 -2
  78. package/.agent/history/snapshots/scripts__validate-payload.js.json +1 -2
  79. package/.agent/history/snapshots/scripts__visual_audit.js.json +11 -0
  80. package/.agent/history/snapshots/test__integration__bridges.test.js.json +1 -2
  81. package/.agent/history/snapshots/test__integration__graceful_degradation.test.js.json +12 -0
  82. package/.agent/history/snapshots/test__integration__init.test.js.json +1 -2
  83. package/.agent/history/snapshots/test__integration__minimal_change_pipeline.test.js.json +13 -0
  84. package/.agent/history/snapshots/test__integration__parallel_tribunal.test.js.json +12 -0
  85. package/.agent/history/snapshots/test__integration__routing.test.js.json +1 -2
  86. package/.agent/history/snapshots/test__integration__swarm_dispatcher.test.js.json +1 -2
  87. package/.agent/history/snapshots/test__integration__sync_status.test.js.json +13 -0
  88. package/.agent/history/snapshots/test__integration__wave2.test.js.json +1 -2
  89. package/.agent/history/snapshots/test__integration__wrapper.test.js.json +13 -0
  90. package/.agent/history/snapshots/test__unit__align.test.js.json +10 -0
  91. package/.agent/history/snapshots/test__unit__args.test.js.json +3 -3
  92. package/.agent/history/snapshots/test__unit__audit_release.test.js.json +16 -0
  93. package/.agent/history/snapshots/test__unit__case_law_manager.test.js.json +1 -2
  94. package/.agent/history/snapshots/test__unit__cicd_validator.test.js.json +12 -0
  95. package/.agent/history/snapshots/test__unit__compile.test.js.json +10 -0
  96. package/.agent/history/snapshots/test__unit__context_broker.test.js.json +1 -2
  97. package/.agent/history/snapshots/test__unit__contract_engine.test.js.json +13 -0
  98. package/.agent/history/snapshots/test__unit__copyDir.test.js.json +3 -3
  99. package/.agent/history/snapshots/test__unit__graph_tools.test.js.json +1 -2
  100. package/.agent/history/snapshots/test__unit__guardrail_engine.test.js.json +10 -0
  101. package/.agent/history/snapshots/test__unit__impact_classifier.test.js.json +12 -0
  102. package/.agent/history/snapshots/test__unit__init.test.js.json +14 -0
  103. package/.agent/history/snapshots/test__unit__inner_loop_validator.test.js.json +1 -2
  104. package/.agent/history/snapshots/test__unit__integrity_manifest.test.js.json +13 -0
  105. package/.agent/history/snapshots/test__unit__learn.test.js.json +11 -0
  106. package/.agent/history/snapshots/test__unit__marathon.test.js.json +22 -0
  107. package/.agent/history/snapshots/test__unit__mcp_server.test.js.json +16 -0
  108. package/.agent/history/snapshots/test__unit__memory.test.js.json +13 -0
  109. package/.agent/history/snapshots/test__unit__minimal_change.test.js.json +10 -0
  110. package/.agent/history/snapshots/test__unit__native.test.js.json +10 -0
  111. package/.agent/history/snapshots/test__unit__optimize.test.js.json +13 -0
  112. package/.agent/history/snapshots/test__unit__path_resolution.test.js.json +14 -0
  113. package/.agent/history/snapshots/test__unit__production_readiness_evidence.test.js.json +21 -0
  114. package/.agent/history/snapshots/test__unit__selfInstall.test.js.json +3 -3
  115. package/.agent/history/snapshots/test__unit__semver.test.js.json +3 -3
  116. package/.agent/history/snapshots/test__unit__skill_evolution.test.js.json +11 -0
  117. package/.agent/history/snapshots/test__unit__stress.test.js.json +15 -0
  118. package/.agent/history/snapshots/test__unit__swarm_dispatcher.test.js.json +3 -3
  119. package/.agent/history/snapshots/test__unit__utils.test.js.json +10 -0
  120. package/.agent/mcp_config.json +1 -6
  121. package/.agent/routing_index.json +2033 -263
  122. package/.agent/rules/GEMINI.md +11 -9
  123. package/.agent/rules/GEMINI_PLANNER.md +19 -21
  124. package/.agent/scripts/_colors.js +52 -54
  125. package/.agent/scripts/_utils.js +52 -53
  126. package/.agent/scripts/ast_context_loader.js +137 -0
  127. package/.agent/scripts/auto_preview.js +39 -43
  128. package/.agent/scripts/bundle_analyzer.js +47 -60
  129. package/.agent/scripts/case_law_manager.js +200 -294
  130. package/.agent/scripts/checklist.js +73 -94
  131. package/.agent/scripts/cicd_validator.js +305 -0
  132. package/.agent/scripts/context_broker.js +317 -412
  133. package/.agent/scripts/contract_engine.js +402 -0
  134. package/.agent/scripts/dependency_analyzer.js +112 -124
  135. package/.agent/scripts/graph_builder.js +75 -103
  136. package/.agent/scripts/graph_visualizer.js +10 -12
  137. package/.agent/scripts/graph_zoom.js +38 -55
  138. package/.agent/scripts/guardrail_engine.js +195 -145
  139. package/.agent/scripts/impact_classifier.js +55 -30
  140. package/.agent/scripts/inner_loop_validator.js +108 -159
  141. package/.agent/scripts/integrity_manifest.js +59 -67
  142. package/.agent/scripts/lint_runner.js +65 -75
  143. package/.agent/scripts/marathon_harness.js +131 -208
  144. package/.agent/scripts/memory_engine.js +581 -0
  145. package/.agent/scripts/minify_context.js +29 -33
  146. package/.agent/scripts/minimal_change_engine.js +95 -87
  147. package/.agent/scripts/mutation_runner.js +46 -62
  148. package/.agent/scripts/payload_schemas.js +146 -0
  149. package/.agent/scripts/pipeline_engine.js +320 -209
  150. package/.agent/scripts/prompt_compiler.js +166 -93
  151. package/.agent/scripts/schema_validator.js +73 -121
  152. package/.agent/scripts/security_scan.js +88 -117
  153. package/.agent/scripts/session_manager.js +52 -69
  154. package/.agent/scripts/signal_detector.js +24 -22
  155. package/.agent/scripts/skill_evolution.js +184 -245
  156. package/.agent/scripts/skill_integrator.js +35 -48
  157. package/.agent/scripts/socratic_gate_policy.js +15 -12
  158. package/.agent/scripts/strengthen_skills.js +29 -33
  159. package/.agent/scripts/swarm_dispatcher.js +397 -200
  160. package/.agent/scripts/test_runner.js +54 -56
  161. package/.agent/scripts/token_budget_broker.js +126 -13
  162. package/.agent/scripts/trace_engine.js +126 -0
  163. package/.agent/scripts/verify_all.js +76 -93
  164. package/.agent/scripts/visual_audit.js +16 -21
  165. package/.agent/skill_topic_map.json +22 -3
  166. package/.agent/skills/12-principles-of-animation/SKILL.md +7 -0
  167. package/.agent/skills/60fps-animation/SKILL.md +7 -0
  168. package/.agent/skills/accessible-animation/SKILL.md +5 -1
  169. package/.agent/skills/adapt/SKILL.md +7 -1
  170. package/.agent/skills/advanced-rag-pipelines/SKILL.md +1 -0
  171. package/.agent/skills/agent-organizer/SKILL.md +1 -0
  172. package/.agent/skills/agentic-patterns/SKILL.md +33 -25
  173. package/.agent/skills/agentic-workflows-2026/SKILL.md +6 -2
  174. package/.agent/skills/ai-app-hardening/SKILL.md +9 -8
  175. package/.agent/skills/ai-prompt-injection-defense/SKILL.md +7 -6
  176. package/.agent/skills/animation-on-scroll/SKILL.md +24 -15
  177. package/.agent/skills/animation-systems/SKILL.md +11 -10
  178. package/.agent/skills/antfu-conventions/SKILL.md +7 -2
  179. package/.agent/skills/api-patterns/SKILL.md +14 -10
  180. package/.agent/skills/api-security-auditor/SKILL.md +15 -14
  181. package/.agent/skills/app-builder/SKILL.md +1 -0
  182. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +2 -2
  183. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
  184. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +12 -12
  185. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +3 -3
  186. package/.agent/skills/apple-design/SKILL.md +8 -7
  187. package/.agent/skills/architecture/SKILL.md +3 -2
  188. package/.agent/skills/audit-and-fix/SKILL.md +8 -5
  189. package/.agent/skills/authentication-best-practices/SKILL.md +9 -8
  190. package/.agent/skills/backend-security-expert/SKILL.md +1 -0
  191. package/.agent/skills/baseline-ui/SKILL.md +8 -7
  192. package/.agent/skills/bash-linux/SKILL.md +1 -0
  193. package/.agent/skills/behavioral-modes/SKILL.md +1 -0
  194. package/.agent/skills/better-colors/SKILL.md +11 -7
  195. package/.agent/skills/better-typography/SKILL.md +30 -16
  196. package/.agent/skills/better-ui/SKILL.md +17 -10
  197. package/.agent/skills/bolder/SKILL.md +6 -0
  198. package/.agent/skills/brainstorming/SKILL.md +6 -4
  199. package/.agent/skills/browser-native-ai/SKILL.md +5 -4
  200. package/.agent/skills/build-primitive/SKILL.md +5 -0
  201. package/.agent/skills/building-native-ui/SKILL.md +1 -0
  202. package/.agent/skills/cicd-pro/SKILL.md +2 -1
  203. package/.agent/skills/clarify/SKILL.md +19 -14
  204. package/.agent/skills/clean-code/SKILL.md +16 -15
  205. package/.agent/skills/cloud-architect/SKILL.md +1 -0
  206. package/.agent/skills/cobejs/SKILL.md +7 -9
  207. package/.agent/skills/code-review-checklist/SKILL.md +1 -0
  208. package/.agent/skills/codebase-design/SKILL.md +7 -2
  209. package/.agent/skills/colorize/SKILL.md +8 -3
  210. package/.agent/skills/compact-landing/SKILL.md +8 -3
  211. package/.agent/skills/company-logos/SKILL.md +6 -0
  212. package/.agent/skills/config-validator/SKILL.md +10 -9
  213. package/.agent/skills/containerization-pro/SKILL.md +6 -5
  214. package/.agent/skills/context-engineering-pro/SKILL.md +5 -4
  215. package/.agent/skills/create-design-md/SKILL.md +13 -5
  216. package/.agent/skills/critique/SKILL.md +10 -8
  217. package/.agent/skills/csharp-developer/SKILL.md +1 -0
  218. package/.agent/skills/data-validation-schemas/SKILL.md +28 -23
  219. package/.agent/skills/database-design/SKILL.md +2 -1
  220. package/.agent/skills/delight/SKILL.md +6 -0
  221. package/.agent/skills/deployment-procedures/SKILL.md +2 -1
  222. package/.agent/skills/design-lab/SKILL.md +5 -0
  223. package/.agent/skills/devops-engineer/SKILL.md +3 -2
  224. package/.agent/skills/devops-incident-responder/SKILL.md +2 -1
  225. package/.agent/skills/diagnosing-bugs/SKILL.md +12 -2
  226. package/.agent/skills/distill/SKILL.md +7 -2
  227. package/.agent/skills/documentation-templates/SKILL.md +3 -2
  228. package/.agent/skills/domain-modeling/SKILL.md +12 -4
  229. package/.agent/skills/duckdb-analytical-sql/SKILL.md +7 -3
  230. package/.agent/skills/edge-ai-mobile/SKILL.md +5 -1
  231. package/.agent/skills/edge-computing/SKILL.md +9 -8
  232. package/.agent/skills/emil-design-eng/SKILL.md +43 -27
  233. package/.agent/skills/error-resilience/SKILL.md +34 -16
  234. package/.agent/skills/expo-router-v4/SKILL.md +2 -1
  235. package/.agent/skills/extract-design-system/SKILL.md +12 -11
  236. package/.agent/skills/fabel-protocol/SKILL.md +24 -17
  237. package/.agent/skills/fixing-accessibility/SKILL.md +23 -16
  238. package/.agent/skills/fixing-metadata/SKILL.md +24 -13
  239. package/.agent/skills/fixing-motion-performance/SKILL.md +7 -5
  240. package/.agent/skills/framer-motion-expert/SKILL.md +29 -15
  241. package/.agent/skills/frontend-design/SKILL.md +21 -13
  242. package/.agent/skills/frontend-security-expert/SKILL.md +1 -0
  243. package/.agent/skills/game-design-expert/SKILL.md +1 -0
  244. package/.agent/skills/game-engineering-expert/SKILL.md +1 -0
  245. package/.agent/skills/generative-ui-expert/SKILL.md +3 -2
  246. package/.agent/skills/geo-fundamentals/SKILL.md +2 -1
  247. package/.agent/skills/git-pro/SKILL.md +10 -9
  248. package/.agent/skills/github-operations/SKILL.md +2 -1
  249. package/.agent/skills/gpt-taste/SKILL.md +7 -0
  250. package/.agent/skills/gsap-core/SKILL.md +26 -22
  251. package/.agent/skills/gsap-frameworks/SKILL.md +6 -5
  252. package/.agent/skills/gsap-performance/SKILL.md +4 -3
  253. package/.agent/skills/gsap-plugins/SKILL.md +34 -33
  254. package/.agent/skills/gsap-react/SKILL.md +9 -8
  255. package/.agent/skills/gsap-scrolltrigger/SKILL.md +34 -33
  256. package/.agent/skills/gsap-timeline/SKILL.md +18 -15
  257. package/.agent/skills/gsap-utils/SKILL.md +25 -24
  258. package/.agent/skills/harden/SKILL.md +9 -3
  259. package/.agent/skills/harness-protocol/SKILL.md +1 -0
  260. package/.agent/skills/i18n-localization/SKILL.md +10 -9
  261. package/.agent/skills/impeccable/SKILL.md +5 -0
  262. package/.agent/skills/improve-codebase-architecture/SKILL.md +10 -5
  263. package/.agent/skills/improve-ui/SKILL.md +12 -5
  264. package/.agent/skills/intelligent-routing/SKILL.md +7 -6
  265. package/.agent/skills/knowledge-graph/SKILL.md +1 -0
  266. package/.agent/skills/landing-page/SKILL.md +1 -0
  267. package/.agent/skills/lint-and-validate/SKILL.md +9 -4
  268. package/.agent/skills/llm-engineering/SKILL.md +55 -54
  269. package/.agent/skills/local-first/SKILL.md +20 -19
  270. package/.agent/skills/local-first-architecture/SKILL.md +6 -1
  271. package/.agent/skills/lottie-animation/SKILL.md +7 -3
  272. package/.agent/skills/marquee-loop/SKILL.md +1 -0
  273. package/.agent/skills/masked-reveal/SKILL.md +17 -4
  274. package/.agent/skills/mcp-builder/SKILL.md +13 -10
  275. package/.agent/skills/micro-interaction/SKILL.md +20 -5
  276. package/.agent/skills/mobile-design/SKILL.md +26 -15
  277. package/.agent/skills/monorepo-management/SKILL.md +3 -2
  278. package/.agent/skills/morphing-icons/SKILL.md +16 -6
  279. package/.agent/skills/motion-engineering/SKILL.md +19 -15
  280. package/.agent/skills/nextjs-react-expert/SKILL.md +26 -21
  281. package/.agent/skills/nodejs-best-practices/SKILL.md +89 -76
  282. package/.agent/skills/observability/SKILL.md +45 -44
  283. package/.agent/skills/opentelemetry-observability/SKILL.md +2 -1
  284. package/.agent/skills/page-transition-animation/SKILL.md +6 -3
  285. package/.agent/skills/parallel-agents/SKILL.md +7 -2
  286. package/.agent/skills/performance-profiling/SKILL.md +24 -13
  287. package/.agent/skills/plan-writing/SKILL.md +1 -0
  288. package/.agent/skills/platform-engineer/SKILL.md +3 -2
  289. package/.agent/skills/platform-engineering-opentofu/SKILL.md +1 -0
  290. package/.agent/skills/playwright-ai-e2e/SKILL.md +3 -2
  291. package/.agent/skills/playwright-best-practices/SKILL.md +29 -28
  292. package/.agent/skills/polish/SKILL.md +13 -12
  293. package/.agent/skills/powershell-windows/SKILL.md +1 -0
  294. package/.agent/skills/pricing-page/SKILL.md +8 -3
  295. package/.agent/skills/product-aware-heuristics/SKILL.md +122 -72
  296. package/.agent/skills/progressive-blur/SKILL.md +9 -4
  297. package/.agent/skills/project-idioms/SKILL.md +1 -0
  298. package/.agent/skills/property-based-testing/SKILL.md +10 -12
  299. package/.agent/skills/python-patterns/SKILL.md +1 -0
  300. package/.agent/skills/python-pro/SKILL.md +1 -0
  301. package/.agent/skills/quieter/SKILL.md +6 -0
  302. package/.agent/skills/react-doctor/SKILL.md +6 -0
  303. package/.agent/skills/react-specialist/SKILL.md +32 -28
  304. package/.agent/skills/readme-builder/SKILL.md +1 -0
  305. package/.agent/skills/realtime-patterns/SKILL.md +34 -33
  306. package/.agent/skills/red-team-tactics/SKILL.md +1 -0
  307. package/.agent/skills/redesign-skill/SKILL.md +6 -0
  308. package/.agent/skills/review-animations/SKILL.md +5 -2
  309. package/.agent/skills/review-animations/STANDARDS.md +37 -23
  310. package/.agent/skills/rust-pro/SKILL.md +1 -0
  311. package/.agent/skills/seo-fundamentals/SKILL.md +4 -3
  312. package/.agent/skills/server-management/SKILL.md +1 -0
  313. package/.agent/skills/shadcn-ui-expert/SKILL.md +28 -22
  314. package/.agent/skills/shape/SKILL.md +9 -2
  315. package/.agent/skills/skill-creator/SKILL.md +1 -0
  316. package/.agent/skills/soft-skill/SKILL.md +6 -0
  317. package/.agent/skills/sounds-on-the-web/SKILL.md +1 -0
  318. package/.agent/skills/sql-pro/SKILL.md +1 -0
  319. package/.agent/skills/supabase-postgres-best-practices/SKILL.md +1 -0
  320. package/.agent/skills/svg-animation/SKILL.md +16 -7
  321. package/.agent/skills/swiftui-expert/SKILL.md +1 -0
  322. package/.agent/skills/swiss-design/SKILL.md +5 -0
  323. package/.agent/skills/system-design-pro/SKILL.md +1 -0
  324. package/.agent/skills/systematic-debugging/SKILL.md +1 -0
  325. package/.agent/skills/tailwind-patterns/SKILL.md +25 -11
  326. package/.agent/skills/taste-skill/SKILL.md +6 -0
  327. package/.agent/skills/tdd-workflow/SKILL.md +5 -0
  328. package/.agent/skills/test-result-analyzer/SKILL.md +1 -0
  329. package/.agent/skills/testing-patterns/SKILL.md +123 -115
  330. package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +5 -0
  331. package/.agent/skills/thinking-protocol/SKILL.md +3 -0
  332. package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +9 -8
  333. package/.agent/skills/transitions-dev/SKILL.md +19 -6
  334. package/.agent/skills/trend-researcher/SKILL.md +1 -0
  335. package/.agent/skills/typescript-advanced/SKILL.md +23 -18
  336. package/.agent/skills/typeset/SKILL.md +10 -1
  337. package/.agent/skills/ui-reasoning-engine/SKILL.md +67 -48
  338. package/.agent/skills/ui-skill-packs/SKILL.md +6 -1
  339. package/.agent/skills/ui-skills-root/SKILL.md +39 -38
  340. package/.agent/skills/ui-ux-pro-max/SKILL.md +34 -26
  341. package/.agent/skills/ui-ux-researcher/SKILL.md +1 -0
  342. package/.agent/skills/vector-search-pgvector/SKILL.md +3 -2
  343. package/.agent/skills/vue-expert/SKILL.md +22 -19
  344. package/.agent/skills/vulnerability-scanner/SKILL.md +22 -21
  345. package/.agent/skills/web-accessibility-auditor/SKILL.md +2 -1
  346. package/.agent/skills/web-design-guidelines/SKILL.md +16 -10
  347. package/.agent/skills/web-quality-audit/SKILL.md +5 -0
  348. package/.agent/skills/webapp-testing/SKILL.md +14 -13
  349. package/.agent/skills/webgpu-performance/SKILL.md +1 -0
  350. package/.agent/skills/whimsy-injector/SKILL.md +9 -5
  351. package/.agent/skills/workflow-optimizer/SKILL.md +1 -0
  352. package/.agent/skills/zero-trust-passkeys/SKILL.md +11 -6
  353. package/.agent/templates/DESIGN.md +119 -110
  354. package/.agent/templates/design-tokens.json +9 -6
  355. package/.agent/workflows/acf.md +1 -0
  356. package/.agent/workflows/api-tester.md +1 -0
  357. package/.agent/workflows/audit.md +1 -0
  358. package/.agent/workflows/brainstorm.md +1 -0
  359. package/.agent/workflows/changelog.md +1 -0
  360. package/.agent/workflows/contract.md +60 -0
  361. package/.agent/workflows/create.md +1 -0
  362. package/.agent/workflows/debug.md +1 -0
  363. package/.agent/workflows/deploy.md +1 -0
  364. package/.agent/workflows/enhance.md +1 -0
  365. package/.agent/workflows/fix-ci.md +89 -0
  366. package/.agent/workflows/fix.md +1 -0
  367. package/.agent/workflows/generate.md +1 -0
  368. package/.agent/workflows/marathon.md +1 -0
  369. package/.agent/workflows/migrate.md +1 -0
  370. package/.agent/workflows/minimal.md +9 -7
  371. package/.agent/workflows/orchestrate.md +1 -0
  372. package/.agent/workflows/performance-benchmarker.md +1 -0
  373. package/.agent/workflows/pipeline.md +26 -21
  374. package/.agent/workflows/plan.md +1 -0
  375. package/.agent/workflows/preview.md +1 -0
  376. package/.agent/workflows/refactor.md +3 -2
  377. package/.agent/workflows/review-ai.md +4 -3
  378. package/.agent/workflows/review.md +1 -0
  379. package/.agent/workflows/session.md +1 -0
  380. package/.agent/workflows/status.md +1 -0
  381. package/.agent/workflows/strengthen-skills.md +1 -0
  382. package/.agent/workflows/super-prompt.md +1 -0
  383. package/.agent/workflows/swarm.md +15 -3
  384. package/.agent/workflows/test.md +8 -7
  385. package/.agent/workflows/tribunal-backend.md +3 -2
  386. package/.agent/workflows/tribunal-cicd.md +104 -0
  387. package/.agent/workflows/tribunal-database.md +1 -0
  388. package/.agent/workflows/tribunal-frontend.md +8 -6
  389. package/.agent/workflows/tribunal-full.md +2 -1
  390. package/.agent/workflows/tribunal-mobile.md +6 -5
  391. package/.agent/workflows/tribunal-performance.md +1 -0
  392. package/.agent/workflows/tribunal-speed.md +1 -0
  393. package/.agent/workflows/tribunal-ui.md +29 -21
  394. package/.agent/workflows/ui-ux-pro-max.md +19 -15
  395. package/.claude/CLAUDE.md +442 -0
  396. package/CONTRIBUTING.md +3 -3
  397. package/README.md +105 -45
  398. package/SECURITY.md +11 -11
  399. package/bin/adapter-install.js +240 -0
  400. package/bin/global-store.js +48 -0
  401. package/bin/mcp-server.js +781 -332
  402. package/bin/proxy-server.js +113 -0
  403. package/bin/spawn-agent.js +39 -0
  404. package/bin/tk-proxy.js +34 -0
  405. package/bin/tribunal-kit.js +29 -30
  406. package/bin/wrapper.js +40 -46
  407. package/dist/cli.js +6 -0
  408. package/dist/commands/case.js +2 -0
  409. package/dist/commands/contract.js +440 -0
  410. package/dist/commands/init.js +8 -51
  411. package/dist/commands/status.js +61 -30
  412. package/dist/commands/validate.js +22 -31
  413. package/dist/index.d.ts +8 -1
  414. package/dist/tui/banner.js +77 -0
  415. package/dist/tui/index.js +21 -0
  416. package/dist/tui/reviewer-grid.js +90 -0
  417. package/dist/tui/shimmer.js +91 -0
  418. package/dist/tui/theme.js +130 -0
  419. package/dist/tui/tree.js +93 -0
  420. package/dist/tui/wizard.js +148 -0
  421. package/dist/utils/helpers.js +5 -41
  422. package/package.json +33 -15
  423. package/scripts/benchmark.js +62 -86
  424. package/scripts/build-graph.js +71 -0
  425. package/scripts/changelog.js +67 -73
  426. package/scripts/fix-vbc.js +13 -15
  427. package/scripts/fix-vbc.ps1 +2 -118
  428. package/scripts/stress_benchmark.js +358 -0
  429. package/scripts/sync-version.js +71 -41
  430. package/scripts/validate-payload.js +23 -30
  431. package/scripts/visual_audit.js +23 -13
  432. package/.agent/history/snapshots/migrate_refs.js.json +0 -11
  433. package/.agent/scripts/compile_router.py +0 -112
  434. package/.agent/scripts/migrate_skills_frontmatter.py +0 -64
package/bin/mcp-server.js CHANGED
@@ -13,16 +13,79 @@
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
+ const GENERAL_TOOL_TIMEOUT_MS = 60000;
24
+
25
+ // --- DSH Guard: Cooperative Timeout ---
26
+ async function withToolTimeout(fn, timeoutMs) {
27
+ let timeoutId;
28
+ const timeoutPromise = new Promise((_, reject) => {
29
+ timeoutId = setTimeout(() => {
30
+ reject(new Error('TOOL_TIMEOUT'));
31
+ }, timeoutMs);
32
+ });
33
+
34
+ try {
35
+ const result = await Promise.race([Promise.resolve().then(fn), timeoutPromise]);
36
+ return result;
37
+ } finally {
38
+ clearTimeout(timeoutId);
39
+ }
40
+ }
41
+
42
+ // --- DSH Guard: Loop Detection ---
43
+ class ToolRepeatGuard {
44
+ constructor() {
45
+ this.history = new Map();
46
+ }
47
+
48
+ observe(toolName, argsObj) {
49
+ const canonicalize = obj => {
50
+ if (Array.isArray(obj)) return obj.map(canonicalize);
51
+ if (obj !== null && typeof obj === 'object') {
52
+ const sorted = {};
53
+ for (const key of Object.keys(obj).sort()) {
54
+ sorted[key] = canonicalize(obj[key]);
55
+ }
56
+ return sorted;
57
+ }
58
+ return obj;
59
+ };
60
+
61
+ const canonicalArgs = JSON.stringify(canonicalize(argsObj) || {});
62
+ const key = `${toolName}::${canonicalArgs}`;
63
+
64
+ const currentCount = (this.history.get(key) || 0) + 1;
65
+ this.history.clear();
66
+ this.history.set(key, currentCount);
67
+
68
+ if (currentCount === 3) {
69
+ return 'SYSTEM NOTIFICATION: You are repeating the exact same tool call with identical arguments. Carefully analyze the previous result before calling again: if the task is not complete, try a different approach or different arguments instead of repeating the call.';
70
+ }
71
+ if (currentCount >= 5) {
72
+ return `SYSTEM NOTIFICATION: Repeated tool call detected:\n- tool: ${toolName}\n- consecutive_calls: ${currentCount}\n- arguments: ${canonicalArgs}\nThe repeated calls are not making progress. Do not call this tool with these exact arguments again. Inspect the latest result and choose a different action, different arguments, or finish the task.`;
73
+ }
74
+ return null;
75
+ }
76
+ }
77
+ const repeatGuard = new ToolRepeatGuard();
78
+
79
+ class RpcError extends Error {
80
+ constructor(code, message) {
81
+ super(message);
82
+ this.code = code;
83
+ this.name = 'RpcError';
84
+ }
85
+ }
23
86
 
24
87
  // Minimal JSON-RPC 2.0 over stdio
25
- const readline = require("readline");
88
+ const readline = require('readline');
26
89
 
27
90
  const rl = readline.createInterface({
28
91
  input: process.stdin,
@@ -36,17 +99,12 @@ const rl = readline.createInterface({
36
99
  * explicitly supplied payload and schema.
37
100
  */
38
101
  function runTribunalAudit() {
39
- const fs = require("fs");
102
+ const fs = require('fs');
40
103
  const projectRoot = process.cwd();
41
- const manifestScript = path.join(
42
- projectRoot,
43
- ".agent",
44
- "scripts",
45
- "integrity_manifest.js",
46
- );
104
+ const manifestScript = path.join(projectRoot, '.agent', 'scripts', 'integrity_manifest.js');
47
105
 
48
106
  if (!fs.existsSync(manifestScript)) {
49
- return "Error: .agent/scripts/integrity_manifest.js was not found. Run `tk init` first.";
107
+ return 'Error: .agent/scripts/integrity_manifest.js was not found. Run `tk init` first.';
50
108
  }
51
109
 
52
110
  try {
@@ -56,7 +114,7 @@ function runTribunalAudit() {
56
114
 
57
115
  const { integrity } = manifest;
58
116
  const lines = [
59
- "Tribunal audit complete.",
117
+ 'Tribunal audit complete.',
60
118
  `Agents: ${manifest.agents.total} (${manifest.agents.reviewer_count} reviewers)`,
61
119
  `Skills: ${manifest.skills.total}`,
62
120
  `Scripts: ${manifest.scripts.total}`,
@@ -66,11 +124,13 @@ function runTribunalAudit() {
66
124
  ];
67
125
 
68
126
  if (integrity.phantom_references > 0 || integrity.invalid_claims > 0) {
69
- lines.push("Audit found integrity issues; run `tk guardrail --scan` for remediation details.");
127
+ lines.push(
128
+ 'Audit found integrity issues; run `tk guardrail --scan` for remediation details.',
129
+ );
70
130
  } else {
71
- lines.push("All discovered references and global asset-count claims are valid.");
131
+ lines.push('All discovered references and global asset-count claims are valid.');
72
132
  }
73
- return lines.join("\n");
133
+ return lines.join('\n');
74
134
  } catch (error) {
75
135
  return `Audit failed: ${error.message}`;
76
136
  }
@@ -80,100 +140,96 @@ function runTribunalAudit() {
80
140
  * Search case law in an isolated process because its CLI owns persistent state.
81
141
  */
82
142
  function searchCaseLaw(query) {
83
- const caseLawScript = path.resolve(
84
- __dirname,
85
- "../.agent/scripts/case_law_manager.js",
86
- );
143
+ const caseLawScript = path.resolve(__dirname, '../.agent/scripts/case_law_manager.js');
87
144
  // 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
- );
145
+ const result = spawnSync(process.execPath, [caseLawScript, 'search-cases', '--query', query], {
146
+ encoding: 'utf8',
147
+ timeout: SPAWN_TIMEOUT_MS,
148
+ });
96
149
  if (result.error) {
97
- if (result.error.code === "ETIMEDOUT") return "Error: Case law search timed out (exceeded 30s limit)";
150
+ if (result.error.code === 'ETIMEDOUT')
151
+ return 'Error: Case law search timed out (exceeded 30s limit)';
98
152
  return `Error executing case law search: ${result.error.message}`;
99
153
  }
100
- return result.stdout || result.stderr || "No results";
154
+ return result.stdout || result.stderr || 'No results';
101
155
  }
102
156
 
103
-
104
157
  function stripBoilerplate(text) {
105
158
  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, "");
159
+ let minified = text.replace(
160
+ /AI coding assistants often fall into specific bad habits[\s\S]*$/g,
161
+ '',
162
+ );
163
+ minified = minified.replace(/## 🤖 LLM-Specific Traps[\s\S]*$/g, '');
164
+ minified = minified.replace(/## 🏛️ Tribunal Integration[\s\S]*$/g, '');
165
+ minified = minified.replace(/## Pre-Flight Checklist[\s\S]*$/g, '');
110
166
  return minified.trim();
111
167
  }
112
168
 
113
169
  function getAgentDir() {
114
- const fs = require("fs");
115
- const local = path.join(process.cwd(), ".agent");
170
+ const fs = require('fs');
171
+ const local = path.join(process.cwd(), '.agent');
116
172
  if (fs.existsSync(local)) return local;
117
- return path.resolve(__dirname, "../.agent");
173
+ return path.resolve(__dirname, '../.agent');
118
174
  }
119
175
 
120
- function handleRequest(req) {
121
- const fs = require("fs");
122
- if (req.method === "notifications/initialized" || req.method === "notifications/cancelled") {
176
+ async function handleRequest(req) {
177
+ const fs = require('fs');
178
+ if (req.method === 'notifications/initialized' || req.method === 'notifications/cancelled') {
123
179
  return null;
124
180
  }
125
- if (req.method === "ping") {
181
+ if (req.method === 'ping') {
126
182
  return {};
127
183
  }
128
184
 
129
185
  // MCP spec: method names follow path-style convention
130
- if (req.method === "initialize") {
186
+ if (req.method === 'initialize') {
131
187
  return {
132
- protocolVersion: "2025-03-26",
188
+ protocolVersion: '2025-03-26',
133
189
  capabilities: {
134
190
  tools: {},
135
191
  resources: { subscribe: false, listChanged: false },
136
192
  prompts: { listChanged: false },
137
193
  },
138
194
  serverInfo: {
139
- name: "tribunal-kit-mcp",
195
+ name: 'tribunal-kit-mcp',
140
196
  version: PKG.version,
141
197
  },
142
198
  };
143
199
  }
144
200
 
145
- if (req.method === "resources/list") {
201
+ if (req.method === 'resources/list') {
146
202
  const agentDir = getAgentDir();
147
203
  const resources = [];
148
-
204
+
149
205
  // Agents
150
- const agentsDir = path.join(agentDir, "agents");
206
+ const agentsDir = path.join(agentDir, 'agents');
151
207
  if (fs.existsSync(agentsDir)) {
152
- const files = fs.readdirSync(agentsDir).filter((f) => f.endsWith(".md"));
208
+ const files = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
153
209
  for (const f of files) {
154
- const name = path.basename(f, ".md");
210
+ const name = path.basename(f, '.md');
155
211
  resources.push({
156
212
  uri: `tribunal://agent/${name}`,
157
213
  name: `Agent: ${name}`,
158
214
  description: `Tribunal Specialist Agent rule file for ${name}`,
159
- mimeType: "text/markdown",
215
+ mimeType: 'text/markdown',
160
216
  });
161
217
  }
162
218
  }
163
219
 
164
220
  // Skills
165
- const skillsDir = path.join(agentDir, "skills");
221
+ const skillsDir = path.join(agentDir, 'skills');
166
222
  if (fs.existsSync(skillsDir)) {
167
223
  const dirs = fs.readdirSync(skillsDir, { withFileTypes: true });
168
224
  for (const d of dirs) {
169
225
  if (d.isDirectory()) {
170
- const skillFile = path.join(skillsDir, d.name, "SKILL.md");
226
+ const skillFile = path.join(skillsDir, d.name, 'SKILL.md');
171
227
  if (fs.existsSync(skillFile)) {
172
228
  resources.push({
173
229
  uri: `tribunal://skill/${d.name}`,
174
230
  name: `Skill: ${d.name}`,
175
231
  description: `Tribunal Skill instruction file for ${d.name}`,
176
- mimeType: "text/markdown",
232
+ mimeType: 'text/markdown',
177
233
  });
178
234
  }
179
235
  }
@@ -181,16 +237,16 @@ function handleRequest(req) {
181
237
  }
182
238
 
183
239
  // Workflows
184
- const workflowsDir = path.join(agentDir, "workflows");
240
+ const workflowsDir = path.join(agentDir, 'workflows');
185
241
  if (fs.existsSync(workflowsDir)) {
186
- const files = fs.readdirSync(workflowsDir).filter((f) => f.endsWith(".md"));
242
+ const files = fs.readdirSync(workflowsDir).filter(f => f.endsWith('.md'));
187
243
  for (const f of files) {
188
- const name = path.basename(f, ".md");
244
+ const name = path.basename(f, '.md');
189
245
  resources.push({
190
246
  uri: `tribunal://workflow/${name}`,
191
247
  name: `Workflow: ${name}`,
192
248
  description: `Tribunal Workflow guide for ${name}`,
193
- mimeType: "text/markdown",
249
+ mimeType: 'text/markdown',
194
250
  });
195
251
  }
196
252
  }
@@ -198,55 +254,55 @@ function handleRequest(req) {
198
254
  return { resources };
199
255
  }
200
256
 
201
- if (req.method === "resources/read") {
257
+ if (req.method === 'resources/read') {
202
258
  const uri = req.params && req.params.uri;
203
- if (!uri) throw new Error("Missing uri parameter");
259
+ if (!uri) throw new Error('Missing uri parameter');
204
260
  const agentDir = getAgentDir();
205
261
  let filePath = null;
206
262
 
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`);
263
+ if (uri.startsWith('tribunal://agent/')) {
264
+ const name = uri.replace('tribunal://agent/', '');
265
+ filePath = path.join(agentDir, 'agents', `${name}.md`);
266
+ } else if (uri.startsWith('tribunal://skill/')) {
267
+ const name = uri.replace('tribunal://skill/', '');
268
+ filePath = path.join(agentDir, 'skills', name, 'SKILL.md');
269
+ } else if (uri.startsWith('tribunal://workflow/')) {
270
+ const name = uri.replace('tribunal://workflow/', '');
271
+ filePath = path.join(agentDir, 'workflows', `${name}.md`);
216
272
  }
217
273
 
218
274
  if (!filePath || !fs.existsSync(filePath)) {
219
275
  throw new Error(`Resource not found: ${uri}`);
220
276
  }
221
277
 
222
- const text = fs.readFileSync(filePath, "utf8");
278
+ const text = fs.readFileSync(filePath, 'utf8');
223
279
  return {
224
280
  contents: [
225
281
  {
226
282
  uri,
227
- mimeType: "text/markdown",
283
+ mimeType: 'text/markdown',
228
284
  text,
229
285
  },
230
286
  ],
231
287
  };
232
288
  }
233
289
 
234
- if (req.method === "prompts/list") {
290
+ if (req.method === 'prompts/list') {
235
291
  const agentDir = getAgentDir();
236
292
  const prompts = [];
237
- const workflowsDir = path.join(agentDir, "workflows");
293
+ const workflowsDir = path.join(agentDir, 'workflows');
238
294
 
239
295
  if (fs.existsSync(workflowsDir)) {
240
- const files = fs.readdirSync(workflowsDir).filter((f) => f.endsWith(".md"));
296
+ const files = fs.readdirSync(workflowsDir).filter(f => f.endsWith('.md'));
241
297
  for (const f of files) {
242
- const name = path.basename(f, ".md");
298
+ const name = path.basename(f, '.md');
243
299
  prompts.push({
244
300
  name,
245
301
  description: `Execute tribunal workflow /${name}`,
246
302
  arguments: [
247
303
  {
248
- name: "task",
249
- description: "The task or target file to execute the workflow against",
304
+ name: 'task',
305
+ description: 'The task or target file to execute the workflow against',
250
306
  required: false,
251
307
  },
252
308
  ],
@@ -257,26 +313,26 @@ function handleRequest(req) {
257
313
  return { prompts };
258
314
  }
259
315
 
260
- if (req.method === "prompts/get") {
316
+ if (req.method === 'prompts/get') {
261
317
  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");
318
+ const task = (req.params && req.params.arguments && req.params.arguments.task) || '';
319
+ if (!name) throw new Error('Missing prompt name parameter');
264
320
 
265
321
  const agentDir = getAgentDir();
266
- const workflowPath = path.join(agentDir, "workflows", `${name}.md`);
322
+ const workflowPath = path.join(agentDir, 'workflows', `${name}.md`);
267
323
  if (!fs.existsSync(workflowPath)) {
268
324
  throw new Error(`Prompt workflow not found: ${name}`);
269
325
  }
270
326
 
271
- const content = fs.readFileSync(workflowPath, "utf8");
327
+ const content = fs.readFileSync(workflowPath, 'utf8');
272
328
  const promptText = task ? `${content}\n\nTarget Task/File: ${task}` : content;
273
329
 
274
330
  return {
275
331
  messages: [
276
332
  {
277
- role: "user",
333
+ role: 'user',
278
334
  content: {
279
- type: "text",
335
+ type: 'text',
280
336
  text: promptText,
281
337
  },
282
338
  },
@@ -284,168 +340,224 @@ function handleRequest(req) {
284
340
  };
285
341
  }
286
342
 
287
- if (req.method === "tools/list") {
343
+ if (req.method === 'tools/list') {
288
344
  return {
289
345
  tools: [
290
346
  {
291
- name: "run_tribunal_audit",
292
- description:
293
- "Runs a full anti-hallucination audit across the workspace.",
347
+ name: 'run_tribunal_audit',
348
+ description: 'Runs a full anti-hallucination audit across the workspace.',
294
349
  inputSchema: {
295
- type: "object",
350
+ type: 'object',
296
351
  properties: {},
297
352
  additionalProperties: false,
298
353
  },
299
354
  },
300
355
  {
301
- name: "sync_ide_bridges",
302
- description:
303
- "Synchronize IDE bridge files with the current GEMINI.md rules.",
356
+ name: 'sync_ide_bridges',
357
+ description: 'Synchronize IDE bridge files with the current GEMINI.md rules.',
304
358
  inputSchema: {
305
- type: "object",
359
+ type: 'object',
306
360
  properties: {},
307
361
  additionalProperties: false,
308
362
  },
309
363
  },
310
364
  {
311
- name: "search_case_law",
365
+ name: 'search_case_law',
312
366
  description:
313
- "Search historical code rejections and legal precedent. Use this before writing code to avoid past mistakes.",
367
+ 'Search historical code rejections and legal precedent. Use this before writing code to avoid past mistakes.',
314
368
  inputSchema: {
315
- type: "object",
369
+ type: 'object',
316
370
  properties: {
317
371
  query: {
318
- type: "string",
372
+ type: 'string',
319
373
  description: "Search query (e.g. 'useEffect state')",
320
374
  },
321
375
  },
322
- required: ["query"],
376
+ required: ['query'],
323
377
  additionalProperties: false,
324
378
  },
325
379
  },
326
380
  {
327
- name: "list_tribunal_agents",
328
- description: "List all available Tribunal Kit agents.",
381
+ name: 'list_tribunal_agents',
382
+ description: 'List all available Tribunal Kit agents.',
329
383
  inputSchema: {
330
- type: "object",
384
+ type: 'object',
331
385
  properties: {},
332
386
  additionalProperties: false,
333
387
  },
334
388
  },
335
389
  {
336
- name: "get_tribunal_agent",
337
- description: "Get the full markdown rules for a specific Tribunal agent.",
390
+ name: 'get_tribunal_agent',
391
+ description: 'Get the full markdown rules for a specific Tribunal agent.',
338
392
  inputSchema: {
339
- type: "object",
393
+ type: 'object',
340
394
  properties: {
341
- name: { type: "string", description: "The agent name (e.g. 'frontend-specialist')" },
395
+ name: { type: 'string', description: "The agent name (e.g. 'frontend-specialist')" },
342
396
  },
343
- required: ["name"],
397
+ required: ['name'],
344
398
  additionalProperties: false,
345
399
  },
346
400
  },
347
401
  {
348
- name: "list_tribunal_skills",
349
- description: "List all available Tribunal Kit skills.",
402
+ name: 'list_tribunal_skills',
403
+ description: 'List all available Tribunal Kit skills.',
350
404
  inputSchema: {
351
- type: "object",
405
+ type: 'object',
352
406
  properties: {},
353
407
  additionalProperties: false,
354
408
  },
355
409
  },
356
410
  {
357
- name: "get_tribunal_skill",
358
- description: "Get the full markdown instructions for a specific Tribunal skill.",
411
+ name: 'get_tribunal_skill',
412
+ description: 'Get the full markdown instructions for a specific Tribunal skill.',
359
413
  inputSchema: {
360
- type: "object",
414
+ type: 'object',
361
415
  properties: {
362
- name: { type: "string", description: "The skill name (e.g. 'react-specialist')" },
416
+ name: { type: 'string', description: "The skill name (e.g. 'react-specialist')" },
363
417
  },
364
- required: ["name"],
418
+ required: ['name'],
365
419
  additionalProperties: false,
366
420
  },
367
421
  },
368
422
  {
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.",
423
+ name: 'recall_memory',
424
+ description:
425
+ '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
426
  inputSchema: {
372
- type: "object",
427
+ type: 'object',
373
428
  properties: {
374
429
  query: {
375
- type: "string",
430
+ type: 'string',
376
431
  description: "Search query (e.g. 'database', 'auth', 'deploy')",
377
432
  },
378
433
  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.",
434
+ type: 'number',
435
+ description:
436
+ 'Maximum token budget for recall (default: 2000). Only the top-ranked memories that fit within this budget are returned.',
381
437
  },
382
438
  },
383
- required: ["query"],
439
+ required: ['query'],
384
440
  additionalProperties: false,
385
441
  },
386
442
  },
387
443
  {
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).",
444
+ name: 'store_memory',
445
+ description:
446
+ '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
447
  inputSchema: {
391
- type: "object",
448
+ type: 'object',
392
449
  properties: {
393
450
  type: {
394
- type: "string",
395
- enum: ["semantic", "procedural", "episodic", "working"],
396
- description: "Memory type: semantic (facts), procedural (recipes), episodic (events), working (scratch)",
451
+ type: 'string',
452
+ enum: ['semantic', 'procedural', 'episodic', 'working'],
453
+ description:
454
+ 'Memory type: semantic (facts), procedural (recipes), episodic (events), working (scratch)',
397
455
  },
398
456
  content: {
399
- type: "string",
400
- description: "The memory content to store",
457
+ type: 'string',
458
+ description: 'The memory content to store',
401
459
  },
402
460
  tags: {
403
- type: "array",
404
- items: { type: "string" },
405
- description: "Searchable tags for this memory",
461
+ type: 'array',
462
+ items: { type: 'string' },
463
+ description: 'Searchable tags for this memory',
406
464
  },
407
465
  },
408
- required: ["type", "content"],
466
+ required: ['type', 'content'],
409
467
  additionalProperties: false,
410
468
  },
411
469
  },
412
470
  {
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.",
471
+ name: 'get_sparse_context',
472
+ description:
473
+ '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
474
  inputSchema: {
416
- type: "object",
475
+ type: 'object',
417
476
  properties: {
418
477
  task: {
419
- type: "string",
478
+ type: 'string',
420
479
  description: "The user task description (e.g. 'JWT auth API')",
421
480
  },
422
481
  files: {
423
- type: "array",
424
- items: { type: "string" },
482
+ type: 'array',
483
+ items: { type: 'string' },
425
484
  description: "List of files being touched (e.g. ['src/auth.js'])",
426
485
  },
427
486
  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)",
487
+ type: 'string',
488
+ enum: ['large', 'small'],
489
+ description:
490
+ 'Model tier: large (default, includes key rules of supplementary skills) or small (essential skills only)',
431
491
  },
432
492
  },
433
- required: ["task"],
493
+ required: ['task'],
434
494
  additionalProperties: false,
435
495
  },
436
496
  },
437
497
  {
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).",
498
+ name: 'align_output',
499
+ description:
500
+ '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
501
  inputSchema: {
441
- type: "object",
502
+ type: 'object',
442
503
  properties: {
443
504
  text: {
444
- type: "string",
445
- description: "The raw output text generated by the model to be aligned.",
505
+ type: 'string',
506
+ description: 'The raw output text generated by the model to be aligned.',
446
507
  },
447
508
  },
448
- required: ["text"],
509
+ required: ['text'],
510
+ additionalProperties: false,
511
+ },
512
+ },
513
+ {
514
+ name: 'verify_contracts',
515
+ description:
516
+ 'Verify proposed code changes against project behavioral contracts. Use BEFORE writing code to ensure compliance with team conventions.',
517
+ inputSchema: {
518
+ type: 'object',
519
+ properties: {
520
+ file: {
521
+ type: 'string',
522
+ description: "Relative or absolute file path to verify (e.g. 'src/api/user.ts')",
523
+ },
524
+ content: {
525
+ type: 'string',
526
+ description: 'Proposed file content to verify against loaded contracts',
527
+ },
528
+ },
529
+ required: ['file', 'content'],
530
+ additionalProperties: false,
531
+ },
532
+ },
533
+ {
534
+ name: 'query_semantic_graph',
535
+ description:
536
+ 'Query the Ahead-of-Time (AOT) Semantic Context Graph to quickly resolve function signatures, dependencies, and file structures without inflating context windows.',
537
+ inputSchema: {
538
+ type: 'object',
539
+ properties: {
540
+ targetPath: {
541
+ type: 'string',
542
+ description: 'The directory to query (defaults to current workspace).',
543
+ },
544
+ },
545
+ additionalProperties: false,
546
+ },
547
+ },
548
+ {
549
+ name: 'exit_plan_mode',
550
+ description:
551
+ 'Present your finished plan for human reviewed designing your approach. Execution will suspend until the user approves or requests changes.',
552
+ inputSchema: {
553
+ type: 'object',
554
+ properties: {
555
+ plan_content: {
556
+ type: 'string',
557
+ description: 'The markdown content of your proposed plan.',
558
+ },
559
+ },
560
+ required: ['plan_content'],
449
561
  additionalProperties: false,
450
562
  },
451
563
  },
@@ -453,253 +565,590 @@ function handleRequest(req) {
453
565
  };
454
566
  }
455
567
 
456
- if (req.method === "tools/call") {
568
+ if (req.method === 'tools/call') {
457
569
  const toolName = req.params && req.params.name;
570
+ const argsObj = req.params && req.params.arguments;
458
571
  if (!toolName) {
459
- throw {
460
- code: -32602,
461
- message: "Missing required parameter: params.name",
462
- };
572
+ throw new RpcError(-32602, 'Missing required parameter: params.name');
463
573
  }
464
574
 
465
- if (toolName === "run_tribunal_audit") {
466
- const text = runTribunalAudit();
467
- return { content: [{ type: "text", text }] };
468
- }
575
+ const reminder = repeatGuard.observe(toolName, argsObj);
469
576
 
470
- if (toolName === "sync_ide_bridges") {
471
- const fs = require("fs");
472
- const cwd = process.cwd();
473
- const agentDest = path.join(cwd, ".agent");
474
- if (!fs.existsSync(agentDest)) {
577
+ const executeTool = async () => {
578
+ if (toolName === 'exit_plan_mode') {
579
+ const planContent = req.params?.arguments?.plan_content;
580
+ if (typeof planContent !== 'string') {
581
+ throw new RpcError(-32602, 'Missing or invalid required argument: plan_content (string)');
582
+ }
583
+ // The wrapper CLI can intercept this, but for the LLM context, we explicitly tell it to wait.
475
584
  return {
476
585
  content: [
477
586
  {
478
- type: "text",
479
- text: "Error: .agent/ directory not found. Run `tk init` first.",
587
+ type: 'text',
588
+ text: 'PLAN_SUBMITTED_FOR_REVIEW: The plan has been presented to the human. Please suspend execution and wait for the human to approve or provide feedback in the next turn. Do not call any further tools until you receive a response.',
480
589
  },
481
590
  ],
482
591
  };
483
592
  }
484
- try {
485
- const { generateIDEBridges } = require(path.resolve(__dirname, "../dist/commands/init.js"));
486
- // generateIDEBridges is async — execute synchronously in MCP context
487
- generateIDEBridges(cwd, agentDest, true).then(() => {}).catch(() => {});
488
- return {
489
- content: [
593
+
594
+ if (toolName === 'dispatch_swarm') {
595
+ const payload = req.params?.arguments?.payload;
596
+ const file = req.params?.arguments?.file;
597
+ const workspace = req.params?.arguments?.workspace || '.';
598
+ const mode = req.params?.arguments?.mode || 'legacy';
599
+ const useTui = req.params?.arguments?.use_tui || false;
600
+
601
+ if (!payload && !file) {
602
+ throw new RpcError(
603
+ -32602,
604
+ 'Missing required argument: either payload or file must be provided',
605
+ );
606
+ }
607
+
608
+ if (payload && file) {
609
+ throw new RpcError(-32602, 'Invalid arguments: provide either payload or file, not both');
610
+ }
611
+
612
+ const agentDir = getAgentDir();
613
+ const fs = require('fs');
614
+ if (!fs.existsSync(agentDir)) {
615
+ return {
616
+ content: [
617
+ { type: 'text', text: 'Error: .agent/ directory not found. Run `tk init` first.' },
618
+ ],
619
+ };
620
+ }
621
+
622
+ try {
623
+ let _payloadData;
624
+ if (file) {
625
+ const filePath = path.resolve(workspace, file);
626
+ if (!fs.existsSync(filePath)) {
627
+ throw new Error(`File not found: ${filePath}`);
628
+ }
629
+ _payloadData = JSON.parse(fs.readFileSync(filePath, 'utf8'));
630
+ } else {
631
+ _payloadData = JSON.parse(payload);
632
+ }
633
+
634
+ // Import swarm dispatcher functions
635
+ const _swarmDispatcher = require(path.join(agentDir, 'scripts', 'swarm_dispatcher.js'));
636
+
637
+ // Execute the swarm dispatcher
638
+ const originalArgv = process.argv;
639
+ process.argv = ['node', 'swarm_dispatcher.js', '--mode', mode, '--workspace', workspace];
640
+
641
+ if (useTui) {
642
+ process.argv.push('--tui');
643
+ }
644
+
645
+ if (file) {
646
+ process.argv.push('--file');
647
+ process.argv.push(file);
648
+ } else if (payload) {
649
+ process.argv.push('--payload');
650
+ process.argv.push(payload);
651
+ }
652
+
653
+ // Capture output
654
+ const { spawnSync } = require('child_process');
655
+ const result = spawnSync(
656
+ process.execPath,
657
+ [path.join(agentDir, 'scripts', 'swarm_dispatcher.js'), ...process.argv.slice(2)],
490
658
  {
491
- type: "text",
492
- text: "Sync complete",
659
+ encoding: 'utf8',
660
+ timeout: 30000,
493
661
  },
494
- ],
495
- };
496
- } catch (e) {
497
- return {
498
- content: [
662
+ );
663
+
664
+ // Restore argv
665
+ process.argv = originalArgv;
666
+
667
+ if (result.error) {
668
+ throw result.error;
669
+ }
670
+
671
+ return {
672
+ content: [
673
+ { type: 'text', text: result.stdout || result.stderr || 'Swarm dispatch completed' },
674
+ ],
675
+ };
676
+ } catch (e) {
677
+ return {
678
+ content: [{ type: 'text', text: `Swarm dispatch failed: ${e.message}` }],
679
+ };
680
+ }
681
+ }
682
+
683
+ if (toolName === 'get_ast_context') {
684
+ const targetPath = req.params?.arguments?.targetPath || process.cwd();
685
+ try {
686
+ const result = spawnSync(
687
+ 'node',
688
+ [path.join(__dirname, '../scripts/build-graph.js'), targetPath],
499
689
  {
500
- type: "text",
501
- text: `Sync failed: ${e.message}`,
690
+ encoding: 'utf8',
691
+ timeout: 10000,
502
692
  },
503
- ],
504
- };
693
+ );
694
+ if (result.error) throw result.error;
695
+ return { content: [{ type: 'text', text: result.stdout || result.stderr }] };
696
+ } catch (e) {
697
+ return { content: [{ type: 'text', text: `Failed to query graph: ${e.message}` }] };
698
+ }
505
699
  }
506
- }
507
700
 
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
- };
516
- }
517
- const text = searchCaseLaw(query);
518
- return { content: [{ type: "text", text }] };
519
- }
701
+ if (toolName === 'validate_payload') {
702
+ const payloadStr = req.params?.arguments?.payload;
703
+ const schemaType = req.params?.arguments?.schemaType;
520
704
 
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- ") }] };
527
- }
705
+ if (!payloadStr || typeof payloadStr !== 'string') {
706
+ throw new RpcError(-32602, 'Missing or invalid required argument: payload (string)');
707
+ }
708
+ if (!schemaType || typeof schemaType !== 'string') {
709
+ throw new RpcError(-32602, 'Missing or invalid required argument: schemaType (string)');
710
+ }
528
711
 
529
- if (toolName === "get_tribunal_agent") {
530
- const fs = require("fs");
531
- const name = req.params?.arguments?.name;
532
- if (!name || typeof name !== "string") throw { code: -32602, message: "Missing or invalid argument: name (string)" };
533
- const sanitizedName = path.basename(name);
534
- const agentsDir = path.resolve(getAgentDir(), "agents");
535
- const agentPath = path.resolve(agentsDir, `${sanitizedName}.md`);
536
- // 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) }] };
541
- }
712
+ const agentDir = getAgentDir();
713
+ const fs = require('fs');
714
+ if (!fs.existsSync(agentDir)) {
715
+ return {
716
+ content: [
717
+ { type: 'text', text: 'Error: .agent/ directory not found. Run `tk init` first.' },
718
+ ],
719
+ };
720
+ }
542
721
 
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- ") }] };
549
- }
722
+ try {
723
+ const payloadData = JSON.parse(payloadStr);
724
+ const {
725
+ WorkerRequestSchema,
726
+ WorkerResultSchema,
727
+ SwarmPayloadSchema,
728
+ validatePayloadOrThrow,
729
+ } = require(path.join(agentDir, 'scripts', 'payload_schemas.js'));
550
730
 
551
- if (toolName === "get_tribunal_skill") {
552
- const fs = require("fs");
553
- const name = req.params?.arguments?.name;
554
- if (!name || typeof name !== "string") throw { code: -32602, message: "Missing or invalid argument: name (string)" };
555
- const sanitizedName = path.basename(name);
556
- const skillsDir = path.resolve(getAgentDir(), "skills");
557
- const skillPath = path.resolve(skillsDir, sanitizedName, "SKILL.md");
558
- // 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) }] };
563
- }
731
+ let schema;
732
+ switch (schemaType) {
733
+ case 'worker-request':
734
+ schema = WorkerRequestSchema;
735
+ break;
736
+ case 'worker-result':
737
+ schema = WorkerResultSchema;
738
+ break;
739
+ case 'swarm-payload':
740
+ schema = SwarmPayloadSchema;
741
+ break;
742
+ default:
743
+ throw new RpcError(
744
+ -32602,
745
+ `Invalid schemaType: ${schemaType}. Must be one of: worker-request, worker-result, swarm-payload`,
746
+ );
747
+ }
748
+
749
+ const validatedData = validatePayloadOrThrow(payloadData, schema);
750
+ return {
751
+ content: [
752
+ {
753
+ type: 'text',
754
+ text: `Payload validation successful.\n\nValidated payload:\n${JSON.stringify(validatedData, null, 2)}`,
755
+ },
756
+ ],
757
+ };
758
+ } catch (e) {
759
+ if (e instanceof SyntaxError) {
760
+ return { content: [{ type: 'text', text: `Invalid JSON payload: ${e.message}` }] };
761
+ } else {
762
+ return { content: [{ type: 'text', text: `Payload validation failed: ${e.message}` }] };
763
+ }
764
+ }
765
+ }
564
766
 
565
- if (toolName === "get_sparse_context") {
566
- const task = req.params?.arguments?.task;
567
- const files = req.params?.arguments?.files || [];
568
- const model = req.params?.arguments?.model || "large";
767
+ if (toolName === 'run_tribunal_audit') {
768
+ const text = runTribunalAudit();
769
+ return { content: [{ type: 'text', text }] };
770
+ }
771
+
772
+ if (toolName === 'sync_ide_bridges') {
773
+ const fs = require('fs');
774
+ const cwd = process.cwd();
775
+ const agentDest = path.join(cwd, '.agent');
776
+ if (!fs.existsSync(agentDest)) {
777
+ return {
778
+ content: [
779
+ {
780
+ type: 'text',
781
+ text: 'Error: .agent/ directory not found. Run `tk init` first.',
782
+ },
783
+ ],
784
+ };
785
+ }
786
+ try {
787
+ const { generateIDEBridges } = require(
788
+ path.resolve(__dirname, '../dist/commands/init.js'),
789
+ );
790
+ // generateIDEBridges is async
791
+ await generateIDEBridges(cwd, agentDest, true);
792
+ return {
793
+ content: [
794
+ {
795
+ type: 'text',
796
+ text: 'Sync complete',
797
+ },
798
+ ],
799
+ };
800
+ } catch (e) {
801
+ return {
802
+ content: [
803
+ {
804
+ type: 'text',
805
+ text: `Sync failed: ${e.message}`,
806
+ },
807
+ ],
808
+ };
809
+ }
810
+ }
569
811
 
570
- if (!task) throw { code: -32602, message: "Missing required argument: task" };
812
+ if (toolName === 'search_case_law') {
813
+ const query = req.params && req.params.arguments && req.params.arguments.query;
814
+ if (!query || typeof query !== 'string') {
815
+ throw new RpcError(-32602, 'Missing or invalid required argument: query (string)');
816
+ }
817
+ const text = searchCaseLaw(query);
818
+ return { content: [{ type: 'text', text }] };
819
+ }
571
820
 
572
- const agentDest = getAgentDir();
573
- const fs = require("fs");
574
- if (!fs.existsSync(agentDest)) {
575
- return { content: [{ type: "text", text: "Error: .agent/ directory not found. Run `tk init` first." }] };
821
+ if (toolName === 'list_tribunal_agents') {
822
+ const fs = require('fs');
823
+ const agentDir = path.join(getAgentDir(), 'agents');
824
+ if (!fs.existsSync(agentDir))
825
+ return {
826
+ content: [{ type: 'text', text: 'No agents found or .agent directory missing.' }],
827
+ };
828
+ const agents = fs
829
+ .readdirSync(agentDir)
830
+ .filter(f => f.endsWith('.md'))
831
+ .map(f => f.replace('.md', ''));
832
+ return { content: [{ type: 'text', text: 'Available Agents:\n- ' + agents.join('\n- ') }] };
576
833
  }
577
834
 
578
- try {
579
- const brokerScript = path.join(agentDest, "scripts", "context_broker.js");
580
- const { broker } = require(brokerScript);
581
- const brokerResult = broker(task, files, model, agentDest);
582
- return { content: [{ type: "text", text: stripBoilerplate(brokerResult.promptText) }] };
583
- } catch (e) {
584
- return { content: [{ type: "text", text: `Failed to retrieve sparse context: ${e.message}` }] };
835
+ if (toolName === 'get_tribunal_agent') {
836
+ const fs = require('fs');
837
+ const name = req.params?.arguments?.name;
838
+ if (!name || typeof name !== 'string')
839
+ throw new RpcError(-32602, 'Missing or invalid argument: name (string)');
840
+ const sanitizedName = path.basename(name);
841
+ const agentsDir = path.resolve(getAgentDir(), 'agents');
842
+ const agentPath = path.resolve(agentsDir, `${sanitizedName}.md`);
843
+ // Path containment: ensure resolved path stays within agents directory
844
+ if (!agentPath.startsWith(agentsDir))
845
+ throw new RpcError(-32602, 'Invalid agent name: path traversal detected');
846
+ if (!fs.existsSync(agentPath))
847
+ return { content: [{ type: 'text', text: `Agent '${sanitizedName}' not found.` }] };
848
+ const text = fs.readFileSync(agentPath, 'utf8');
849
+ return { content: [{ type: 'text', text: stripBoilerplate(text) }] };
585
850
  }
586
- }
587
851
 
588
- if (toolName === "recall_memory") {
589
- const query = req.params?.arguments?.query;
590
- if (!query || typeof query !== "string") {
591
- throw { code: -32602, message: "Missing or invalid required argument: query (string)" };
852
+ if (toolName === 'list_tribunal_skills') {
853
+ const fs = require('fs');
854
+ const skillsDir = path.join(getAgentDir(), 'skills');
855
+ if (!fs.existsSync(skillsDir))
856
+ return {
857
+ content: [{ type: 'text', text: 'No skills found or .agent directory missing.' }],
858
+ };
859
+ const skills = fs
860
+ .readdirSync(skillsDir, { withFileTypes: true })
861
+ .filter(d => d.isDirectory())
862
+ .map(d => d.name);
863
+ return { content: [{ type: 'text', text: 'Available Skills:\n- ' + skills.join('\n- ') }] };
592
864
  }
593
- const budget = req.params?.arguments?.budget || 2000;
594
- const agentDest = getAgentDir();
595
- const fs = require("fs");
596
- if (!fs.existsSync(agentDest)) {
597
- return { content: [{ type: "text", text: "Error: .agent/ directory not found. Run `tk init` first." }] };
865
+
866
+ if (toolName === 'get_tribunal_skill') {
867
+ const fs = require('fs');
868
+ const name = req.params?.arguments?.name;
869
+ if (!name || typeof name !== 'string')
870
+ throw new RpcError(-32602, 'Missing or invalid argument: name (string)');
871
+ const sanitizedName = path.basename(name);
872
+ const skillsDir = path.resolve(getAgentDir(), 'skills');
873
+ const skillPath = path.resolve(skillsDir, sanitizedName, 'SKILL.md');
874
+ // Path containment: ensure resolved path stays within skills directory
875
+ if (!skillPath.startsWith(skillsDir))
876
+ throw new RpcError(-32602, 'Invalid skill name: path traversal detected');
877
+ if (!fs.existsSync(skillPath))
878
+ return { content: [{ type: 'text', text: `Skill '${sanitizedName}' not found.` }] };
879
+ const text = fs.readFileSync(skillPath, 'utf8');
880
+ return { content: [{ type: 'text', text: stripBoilerplate(text) }] };
598
881
  }
599
- try {
600
- const { _memoryRecall } = require("../dist/commands/memory.js");
601
- const { results, tokens_used } = _memoryRecall(agentDest, query, budget);
602
- if (results.length === 0) {
603
- return { content: [{ type: "text", text: `No memories match query: "${query}"` }] };
882
+
883
+ if (toolName === 'get_sparse_context') {
884
+ const task = req.params?.arguments?.task;
885
+ const files = req.params?.arguments?.files || [];
886
+ const model = req.params?.arguments?.model || 'large';
887
+
888
+ if (!task) throw new RpcError(-32602, 'Missing required argument: task');
889
+
890
+ const agentDest = getAgentDir();
891
+ const fs = require('fs');
892
+ if (!fs.existsSync(agentDest)) {
893
+ return {
894
+ content: [
895
+ { type: 'text', text: 'Error: .agent/ directory not found. Run `tk init` first.' },
896
+ ],
897
+ };
604
898
  }
605
- let text = `## Memory Recall (${results.length} results, ~${tokens_used}/${budget} tokens)\n\n`;
606
- for (const entry of results) {
607
- text += `- **[${entry.memory_type.toUpperCase()}]** #${entry.id}: ${entry.content}`;
608
- if (entry.tags.length > 0) text += ` _(${entry.tags.join(", ")})_`;
609
- text += `\n`;
899
+
900
+ try {
901
+ const brokerScript = path.join(agentDest, 'scripts', 'context_broker.js');
902
+ const { broker } = require(brokerScript);
903
+ const brokerResult = broker(task, files, model, agentDest);
904
+ return { content: [{ type: 'text', text: stripBoilerplate(brokerResult.promptText) }] };
905
+ } catch (e) {
906
+ return {
907
+ content: [{ type: 'text', text: `Failed to retrieve sparse context: ${e.message}` }],
908
+ };
610
909
  }
611
- return { content: [{ type: "text", text }] };
612
- } catch (e) {
613
- return { content: [{ type: "text", text: `Memory recall failed: ${e.message}` }] };
614
910
  }
615
- }
616
911
 
617
- if (toolName === "store_memory") {
618
- const memType = req.params?.arguments?.type;
619
- const content = req.params?.arguments?.content;
620
- const tags = req.params?.arguments?.tags || [];
621
- if (!memType || !content) {
622
- throw { code: -32602, message: "Missing required arguments: type (string), content (string)" };
623
- }
624
- const validTypes = ["semantic", "procedural", "episodic", "working"];
625
- if (!validTypes.includes(memType)) {
626
- throw { code: -32602, message: `Invalid memory type: "${memType}". Must be one of: ${validTypes.join(", ")}` };
912
+ if (toolName === 'recall_memory') {
913
+ const query = req.params?.arguments?.query;
914
+ if (!query || typeof query !== 'string') {
915
+ throw new RpcError(-32602, 'Missing or invalid required argument: query (string)');
916
+ }
917
+ const budget = req.params?.arguments?.budget || 2000;
918
+ const agentDest = getAgentDir();
919
+ const fs = require('fs');
920
+ if (!fs.existsSync(agentDest)) {
921
+ return {
922
+ content: [
923
+ { type: 'text', text: 'Error: .agent/ directory not found. Run `tk init` first.' },
924
+ ],
925
+ };
926
+ }
927
+ try {
928
+ const { _memoryRecall } = require('../dist/commands/memory.js');
929
+ const { results, tokens_used } = _memoryRecall(agentDest, query, budget);
930
+ if (results.length === 0) {
931
+ return { content: [{ type: 'text', text: `No memories match query: "${query}"` }] };
932
+ }
933
+ let text = `## Memory Recall (${results.length} results, ~${tokens_used}/${budget} tokens)\n\n`;
934
+ for (const entry of results) {
935
+ text += `- **[${entry.memory_type.toUpperCase()}]** #${entry.id}: ${entry.content}`;
936
+ if (entry.tags.length > 0) text += ` _(${entry.tags.join(', ')})_`;
937
+ text += `\n`;
938
+ }
939
+ return { content: [{ type: 'text', text }] };
940
+ } catch (e) {
941
+ return { content: [{ type: 'text', text: `Memory recall failed: ${e.message}` }] };
942
+ }
627
943
  }
628
- const agentDest = getAgentDir();
629
- const fs = require("fs");
630
- if (!fs.existsSync(agentDest)) {
631
- return { content: [{ type: "text", text: "Error: .agent/ directory not found. Run `tk init` first." }] };
944
+
945
+ if (toolName === 'store_memory') {
946
+ const memType = req.params?.arguments?.type;
947
+ const content = req.params?.arguments?.content;
948
+ const tags = req.params?.arguments?.tags || [];
949
+ if (!memType || !content) {
950
+ throw new RpcError(-32602, 'Missing required arguments: type (string), content (string)');
951
+ }
952
+ const validTypes = ['semantic', 'procedural', 'episodic', 'working'];
953
+ if (!validTypes.includes(memType)) {
954
+ throw new RpcError(
955
+ -32602,
956
+ `Invalid memory type: "${memType}". Must be one of: ${validTypes.join(', ')}`,
957
+ );
958
+ }
959
+ const agentDest = getAgentDir();
960
+ const fs = require('fs');
961
+ if (!fs.existsSync(agentDest)) {
962
+ return {
963
+ content: [
964
+ { type: 'text', text: 'Error: .agent/ directory not found. Run `tk init` first.' },
965
+ ],
966
+ };
967
+ }
968
+ try {
969
+ const { _memoryStore } = require('../dist/commands/memory.js');
970
+ const result = _memoryStore(agentDest, memType, content, tags, null);
971
+ return {
972
+ content: [
973
+ {
974
+ type: 'text',
975
+ text: `Memory stored: #${result.id} (${memType}, ~${result.token_estimate} tokens)`,
976
+ },
977
+ ],
978
+ };
979
+ } catch (e) {
980
+ return { content: [{ type: 'text', text: `Memory store failed: ${e.message}` }] };
981
+ }
632
982
  }
633
- try {
634
- const { _memoryStore } = require("../dist/commands/memory.js");
635
- const result = _memoryStore(agentDest, memType, content, tags, null);
636
- return { content: [{ type: "text", text: `Memory stored: #${result.id} (${memType}, ~${result.token_estimate} tokens)` }] };
637
- } catch (e) {
638
- return { content: [{ type: "text", text: `Memory store failed: ${e.message}` }] };
983
+
984
+ if (toolName === 'query_semantic_graph') {
985
+ const targetPath = req.params?.arguments?.targetPath || process.cwd();
986
+ try {
987
+ const result = spawnSync(
988
+ 'node',
989
+ [path.join(__dirname, '../scripts/build-graph.js'), targetPath],
990
+ {
991
+ encoding: 'utf8',
992
+ timeout: 10000,
993
+ },
994
+ );
995
+ if (result.error) throw result.error;
996
+ return { content: [{ type: 'text', text: result.stdout || result.stderr }] };
997
+ } catch (e) {
998
+ return { content: [{ type: 'text', text: `Failed to query graph: ${e.message}` }] };
999
+ }
639
1000
  }
640
- }
641
1001
 
642
- if (toolName === "align_output") {
643
- const text = req.params?.arguments?.text;
644
- if (typeof text !== "string") {
645
- throw { code: -32602, message: "Missing or invalid required argument: text (string)" };
1002
+ if (toolName === 'align_output') {
1003
+ const text = req.params?.arguments?.text;
1004
+ if (typeof text !== 'string') {
1005
+ throw new RpcError(-32602, 'Missing or invalid required argument: text (string)');
1006
+ }
1007
+ try {
1008
+ const { alignText, validateCodeContent } = require('../dist/commands/align.js');
1009
+ const aligned = alignText(text);
1010
+ const warnings = validateCodeContent(aligned);
1011
+
1012
+ let outputText = aligned;
1013
+ if (warnings.length > 0) {
1014
+ outputText += '\n\n⚠️ OCAE Alignment Validator Warnings:\n';
1015
+ for (const warnMsg of warnings) {
1016
+ outputText += `● ${warnMsg}\n`;
1017
+ }
1018
+ }
1019
+ return { content: [{ type: 'text', text: outputText }] };
1020
+ } catch (e) {
1021
+ return { content: [{ type: 'text', text: `Output alignment failed: ${e.message}` }] };
1022
+ }
646
1023
  }
647
- try {
648
- const { alignText, validateCodeContent } = require("../dist/commands/align.js");
649
- const aligned = alignText(text);
650
- const warnings = validateCodeContent(aligned);
651
-
652
- let outputText = aligned;
653
- if (warnings.length > 0) {
654
- outputText += "\n\n⚠️ OCAE Alignment Validator Warnings:\n";
655
- for (const warnMsg of warnings) {
656
- outputText += `● ${warnMsg}\n`;
1024
+
1025
+ if (toolName === 'verify_contracts') {
1026
+ const file = req.params?.arguments?.file;
1027
+ const content = req.params?.arguments?.content;
1028
+
1029
+ if (!file || typeof file !== 'string' || typeof content !== 'string') {
1030
+ throw new RpcError(
1031
+ -32602,
1032
+ 'Missing or invalid required arguments: file (string), content (string)',
1033
+ );
1034
+ }
1035
+
1036
+ try {
1037
+ const projectRoot = process.cwd();
1038
+ const contractEnginePath = path.join(getAgentDir(), 'scripts', 'contract_engine.js');
1039
+ if (!require('fs').existsSync(contractEnginePath)) {
1040
+ return {
1041
+ content: [
1042
+ { type: 'text', text: 'Error: contract_engine.js not found. Run `tk init` first.' },
1043
+ ],
1044
+ };
657
1045
  }
1046
+
1047
+ const contractEngine = require(contractEnginePath);
1048
+ const contracts = contractEngine.loadContracts(projectRoot);
1049
+
1050
+ if (contracts.length === 0) {
1051
+ return {
1052
+ content: [
1053
+ {
1054
+ type: 'text',
1055
+ text: 'No active behavioral contracts found in .tribunal/contracts/.',
1056
+ },
1057
+ ],
1058
+ };
1059
+ }
1060
+
1061
+ const relativePath = path.relative(projectRoot, file).replace(/\\/g, '/');
1062
+ const allViolations = [];
1063
+
1064
+ for (const contract of contracts) {
1065
+ const vList = contractEngine.evaluateContract(contract, relativePath, content);
1066
+ if (vList.length > 0) {
1067
+ allViolations.push(...vList);
1068
+ }
1069
+ }
1070
+
1071
+ if (allViolations.length === 0) {
1072
+ return {
1073
+ content: [
1074
+ {
1075
+ type: 'text',
1076
+ text: '✅ Contract check passed. Zero behavioral violations detected.',
1077
+ },
1078
+ ],
1079
+ };
1080
+ }
1081
+
1082
+ let report = `📜 Contract Verification Results (${allViolations.length} violations):\n`;
1083
+ for (const v of allViolations) {
1084
+ report += `● [${v.severity.toUpperCase()}] ${v.contract}: ${v.message}\n`;
1085
+ if (v.line) report += ` Line ${v.line}: ${v.snippet || ''}\n`;
1086
+ }
1087
+
1088
+ return { content: [{ type: 'text', text: report }] };
1089
+ } catch (e) {
1090
+ return {
1091
+ content: [{ type: 'text', text: `Contract verification failed: ${e.message}` }],
1092
+ };
658
1093
  }
659
- return { content: [{ type: "text", text: outputText }] };
660
- } catch (e) {
661
- return { content: [{ type: "text", text: `Alignment failed: ${e.message}` }] };
662
1094
  }
663
- }
664
1095
 
665
- throw { code: -32601, message: `Unknown tool: ${toolName}` };
1096
+ throw new RpcError(-32601, `Unknown tool: ${toolName}`);
1097
+ };
1098
+
1099
+ try {
1100
+ const result = await withToolTimeout(executeTool, GENERAL_TOOL_TIMEOUT_MS);
1101
+ if (reminder) {
1102
+ result.content.push({ type: 'text', text: '\n\n' + reminder });
1103
+ }
1104
+ return result;
1105
+ } catch (e) {
1106
+ if (e.message === 'TOOL_TIMEOUT') {
1107
+ const errorMsg = `Error: Tool execution timed out after ${GENERAL_TOOL_TIMEOUT_MS}ms`;
1108
+ const result = { content: [{ type: 'text', text: errorMsg }] };
1109
+ if (reminder) result.content.push({ type: 'text', text: '\n\n' + reminder });
1110
+ return result;
1111
+ }
1112
+ throw e;
1113
+ }
666
1114
  }
667
1115
 
668
- throw { code: -32601, message: `Unknown method: ${req.method}` };
1116
+ throw new RpcError(-32601, `Unknown method: ${req.method}`);
669
1117
  }
670
1118
 
671
- function processSingleRequest(req) {
1119
+ async function processSingleRequest(req) {
672
1120
  try {
673
- const result = handleRequest(req);
1121
+ const result = await handleRequest(req);
674
1122
  // If it's a notification, do not send a response
675
1123
  if (req.id === undefined || req.id === null) {
676
1124
  return null;
677
1125
  }
678
- return { jsonrpc: "2.0", id: req.id, result };
1126
+ return { jsonrpc: '2.0', id: req.id, result };
679
1127
  } catch (e) {
680
- const code = e && typeof e.code === "number" ? e.code : -32603;
681
- const message = e && e.message ? e.message : "Internal server error";
1128
+ const code = e && typeof e.code === 'number' ? e.code : -32603;
1129
+ const message = e && e.message ? e.message : 'Internal server error';
682
1130
  if (req.id === undefined || req.id === null) {
683
1131
  return {
684
- jsonrpc: "2.0",
1132
+ jsonrpc: '2.0',
685
1133
  id: null,
686
1134
  error: { code, message },
687
1135
  };
688
1136
  }
689
1137
  return {
690
- jsonrpc: "2.0",
1138
+ jsonrpc: '2.0',
691
1139
  id: req.id,
692
1140
  error: { code, message },
693
1141
  };
694
1142
  }
695
1143
  }
696
1144
 
697
- rl.on("line", (line) => {
698
- if (line.length > 1048576) { // 1MB limit
1145
+ rl.on('line', async line => {
1146
+ if (line.length > 1048576) {
1147
+ // 1MB limit
699
1148
  const errorRes = {
700
- jsonrpc: "2.0",
1149
+ jsonrpc: '2.0',
701
1150
  id: null,
702
- error: { code: -32700, message: "Parse error: input line too long (exceeds 1MB limit)" },
1151
+ error: { code: -32700, message: 'Parse error: input line too long (exceeds 1MB limit)' },
703
1152
  };
704
1153
  console.log(JSON.stringify(errorRes));
705
1154
  return;
@@ -712,9 +1161,9 @@ rl.on("line", (line) => {
712
1161
  } catch (parseErr) {
713
1162
  // Invalid JSON — send a parse error
714
1163
  const errorRes = {
715
- jsonrpc: "2.0",
1164
+ jsonrpc: '2.0',
716
1165
  id: null,
717
- error: { code: -32700, message: "Parse error: " + parseErr.message },
1166
+ error: { code: -32700, message: 'Parse error: ' + parseErr.message },
718
1167
  };
719
1168
  console.log(JSON.stringify(errorRes));
720
1169
  return;
@@ -723,7 +1172,7 @@ rl.on("line", (line) => {
723
1172
  if (Array.isArray(req)) {
724
1173
  const responses = [];
725
1174
  for (const singleReq of req) {
726
- const response = processSingleRequest(singleReq);
1175
+ const response = await processSingleRequest(singleReq);
727
1176
  if (response) {
728
1177
  responses.push(response);
729
1178
  }
@@ -732,14 +1181,14 @@ rl.on("line", (line) => {
732
1181
  console.log(JSON.stringify(responses));
733
1182
  }
734
1183
  } else {
735
- const response = processSingleRequest(req);
1184
+ const response = await processSingleRequest(req);
736
1185
  if (response) {
737
1186
  console.log(JSON.stringify(response));
738
1187
  }
739
1188
  }
740
1189
  });
741
1190
 
742
- if (process.env.NODE_ENV === "test") {
1191
+ if (process.env.NODE_ENV === 'test') {
743
1192
  module.exports = {
744
1193
  handleRequest,
745
1194
  stripBoilerplate,