tribunal-kit 6.0.1 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (349) hide show
  1. package/.agent/ARCHITECTURE.md +9 -6
  2. package/.agent/agents/accessibility-reviewer.md +23 -16
  3. package/.agent/agents/ai-code-reviewer.md +25 -21
  4. package/.agent/agents/anti-pattern-reviewer.md +12 -7
  5. package/.agent/agents/api-architect.md +1 -0
  6. package/.agent/agents/backend-specialist.md +23 -22
  7. package/.agent/agents/cloud-engineer.md +1 -0
  8. package/.agent/agents/code-archaeologist.md +1 -0
  9. package/.agent/agents/complexity-reviewer.md +10 -7
  10. package/.agent/agents/database-architect.md +3 -2
  11. package/.agent/agents/db-latency-auditor.md +6 -2
  12. package/.agent/agents/debugger.md +3 -2
  13. package/.agent/agents/dependency-reviewer.md +1 -0
  14. package/.agent/agents/devops-engineer.md +9 -8
  15. package/.agent/agents/documentation-writer.md +6 -5
  16. package/.agent/agents/explorer-agent.md +1 -0
  17. package/.agent/agents/frontend-reviewer.md +21 -17
  18. package/.agent/agents/frontend-specialist.md +23 -20
  19. package/.agent/agents/game-developer.md +1 -0
  20. package/.agent/agents/interaction-reviewer.md +10 -5
  21. package/.agent/agents/logic-reviewer.md +3 -0
  22. package/.agent/agents/minimalist-reviewer.md +6 -0
  23. package/.agent/agents/mobile-developer.md +7 -6
  24. package/.agent/agents/mobile-reviewer.md +14 -13
  25. package/.agent/agents/orchestrator.md +3 -0
  26. package/.agent/agents/penetration-tester.md +1 -0
  27. package/.agent/agents/performance-optimizer.md +6 -5
  28. package/.agent/agents/performance-reviewer.md +6 -6
  29. package/.agent/agents/pipeline-reviewer.md +144 -0
  30. package/.agent/agents/precedence-reviewer.md +1 -0
  31. package/.agent/agents/product-manager.md +1 -0
  32. package/.agent/agents/product-owner.md +1 -0
  33. package/.agent/agents/product-reviewer.md +12 -7
  34. package/.agent/agents/project-planner.md +3 -0
  35. package/.agent/agents/qa-automation-engineer.md +50 -43
  36. package/.agent/agents/resilience-reviewer.md +1 -0
  37. package/.agent/agents/schema-reviewer.md +1 -0
  38. package/.agent/agents/security-auditor.md +24 -24
  39. package/.agent/agents/seo-specialist.md +33 -23
  40. package/.agent/agents/sql-reviewer.md +5 -4
  41. package/.agent/agents/supervisor-agent.md +12 -2
  42. package/.agent/agents/swarm-worker-contracts.md +13 -13
  43. package/.agent/agents/swarm-worker-registry.md +51 -51
  44. package/.agent/agents/system-architect.md +1 -0
  45. package/.agent/agents/test-coverage-reviewer.md +25 -22
  46. package/.agent/agents/test-engineer.md +12 -11
  47. package/.agent/agents/throughput-optimizer.md +45 -40
  48. package/.agent/agents/type-safety-reviewer.md +5 -4
  49. package/.agent/agents/ui-ux-auditor.md +6 -4
  50. package/.agent/agents/ui-visual-auditor.md +3 -0
  51. package/.agent/agents/ux-reviewer.md +11 -6
  52. package/.agent/agents/visual-reviewer.md +11 -6
  53. package/.agent/agents/vitals-reviewer.md +5 -4
  54. package/.agent/history/memory/.memory.idx +1532 -1
  55. package/.agent/history/memory/MEMORY.md +102 -1
  56. package/.agent/mcp_config.json +1 -6
  57. package/.agent/routing_index.json +2033 -263
  58. package/.agent/rules/GEMINI.md +11 -9
  59. package/.agent/rules/GEMINI_PLANNER.md +19 -21
  60. package/.agent/scripts/_colors.js +52 -54
  61. package/.agent/scripts/_utils.js +52 -53
  62. package/.agent/scripts/auto_preview.js +39 -43
  63. package/.agent/scripts/bundle_analyzer.js +47 -60
  64. package/.agent/scripts/case_law_manager.js +200 -294
  65. package/.agent/scripts/checklist.js +73 -94
  66. package/.agent/scripts/cicd_validator.js +305 -0
  67. package/.agent/scripts/compile_router.py +4 -111
  68. package/.agent/scripts/context_broker.js +317 -412
  69. package/.agent/scripts/contract_engine.js +402 -0
  70. package/.agent/scripts/dependency_analyzer.js +112 -124
  71. package/.agent/scripts/graph_builder.js +75 -103
  72. package/.agent/scripts/graph_visualizer.js +10 -12
  73. package/.agent/scripts/graph_zoom.js +38 -55
  74. package/.agent/scripts/guardrail_engine.js +195 -145
  75. package/.agent/scripts/impact_classifier.js +55 -30
  76. package/.agent/scripts/inner_loop_validator.js +108 -159
  77. package/.agent/scripts/integrity_manifest.js +59 -67
  78. package/.agent/scripts/lint_runner.js +65 -75
  79. package/.agent/scripts/marathon_harness.js +131 -208
  80. package/.agent/scripts/migrate_skills_frontmatter.py +4 -63
  81. package/.agent/scripts/minify_context.js +29 -33
  82. package/.agent/scripts/minimal_change_engine.js +95 -87
  83. package/.agent/scripts/mutation_runner.js +46 -62
  84. package/.agent/scripts/pipeline_engine.js +320 -209
  85. package/.agent/scripts/prompt_compiler.js +118 -93
  86. package/.agent/scripts/schema_validator.js +73 -121
  87. package/.agent/scripts/security_scan.js +88 -117
  88. package/.agent/scripts/session_manager.js +52 -69
  89. package/.agent/scripts/signal_detector.js +24 -22
  90. package/.agent/scripts/skill_evolution.js +184 -245
  91. package/.agent/scripts/skill_integrator.js +35 -48
  92. package/.agent/scripts/socratic_gate_policy.js +15 -12
  93. package/.agent/scripts/strengthen_skills.js +29 -33
  94. package/.agent/scripts/swarm_dispatcher.js +120 -151
  95. package/.agent/scripts/test_runner.js +54 -56
  96. package/.agent/scripts/token_budget_broker.js +9 -7
  97. package/.agent/scripts/trace_engine.js +126 -0
  98. package/.agent/scripts/verify_all.js +76 -93
  99. package/.agent/scripts/visual_audit.js +16 -21
  100. package/.agent/skill_topic_map.json +22 -3
  101. package/.agent/skills/12-principles-of-animation/SKILL.md +7 -0
  102. package/.agent/skills/60fps-animation/SKILL.md +7 -0
  103. package/.agent/skills/accessible-animation/SKILL.md +5 -1
  104. package/.agent/skills/adapt/SKILL.md +7 -1
  105. package/.agent/skills/advanced-rag-pipelines/SKILL.md +1 -0
  106. package/.agent/skills/agent-organizer/SKILL.md +1 -0
  107. package/.agent/skills/agentic-patterns/SKILL.md +33 -25
  108. package/.agent/skills/agentic-workflows-2026/SKILL.md +6 -2
  109. package/.agent/skills/ai-app-hardening/SKILL.md +9 -8
  110. package/.agent/skills/ai-prompt-injection-defense/SKILL.md +7 -6
  111. package/.agent/skills/animation-on-scroll/SKILL.md +24 -15
  112. package/.agent/skills/animation-systems/SKILL.md +11 -10
  113. package/.agent/skills/antfu-conventions/SKILL.md +7 -2
  114. package/.agent/skills/api-patterns/SKILL.md +14 -10
  115. package/.agent/skills/api-security-auditor/SKILL.md +15 -14
  116. package/.agent/skills/app-builder/SKILL.md +1 -0
  117. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +2 -2
  118. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
  119. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +12 -12
  120. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +3 -3
  121. package/.agent/skills/apple-design/SKILL.md +8 -7
  122. package/.agent/skills/architecture/SKILL.md +3 -2
  123. package/.agent/skills/audit-and-fix/SKILL.md +8 -5
  124. package/.agent/skills/authentication-best-practices/SKILL.md +9 -8
  125. package/.agent/skills/backend-security-expert/SKILL.md +1 -0
  126. package/.agent/skills/baseline-ui/SKILL.md +8 -7
  127. package/.agent/skills/bash-linux/SKILL.md +1 -0
  128. package/.agent/skills/behavioral-modes/SKILL.md +1 -0
  129. package/.agent/skills/better-colors/SKILL.md +11 -7
  130. package/.agent/skills/better-typography/SKILL.md +30 -16
  131. package/.agent/skills/better-ui/SKILL.md +17 -10
  132. package/.agent/skills/bolder/SKILL.md +6 -0
  133. package/.agent/skills/brainstorming/SKILL.md +6 -4
  134. package/.agent/skills/browser-native-ai/SKILL.md +5 -4
  135. package/.agent/skills/build-primitive/SKILL.md +5 -0
  136. package/.agent/skills/building-native-ui/SKILL.md +1 -0
  137. package/.agent/skills/cicd-pro/SKILL.md +2 -1
  138. package/.agent/skills/clarify/SKILL.md +19 -14
  139. package/.agent/skills/clean-code/SKILL.md +16 -15
  140. package/.agent/skills/cloud-architect/SKILL.md +1 -0
  141. package/.agent/skills/cobejs/SKILL.md +7 -9
  142. package/.agent/skills/code-review-checklist/SKILL.md +1 -0
  143. package/.agent/skills/codebase-design/SKILL.md +7 -2
  144. package/.agent/skills/colorize/SKILL.md +8 -3
  145. package/.agent/skills/compact-landing/SKILL.md +8 -3
  146. package/.agent/skills/company-logos/SKILL.md +6 -0
  147. package/.agent/skills/config-validator/SKILL.md +10 -9
  148. package/.agent/skills/containerization-pro/SKILL.md +6 -5
  149. package/.agent/skills/context-engineering-pro/SKILL.md +5 -4
  150. package/.agent/skills/create-design-md/SKILL.md +13 -5
  151. package/.agent/skills/critique/SKILL.md +10 -8
  152. package/.agent/skills/csharp-developer/SKILL.md +1 -0
  153. package/.agent/skills/data-validation-schemas/SKILL.md +28 -23
  154. package/.agent/skills/database-design/SKILL.md +2 -1
  155. package/.agent/skills/delight/SKILL.md +6 -0
  156. package/.agent/skills/deployment-procedures/SKILL.md +2 -1
  157. package/.agent/skills/design-lab/SKILL.md +5 -0
  158. package/.agent/skills/devops-engineer/SKILL.md +3 -2
  159. package/.agent/skills/devops-incident-responder/SKILL.md +2 -1
  160. package/.agent/skills/diagnosing-bugs/SKILL.md +12 -2
  161. package/.agent/skills/distill/SKILL.md +7 -2
  162. package/.agent/skills/documentation-templates/SKILL.md +3 -2
  163. package/.agent/skills/domain-modeling/SKILL.md +12 -4
  164. package/.agent/skills/duckdb-analytical-sql/SKILL.md +7 -3
  165. package/.agent/skills/edge-ai-mobile/SKILL.md +5 -1
  166. package/.agent/skills/edge-computing/SKILL.md +9 -8
  167. package/.agent/skills/emil-design-eng/SKILL.md +43 -27
  168. package/.agent/skills/error-resilience/SKILL.md +34 -16
  169. package/.agent/skills/expo-router-v4/SKILL.md +2 -1
  170. package/.agent/skills/extract-design-system/SKILL.md +12 -11
  171. package/.agent/skills/fabel-protocol/SKILL.md +24 -17
  172. package/.agent/skills/fixing-accessibility/SKILL.md +23 -16
  173. package/.agent/skills/fixing-metadata/SKILL.md +24 -13
  174. package/.agent/skills/fixing-motion-performance/SKILL.md +7 -5
  175. package/.agent/skills/framer-motion-expert/SKILL.md +29 -15
  176. package/.agent/skills/frontend-design/SKILL.md +21 -13
  177. package/.agent/skills/frontend-security-expert/SKILL.md +1 -0
  178. package/.agent/skills/game-design-expert/SKILL.md +1 -0
  179. package/.agent/skills/game-engineering-expert/SKILL.md +1 -0
  180. package/.agent/skills/generative-ui-expert/SKILL.md +3 -2
  181. package/.agent/skills/geo-fundamentals/SKILL.md +2 -1
  182. package/.agent/skills/git-pro/SKILL.md +10 -9
  183. package/.agent/skills/github-operations/SKILL.md +2 -1
  184. package/.agent/skills/gpt-taste/SKILL.md +7 -0
  185. package/.agent/skills/gsap-core/SKILL.md +26 -22
  186. package/.agent/skills/gsap-frameworks/SKILL.md +6 -5
  187. package/.agent/skills/gsap-performance/SKILL.md +4 -3
  188. package/.agent/skills/gsap-plugins/SKILL.md +34 -33
  189. package/.agent/skills/gsap-react/SKILL.md +9 -8
  190. package/.agent/skills/gsap-scrolltrigger/SKILL.md +34 -33
  191. package/.agent/skills/gsap-timeline/SKILL.md +18 -15
  192. package/.agent/skills/gsap-utils/SKILL.md +25 -24
  193. package/.agent/skills/harden/SKILL.md +9 -3
  194. package/.agent/skills/harness-protocol/SKILL.md +1 -0
  195. package/.agent/skills/i18n-localization/SKILL.md +10 -9
  196. package/.agent/skills/impeccable/SKILL.md +5 -0
  197. package/.agent/skills/improve-codebase-architecture/SKILL.md +10 -5
  198. package/.agent/skills/improve-ui/SKILL.md +12 -5
  199. package/.agent/skills/intelligent-routing/SKILL.md +7 -6
  200. package/.agent/skills/knowledge-graph/SKILL.md +1 -0
  201. package/.agent/skills/landing-page/SKILL.md +1 -0
  202. package/.agent/skills/lint-and-validate/SKILL.md +9 -4
  203. package/.agent/skills/llm-engineering/SKILL.md +55 -54
  204. package/.agent/skills/local-first/SKILL.md +20 -19
  205. package/.agent/skills/local-first-architecture/SKILL.md +6 -1
  206. package/.agent/skills/lottie-animation/SKILL.md +7 -3
  207. package/.agent/skills/marquee-loop/SKILL.md +1 -0
  208. package/.agent/skills/masked-reveal/SKILL.md +17 -4
  209. package/.agent/skills/mcp-builder/SKILL.md +13 -10
  210. package/.agent/skills/micro-interaction/SKILL.md +20 -5
  211. package/.agent/skills/mobile-design/SKILL.md +26 -15
  212. package/.agent/skills/monorepo-management/SKILL.md +3 -2
  213. package/.agent/skills/morphing-icons/SKILL.md +16 -6
  214. package/.agent/skills/motion-engineering/SKILL.md +19 -15
  215. package/.agent/skills/nextjs-react-expert/SKILL.md +26 -21
  216. package/.agent/skills/nodejs-best-practices/SKILL.md +89 -76
  217. package/.agent/skills/observability/SKILL.md +45 -44
  218. package/.agent/skills/opentelemetry-observability/SKILL.md +2 -1
  219. package/.agent/skills/page-transition-animation/SKILL.md +6 -3
  220. package/.agent/skills/parallel-agents/SKILL.md +7 -2
  221. package/.agent/skills/performance-profiling/SKILL.md +24 -13
  222. package/.agent/skills/plan-writing/SKILL.md +1 -0
  223. package/.agent/skills/platform-engineer/SKILL.md +3 -2
  224. package/.agent/skills/platform-engineering-opentofu/SKILL.md +1 -0
  225. package/.agent/skills/playwright-ai-e2e/SKILL.md +3 -2
  226. package/.agent/skills/playwright-best-practices/SKILL.md +29 -28
  227. package/.agent/skills/polish/SKILL.md +13 -12
  228. package/.agent/skills/powershell-windows/SKILL.md +1 -0
  229. package/.agent/skills/pricing-page/SKILL.md +8 -3
  230. package/.agent/skills/product-aware-heuristics/SKILL.md +122 -72
  231. package/.agent/skills/progressive-blur/SKILL.md +9 -4
  232. package/.agent/skills/project-idioms/SKILL.md +1 -0
  233. package/.agent/skills/property-based-testing/SKILL.md +10 -12
  234. package/.agent/skills/python-patterns/SKILL.md +1 -0
  235. package/.agent/skills/python-pro/SKILL.md +1 -0
  236. package/.agent/skills/quieter/SKILL.md +6 -0
  237. package/.agent/skills/react-doctor/SKILL.md +6 -0
  238. package/.agent/skills/react-specialist/SKILL.md +32 -28
  239. package/.agent/skills/readme-builder/SKILL.md +1 -0
  240. package/.agent/skills/realtime-patterns/SKILL.md +34 -33
  241. package/.agent/skills/red-team-tactics/SKILL.md +1 -0
  242. package/.agent/skills/redesign-skill/SKILL.md +6 -0
  243. package/.agent/skills/review-animations/SKILL.md +5 -2
  244. package/.agent/skills/review-animations/STANDARDS.md +37 -23
  245. package/.agent/skills/rust-pro/SKILL.md +1 -0
  246. package/.agent/skills/seo-fundamentals/SKILL.md +4 -3
  247. package/.agent/skills/server-management/SKILL.md +1 -0
  248. package/.agent/skills/shadcn-ui-expert/SKILL.md +28 -22
  249. package/.agent/skills/shape/SKILL.md +9 -2
  250. package/.agent/skills/skill-creator/SKILL.md +1 -0
  251. package/.agent/skills/soft-skill/SKILL.md +6 -0
  252. package/.agent/skills/sounds-on-the-web/SKILL.md +1 -0
  253. package/.agent/skills/sql-pro/SKILL.md +1 -0
  254. package/.agent/skills/supabase-postgres-best-practices/SKILL.md +1 -0
  255. package/.agent/skills/svg-animation/SKILL.md +16 -7
  256. package/.agent/skills/swiftui-expert/SKILL.md +1 -0
  257. package/.agent/skills/swiss-design/SKILL.md +5 -0
  258. package/.agent/skills/system-design-pro/SKILL.md +1 -0
  259. package/.agent/skills/systematic-debugging/SKILL.md +1 -0
  260. package/.agent/skills/tailwind-patterns/SKILL.md +25 -11
  261. package/.agent/skills/taste-skill/SKILL.md +6 -0
  262. package/.agent/skills/tdd-workflow/SKILL.md +5 -0
  263. package/.agent/skills/test-result-analyzer/SKILL.md +1 -0
  264. package/.agent/skills/testing-patterns/SKILL.md +123 -115
  265. package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +5 -0
  266. package/.agent/skills/thinking-protocol/SKILL.md +3 -0
  267. package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +9 -8
  268. package/.agent/skills/transitions-dev/SKILL.md +19 -6
  269. package/.agent/skills/trend-researcher/SKILL.md +1 -0
  270. package/.agent/skills/typescript-advanced/SKILL.md +23 -18
  271. package/.agent/skills/typeset/SKILL.md +10 -1
  272. package/.agent/skills/ui-reasoning-engine/SKILL.md +67 -48
  273. package/.agent/skills/ui-skill-packs/SKILL.md +6 -1
  274. package/.agent/skills/ui-skills-root/SKILL.md +39 -38
  275. package/.agent/skills/ui-ux-pro-max/SKILL.md +34 -26
  276. package/.agent/skills/ui-ux-researcher/SKILL.md +1 -0
  277. package/.agent/skills/vector-search-pgvector/SKILL.md +3 -2
  278. package/.agent/skills/vue-expert/SKILL.md +22 -19
  279. package/.agent/skills/vulnerability-scanner/SKILL.md +22 -21
  280. package/.agent/skills/web-accessibility-auditor/SKILL.md +2 -1
  281. package/.agent/skills/web-design-guidelines/SKILL.md +16 -10
  282. package/.agent/skills/web-quality-audit/SKILL.md +5 -0
  283. package/.agent/skills/webapp-testing/SKILL.md +14 -13
  284. package/.agent/skills/webgpu-performance/SKILL.md +1 -0
  285. package/.agent/skills/whimsy-injector/SKILL.md +9 -5
  286. package/.agent/skills/workflow-optimizer/SKILL.md +1 -0
  287. package/.agent/skills/zero-trust-passkeys/SKILL.md +11 -6
  288. package/.agent/templates/DESIGN.md +119 -110
  289. package/.agent/templates/design-tokens.json +9 -6
  290. package/.agent/workflows/acf.md +1 -0
  291. package/.agent/workflows/api-tester.md +1 -0
  292. package/.agent/workflows/audit.md +1 -0
  293. package/.agent/workflows/brainstorm.md +1 -0
  294. package/.agent/workflows/changelog.md +1 -0
  295. package/.agent/workflows/contract.md +60 -0
  296. package/.agent/workflows/create.md +1 -0
  297. package/.agent/workflows/debug.md +1 -0
  298. package/.agent/workflows/deploy.md +1 -0
  299. package/.agent/workflows/enhance.md +1 -0
  300. package/.agent/workflows/fix-ci.md +89 -0
  301. package/.agent/workflows/fix.md +1 -0
  302. package/.agent/workflows/generate.md +1 -0
  303. package/.agent/workflows/marathon.md +1 -0
  304. package/.agent/workflows/migrate.md +1 -0
  305. package/.agent/workflows/minimal.md +9 -7
  306. package/.agent/workflows/orchestrate.md +1 -0
  307. package/.agent/workflows/performance-benchmarker.md +1 -0
  308. package/.agent/workflows/pipeline.md +26 -21
  309. package/.agent/workflows/plan.md +1 -0
  310. package/.agent/workflows/preview.md +1 -0
  311. package/.agent/workflows/refactor.md +3 -2
  312. package/.agent/workflows/review-ai.md +4 -3
  313. package/.agent/workflows/review.md +1 -0
  314. package/.agent/workflows/session.md +1 -0
  315. package/.agent/workflows/status.md +1 -0
  316. package/.agent/workflows/strengthen-skills.md +1 -0
  317. package/.agent/workflows/super-prompt.md +1 -0
  318. package/.agent/workflows/swarm.md +15 -3
  319. package/.agent/workflows/test.md +8 -7
  320. package/.agent/workflows/tribunal-backend.md +3 -2
  321. package/.agent/workflows/tribunal-cicd.md +104 -0
  322. package/.agent/workflows/tribunal-database.md +1 -0
  323. package/.agent/workflows/tribunal-frontend.md +8 -6
  324. package/.agent/workflows/tribunal-full.md +2 -1
  325. package/.agent/workflows/tribunal-mobile.md +6 -5
  326. package/.agent/workflows/tribunal-performance.md +1 -0
  327. package/.agent/workflows/tribunal-speed.md +1 -0
  328. package/.agent/workflows/tribunal-ui.md +29 -21
  329. package/.agent/workflows/ui-ux-pro-max.md +19 -15
  330. package/CONTRIBUTING.md +3 -3
  331. package/README.md +94 -44
  332. package/SECURITY.md +10 -10
  333. package/bin/mcp-server.js +385 -252
  334. package/bin/tribunal-kit.js +29 -30
  335. package/bin/wrapper.js +40 -46
  336. package/dist/cli.js +6 -0
  337. package/dist/commands/case.js +2 -0
  338. package/dist/commands/contract.js +440 -0
  339. package/dist/commands/status.js +6 -0
  340. package/dist/index.d.ts +8 -1
  341. package/package.json +13 -12
  342. package/scripts/benchmark.js +62 -86
  343. package/scripts/changelog.js +67 -73
  344. package/scripts/fix-vbc.js +13 -15
  345. package/scripts/fix-vbc.ps1 +2 -118
  346. package/scripts/stress_benchmark.js +358 -0
  347. package/scripts/sync-version.js +71 -41
  348. package/scripts/validate-payload.js +23 -30
  349. package/scripts/visual_audit.js +23 -13
@@ -45,37 +45,41 @@
45
45
  * prompt — full injected prompt text ready for an LLM
46
46
  */
47
47
 
48
- "use strict";
48
+ 'use strict';
49
49
 
50
- const fs = require("fs");
51
- const path = require("path");
52
- const { execFileSync } = require("child_process");
50
+ const fs = require('fs');
51
+ const path = require('path');
52
+ const { execFileSync } = require('child_process');
53
53
 
54
54
  // ── Colours & Shared Utilities ────────────────────────────────────────────────
55
- const { GREEN, YELLOW, CYAN, RED, BOLD, DIM, RESET } = require("./_colors");
56
- const { findAgentDir } = require("./_utils");
55
+ const { GREEN, YELLOW, CYAN, RED, BOLD, DIM, RESET } = require('./_colors');
56
+ const { findAgentDir } = require('./_utils');
57
57
 
58
58
  /**
59
59
  * Attempt native Rust context resolution for sub-15ms execution
60
60
  */
61
61
  function tryNativeContextBroker(repoPath, targetFile) {
62
- if (process.env.TK_DISABLE_RUST === "1") return null;
62
+ if (process.env.TK_DISABLE_RUST === '1') return null;
63
63
 
64
64
  const candidates = [
65
- path.join(__dirname, "../../target/release/tribunal-core.exe"),
66
- path.join(__dirname, "../../target/release/tribunal-core"),
67
- path.join(__dirname, "../../target/debug/tribunal-core.exe"),
68
- path.join(__dirname, "../../target/debug/tribunal-core"),
69
- "tribunal-core"
65
+ path.join(__dirname, '../../target/release/tribunal-core.exe'),
66
+ path.join(__dirname, '../../target/release/tribunal-core'),
67
+ path.join(__dirname, '../../target/debug/tribunal-core.exe'),
68
+ path.join(__dirname, '../../target/debug/tribunal-core'),
69
+ 'tribunal-core',
70
70
  ];
71
71
 
72
72
  for (const bin of candidates) {
73
73
  try {
74
74
  if (bin.includes(path.sep) && !fs.existsSync(bin)) continue;
75
- const args = ["context-broker", "--repo-path", repoPath];
76
- if (targetFile) args.push("--target-file", targetFile);
77
- const out = execFileSync(bin, args, { encoding: "utf8", timeout: 2000, stdio: ["ignore", "pipe", "ignore"] });
78
- if (out && out.trim().startsWith("{")) {
75
+ const args = ['context-broker', '--repo-path', repoPath];
76
+ if (targetFile) args.push('--target-file', targetFile);
77
+ const out = execFileSync(bin, args, {
78
+ encoding: 'utf8',
79
+ timeout: 2000,
80
+ stdio: ['ignore', 'pipe', 'ignore'],
81
+ });
82
+ if (out && out.trim().startsWith('{')) {
79
83
  return JSON.parse(out);
80
84
  }
81
85
  } catch (_) {
@@ -85,305 +89,187 @@ function tryNativeContextBroker(repoPath, targetFile) {
85
89
  return null;
86
90
  }
87
91
 
88
-
89
-
90
92
  // ── Domain → Skill affinity map ───────────────────────────────────────────────
91
93
  // Keywords in the user's task that strongly indicate specific skills.
92
94
  // Higher weight = stronger signal.
93
95
  const DOMAIN_AFFINITIES = [
94
96
  // Backend / API
95
97
  {
96
- keywords: [
97
- "api",
98
- "rest",
99
- "route",
100
- "endpoint",
101
- "handler",
102
- "express",
103
- "fastapi",
104
- "hono",
105
- ],
106
- skills: [
107
- "api-patterns",
108
- "nodejs-best-practices",
109
- "backend-specialist",
110
- "error-resilience",
111
- ],
98
+ keywords: ['api', 'rest', 'route', 'endpoint', 'handler', 'express', 'fastapi', 'hono'],
99
+ skills: ['api-patterns', 'nodejs-best-practices', 'backend-specialist', 'error-resilience'],
112
100
  weight: 3,
113
101
  },
114
102
  // Database
115
103
  {
116
104
  keywords: [
117
- "sql",
118
- "query",
119
- "database",
120
- "prisma",
121
- "drizzle",
122
- "orm",
123
- "postgres",
124
- "mysql",
125
- "schema",
105
+ 'sql',
106
+ 'query',
107
+ 'database',
108
+ 'prisma',
109
+ 'drizzle',
110
+ 'orm',
111
+ 'postgres',
112
+ 'mysql',
113
+ 'schema',
126
114
  ],
127
- skills: ["database-design", "sql-pro", "supabase-postgres-best-practices"],
115
+ skills: ['database-design', 'sql-pro', 'supabase-postgres-best-practices'],
128
116
  weight: 3,
129
117
  },
130
118
  // Authentication
131
119
  {
132
- keywords: [
133
- "auth",
134
- "jwt",
135
- "login",
136
- "oauth",
137
- "session",
138
- "password",
139
- "token",
140
- "rbac",
141
- ],
142
- skills: [
143
- "authentication-best-practices",
144
- "vulnerability-scanner",
145
- "api-security-auditor",
146
- ],
120
+ keywords: ['auth', 'jwt', 'login', 'oauth', 'session', 'password', 'token', 'rbac'],
121
+ skills: ['authentication-best-practices', 'vulnerability-scanner', 'api-security-auditor'],
147
122
  weight: 3,
148
123
  },
149
124
  // React / Next.js
150
125
  {
151
126
  keywords: [
152
- "react",
153
- "next",
154
- "nextjs",
155
- "component",
156
- "hook",
157
- "jsx",
158
- "tsx",
159
- "server component",
160
- "server action",
127
+ 'react',
128
+ 'next',
129
+ 'nextjs',
130
+ 'component',
131
+ 'hook',
132
+ 'jsx',
133
+ 'tsx',
134
+ 'server component',
135
+ 'server action',
161
136
  ],
162
- skills: ["react-specialist", "nextjs-react-expert", "frontend-design"],
137
+ skills: ['react-specialist', 'nextjs-react-expert', 'frontend-design'],
163
138
  weight: 3,
164
139
  },
165
140
  // Frontend / UI
166
141
  {
167
142
  keywords: [
168
- "ui",
169
- "design",
170
- "landing",
171
- "page",
172
- "layout",
173
- "responsive",
174
- "tailwind",
175
- "css",
176
- "style",
177
- ],
178
- skills: [
179
- "frontend-design",
180
- "ui-ux-pro-max",
181
- "tailwind-patterns",
182
- "web-design-guidelines",
143
+ 'ui',
144
+ 'design',
145
+ 'landing',
146
+ 'page',
147
+ 'layout',
148
+ 'responsive',
149
+ 'tailwind',
150
+ 'css',
151
+ 'style',
183
152
  ],
153
+ skills: ['frontend-design', 'ui-ux-pro-max', 'tailwind-patterns', 'web-design-guidelines'],
184
154
  weight: 2,
185
155
  },
186
156
  // Animation / Motion
187
157
  {
188
- keywords: [
189
- "animation",
190
- "gsap",
191
- "framer",
192
- "motion",
193
- "scroll",
194
- "transition",
195
- "parallax",
196
- ],
197
- skills: [
198
- "motion-engineering",
199
- "framer-motion-expert",
200
- "gsap-core",
201
- "gsap-scrolltrigger",
202
- ],
158
+ keywords: ['animation', 'gsap', 'framer', 'motion', 'scroll', 'transition', 'parallax'],
159
+ skills: ['motion-engineering', 'framer-motion-expert', 'gsap-core', 'gsap-scrolltrigger'],
203
160
  weight: 3,
204
161
  },
205
162
  // AI / LLM
206
163
  {
207
164
  keywords: [
208
- "llm",
209
- "openai",
210
- "anthropic",
211
- "gemini",
212
- "embedding",
213
- "ai",
214
- "rag",
215
- "vector",
216
- "chat",
217
- "prompt",
218
- ],
219
- skills: [
220
- "llm-engineering",
221
- "ai-prompt-injection-defense",
222
- "agentic-patterns",
165
+ 'llm',
166
+ 'openai',
167
+ 'anthropic',
168
+ 'gemini',
169
+ 'embedding',
170
+ 'ai',
171
+ 'rag',
172
+ 'vector',
173
+ 'chat',
174
+ 'prompt',
223
175
  ],
176
+ skills: ['llm-engineering', 'ai-prompt-injection-defense', 'agentic-patterns'],
224
177
  weight: 3,
225
178
  },
226
179
  // Security
227
180
  {
228
181
  keywords: [
229
- "security",
230
- "xss",
231
- "injection",
232
- "owasp",
233
- "vulnerability",
234
- "csrf",
235
- "sanitize",
236
- "audit",
237
- ],
238
- skills: [
239
- "vulnerability-scanner",
240
- "api-security-auditor",
241
- "authentication-best-practices",
182
+ 'security',
183
+ 'xss',
184
+ 'injection',
185
+ 'owasp',
186
+ 'vulnerability',
187
+ 'csrf',
188
+ 'sanitize',
189
+ 'audit',
242
190
  ],
191
+ skills: ['vulnerability-scanner', 'api-security-auditor', 'authentication-best-practices'],
243
192
  weight: 3,
244
193
  },
245
194
  // Testing
246
195
  {
247
- keywords: [
248
- "test",
249
- "spec",
250
- "jest",
251
- "vitest",
252
- "playwright",
253
- "unit test",
254
- "e2e",
255
- "mock",
256
- ],
257
- skills: ["testing-patterns", "playwright-best-practices", "tdd-workflow"],
196
+ keywords: ['test', 'spec', 'jest', 'vitest', 'playwright', 'unit test', 'e2e', 'mock'],
197
+ skills: ['testing-patterns', 'playwright-best-practices', 'tdd-workflow'],
258
198
  weight: 3,
259
199
  },
260
200
  // Performance
261
201
  {
262
- keywords: [
263
- "performance",
264
- "optimize",
265
- "bundle",
266
- "cache",
267
- "speed",
268
- "slow",
269
- "lighthouse",
270
- "cwv",
271
- ],
272
- skills: ["performance-profiling", "motion-engineering", "edge-computing"],
202
+ keywords: ['performance', 'optimize', 'bundle', 'cache', 'speed', 'slow', 'lighthouse', 'cwv'],
203
+ skills: ['performance-profiling', 'motion-engineering', 'edge-computing'],
273
204
  weight: 2,
274
205
  },
275
206
  // Mobile
276
207
  {
277
- keywords: [
278
- "mobile",
279
- "react native",
280
- "expo",
281
- "ios",
282
- "android",
283
- "gesture",
284
- "haptic",
285
- ],
286
- skills: ["building-native-ui", "mobile-design", "agentic-patterns"],
208
+ keywords: ['mobile', 'react native', 'expo', 'ios', 'android', 'gesture', 'haptic'],
209
+ skills: ['building-native-ui', 'mobile-design', 'agentic-patterns'],
287
210
  weight: 3,
288
211
  },
289
212
  // DevOps / CI
290
213
  {
291
- keywords: [
292
- "docker",
293
- "ci",
294
- "cd",
295
- "deploy",
296
- "pipeline",
297
- "k8s",
298
- "kubernetes",
299
- "github actions",
300
- ],
301
- skills: ["devops-engineer", "deployment-procedures", "observability"],
214
+ keywords: ['docker', 'ci', 'cd', 'deploy', 'pipeline', 'k8s', 'kubernetes', 'github actions'],
215
+ skills: ['devops-engineer', 'deployment-procedures', 'observability'],
302
216
  weight: 2,
303
217
  },
304
218
  // Real-time
305
219
  {
306
- keywords: [
307
- "realtime",
308
- "websocket",
309
- "sse",
310
- "socket",
311
- "live",
312
- "multiplayer",
313
- "collaborative",
314
- ],
315
- skills: ["realtime-patterns", "error-resilience"],
220
+ keywords: ['realtime', 'websocket', 'sse', 'socket', 'live', 'multiplayer', 'collaborative'],
221
+ skills: ['realtime-patterns', 'error-resilience'],
316
222
  weight: 3,
317
223
  },
318
224
  // TypeScript
319
225
  {
320
- keywords: [
321
- "typescript",
322
- "type",
323
- "generic",
324
- "interface",
325
- "satisfies",
326
- "zod",
327
- "pydantic",
328
- ],
329
- skills: ["typescript-advanced", "data-validation-schemas"],
226
+ keywords: ['typescript', 'type', 'generic', 'interface', 'satisfies', 'zod', 'pydantic'],
227
+ skills: ['typescript-advanced', 'data-validation-schemas'],
330
228
  weight: 2,
331
229
  },
332
230
  // Python
333
231
  {
334
- keywords: ["python", "fastapi", "django", "flask", "pydantic", "asyncio"],
335
- skills: ["python-pro", "python-patterns"],
232
+ keywords: ['python', 'fastapi', 'django', 'flask', 'pydantic', 'asyncio'],
233
+ skills: ['python-pro', 'python-patterns'],
336
234
  weight: 3,
337
235
  },
338
236
  // Architecture
339
237
  {
340
238
  keywords: [
341
- "architecture",
342
- "refactor",
343
- "clean",
344
- "solid",
345
- "design pattern",
346
- "monorepo",
347
- "microservice",
239
+ 'architecture',
240
+ 'refactor',
241
+ 'clean',
242
+ 'solid',
243
+ 'design pattern',
244
+ 'monorepo',
245
+ 'microservice',
348
246
  ],
349
- skills: ["architecture", "clean-code", "monorepo-management"],
247
+ skills: ['architecture', 'clean-code', 'monorepo-management'],
350
248
  weight: 2,
351
249
  },
352
250
  // C# / .NET
353
251
  {
354
- keywords: [
355
- "csharp",
356
- "c#",
357
- "dotnet",
358
- ".net",
359
- "blazor",
360
- "aspnet",
361
- "entity framework",
362
- ],
363
- skills: ["csharp-developer"],
252
+ keywords: ['csharp', 'c#', 'dotnet', '.net', 'blazor', 'aspnet', 'entity framework'],
253
+ skills: ['csharp-developer'],
364
254
  weight: 3,
365
255
  },
366
256
  ];
367
257
 
368
258
  // ── File extension → skill boost map ─────────────────────────────────────────
369
259
  const EXT_AFFINITIES = {
370
- ".tsx": ["react-specialist", "nextjs-react-expert", "typescript-advanced"],
371
- ".jsx": ["react-specialist", "frontend-design"],
372
- ".ts": ["typescript-advanced", "nodejs-best-practices"],
373
- ".vue": ["vue-expert"],
374
- ".py": ["python-pro", "python-patterns"],
375
- ".cs": ["csharp-developer"],
376
- ".sql": ["sql-pro", "database-design"],
377
- ".css": ["tailwind-patterns", "frontend-design"],
260
+ '.tsx': ['react-specialist', 'nextjs-react-expert', 'typescript-advanced'],
261
+ '.jsx': ['react-specialist', 'frontend-design'],
262
+ '.ts': ['typescript-advanced', 'nodejs-best-practices'],
263
+ '.vue': ['vue-expert'],
264
+ '.py': ['python-pro', 'python-patterns'],
265
+ '.cs': ['csharp-developer'],
266
+ '.sql': ['sql-pro', 'database-design'],
267
+ '.css': ['tailwind-patterns', 'frontend-design'],
378
268
  };
379
269
 
380
270
  // ── Core baseline skills — always available to all model sizes ────────────────
381
271
  // These are injected for every request at a condensed level.
382
- const BASELINE_SKILLS = [
383
- "clean-code",
384
- "systematic-debugging",
385
- "error-resilience",
386
- ];
272
+ const BASELINE_SKILLS = ['clean-code', 'systematic-debugging', 'error-resilience'];
387
273
 
388
274
  // ── Skill catalogue (loaded from disk) ───────────────────────────────────────
389
275
 
@@ -397,14 +283,14 @@ function parseFrontmatter(content) {
397
283
  if (!match) return null;
398
284
  const yaml = match[1];
399
285
  const obj = {};
400
- for (const line of yaml.split("\n")) {
401
- const sep = line.indexOf(":");
286
+ for (const line of yaml.split('\n')) {
287
+ const sep = line.indexOf(':');
402
288
  if (sep === -1) continue;
403
289
  const key = line.slice(0, sep).trim();
404
290
  const val = line
405
291
  .slice(sep + 1)
406
292
  .trim()
407
- .replace(/^["']|["']$/g, "");
293
+ .replace(/^["']|["']$/g, '');
408
294
  obj[key] = val;
409
295
  }
410
296
  return obj;
@@ -422,18 +308,25 @@ function extractKeyRules(content) {
422
308
  );
423
309
  if (sectionMatch) return sectionMatch[1].trim().slice(0, 1200);
424
310
  // Fallback: strip frontmatter and take first 800 chars
425
- const bodyStart = content.indexOf("---", 3);
311
+ const bodyStart = content.indexOf('---', 3);
426
312
  const body = bodyStart !== -1 ? content.slice(bodyStart + 3).trim() : content;
427
313
  return body.slice(0, 800).trim();
428
314
  }
429
315
 
316
+ let _loadedSkillsCache = null;
317
+ let _loadedSkillsAgentDir = null;
318
+
430
319
  /**
431
320
  * Load all skills from .agent/skills/ directory.
432
- * Returns an array of { name, file, frontmatter, content, keyRules } objects.
321
+ * Returns an array of { name, file, frontmatter, content, keyRules, tokens } objects.
433
322
  * @param {string} agentDir
434
323
  */
435
324
  function loadSkills(agentDir) {
436
- const skillsDir = path.join(agentDir, "skills");
325
+ if (_loadedSkillsCache && _loadedSkillsAgentDir === agentDir) {
326
+ return _loadedSkillsCache;
327
+ }
328
+
329
+ const skillsDir = path.join(agentDir, 'skills');
437
330
  if (!fs.existsSync(skillsDir)) return [];
438
331
 
439
332
  const skills = [];
@@ -441,33 +334,44 @@ function loadSkills(agentDir) {
441
334
 
442
335
  for (const entry of entries) {
443
336
  if (!entry.isDirectory()) continue;
444
- const skillFile = path.join(skillsDir, entry.name, "SKILL.md");
337
+ const skillFile = path.join(skillsDir, entry.name, 'SKILL.md');
445
338
  if (!fs.existsSync(skillFile)) continue;
446
339
 
447
340
  try {
448
- let content = fs.readFileSync(skillFile, "utf8");
449
-
341
+ let content = fs.readFileSync(skillFile, 'utf8');
342
+
450
343
  // Strip duplicated global boilerplate sections
451
- content = content.replace(/AI coding assistants often fall into specific bad habits[\s\S]*$/g, "");
452
- content = content.replace(/## 🤖 LLM-Specific Traps[\s\S]*$/g, "");
453
- content = content.replace(/## 🏛️ Tribunal Integration[\s\S]*$/g, "");
454
- content = content.replace(/## Pre-Flight Checklist[\s\S]*$/g, "");
344
+ content = content.replace(
345
+ /AI coding assistants often fall into specific bad habits[\s\S]*$/g,
346
+ '',
347
+ );
348
+ content = content.replace(/## 🤖 LLM-Specific Traps[\s\S]*$/g, '');
349
+ content = content.replace(/## 🏛️ Tribunal Integration[\s\S]*$/g, '');
350
+ content = content.replace(/## Pre-Flight Checklist[\s\S]*$/g, '');
455
351
  content = content.trim();
456
352
 
457
353
  const frontmatter = parseFrontmatter(content) || {};
458
354
  const keyRules = extractKeyRules(content);
355
+ const description = frontmatter.description || '';
356
+ const skillText = (entry.name + ' ' + description).toLowerCase();
357
+ const tokens = new Set(tokenize(skillText));
358
+
459
359
  skills.push({
460
360
  name: entry.name,
461
361
  file: skillFile,
462
362
  frontmatter,
463
363
  content,
464
364
  keyRules,
465
- description: frontmatter.description || "",
365
+ description,
366
+ tokens,
466
367
  });
467
368
  } catch {
468
369
  // Skip unreadable skills silently
469
370
  }
470
371
  }
372
+
373
+ _loadedSkillsCache = skills;
374
+ _loadedSkillsAgentDir = agentDir;
471
375
  return skills;
472
376
  }
473
377
 
@@ -479,9 +383,13 @@ function loadSkills(agentDir) {
479
383
  * @returns {string[]}
480
384
  */
481
385
  function tokenize(text) {
482
- return (text.match(/\b[a-zA-Z_][a-zA-Z0-9_]{2,}\b/g) || []).map((t) =>
483
- t.toLowerCase(),
484
- );
386
+ const str =
387
+ typeof text === 'string'
388
+ ? text
389
+ : text && typeof text === 'object'
390
+ ? text.task || text.spec || JSON.stringify(text)
391
+ : String(text || '');
392
+ return (str.match(/\b[a-zA-Z_][a-zA-Z0-9_]{2,}\b/g) || []).map(t => t.toLowerCase());
485
393
  }
486
394
 
487
395
  /**
@@ -493,7 +401,7 @@ function tokenize(text) {
493
401
  * - File extension affinity: +2 per match
494
402
  * - Baseline skill bonus: +1 (always present)
495
403
  *
496
- * @param {{ name, description, content }} skill
404
+ * @param {{ name, description, content, tokens }} skill
497
405
  * @param {string} task - Raw task text from the user
498
406
  * @param {string[]} fileExts - File extensions being touched
499
407
  * @param {string[]} taskTokens - Pre-tokenized task
@@ -501,19 +409,24 @@ function tokenize(text) {
501
409
  */
502
410
  function scoreSkill(skill, task, fileExts, taskTokens) {
503
411
  let score = 0;
504
- const taskLower = task.toLowerCase();
505
- const skillText = (skill.name + " " + skill.description).toLowerCase();
506
- const skillTokens = tokenize(skillText);
507
-
508
- // 1. Token overlap (lightweight TF match — no IDF needed at this scale)
509
- const skillSet = new Set(skillTokens);
412
+ const taskStr =
413
+ typeof task === 'string'
414
+ ? task
415
+ : task && typeof task === 'object'
416
+ ? task.task || task.spec || ''
417
+ : String(task || '');
418
+ const taskLower = taskStr.toLowerCase();
419
+
420
+ // 1. Token overlap (lightweight TF match using pre-built Set)
421
+ const skillSet =
422
+ skill.tokens || new Set(tokenize((skill.name + ' ' + skill.description).toLowerCase()));
510
423
  for (const token of taskTokens) {
511
424
  if (skillSet.has(token)) score += 1;
512
425
  }
513
426
 
514
427
  // 2. Domain affinity boost
515
428
  for (const affinity of DOMAIN_AFFINITIES) {
516
- const keywordMatch = affinity.keywords.some((k) => taskLower.includes(k));
429
+ const keywordMatch = affinity.keywords.some(k => taskLower.includes(k));
517
430
  if (!keywordMatch) continue;
518
431
  if (affinity.skills.includes(skill.name)) {
519
432
  score += affinity.weight;
@@ -541,16 +454,22 @@ function scoreSkill(skill, task, fileExts, taskTokens) {
541
454
  * @param {object[]} skills - Loaded skills array from loadSkills()
542
455
  * @returns {{ essential: object[], supplementary: object[], available: object[], scores: Map }}
543
456
  */
544
- function selectSkills(task, files, model, skills) {
545
- const taskTokens = tokenize(task);
546
- const fileExts = files
547
- .map((f) => path.extname(f).toLowerCase())
457
+ function selectSkills(task, files = [], model = 'large', skills = []) {
458
+ const taskStr =
459
+ typeof task === 'string'
460
+ ? task
461
+ : task && typeof task === 'object'
462
+ ? task.task || task.spec || ''
463
+ : String(task || '');
464
+ const taskTokens = tokenize(taskStr);
465
+ const fileExts = (Array.isArray(files) ? files : [])
466
+ .map(f => path.extname(f).toLowerCase())
548
467
  .filter(Boolean);
549
468
 
550
469
  // Score every available skill
551
- const scored = skills.map((skill) => ({
470
+ const scored = skills.map(skill => ({
552
471
  ...skill,
553
- score: scoreSkill(skill, task, fileExts, taskTokens),
472
+ score: scoreSkill(skill, taskStr, fileExts, taskTokens),
554
473
  }));
555
474
  scored.sort((a, b) => b.score - a.score);
556
475
 
@@ -559,26 +478,22 @@ function selectSkills(task, files, model, skills) {
559
478
  const tier0Cut = Math.max(maxScore * 0.65, 2); // Essential: top 65%+ of max score
560
479
  const tier1Cut = Math.max(maxScore * 0.3, 1); // Supplementary: 30–65%
561
480
 
562
- const essential = scored.filter((s) => s.score >= tier0Cut).slice(0, 10);
563
- const supplementary = scored
564
- .filter((s) => s.score < tier0Cut && s.score >= tier1Cut)
565
- .slice(0, 8);
566
- const available = scored
567
- .filter((s) => s.score < tier1Cut && s.score > 0)
568
- .slice(0, 10);
481
+ const essential = scored.filter(s => s.score >= tier0Cut).slice(0, 10);
482
+ const supplementary = scored.filter(s => s.score < tier0Cut && s.score >= tier1Cut).slice(0, 8);
483
+ const available = scored.filter(s => s.score < tier1Cut && s.score > 0).slice(0, 10);
569
484
 
570
485
  // Ensure baseline skills always appear at minimum in supplementary
571
486
  for (const base of BASELINE_SKILLS) {
572
- const inEssential = essential.find((s) => s.name === base);
573
- const inSupplementary = supplementary.find((s) => s.name === base);
487
+ const inEssential = essential.find(s => s.name === base);
488
+ const inSupplementary = supplementary.find(s => s.name === base);
574
489
  if (!inEssential && !inSupplementary) {
575
- const baseSkill = skills.find((s) => s.name === base);
490
+ const baseSkill = skills.find(s => s.name === base);
576
491
  if (baseSkill) supplementary.push({ ...baseSkill, score: 0.5 });
577
492
  }
578
493
  }
579
494
 
580
495
  // For small models: collapse supplementary into available
581
- if (model === "small") {
496
+ if (model === 'small') {
582
497
  return {
583
498
  essential: essential.slice(0, 6),
584
499
  supplementary: [],
@@ -602,14 +517,10 @@ function formatReport(task, model, selection, elapsed) {
602
517
  const { essential, supplementary, available } = selection;
603
518
  const total = essential.length + supplementary.length + available.length;
604
519
 
520
+ console.log(`\n${BOLD}${CYAN}━━━ Context Broker — Skill Selection ━━━━━━━━━━━━━━━${RESET}`);
521
+ console.log(` Task : ${BOLD}${task.slice(0, 80)}${task.length > 80 ? '...' : ''}${RESET}`);
605
522
  console.log(
606
- `\n${BOLD}${CYAN}━━━ Context Broker Skill Selection ━━━━━━━━━━━━━━━${RESET}`,
607
- );
608
- console.log(
609
- ` Task : ${BOLD}${task.slice(0, 80)}${task.length > 80 ? "..." : ""}${RESET}`,
610
- );
611
- console.log(
612
- ` Model : ${model === "large" ? GREEN : YELLOW}${model}${RESET} ${DIM}(Focus without Compromise)${RESET}`,
523
+ ` Model : ${model === 'large' ? GREEN : YELLOW}${model}${RESET} ${DIM}(Focus without Compromise)${RESET}`,
613
524
  );
614
525
  console.log(
615
526
  ` Skills : ${GREEN}${essential.length} essential${RESET} + ${YELLOW}${supplementary.length} supplementary${RESET} + ${DIM}${available.length} available${RESET} of ${total} matched`,
@@ -617,47 +528,36 @@ function formatReport(task, model, selection, elapsed) {
617
528
  console.log(` Time : ${elapsed}ms\n`);
618
529
 
619
530
  if (essential.length) {
620
- console.log(
621
- ` ${GREEN}${BOLD}▶ Level 0 — Essential (Full Context, Top Priority):${RESET}`,
622
- );
531
+ console.log(` ${GREEN}${BOLD}▶ Level 0 — Essential (Full Context, Top Priority):${RESET}`);
623
532
  for (const s of essential) {
624
533
  const score = selection.scores.get(s.name) || 0;
625
534
  console.log(
626
535
  ` ${GREEN}✦${RESET} ${BOLD}${s.name}${RESET} ${DIM}score=${score.toFixed(1)}${RESET}`,
627
536
  );
628
- if (s.description)
629
- console.log(` ${DIM}${s.description.slice(0, 90)}${RESET}`);
537
+ if (s.description) console.log(` ${DIM}${s.description.slice(0, 90)}${RESET}`);
630
538
  }
631
539
  }
632
540
 
633
541
  if (supplementary.length) {
634
- console.log(
635
- `\n ${YELLOW}${BOLD}▶ Level 1 — Supplementary (Key Rules Only):${RESET}`,
636
- );
542
+ console.log(`\n ${YELLOW}${BOLD}▶ Level 1 — Supplementary (Key Rules Only):${RESET}`);
637
543
  for (const s of supplementary) {
638
544
  const score = selection.scores.get(s.name) || 0;
639
- console.log(
640
- ` ${YELLOW}◆${RESET} ${s.name} ${DIM}score=${score.toFixed(1)}${RESET}`,
641
- );
545
+ console.log(` ${YELLOW}◆${RESET} ${s.name} ${DIM}score=${score.toFixed(1)}${RESET}`);
642
546
  }
643
547
  }
644
548
 
645
549
  if (available.length) {
646
- console.log(
647
- `\n ${DIM} Level 2 — Available (Name Reference Only):${RESET}`,
648
- );
649
- console.log(` ${DIM}${available.map((s) => s.name).join(", ")}${RESET}`);
550
+ console.log(`\n ${DIM}▶ Level 2 — Available (Name Reference Only):${RESET}`);
551
+ console.log(` ${DIM}${available.map(s => s.name).join(', ')}${RESET}`);
650
552
  }
651
553
 
652
- if (model === "small") {
554
+ if (model === 'small') {
653
555
  console.log(
654
556
  `\n ${YELLOW}⚡ Small model mode: supplementary collapsed. Essential only injected.${RESET}`,
655
557
  );
656
558
  }
657
559
 
658
- console.log(
659
- `\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n`,
660
- );
560
+ console.log(`\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n`);
661
561
  }
662
562
 
663
563
  function formatJson(task, model, selection) {
@@ -666,16 +566,16 @@ function formatJson(task, model, selection) {
666
566
  task,
667
567
  model,
668
568
  timestamp: new Date().toISOString(),
669
- essential: selection.essential.map((s) => ({
569
+ essential: selection.essential.map(s => ({
670
570
  name: s.name,
671
571
  score: selection.scores.get(s.name),
672
572
  description: s.description,
673
573
  })),
674
- supplementary: selection.supplementary.map((s) => ({
574
+ supplementary: selection.supplementary.map(s => ({
675
575
  name: s.name,
676
576
  score: selection.scores.get(s.name),
677
577
  })),
678
- available: selection.available.map((s) => s.name),
578
+ available: selection.available.map(s => s.name),
679
579
  },
680
580
  null,
681
581
  2,
@@ -684,10 +584,8 @@ function formatJson(task, model, selection) {
684
584
 
685
585
  function formatNames(selection, model) {
686
586
  const all =
687
- model === "large"
688
- ? [...selection.essential, ...selection.supplementary]
689
- : selection.essential;
690
- return all.map((s) => s.name).join("\n");
587
+ model === 'large' ? [...selection.essential, ...selection.supplementary] : selection.essential;
588
+ return all.map(s => s.name).join('\n');
691
589
  }
692
590
 
693
591
  /**
@@ -708,60 +606,57 @@ function formatPrompt(task, model, selection) {
708
606
  `# Task: ${task}`,
709
607
  `# Model tier: ${model}`,
710
608
  `# Generated: ${new Date().toISOString()}`,
711
- "",
712
- "## Instructions for the AI",
713
- "The following skills are ordered by relevance to the current task.",
714
- "Level 0 skills contain full rule sets. Level 1 skills contain key rules only.",
715
- "Treat ALL injected rules as mandatory constraints, not suggestions.",
716
- "",
717
- "---",
718
- "",
609
+ '',
610
+ '## Instructions for the AI',
611
+ 'The following skills are ordered by relevance to the current task.',
612
+ 'Level 0 skills contain full rule sets. Level 1 skills contain key rules only.',
613
+ 'Treat ALL injected rules as mandatory constraints, not suggestions.',
614
+ '',
615
+ '---',
616
+ '',
719
617
  ];
720
618
 
721
619
  if (selection.essential.length) {
722
- lines.push("## Level 0 — Essential Skills (Full Context)");
723
- lines.push("");
620
+ lines.push('## Level 0 — Essential Skills (Full Context)');
621
+ lines.push('');
724
622
  for (const s of selection.essential) {
725
623
  lines.push(`### Skill: ${s.name}`);
726
- lines.push("");
727
- if (model === "large") {
624
+ lines.push('');
625
+ if (model === 'large') {
728
626
  lines.push(s.content || s.keyRules);
729
627
  } else {
730
628
  lines.push(s.keyRules);
731
629
  }
732
- lines.push("");
733
- lines.push("---");
734
- lines.push("");
630
+ lines.push('');
631
+ lines.push('---');
632
+ lines.push('');
735
633
  }
736
634
  }
737
635
 
738
- if (model === "large" && selection.supplementary.length) {
739
- lines.push("## Level 1 — Supplementary Skills (Key Rules)");
740
- lines.push("");
636
+ if (model === 'large' && selection.supplementary.length) {
637
+ lines.push('## Level 1 — Supplementary Skills (Key Rules)');
638
+ lines.push('');
741
639
  for (const s of selection.supplementary) {
742
640
  lines.push(`### Skill: ${s.name} (condensed)`);
743
- lines.push("");
641
+ lines.push('');
744
642
  lines.push(s.keyRules);
745
- lines.push("");
746
- lines.push("---");
747
- lines.push("");
643
+ lines.push('');
644
+ lines.push('---');
645
+ lines.push('');
748
646
  }
749
647
  }
750
648
 
751
649
  if (selection.available.length) {
752
- lines.push("## Level 2 — Available Skills (Reference Names Only)");
753
- lines.push("");
650
+ lines.push('## Level 2 — Available Skills (Reference Names Only)');
651
+ lines.push('');
652
+ lines.push('The following skills are relevant but not injected to maintain context density.');
754
653
  lines.push(
755
- "The following skills are relevant but not injected to maintain context density.",
654
+ 'Request their full content if needed: ' + selection.available.map(s => s.name).join(', '),
756
655
  );
757
- lines.push(
758
- "Request their full content if needed: " +
759
- selection.available.map((s) => s.name).join(", "),
760
- );
761
- lines.push("");
656
+ lines.push('');
762
657
  }
763
658
 
764
- return lines.join("\n");
659
+ return lines.join('\n');
765
660
  }
766
661
 
767
662
  // ── Built-in demo ─────────────────────────────────────────────────────────────
@@ -771,58 +666,49 @@ function runDemo(agentDir) {
771
666
 
772
667
  const scenarios = [
773
668
  {
774
- task: "Build a JWT authentication API with Express.js and Zod validation",
775
- file: "auth.ts",
776
- model: "large",
669
+ task: 'Build a JWT authentication API with Express.js and Zod validation',
670
+ file: 'auth.ts',
671
+ model: 'large',
777
672
  },
778
673
  {
779
- task: "Design a premium landing page with GSAP scroll animations",
780
- file: "Hero.tsx",
781
- model: "large",
674
+ task: 'Design a premium landing page with GSAP scroll animations',
675
+ file: 'Hero.tsx',
676
+ model: 'large',
782
677
  },
783
678
  {
784
- task: "Write a Prisma query for paginated user orders",
785
- file: "orders.ts",
786
- model: "small",
679
+ task: 'Write a Prisma query for paginated user orders',
680
+ file: 'orders.ts',
681
+ model: 'small',
787
682
  },
788
683
  {
789
- task: "Add RAG pipeline to an OpenAI-powered chat interface",
790
- file: "chat.ts",
791
- model: "large",
684
+ task: 'Add RAG pipeline to an OpenAI-powered chat interface',
685
+ file: 'chat.ts',
686
+ model: 'large',
792
687
  },
793
688
  ];
794
689
 
795
- console.log(
796
- `\n${BOLD}${CYAN}━━━ Context Broker — Demo Mode ━━━━━━━━━━━━━━━━━━━━━${RESET}`,
797
- );
690
+ console.log(`\n${BOLD}${CYAN}━━━ Context Broker — Demo Mode ━━━━━━━━━━━━━━━━━━━━━${RESET}`);
798
691
  console.log(` Loaded ${skills.length} skills from .agent/skills/\n`);
799
692
 
800
693
  for (const scenario of scenarios) {
801
694
  const t0 = Date.now();
802
695
  const model = scenario.model;
803
- const selection = selectSkills(
804
- scenario.task,
805
- [scenario.file],
806
- model,
807
- skills,
808
- );
696
+ const selection = selectSkills(scenario.task, [scenario.file], model, skills);
809
697
  const elapsed = Date.now() - t0;
810
698
 
811
699
  console.log(
812
700
  `\n ${BOLD}Task: "${scenario.task.slice(0, 70)}"${RESET} ${DIM}[${model} model]${RESET}`,
813
701
  );
814
702
  console.log(
815
- ` Essential : ${GREEN}${selection.essential.map((s) => s.name).join(", ")}${RESET}`,
703
+ ` Essential : ${GREEN}${selection.essential.map(s => s.name).join(', ')}${RESET}`,
816
704
  );
817
705
  console.log(
818
- ` Supplementary : ${YELLOW}${selection.supplementary.map((s) => s.name).join(", ") || "(small mode)"}${RESET}`,
706
+ ` Supplementary : ${YELLOW}${selection.supplementary.map(s => s.name).join(', ') || '(small mode)'}${RESET}`,
819
707
  );
820
708
  console.log(` Time : ${DIM}${elapsed}ms${RESET}`);
821
709
  }
822
710
 
823
- console.log(
824
- `\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n`,
825
- );
711
+ console.log(`\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n`);
826
712
  }
827
713
 
828
714
  // ── Public API ────────────────────────────────────────────────────────────────
@@ -836,11 +722,22 @@ function runDemo(agentDir) {
836
722
  * @param {string} agentDir - Path to .agent/ directory
837
723
  * @returns {{ essential, supplementary, available, promptText }}
838
724
  */
839
- function broker(task, files = [], model = "large", agentDir = null) {
725
+ function broker(task, files = [], model = 'large', agentDir = null) {
726
+ let taskStr = task;
727
+ let filesArr = files;
728
+ let modelStr = model;
729
+
730
+ if (typeof task === 'object' && task !== null) {
731
+ taskStr = task.task || task.spec || '';
732
+ if (task.files) filesArr = task.files;
733
+ if (task.file) filesArr = [task.file];
734
+ if (task.model) modelStr = task.model;
735
+ }
736
+
840
737
  const resolvedAgentDir = agentDir || findAgentDir();
841
738
  const skills = loadSkills(resolvedAgentDir);
842
- const selection = selectSkills(task, files, model, skills);
843
- const promptText = formatPrompt(task, model, selection);
739
+ const selection = selectSkills(taskStr, filesArr, modelStr, skills);
740
+ const promptText = formatPrompt(taskStr, modelStr, selection);
844
741
  return { ...selection, promptText };
845
742
  }
846
743
 
@@ -857,16 +754,16 @@ function broker(task, files = [], model = "large", agentDir = null) {
857
754
  * @param {string} agentDir - Path to .agent/ directory
858
755
  * @returns {object} Phase-specific context
859
756
  */
860
- function brokerForPipeline(task, files = [], phase = "build", agentDir = null) {
757
+ function brokerForPipeline(task, files = [], phase = 'build', agentDir = null) {
861
758
  const resolvedAgentDir = agentDir || findAgentDir();
862
759
  const skills = loadSkills(resolvedAgentDir);
863
760
  // Always use "small" model tier for aggressive pruning in pipeline mode
864
- const selection = selectSkills(task, files, "small", skills);
761
+ const selection = selectSkills(task, files, 'small', skills);
865
762
 
866
- if (phase === "plan") {
763
+ if (phase === 'plan') {
867
764
  // Plan phase: skill names and descriptions only — no content, no keyRules
868
765
  return {
869
- phase: "plan",
766
+ phase: 'plan',
870
767
  skills: selection.essential.slice(0, 6).map(s => ({
871
768
  name: s.name,
872
769
  description: s.description,
@@ -876,23 +773,23 @@ function brokerForPipeline(task, files = [], phase = "build", agentDir = null) {
876
773
  };
877
774
  }
878
775
 
879
- if (phase === "build") {
776
+ if (phase === 'build') {
880
777
  // Build phase: top 3 essential keyRules — maximum density, minimum tokens
881
778
  return {
882
- phase: "build",
779
+ phase: 'build',
883
780
  skills: selection.essential.slice(0, 3).map(s => ({
884
781
  name: s.name,
885
- keyRules: s.keyRules || "",
782
+ keyRules: s.keyRules || '',
886
783
  score: selection.scores.get(s.name) || 0,
887
784
  })),
888
785
  };
889
786
  }
890
787
 
891
- if (phase === "validate") {
788
+ if (phase === 'validate') {
892
789
  // Validate phase: return detected stack for targeted pattern matching
893
790
  const fileExts = files.map(f => path.extname(f).toLowerCase()).filter(Boolean);
894
791
  return {
895
- phase: "validate",
792
+ phase: 'validate',
896
793
  detectedExtensions: fileExts,
897
794
  essentialSkillNames: selection.essential.slice(0, 3).map(s => s.name),
898
795
  };
@@ -910,18 +807,20 @@ function brokerForPipeline(task, files = [], phase = "build", agentDir = null) {
910
807
  */
911
808
  function formatPipelinePlan(task, pipelineResult) {
912
809
  const lines = [
913
- "# Pipeline Planner Context",
810
+ '# Pipeline Planner Context',
914
811
  `# Task: ${task}`,
915
- "",
916
- "## Matched Skills (by relevance)",
917
- "",
812
+ '',
813
+ '## Matched Skills (by relevance)',
814
+ '',
918
815
  ];
919
816
  for (const s of pipelineResult.skills) {
920
- lines.push(`- **${s.name}** (score: ${s.score.toFixed(1)}): ${(s.description || "").slice(0, 120)}`);
817
+ lines.push(
818
+ `- **${s.name}** (score: ${s.score.toFixed(1)}): ${(s.description || '').slice(0, 120)}`,
819
+ );
921
820
  }
922
- lines.push("");
821
+ lines.push('');
923
822
  lines.push(`Total matched: ${pipelineResult.total_matched}`);
924
- return lines.join("\n");
823
+ return lines.join('\n');
925
824
  }
926
825
 
927
826
  /**
@@ -931,24 +830,38 @@ function formatPipelinePlan(task, pipelineResult) {
931
830
  * @returns {string}
932
831
  */
933
832
  function formatPipelineBuild(task, pipelineResult) {
934
- const lines = [
935
- "# Builder Context — Essential Rules Only",
936
- `# Task: ${task}`,
937
- "",
938
- ];
833
+ const lines = ['# Builder Context — Essential Rules Only', `# Task: ${task}`, ''];
939
834
  for (const s of pipelineResult.skills) {
940
835
  lines.push(`## ${s.name}`);
941
- lines.push("");
942
- lines.push(s.keyRules || "(no key rules extracted)");
943
- lines.push("");
944
- lines.push("---");
945
- lines.push("");
836
+ lines.push('');
837
+ lines.push(s.keyRules || '(no key rules extracted)');
838
+ lines.push('');
839
+ lines.push('---');
840
+ lines.push('');
946
841
  }
947
- return lines.join("\n");
842
+ return lines.join('\n');
843
+ }
844
+
845
+ function resolveContext(opts = {}) {
846
+ let task = '';
847
+ let files = [];
848
+ let model = 'large';
849
+ let agentDir = null;
850
+
851
+ if (typeof opts === 'string') {
852
+ task = opts;
853
+ } else if (opts && typeof opts === 'object') {
854
+ task = opts.task || opts.spec || '';
855
+ files = opts.files || (opts.file ? [opts.file] : []);
856
+ model = opts.model || 'large';
857
+ agentDir = opts.agentDir || null;
858
+ }
859
+ return broker(task, files, model, agentDir);
948
860
  }
949
861
 
950
862
  module.exports = {
951
863
  broker,
864
+ resolveContext,
952
865
  brokerForPipeline,
953
866
  selectSkills,
954
867
  loadSkills,
@@ -964,7 +877,7 @@ module.exports = {
964
877
  if (require.main === module) {
965
878
  const argv = process.argv.slice(2);
966
879
 
967
- if (!argv.length || argv.includes("--help") || argv.includes("-h")) {
880
+ if (!argv.length || argv.includes('--help') || argv.includes('-h')) {
968
881
  console.log(`
969
882
  ${BOLD}context_broker.js${RESET} — Tribunal Focus-without-Compromise Context Engine
970
883
 
@@ -993,21 +906,19 @@ ${BOLD}Examples:${RESET}
993
906
 
994
907
  const agentDir = findAgentDir();
995
908
 
996
- if (argv[0] === "demo") {
909
+ if (argv[0] === 'demo') {
997
910
  runDemo(agentDir);
998
911
  process.exit(0);
999
912
  }
1000
913
 
1001
914
  // Parse args
1002
- const taskIdx = argv.indexOf("--task");
1003
- const modelIdx = argv.indexOf("--model");
1004
- const outputIdx = argv.indexOf("--output");
915
+ const taskIdx = argv.indexOf('--task');
916
+ const modelIdx = argv.indexOf('--model');
917
+ const outputIdx = argv.indexOf('--output');
1005
918
 
1006
- const task = taskIdx !== -1 && argv[taskIdx + 1] ? argv[taskIdx + 1] : "";
1007
- const model =
1008
- modelIdx !== -1 && argv[modelIdx + 1] ? argv[modelIdx + 1] : "large";
1009
- const output =
1010
- outputIdx !== -1 && argv[outputIdx + 1] ? argv[outputIdx + 1] : "report";
919
+ const task = taskIdx !== -1 && argv[taskIdx + 1] ? argv[taskIdx + 1] : '';
920
+ const model = modelIdx !== -1 && argv[modelIdx + 1] ? argv[modelIdx + 1] : 'large';
921
+ const output = outputIdx !== -1 && argv[outputIdx + 1] ? argv[outputIdx + 1] : 'report';
1011
922
 
1012
923
  if (!task) {
1013
924
  console.error(`${RED}✖ --task is required${RESET}`);
@@ -1017,16 +928,14 @@ ${BOLD}Examples:${RESET}
1017
928
  // Collect --file arguments (may appear multiple times)
1018
929
  const files = [];
1019
930
  for (let i = 0; i < argv.length; i++) {
1020
- if (argv[i] === "--file" && argv[i + 1]) files.push(argv[i + 1]);
931
+ if (argv[i] === '--file' && argv[i + 1]) files.push(argv[i + 1]);
1021
932
  }
1022
933
 
1023
- const validModels = ["large", "small"];
934
+ const validModels = ['large', 'small'];
1024
935
  let effectiveModel = model;
1025
936
  if (!validModels.includes(model)) {
1026
- console.error(
1027
- `${YELLOW}⚠ Unknown model tier "${model}" — defaulting to "large"${RESET}`,
1028
- );
1029
- effectiveModel = "large";
937
+ console.error(`${YELLOW}⚠ Unknown model tier "${model}" — defaulting to "large"${RESET}`);
938
+ effectiveModel = 'large';
1030
939
  }
1031
940
 
1032
941
  const t0 = Date.now();
@@ -1035,22 +944,22 @@ ${BOLD}Examples:${RESET}
1035
944
  const elapsed = Date.now() - t0;
1036
945
 
1037
946
  switch (output) {
1038
- case "json":
947
+ case 'json':
1039
948
  console.log(formatJson(task, effectiveModel, selection));
1040
949
  break;
1041
- case "names":
950
+ case 'names':
1042
951
  console.log(formatNames(selection, effectiveModel));
1043
952
  break;
1044
- case "prompt":
953
+ case 'prompt':
1045
954
  console.log(formatPrompt(task, effectiveModel, selection));
1046
955
  break;
1047
- case "pipeline-plan": {
1048
- const pipelinePlan = brokerForPipeline(task, files, "plan", agentDir);
956
+ case 'pipeline-plan': {
957
+ const pipelinePlan = brokerForPipeline(task, files, 'plan', agentDir);
1049
958
  console.log(formatPipelinePlan(task, pipelinePlan));
1050
959
  break;
1051
960
  }
1052
- case "pipeline-build": {
1053
- const pipelineBuild = brokerForPipeline(task, files, "build", agentDir);
961
+ case 'pipeline-build': {
962
+ const pipelineBuild = brokerForPipeline(task, files, 'build', agentDir);
1054
963
  console.log(formatPipelineBuild(task, pipelineBuild));
1055
964
  break;
1056
965
  }
@@ -1059,7 +968,3 @@ ${BOLD}Examples:${RESET}
1059
968
  break;
1060
969
  }
1061
970
  }
1062
-
1063
-
1064
-
1065
-