@triedotdev/mcp 1.0.33 → 1.0.35

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.
package/README.md CHANGED
@@ -4,6 +4,16 @@
4
4
 
5
5
  20 specialized agents scan your code for security, privacy, compliance, and bugs—all running in parallel with intelligent caching and real-time streaming.
6
6
 
7
+ ## Why Trie
8
+
9
+ I like Claude Code Skills, but I found myself wanting more control. Trie keeps one code-first harness (registry + triager) across MCP, CLI, and CI, so the same agents and policies run everywhere—no shuffling separate .md skills per tool. It can turn my docs (PDF/TXT/MD/RTF) into agents (ingests, compresses, builds prompts, saves to `.trie/agents/`), lets me version and test them in TypeScript/JSON with identical behavior locally and in CI, and triager logs show which agents ran and why—no implicit routing. Trie is for people who want to build and govern their own agents with source-controlled prompts and transparent routing.
10
+
11
+ ## What's New (latest updates)
12
+ - Slash-friendly commands: `/trie` and `/trie_<tool>` work the same as `trie`.
13
+ - Command palette: call `trie` with `action` to dispatch (scan, any agent, agent_smith, pr_review, watch, test, fix, explain, list_agents).
14
+ - Clear MCP naming: all tools are discoverable with `trie_*` prefixes while short aliases still work.
15
+ - Agent Smith speedups: single-pass file loading (skips binaries/giants), shared content across hunters, and stable memory hashes for better resurrected-issue tracking.
16
+
7
17
  ---
8
18
 
9
19
  ## Table of Contents
@@ -112,6 +122,12 @@ Run trie_security on this file
112
122
  Run trie_soc2 to check compliance
113
123
  ```
114
124
 
125
+ Slash-friendly command palette:
126
+
127
+ - `trie` or `/trie` shows the quick menu.
128
+ - `trie` / `/trie` with `{ action: "scan", files?: [], directory?: "" }` runs a full triaged scan.
129
+ - `trie` / `/trie` with `{ action: "<agent>", files?: [] }` runs one agent (e.g., `security`, `ux`, `soc2`, `agent_smith`).
130
+
115
131
  ### How It Works
116
132
 
117
133
  Trie generates **actionable reports** with high-confidence issues. It does not auto-fix code. Instead:
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  AgentSmithAgent,
3
3
  SUB_AGENT_PATTERNS
4
- } from "./chunk-ARUHDATG.js";
4
+ } from "./chunk-OB45V2QC.js";
5
5
  import "./chunk-IMFD4SJC.js";
6
6
  import "./chunk-DGUM43GV.js";
7
7
  export {
8
8
  AgentSmithAgent,
9
9
  SUB_AGENT_PATTERNS
10
10
  };
11
- //# sourceMappingURL=agent-smith-TNDAPXIU.js.map
11
+ //# sourceMappingURL=agent-smith-W7F55E6P.js.map
@@ -3,7 +3,7 @@ import {
3
3
  getAIStatusMessage,
4
4
  isAIAvailable,
5
5
  runAIAnalysis
6
- } from "./chunk-ARUHDATG.js";
6
+ } from "./chunk-OB45V2QC.js";
7
7
  import {
8
8
  getWorkingDirectory
9
9
  } from "./chunk-IMFD4SJC.js";
@@ -553,4 +553,4 @@ ${getAIStatusMessage()}`);
553
553
  export {
554
554
  runAgentSmith
555
555
  };
556
- //# sourceMappingURL=agent-smith-runner-63Q6D473.js.map
556
+ //# sourceMappingURL=agent-smith-runner-SH76O724.js.map
@@ -609,6 +609,10 @@ var MEMORY_LIMITS = {
609
609
  MAX_TRACKED_ISSUES: 500,
610
610
  PRUNE_AFTER_DAYS: 30
611
611
  };
612
+ var FILE_SCAN_LIMITS = {
613
+ MAX_BYTES: 75e4
614
+ // Skip extremely large files to avoid thrashing
615
+ };
612
616
  var SUB_AGENT_PATTERNS = {
613
617
  // === CRITICAL: Security (AI exposes secrets constantly) ===
614
618
  "exposed-secret-hunter": {
@@ -869,6 +873,7 @@ var AgentSmithAgent = class extends BaseAgent {
869
873
  description = "Ultimate vibe code enforcer: 35 hunters, file analysis, cross-file detection, persistent memory";
870
874
  version = "2.0.0";
871
875
  memoryPath = "";
876
+ memoryBaseDir = null;
872
877
  memory = null;
873
878
  swarmAnimationLog = [];
874
879
  shouldActivate(_context) {
@@ -884,17 +889,22 @@ var AgentSmithAgent = class extends BaseAgent {
884
889
  // No override needed — base class returns 0 when shouldActivate is false
885
890
  async analyzeFiles(files, context) {
886
891
  const issues = [];
892
+ const fileContents = await this.loadFileContents(files);
893
+ const loadedFiles = Array.from(fileContents.keys());
887
894
  this.displaySmithEntrance();
888
895
  await this.loadMemory(context.workingDir);
889
896
  console.error(`
890
- \u{1F574}\uFE0F Deploying sub-agent swarm across ${files.length} files...`);
891
- const subAgentResults = await this.deploySubAgents(files);
897
+ \u{1F574}\uFE0F Deploying sub-agent swarm across ${loadedFiles.length} files...`);
898
+ const subAgentResults = await this.deploySubAgents(loadedFiles, fileContents);
899
+ if (this.swarmAnimationLog.length > 0) {
900
+ console.error(this.swarmAnimationLog.join("\n"));
901
+ }
892
902
  for (const result of subAgentResults) {
893
903
  const subIssues = await this.processSubAgentResult(result, context);
894
904
  issues.push(...subIssues);
895
905
  }
896
906
  console.error(`\u{1F574}\uFE0F Analyzing file-level metrics...`);
897
- const fileLevelResults = await this.analyzeFileLevelIssues(files);
907
+ const fileLevelResults = await this.analyzeFileLevelIssues(fileContents);
898
908
  for (const result of fileLevelResults) {
899
909
  for (const fileIssue of result.issues) {
900
910
  issues.push(this.createSmithIssue(
@@ -930,8 +940,8 @@ Found in ${result.occurrences.length} files, ${result.totalCount} total instance
930
940
  const resurrectedIssues = this.checkForResurrectedIssues(issues);
931
941
  issues.push(...resurrectedIssues);
932
942
  await this.saveMemory();
933
- if (files.length > 0) {
934
- const aiIssue = this.createAIAnalysisIssue(files, subAgentResults);
943
+ if (loadedFiles.length > 0) {
944
+ const aiIssue = this.createAIAnalysisIssue(loadedFiles, subAgentResults);
935
945
  issues.push(aiIssue);
936
946
  }
937
947
  console.error(`
@@ -942,11 +952,10 @@ Found in ${result.occurrences.length} files, ${result.totalCount} total instance
942
952
  /**
943
953
  * Analyze file-level issues (size, hook counts, complexity)
944
954
  */
945
- async analyzeFileLevelIssues(files) {
955
+ async analyzeFileLevelIssues(fileContents) {
946
956
  const results = [];
947
- for (const file of files) {
957
+ for (const [file, content] of fileContents.entries()) {
948
958
  try {
949
- const content = await this.readFileContent(file);
950
959
  const lines = content.split("\n");
951
960
  const lineCount = lines.length;
952
961
  const fileName = file.split("/").pop() || "";
@@ -1092,7 +1101,7 @@ Found in ${result.occurrences.length} files, ${result.totalCount} total instance
1092
1101
  * VIBE CODE FOCUSED: 35 specialized hunters targeting AI-generated anti-patterns.
1093
1102
  * Agent Smith hunts down EVERY instance across the entire codebase.
1094
1103
  */
1095
- async deploySubAgents(files) {
1104
+ async deploySubAgents(files, fileContents) {
1096
1105
  const subAgentTypes = [
1097
1106
  // === CRITICAL: Security (AI exposes secrets constantly) ===
1098
1107
  "exposed-secret-hunter",
@@ -1142,7 +1151,7 @@ Found in ${result.occurrences.length} files, ${result.totalCount} total instance
1142
1151
  "inter-font-hunter"
1143
1152
  ];
1144
1153
  console.error(` Deploying ${subAgentTypes.length} specialized hunters across ${files.length} files...`);
1145
- const { results, animationLog } = await this.runAgentSwarm(subAgentTypes, files);
1154
+ const { results, animationLog } = await this.runAgentSwarm(subAgentTypes, fileContents);
1146
1155
  this.swarmAnimationLog = animationLog;
1147
1156
  const activeHunters = results.filter((r) => r.instances.length > 0);
1148
1157
  console.error(`
@@ -1153,7 +1162,7 @@ Found in ${result.occurrences.length} files, ${result.totalCount} total instance
1153
1162
  /**
1154
1163
  * Run agents with visual swarming animation - captures output for display
1155
1164
  */
1156
- async runAgentSwarm(subAgentTypes, files) {
1165
+ async runAgentSwarm(subAgentTypes, fileContents) {
1157
1166
  const results = [];
1158
1167
  const animationLog = [];
1159
1168
  const agentChars = ["\u25E2", "\u25E3", "\u25E4", "\u25E5", "\u25B2", "\u25BC", "\u25C6", "\u25CF", "\u25B6", "\u25C0"];
@@ -1168,7 +1177,7 @@ Found in ${result.occurrences.length} files, ${result.totalCount} total instance
1168
1177
  animationLog.push(` Batch ${batchNum}/${totalBatches}: [${batchDisplay}] deploying...`);
1169
1178
  const startTime = Date.now();
1170
1179
  const batchPromises = batch.map(async (type, idx) => {
1171
- const result = await this.runSubAgent(type, files);
1180
+ const result = await this.runSubAgent(type, fileContents);
1172
1181
  return { result, agentChar: agentChars[idx % agentChars.length], type };
1173
1182
  });
1174
1183
  const batchResults = await Promise.all(batchPromises);
@@ -1206,25 +1215,14 @@ Found in ${result.occurrences.length} files, ${result.totalCount} total instance
1206
1215
  if (seriousAgents.includes(agentType)) return "serious";
1207
1216
  return "moderate";
1208
1217
  }
1209
- /**
1210
- * Get inevitability interpretation
1211
- */
1212
- getInevitabilityInterpretation(score) {
1213
- if (score >= 80) return { level: "INEVITABLE", message: "Will cause production issues", emoji: "\u{1F480}" };
1214
- if (score >= 60) return { level: "HIGHLY LIKELY", message: "Significant risk pattern", emoji: "\u26A0\uFE0F" };
1215
- if (score >= 40) return { level: "PROBABLE", message: "Worth addressing soon", emoji: "\u{1F50D}" };
1216
- if (score >= 20) return { level: "POSSIBLE", message: "Monitor for spread", emoji: "\u{1F441}\uFE0F" };
1217
- return { level: "UNLIKELY", message: "Low priority pattern", emoji: "\u2713" };
1218
- }
1219
1218
  /**
1220
1219
  * Run a single sub-agent across all files
1221
1220
  */
1222
- async runSubAgent(type, files) {
1221
+ async runSubAgent(type, fileContents) {
1223
1222
  const config = SUB_AGENT_PATTERNS[type];
1224
1223
  const instances = [];
1225
- for (const file of files) {
1224
+ for (const [file, content] of fileContents.entries()) {
1226
1225
  try {
1227
- const content = await this.readFileContent(file);
1228
1226
  const lines = content.split("\n");
1229
1227
  if (this.isTestFile(file) && type !== "todo-hunter") {
1230
1228
  continue;
@@ -1266,11 +1264,12 @@ Found in ${result.occurrences.length} files, ${result.totalCount} total instance
1266
1264
  const inevitabilityScore = this.calculateInevitabilityScore(result.type, instances.length);
1267
1265
  const hash = this.createPatternHash(result.type, file);
1268
1266
  await this.updateMemory(hash, result.pattern, result.type, file, instances.length);
1267
+ const issueId = this.generateSmithIssueId(hash);
1269
1268
  const severity = this.determineSeverity(instances.length, inevitabilityScore);
1270
1269
  const smithNote = this.getPhilosophicalNote(result.type, instances.length);
1271
1270
  const locationsStr = instances.map((i) => `${basename(i.file)}:${i.line}`).slice(0, 5).join(", ");
1272
1271
  issues.push(this.createSmithIssue(
1273
- this.generateSmithIssueId(),
1272
+ issueId,
1274
1273
  severity,
1275
1274
  `\u{1F574}\uFE0F ${config.description} \u2014 ${instances.length} instance${instances.length > 1 ? "s" : ""} in ${basename(file)}
1276
1275
 
@@ -1367,6 +1366,12 @@ Dismissed: ${new Date(memory.dismissedAt).toLocaleDateString()}
1367
1366
  "placeholder-hunter": 55,
1368
1367
  "sleep-hack-hunter": 65,
1369
1368
  "fallback-hunter": 75,
1369
+ // LOW: Dead code
1370
+ "commented-code-hunter": 25,
1371
+ "unreachable-code-hunter": 45,
1372
+ "unused-import-hunter": 20,
1373
+ "empty-function-hunter": 35,
1374
+ "dead-branch-hunter": 30,
1370
1375
  // LOW: AI Slop Aesthetic
1371
1376
  "purple-gradient-hunter": 25,
1372
1377
  "star-icon-hunter": 20,
@@ -1567,6 +1572,32 @@ Dismissed: ${new Date(memory.dismissedAt).toLocaleDateString()}
1567
1572
  '"return []. Empty array, empty understanding, empty debugging."',
1568
1573
  `"Fallback code. The bug is still there. You just can't see it anymore."`
1569
1574
  ],
1575
+ // === DEAD CODE (AI leaves cruft everywhere) ===
1576
+ "commented-code-hunter": [
1577
+ '"Commented-out blocks. Fossils of code past. Confusion for the future."',
1578
+ '"Large comment blocks hide history. Git already remembers. Delete the noise."',
1579
+ '"Dead code in comments. The AI was unsure. You should be certain."'
1580
+ ],
1581
+ "unreachable-code-hunter": [
1582
+ '"Code after return. Forever skipped. Forever confusing."',
1583
+ '"Unreachable branches. They stay forever. Bugs hide behind them."',
1584
+ '"Execution stops. The dead code remains. Remove the ghosts."'
1585
+ ],
1586
+ "unused-import-hunter": [
1587
+ '"Imports unused. Bundles bloated. Intent unclear."',
1588
+ '"An import with no purpose. The AI added it. You can remove it."',
1589
+ '"Unused imports multiply. Tree shaking sighs."'
1590
+ ],
1591
+ "empty-function-hunter": [
1592
+ '"Empty function bodies. Promises without delivery."',
1593
+ '"Stub functions linger. The AI forgot to finish."',
1594
+ '"Empty handlers. They do nothing. They hide missing behavior."'
1595
+ ],
1596
+ "dead-branch-hunter": [
1597
+ '"if (true) with no reason. if (false) with no hope."',
1598
+ '"Dead conditionals: code that never runs, but always confuses."',
1599
+ '"Always-true or always-false. Remove the illusion of choice."'
1600
+ ],
1570
1601
  // AI Slop Aesthetic
1571
1602
  "purple-gradient-hunter": [
1572
1603
  `"Purple gradient. The AI's signature. Every vibe-coded site... looks the same."`,
@@ -1625,6 +1656,7 @@ Files scanned: ${files.length}
1625
1656
  * Load memory from disk
1626
1657
  */
1627
1658
  async loadMemory(workingDir) {
1659
+ this.memoryBaseDir = workingDir;
1628
1660
  this.memoryPath = join2(workingDir, ".trie", "smith-memory.json");
1629
1661
  try {
1630
1662
  if (existsSync2(this.memoryPath)) {
@@ -1787,8 +1819,9 @@ Files scanned: ${files.length}
1787
1819
  /**
1788
1820
  * Dismiss an issue (mark it as seen/accepted)
1789
1821
  */
1790
- async dismissIssue(hash) {
1791
- await this.loadMemory(process.cwd());
1822
+ async dismissIssue(hash, workingDir) {
1823
+ const baseDir = this.memoryBaseDir ?? workingDir ?? process.cwd();
1824
+ await this.loadMemory(baseDir);
1792
1825
  if (this.memory && this.memory.issues[hash]) {
1793
1826
  this.memory.issues[hash].dismissedAt = (/* @__PURE__ */ new Date()).toISOString();
1794
1827
  await this.saveMemory();
@@ -1806,7 +1839,9 @@ Files scanned: ${files.length}
1806
1839
  countCurrentOccurrences(hash, issues) {
1807
1840
  const memory = this.memory?.issues[hash];
1808
1841
  if (!memory) return 0;
1809
- return issues.filter((i) => i.category === memory.category || i.issue.includes(memory.category)).length;
1842
+ return issues.filter(
1843
+ (i) => i.id.includes(hash) || i.category === memory.category || (memory.category ? i.issue.includes(memory.category) : false)
1844
+ ).length;
1810
1845
  }
1811
1846
  /**
1812
1847
  * Check if file is a test file
@@ -1815,8 +1850,22 @@ Files scanned: ${files.length}
1815
1850
  return /\.(test|spec)\.[jt]sx?$/.test(file) || /__(tests|mocks)__/.test(file) || /\/test\//.test(file);
1816
1851
  }
1817
1852
  // ============ Helper Methods ============
1818
- async readFileContent(filePath) {
1819
- return await readFile(filePath, "utf-8");
1853
+ /**
1854
+ * Preload file contents once to avoid repeated I/O across sub-agents
1855
+ */
1856
+ async loadFileContents(files) {
1857
+ const contents = /* @__PURE__ */ new Map();
1858
+ for (const file of files) {
1859
+ try {
1860
+ const buffer = await readFile(file);
1861
+ if (buffer.includes(0) || buffer.byteLength > FILE_SCAN_LIMITS.MAX_BYTES) {
1862
+ continue;
1863
+ }
1864
+ contents.set(file, buffer.toString("utf-8"));
1865
+ } catch {
1866
+ }
1867
+ }
1868
+ return contents;
1820
1869
  }
1821
1870
  createSmithIssue(id, severity, issue, fix, file, line, category) {
1822
1871
  const result = {
@@ -1837,8 +1886,9 @@ Files scanned: ${files.length}
1837
1886
  }
1838
1887
  return result;
1839
1888
  }
1840
- generateSmithIssueId() {
1841
- return `smith-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1889
+ generateSmithIssueId(seed) {
1890
+ const base = seed ? `smith-${seed}` : "smith";
1891
+ return `${base}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1842
1892
  }
1843
1893
  };
1844
1894
 
@@ -1851,4 +1901,4 @@ export {
1851
1901
  SUB_AGENT_PATTERNS,
1852
1902
  AgentSmithAgent
1853
1903
  };
1854
- //# sourceMappingURL=chunk-ARUHDATG.js.map
1904
+ //# sourceMappingURL=chunk-OB45V2QC.js.map