@triedotdev/mcp 1.0.94 → 1.0.97
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 +145 -137
- package/dist/{chunk-JAAIHNOE.js → chunk-APMV77PU.js} +21 -6
- package/dist/chunk-APMV77PU.js.map +1 -0
- package/dist/{chunk-HLSBTOVE.js → chunk-B3MNN3XB.js} +13 -18
- package/dist/{chunk-HLSBTOVE.js.map → chunk-B3MNN3XB.js.map} +1 -1
- package/dist/{chunk-JO6RVXS6.js → chunk-F4NJ4CBP.js} +2 -2
- package/dist/{chunk-AZRCKBGF.js → chunk-FNCCZ3XB.js} +1222 -75
- package/dist/chunk-FNCCZ3XB.js.map +1 -0
- package/dist/chunk-G76DYVGX.js +136 -0
- package/dist/chunk-G76DYVGX.js.map +1 -0
- package/dist/chunk-HSNE46VE.js +956 -0
- package/dist/chunk-HSNE46VE.js.map +1 -0
- package/dist/{chunk-STEFLYPR.js → chunk-IXO4G4D3.js} +2 -2
- package/dist/{chunk-OEYIOOYB.js → chunk-JDHR5BDR.js} +2 -3
- package/dist/chunk-NIASHOAB.js +1304 -0
- package/dist/chunk-NIASHOAB.js.map +1 -0
- package/dist/{chunk-CKM6A3G6.js → chunk-OVRG5RP3.js} +6 -7
- package/dist/chunk-OVRG5RP3.js.map +1 -0
- package/dist/{chunk-RYRVEO2B.js → chunk-R3I2GCZC.js} +3 -3
- package/dist/{chunk-WT3XQCG2.js → chunk-R4AAPFXC.js} +2 -2
- package/dist/{chunk-IIF5XDCJ.js → chunk-SLL2MDJD.js} +786 -4694
- package/dist/chunk-SLL2MDJD.js.map +1 -0
- package/dist/cli/create-agent.js +931 -7
- package/dist/cli/create-agent.js.map +1 -1
- package/dist/cli/main.js +151 -383
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +13 -20
- package/dist/cli/yolo-daemon.js.map +1 -1
- package/dist/{goal-manager-HOZ7R2QV.js → goal-manager-LAOT4QQX.js} +6 -6
- package/dist/guardian-agent-M352CBE5.js +19 -0
- package/dist/index.js +1025 -1550
- package/dist/index.js.map +1 -1
- package/dist/{issue-store-DXIOP6AK.js → issue-store-W2X33X2X.js} +4 -4
- package/dist/{progress-LHI66U7B.js → progress-PQVEM7BR.js} +2 -2
- package/dist/{vibe-code-signatures-C5A4BHXD.js → vibe-code-signatures-ELEWJFGZ.js} +3 -3
- package/dist/{vulnerability-signatures-SVIHJQO5.js → vulnerability-signatures-EIJQX2TS.js} +3 -3
- package/dist/workers/agent-worker.js +2 -11
- package/dist/workers/agent-worker.js.map +1 -1
- package/package.json +2 -2
- package/dist/agent-smith-MYQ35URL.js +0 -14
- package/dist/agent-smith-runner-4TBONXCP.js +0 -573
- package/dist/agent-smith-runner-4TBONXCP.js.map +0 -1
- package/dist/cache-manager-RMPRPD5T.js +0 -10
- package/dist/chunk-AZRCKBGF.js.map +0 -1
- package/dist/chunk-CKM6A3G6.js.map +0 -1
- package/dist/chunk-E2ZATINO.js +0 -10879
- package/dist/chunk-E2ZATINO.js.map +0 -1
- package/dist/chunk-FFWNZUG2.js +0 -266
- package/dist/chunk-FFWNZUG2.js.map +0 -1
- package/dist/chunk-FK6DQKDY.js +0 -175
- package/dist/chunk-FK6DQKDY.js.map +0 -1
- package/dist/chunk-IFGF33R5.js +0 -279
- package/dist/chunk-IFGF33R5.js.map +0 -1
- package/dist/chunk-IIF5XDCJ.js.map +0 -1
- package/dist/chunk-JAAIHNOE.js.map +0 -1
- package/dist/chunk-ODWDESYP.js +0 -141
- package/dist/chunk-ODWDESYP.js.map +0 -1
- package/dist/chunk-OWBWNXSC.js +0 -955
- package/dist/chunk-OWBWNXSC.js.map +0 -1
- package/dist/chunk-Q764X2WD.js +0 -2124
- package/dist/chunk-Q764X2WD.js.map +0 -1
- package/dist/chunk-RE6ZWXJC.js +0 -279
- package/dist/chunk-RE6ZWXJC.js.map +0 -1
- package/dist/chunk-RNJ6JKMA.js +0 -2270
- package/dist/chunk-RNJ6JKMA.js.map +0 -1
- package/dist/chunk-Y62VM3ER.js +0 -536
- package/dist/chunk-Y62VM3ER.js.map +0 -1
- package/dist/git-45LZUUYA.js +0 -29
- package/dist/guardian-agent-RB2UQP5V.js +0 -21
- package/dist/progress-LHI66U7B.js.map +0 -1
- package/dist/vibe-code-signatures-C5A4BHXD.js.map +0 -1
- package/dist/vulnerability-signatures-SVIHJQO5.js.map +0 -1
- /package/dist/{chunk-JO6RVXS6.js.map → chunk-F4NJ4CBP.js.map} +0 -0
- /package/dist/{chunk-STEFLYPR.js.map → chunk-IXO4G4D3.js.map} +0 -0
- /package/dist/{chunk-OEYIOOYB.js.map → chunk-JDHR5BDR.js.map} +0 -0
- /package/dist/{chunk-RYRVEO2B.js.map → chunk-R3I2GCZC.js.map} +0 -0
- /package/dist/{chunk-WT3XQCG2.js.map → chunk-R4AAPFXC.js.map} +0 -0
- /package/dist/{agent-smith-MYQ35URL.js.map → goal-manager-LAOT4QQX.js.map} +0 -0
- /package/dist/{cache-manager-RMPRPD5T.js.map → guardian-agent-M352CBE5.js.map} +0 -0
- /package/dist/{git-45LZUUYA.js.map → issue-store-W2X33X2X.js.map} +0 -0
- /package/dist/{goal-manager-HOZ7R2QV.js.map → progress-PQVEM7BR.js.map} +0 -0
- /package/dist/{guardian-agent-RB2UQP5V.js.map → vibe-code-signatures-ELEWJFGZ.js.map} +0 -0
- /package/dist/{issue-store-DXIOP6AK.js.map → vulnerability-signatures-EIJQX2TS.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
listCustomAgents,
|
|
4
|
-
loadAgentConfig,
|
|
5
|
-
parseDocument
|
|
6
|
-
} from "./chunk-OWBWNXSC.js";
|
|
7
2
|
import {
|
|
8
3
|
IncidentIndex,
|
|
9
4
|
LearningEngine,
|
|
@@ -17,6 +12,7 @@ import {
|
|
|
17
12
|
initializeBootstrapFiles,
|
|
18
13
|
listCheckpoints,
|
|
19
14
|
loadBootstrapContext,
|
|
15
|
+
loadConfig,
|
|
20
16
|
loadRules,
|
|
21
17
|
loadTeamInfo,
|
|
22
18
|
needsBootstrap,
|
|
@@ -24,50 +20,45 @@ import {
|
|
|
24
20
|
reasonAboutChangesHumanReadable,
|
|
25
21
|
saveCheckpoint,
|
|
26
22
|
trackIssueOccurrence
|
|
27
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-FNCCZ3XB.js";
|
|
28
24
|
import {
|
|
29
25
|
InteractiveDashboard,
|
|
30
26
|
StreamingManager,
|
|
31
|
-
TrieScanTool
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
import
|
|
36
|
-
isTrieInitialized,
|
|
37
|
-
loadConfig
|
|
38
|
-
} from "./chunk-Q764X2WD.js";
|
|
39
|
-
import "./chunk-RE6ZWXJC.js";
|
|
40
|
-
import "./chunk-FK6DQKDY.js";
|
|
41
|
-
import {
|
|
42
|
-
ContextGraph
|
|
43
|
-
} from "./chunk-Y62VM3ER.js";
|
|
44
|
-
import "./chunk-JO6RVXS6.js";
|
|
45
|
-
import "./chunk-RYRVEO2B.js";
|
|
27
|
+
TrieScanTool,
|
|
28
|
+
getOutputManager,
|
|
29
|
+
listInstalledSkills
|
|
30
|
+
} from "./chunk-SLL2MDJD.js";
|
|
31
|
+
import "./chunk-B3MNN3XB.js";
|
|
46
32
|
import {
|
|
47
|
-
CRITICAL_REVIEW_CHECKLIST,
|
|
48
|
-
SuperReviewerSkill,
|
|
49
33
|
appendToSection,
|
|
50
34
|
getContextForAI,
|
|
51
35
|
getProjectInfoStructured,
|
|
52
36
|
getProjectSection,
|
|
53
37
|
getProjectSections,
|
|
54
|
-
getSkillRegistry,
|
|
55
38
|
initProjectInfo,
|
|
56
|
-
|
|
39
|
+
isTrieInitialized,
|
|
57
40
|
loadContextState,
|
|
58
41
|
loadProjectInfo,
|
|
59
42
|
projectInfoExists,
|
|
43
|
+
runShellCommandSync,
|
|
60
44
|
updateProjectSection
|
|
61
|
-
} from "./chunk-
|
|
62
|
-
import {
|
|
63
|
-
runShellCommandSync
|
|
64
|
-
} from "./chunk-IFGF33R5.js";
|
|
45
|
+
} from "./chunk-HSNE46VE.js";
|
|
65
46
|
import {
|
|
47
|
+
ContextGraph,
|
|
66
48
|
findCrossProjectPatterns,
|
|
67
49
|
getGlobalMemoryStats,
|
|
50
|
+
getStorage,
|
|
68
51
|
listTrackedProjects,
|
|
69
52
|
searchGlobalPatterns
|
|
70
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-NIASHOAB.js";
|
|
54
|
+
import "./chunk-F4NJ4CBP.js";
|
|
55
|
+
import "./chunk-IXO4G4D3.js";
|
|
56
|
+
import "./chunk-6NLHFIYA.js";
|
|
57
|
+
import {
|
|
58
|
+
getSkillRegistry
|
|
59
|
+
} from "./chunk-G76DYVGX.js";
|
|
60
|
+
import "./chunk-OVRG5RP3.js";
|
|
61
|
+
import "./chunk-R3I2GCZC.js";
|
|
71
62
|
import {
|
|
72
63
|
findSimilarIssues,
|
|
73
64
|
getMemoryStats,
|
|
@@ -75,20 +66,14 @@ import {
|
|
|
75
66
|
markIssueResolved,
|
|
76
67
|
purgeIssues,
|
|
77
68
|
searchIssues
|
|
78
|
-
} from "./chunk-
|
|
79
|
-
import "./chunk-STEFLYPR.js";
|
|
80
|
-
import "./chunk-6NLHFIYA.js";
|
|
81
|
-
import {
|
|
82
|
-
getOutputManager
|
|
83
|
-
} from "./chunk-RNJ6JKMA.js";
|
|
84
|
-
import "./chunk-ODWDESYP.js";
|
|
69
|
+
} from "./chunk-JDHR5BDR.js";
|
|
85
70
|
import {
|
|
86
71
|
getTrieDirectory,
|
|
87
72
|
getWorkingDirectory
|
|
88
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-R4AAPFXC.js";
|
|
89
74
|
import {
|
|
90
75
|
isInteractiveMode
|
|
91
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-APMV77PU.js";
|
|
92
77
|
import "./chunk-DGUM43GV.js";
|
|
93
78
|
|
|
94
79
|
// src/server/mcp-server.ts
|
|
@@ -223,43 +208,6 @@ Provide:
|
|
|
223
208
|
1. The exact code fix (ready to apply)
|
|
224
209
|
2. Explanation of why this fix works
|
|
225
210
|
3. Any additional hardening recommendations`
|
|
226
|
-
},
|
|
227
|
-
privacy: {
|
|
228
|
-
system: `You are a data privacy officer and GDPR/HIPAA compliance expert.
|
|
229
|
-
Analyze code for privacy violations and data protection issues.
|
|
230
|
-
|
|
231
|
-
Key regulations to enforce:
|
|
232
|
-
- GDPR (EU data protection)
|
|
233
|
-
- CCPA (California privacy)
|
|
234
|
-
- HIPAA (health data)
|
|
235
|
-
- COPPA (children's privacy)
|
|
236
|
-
- PCI DSS (payment data)
|
|
237
|
-
|
|
238
|
-
Look for:
|
|
239
|
-
- PII without encryption
|
|
240
|
-
- Missing consent mechanisms
|
|
241
|
-
- Data retention violations
|
|
242
|
-
- Cross-border data transfer issues
|
|
243
|
-
- Third-party data sharing without disclosure`,
|
|
244
|
-
analysis: `## Privacy Compliance Audit
|
|
245
|
-
|
|
246
|
-
Analyze this code for privacy/compliance issues:
|
|
247
|
-
|
|
248
|
-
\`\`\`{{language}}
|
|
249
|
-
{{code}}
|
|
250
|
-
\`\`\`
|
|
251
|
-
|
|
252
|
-
**File:** {{filePath}}
|
|
253
|
-
**Data Types Detected:** {{dataTypes}}
|
|
254
|
-
|
|
255
|
-
For each issue:
|
|
256
|
-
1. Regulation violated (e.g., GDPR Article 32)
|
|
257
|
-
2. Specific requirement not met
|
|
258
|
-
3. Risk level and potential fine exposure
|
|
259
|
-
4. Remediation steps with code examples
|
|
260
|
-
5. Documentation requirements
|
|
261
|
-
|
|
262
|
-
Reference current regulatory guidance when applicable.`
|
|
263
211
|
},
|
|
264
212
|
legal: {
|
|
265
213
|
system: `You are a tech-focused legal compliance analyst.
|
|
@@ -2518,27 +2466,585 @@ trie_test action:"run" files:["src/utils.test.ts"]
|
|
|
2518
2466
|
}
|
|
2519
2467
|
};
|
|
2520
2468
|
|
|
2521
|
-
// src/tools/
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2469
|
+
// src/tools/watch.ts
|
|
2470
|
+
import { watch, existsSync as existsSync4, readFileSync } from "fs";
|
|
2471
|
+
import { stat, readFile as readFile4 } from "fs/promises";
|
|
2472
|
+
import { join as join2, extname as extname4, basename as basename2 } from "path";
|
|
2473
|
+
|
|
2474
|
+
// src/extraction/signal-extractor.ts
|
|
2475
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2476
|
+
var EXTRACTION_PROMPT = `You are a signal extraction system. Your job is to extract structured information from raw content.
|
|
2477
|
+
|
|
2478
|
+
Extract:
|
|
2479
|
+
1. DECISIONS - Clear choices made during development
|
|
2480
|
+
- What was decided
|
|
2481
|
+
- Why it was decided (reasoning/tradeoffs)
|
|
2482
|
+
- What alternatives were considered but NOT chosen
|
|
2483
|
+
- Which files are affected
|
|
2484
|
+
|
|
2485
|
+
2. FACTS - Concrete, verifiable information
|
|
2486
|
+
- Technical constraints (e.g., "Stripe requires TLS 1.2+")
|
|
2487
|
+
- API requirements
|
|
2488
|
+
- Business rules
|
|
2489
|
+
- Dependencies
|
|
2490
|
+
|
|
2491
|
+
3. BLOCKERS - Things preventing progress
|
|
2492
|
+
- What's blocked
|
|
2493
|
+
- Impact level (critical/high/medium/low)
|
|
2494
|
+
- What areas are affected
|
|
2495
|
+
|
|
2496
|
+
4. QUESTIONS - Open items needing resolution
|
|
2497
|
+
- What's unclear
|
|
2498
|
+
- Context around the question
|
|
2499
|
+
|
|
2500
|
+
CRITICAL: Extract rich metadata:
|
|
2501
|
+
- Tags: Use specific, searchable tags (e.g., "auth", "payments", "eu-compliance", "validation")
|
|
2502
|
+
- Files: Full paths when mentioned (e.g., "src/auth/validator.ts")
|
|
2503
|
+
- Tradeoffs: What was considered but rejected
|
|
2504
|
+
- Related terms: Alternative names/keywords (e.g., "password" + "credentials" + "auth")
|
|
2505
|
+
|
|
2506
|
+
Format as JSON:
|
|
2507
|
+
{
|
|
2508
|
+
"decisions": [{
|
|
2509
|
+
"decision": "Use bcrypt for password hashing",
|
|
2510
|
+
"context": "Security requirement for user authentication",
|
|
2511
|
+
"reasoning": "Industry standard, resistant to GPU attacks",
|
|
2512
|
+
"files": ["src/auth/hash.ts", "src/models/user.ts"],
|
|
2513
|
+
"tags": ["security", "auth", "passwords", "encryption"],
|
|
2514
|
+
"tradeoffs": ["Considered argon2 but bcrypt has better library support"]
|
|
2515
|
+
}],
|
|
2516
|
+
"facts": [{
|
|
2517
|
+
"fact": "Stripe requires TLS 1.2+ for all API calls",
|
|
2518
|
+
"source": "Stripe API docs",
|
|
2519
|
+
"tags": ["payments", "stripe", "security", "api"],
|
|
2520
|
+
"confidence": 0.95
|
|
2521
|
+
}],
|
|
2522
|
+
"blockers": [{
|
|
2523
|
+
"blocker": "Missing VAT calculation endpoint",
|
|
2524
|
+
"impact": "high",
|
|
2525
|
+
"affectedAreas": ["checkout", "eu-payments"],
|
|
2526
|
+
"tags": ["payments", "eu", "compliance", "vat"]
|
|
2527
|
+
}],
|
|
2528
|
+
"questions": [{
|
|
2529
|
+
"question": "Should we cache user sessions in Redis or memory?",
|
|
2530
|
+
"context": "Performance optimization for auth layer",
|
|
2531
|
+
"tags": ["auth", "performance", "caching", "sessions"]
|
|
2532
|
+
}]
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
Be specific with tags. Use concrete technical terms. Extract ALL file paths mentioned.
|
|
2536
|
+
Empty arrays are fine if nothing to extract.`;
|
|
2537
|
+
var SignalExtractor = class {
|
|
2538
|
+
client = null;
|
|
2539
|
+
model;
|
|
2540
|
+
constructor(model = "claude-3-haiku-20240307") {
|
|
2541
|
+
this.model = model;
|
|
2542
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
2543
|
+
if (apiKey) {
|
|
2544
|
+
this.client = new Anthropic({ apiKey });
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
/**
|
|
2548
|
+
* Extract structured signals from raw content
|
|
2549
|
+
*/
|
|
2550
|
+
async extract(content, sourceType, sourceId) {
|
|
2551
|
+
if (!this.client) {
|
|
2552
|
+
return this.basicExtraction(content, sourceType, sourceId);
|
|
2553
|
+
}
|
|
2554
|
+
try {
|
|
2555
|
+
const response = await this.client.messages.create({
|
|
2556
|
+
model: this.model,
|
|
2557
|
+
max_tokens: 2048,
|
|
2558
|
+
temperature: 0.3,
|
|
2559
|
+
messages: [{
|
|
2560
|
+
role: "user",
|
|
2561
|
+
content: `${EXTRACTION_PROMPT}
|
|
2562
|
+
|
|
2563
|
+
Content to analyze:
|
|
2564
|
+
${content}`
|
|
2565
|
+
}]
|
|
2566
|
+
});
|
|
2567
|
+
const firstBlock = response.content[0];
|
|
2568
|
+
const text = firstBlock && firstBlock.type === "text" ? firstBlock.text : "";
|
|
2569
|
+
const extracted = this.parseExtraction(text);
|
|
2570
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2571
|
+
const metadata = {
|
|
2572
|
+
extractedAt: now,
|
|
2573
|
+
sourceType,
|
|
2574
|
+
extractionModel: this.model
|
|
2575
|
+
};
|
|
2576
|
+
if (sourceId !== void 0) {
|
|
2577
|
+
metadata.sourceId = sourceId;
|
|
2578
|
+
}
|
|
2579
|
+
const signal = {
|
|
2580
|
+
decisions: extracted.decisions.map((d, i) => ({
|
|
2581
|
+
id: `dec-${Date.now()}-${i}`,
|
|
2582
|
+
decision: d.decision || "",
|
|
2583
|
+
context: d.context || "",
|
|
2584
|
+
files: d.files || [],
|
|
2585
|
+
tags: d.tags || [],
|
|
2586
|
+
...d,
|
|
2587
|
+
when: now,
|
|
2588
|
+
status: "active"
|
|
2589
|
+
})),
|
|
2590
|
+
facts: extracted.facts.map((f, i) => ({
|
|
2591
|
+
id: `fact-${Date.now()}-${i}`,
|
|
2592
|
+
fact: f.fact || "",
|
|
2593
|
+
source: f.source || sourceType,
|
|
2594
|
+
tags: f.tags || [],
|
|
2595
|
+
confidence: f.confidence ?? 0.8,
|
|
2596
|
+
...f,
|
|
2597
|
+
when: now
|
|
2598
|
+
})),
|
|
2599
|
+
blockers: extracted.blockers.map((b, i) => ({
|
|
2600
|
+
id: `block-${Date.now()}-${i}`,
|
|
2601
|
+
blocker: b.blocker || "",
|
|
2602
|
+
impact: b.impact || "medium",
|
|
2603
|
+
affectedAreas: b.affectedAreas || [],
|
|
2604
|
+
tags: b.tags || [],
|
|
2605
|
+
...b,
|
|
2606
|
+
when: now
|
|
2607
|
+
})),
|
|
2608
|
+
questions: extracted.questions.map((q, i) => ({
|
|
2609
|
+
id: `q-${Date.now()}-${i}`,
|
|
2610
|
+
question: q.question || "",
|
|
2611
|
+
context: q.context || "",
|
|
2612
|
+
tags: q.tags || [],
|
|
2613
|
+
...q,
|
|
2614
|
+
when: now
|
|
2615
|
+
})),
|
|
2616
|
+
metadata
|
|
2617
|
+
};
|
|
2618
|
+
return signal;
|
|
2619
|
+
} catch (error) {
|
|
2620
|
+
console.error("Extraction failed, using basic extraction:", error);
|
|
2621
|
+
return this.basicExtraction(content, sourceType, sourceId);
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
/**
|
|
2625
|
+
* Parse extraction from model response
|
|
2626
|
+
*/
|
|
2627
|
+
parseExtraction(text) {
|
|
2628
|
+
try {
|
|
2629
|
+
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
2630
|
+
if (jsonMatch) {
|
|
2631
|
+
return JSON.parse(jsonMatch[0]);
|
|
2632
|
+
}
|
|
2633
|
+
} catch (e) {
|
|
2634
|
+
}
|
|
2525
2635
|
return {
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2636
|
+
decisions: [],
|
|
2637
|
+
facts: [],
|
|
2638
|
+
blockers: [],
|
|
2639
|
+
questions: []
|
|
2640
|
+
};
|
|
2641
|
+
}
|
|
2642
|
+
/**
|
|
2643
|
+
* Basic extraction without AI (fallback)
|
|
2644
|
+
*/
|
|
2645
|
+
basicExtraction(content, sourceType, sourceId) {
|
|
2646
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2647
|
+
const hasDecision = /\b(decided|decision|chose|picked)\b/i.test(content);
|
|
2648
|
+
const hasBlocker = /\b(blocked|blocker|blocked by|can't|cannot|unable)\b/i.test(content);
|
|
2649
|
+
const hasQuestion = /\?|what|how|why|should we/i.test(content);
|
|
2650
|
+
const decisions = [];
|
|
2651
|
+
const facts = [];
|
|
2652
|
+
const blockers = [];
|
|
2653
|
+
const questions = [];
|
|
2654
|
+
if (hasDecision) {
|
|
2655
|
+
decisions.push({
|
|
2656
|
+
id: `dec-${Date.now()}`,
|
|
2657
|
+
decision: content.substring(0, 200),
|
|
2658
|
+
context: sourceType,
|
|
2659
|
+
when: now,
|
|
2660
|
+
files: [],
|
|
2661
|
+
tags: [sourceType],
|
|
2662
|
+
status: "active"
|
|
2663
|
+
});
|
|
2664
|
+
}
|
|
2665
|
+
if (hasBlocker) {
|
|
2666
|
+
blockers.push({
|
|
2667
|
+
id: `block-${Date.now()}`,
|
|
2668
|
+
blocker: content.substring(0, 200),
|
|
2669
|
+
impact: "medium",
|
|
2670
|
+
affectedAreas: [],
|
|
2671
|
+
when: now,
|
|
2672
|
+
tags: [sourceType]
|
|
2673
|
+
});
|
|
2674
|
+
}
|
|
2675
|
+
if (hasQuestion) {
|
|
2676
|
+
questions.push({
|
|
2677
|
+
id: `q-${Date.now()}`,
|
|
2678
|
+
question: content.substring(0, 200),
|
|
2679
|
+
context: sourceType,
|
|
2680
|
+
when: now,
|
|
2681
|
+
tags: [sourceType]
|
|
2682
|
+
});
|
|
2683
|
+
}
|
|
2684
|
+
const metadata = {
|
|
2685
|
+
extractedAt: now,
|
|
2686
|
+
sourceType,
|
|
2687
|
+
extractionModel: "basic"
|
|
2688
|
+
};
|
|
2689
|
+
if (sourceId !== void 0) {
|
|
2690
|
+
metadata.sourceId = sourceId;
|
|
2691
|
+
}
|
|
2692
|
+
return {
|
|
2693
|
+
decisions,
|
|
2694
|
+
facts,
|
|
2695
|
+
blockers,
|
|
2696
|
+
questions,
|
|
2697
|
+
metadata
|
|
2698
|
+
};
|
|
2699
|
+
}
|
|
2700
|
+
/**
|
|
2701
|
+
* Extract from incident report (trie tell)
|
|
2702
|
+
*/
|
|
2703
|
+
async extractFromIncident(incidentText) {
|
|
2704
|
+
return this.extract(incidentText, "incident");
|
|
2705
|
+
}
|
|
2706
|
+
/**
|
|
2707
|
+
* Extract from commit message and diff
|
|
2708
|
+
*/
|
|
2709
|
+
async extractFromCommit(message, diff, commitId) {
|
|
2710
|
+
const content = diff ? `${message}
|
|
2711
|
+
|
|
2712
|
+
Changes:
|
|
2713
|
+
${diff}` : message;
|
|
2714
|
+
return this.extract(content, "commit", commitId);
|
|
2715
|
+
}
|
|
2716
|
+
/**
|
|
2717
|
+
* Extract from PR description and comments
|
|
2718
|
+
*/
|
|
2719
|
+
async extractFromPR(title, description, comments, prNumber) {
|
|
2720
|
+
const content = `
|
|
2721
|
+
Title: ${title}
|
|
2722
|
+
|
|
2723
|
+
Description:
|
|
2724
|
+
${description}
|
|
2725
|
+
|
|
2726
|
+
Comments:
|
|
2727
|
+
${comments.join("\n\n")}
|
|
2728
|
+
`.trim();
|
|
2729
|
+
return this.extract(content, "pr", prNumber);
|
|
2730
|
+
}
|
|
2731
|
+
};
|
|
2732
|
+
|
|
2733
|
+
// src/extraction/metadata-enricher.ts
|
|
2734
|
+
var MetadataEnricher = class {
|
|
2735
|
+
tagSynonyms;
|
|
2736
|
+
constructor() {
|
|
2737
|
+
this.tagSynonyms = this.initializeTagSynonyms();
|
|
2738
|
+
}
|
|
2739
|
+
/**
|
|
2740
|
+
* Enrich an extracted signal with additional metadata
|
|
2741
|
+
*/
|
|
2742
|
+
async enrichSignal(signal, context) {
|
|
2743
|
+
const gitContext = {};
|
|
2744
|
+
if (context?.gitBranch) gitContext.branch = context.gitBranch;
|
|
2745
|
+
if (context?.gitCommit) gitContext.commit = context.gitCommit;
|
|
2746
|
+
const metadata = {
|
|
2747
|
+
relatedFiles: await this.findRelatedFiles(signal),
|
|
2748
|
+
dependencies: await this.extractDependencies(signal),
|
|
2749
|
+
expandedTags: this.expandTags(signal),
|
|
2750
|
+
codebaseArea: this.inferCodebaseArea(signal),
|
|
2751
|
+
domain: this.inferDomain(signal),
|
|
2752
|
+
relatedDecisions: [],
|
|
2753
|
+
// Will be populated by storage layer
|
|
2754
|
+
extractedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2755
|
+
};
|
|
2756
|
+
if (Object.keys(gitContext).length > 0) {
|
|
2757
|
+
metadata.gitContext = gitContext;
|
|
2758
|
+
}
|
|
2759
|
+
return {
|
|
2760
|
+
signal,
|
|
2761
|
+
metadata
|
|
2762
|
+
};
|
|
2763
|
+
}
|
|
2764
|
+
/**
|
|
2765
|
+
* Expand tags with synonyms and related terms
|
|
2766
|
+
* This is our "semantic" layer without embeddings
|
|
2767
|
+
*/
|
|
2768
|
+
expandTags(signal) {
|
|
2769
|
+
const allTags = /* @__PURE__ */ new Set();
|
|
2770
|
+
for (const decision of signal.decisions) {
|
|
2771
|
+
decision.tags.forEach((tag) => allTags.add(tag.toLowerCase()));
|
|
2772
|
+
}
|
|
2773
|
+
for (const fact of signal.facts) {
|
|
2774
|
+
fact.tags.forEach((tag) => allTags.add(tag.toLowerCase()));
|
|
2775
|
+
}
|
|
2776
|
+
for (const blocker of signal.blockers) {
|
|
2777
|
+
blocker.tags.forEach((tag) => allTags.add(tag.toLowerCase()));
|
|
2778
|
+
}
|
|
2779
|
+
for (const question of signal.questions) {
|
|
2780
|
+
question.tags.forEach((tag) => allTags.add(tag.toLowerCase()));
|
|
2781
|
+
}
|
|
2782
|
+
const expandedTags = new Set(allTags);
|
|
2783
|
+
for (const tag of allTags) {
|
|
2784
|
+
const synonyms = this.tagSynonyms.get(tag) || [];
|
|
2785
|
+
synonyms.forEach((syn) => expandedTags.add(syn));
|
|
2786
|
+
}
|
|
2787
|
+
return Array.from(expandedTags);
|
|
2788
|
+
}
|
|
2789
|
+
/**
|
|
2790
|
+
* Find related files based on signal content
|
|
2791
|
+
*/
|
|
2792
|
+
async findRelatedFiles(signal) {
|
|
2793
|
+
const relatedFiles = /* @__PURE__ */ new Set();
|
|
2794
|
+
for (const decision of signal.decisions) {
|
|
2795
|
+
decision.files.forEach((file) => relatedFiles.add(file));
|
|
2796
|
+
}
|
|
2797
|
+
const inferredFiles = await this.inferFilesFromTags(signal);
|
|
2798
|
+
inferredFiles.forEach((file) => relatedFiles.add(file));
|
|
2799
|
+
return Array.from(relatedFiles);
|
|
2800
|
+
}
|
|
2801
|
+
/**
|
|
2802
|
+
* Extract dependencies from signal
|
|
2803
|
+
*/
|
|
2804
|
+
async extractDependencies(signal) {
|
|
2805
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
2806
|
+
const allText = [
|
|
2807
|
+
...signal.decisions.map((d) => `${d.decision} ${d.context} ${d.reasoning}`),
|
|
2808
|
+
...signal.facts.map((f) => `${f.fact} ${f.source}`)
|
|
2809
|
+
].join(" ");
|
|
2810
|
+
const packagePatterns = [
|
|
2811
|
+
/\b(react|vue|angular|next|express|fastify|stripe|bcrypt|jwt|redis|prisma)\b/gi
|
|
2812
|
+
];
|
|
2813
|
+
for (const pattern of packagePatterns) {
|
|
2814
|
+
const matches = allText.match(pattern) || [];
|
|
2815
|
+
matches.forEach((dep) => dependencies.add(dep.toLowerCase()));
|
|
2816
|
+
}
|
|
2817
|
+
return Array.from(dependencies);
|
|
2818
|
+
}
|
|
2819
|
+
/**
|
|
2820
|
+
* Infer codebase area from file paths and tags
|
|
2821
|
+
*/
|
|
2822
|
+
inferCodebaseArea(signal) {
|
|
2823
|
+
const areas = /* @__PURE__ */ new Set();
|
|
2824
|
+
for (const decision of signal.decisions) {
|
|
2825
|
+
for (const file of decision.files) {
|
|
2826
|
+
const area = this.filePathToArea(file);
|
|
2827
|
+
if (area) areas.add(area);
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
const areaKeywords = ["frontend", "backend", "api", "ui", "database", "auth", "payments"];
|
|
2831
|
+
const allTags = this.expandTags(signal);
|
|
2832
|
+
for (const tag of allTags) {
|
|
2833
|
+
if (areaKeywords.includes(tag)) {
|
|
2834
|
+
areas.add(tag);
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
return Array.from(areas);
|
|
2838
|
+
}
|
|
2839
|
+
/**
|
|
2840
|
+
* Infer domain from tags and content
|
|
2841
|
+
*/
|
|
2842
|
+
inferDomain(signal) {
|
|
2843
|
+
const domains = /* @__PURE__ */ new Set();
|
|
2844
|
+
const domainKeywords = [
|
|
2845
|
+
"payments",
|
|
2846
|
+
"billing",
|
|
2847
|
+
"compliance",
|
|
2848
|
+
"security",
|
|
2849
|
+
"auth",
|
|
2850
|
+
"analytics",
|
|
2851
|
+
"notifications",
|
|
2852
|
+
"messaging",
|
|
2853
|
+
"search"
|
|
2854
|
+
];
|
|
2855
|
+
const allTags = this.expandTags(signal);
|
|
2856
|
+
for (const tag of allTags) {
|
|
2857
|
+
if (domainKeywords.includes(tag)) {
|
|
2858
|
+
domains.add(tag);
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
return Array.from(domains);
|
|
2862
|
+
}
|
|
2863
|
+
/**
|
|
2864
|
+
* Convert file path to codebase area
|
|
2865
|
+
*/
|
|
2866
|
+
filePathToArea(filePath) {
|
|
2867
|
+
const normalized = filePath.toLowerCase();
|
|
2868
|
+
if (normalized.includes("/frontend/") || normalized.includes("/client/") || normalized.includes("/ui/")) {
|
|
2869
|
+
return "frontend";
|
|
2870
|
+
}
|
|
2871
|
+
if (normalized.includes("/backend/") || normalized.includes("/server/") || normalized.includes("/api/")) {
|
|
2872
|
+
return "backend";
|
|
2873
|
+
}
|
|
2874
|
+
if (normalized.includes("/database/") || normalized.includes("/models/") || normalized.includes("/schema/")) {
|
|
2875
|
+
return "database";
|
|
2876
|
+
}
|
|
2877
|
+
if (normalized.includes("/auth/")) {
|
|
2878
|
+
return "auth";
|
|
2879
|
+
}
|
|
2880
|
+
return null;
|
|
2881
|
+
}
|
|
2882
|
+
/**
|
|
2883
|
+
* Infer related files from tags
|
|
2884
|
+
*/
|
|
2885
|
+
async inferFilesFromTags(_signal) {
|
|
2886
|
+
return [];
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2889
|
+
* Initialize tag synonyms and related terms
|
|
2890
|
+
* This is our "semantic" understanding without embeddings
|
|
2891
|
+
*/
|
|
2892
|
+
initializeTagSynonyms() {
|
|
2893
|
+
return /* @__PURE__ */ new Map([
|
|
2894
|
+
// Auth & Security
|
|
2895
|
+
["auth", ["authentication", "login", "signin", "credentials", "password"]],
|
|
2896
|
+
["password", ["credentials", "auth", "hashing", "bcrypt"]],
|
|
2897
|
+
["security", ["vulnerability", "exploit", "attack", "protection"]],
|
|
2898
|
+
["encryption", ["crypto", "hashing", "encoding", "security"]],
|
|
2899
|
+
// Payments
|
|
2900
|
+
["payments", ["billing", "checkout", "stripe", "pricing"]],
|
|
2901
|
+
["stripe", ["payments", "billing", "api", "checkout"]],
|
|
2902
|
+
["vat", ["tax", "eu", "compliance", "billing"]],
|
|
2903
|
+
// Database & Performance
|
|
2904
|
+
["database", ["db", "sql", "query", "storage", "persistence"]],
|
|
2905
|
+
["cache", ["caching", "redis", "memory", "performance"]],
|
|
2906
|
+
["performance", ["optimization", "speed", "latency", "cache"]],
|
|
2907
|
+
// Frontend
|
|
2908
|
+
["ui", ["frontend", "interface", "component", "view"]],
|
|
2909
|
+
["component", ["ui", "react", "vue", "frontend"]],
|
|
2910
|
+
["validation", ["form", "input", "error", "ui"]],
|
|
2911
|
+
// Backend & API
|
|
2912
|
+
["api", ["endpoint", "route", "backend", "server"]],
|
|
2913
|
+
["endpoint", ["api", "route", "url", "backend"]],
|
|
2914
|
+
["backend", ["server", "api", "service"]],
|
|
2915
|
+
// Compliance & Legal
|
|
2916
|
+
["compliance", ["gdpr", "hipaa", "legal", "regulation"]],
|
|
2917
|
+
["gdpr", ["compliance", "privacy", "eu", "data-protection"]],
|
|
2918
|
+
["privacy", ["gdpr", "compliance", "data-protection", "security"]]
|
|
2919
|
+
]);
|
|
2920
|
+
}
|
|
2921
|
+
};
|
|
2530
2922
|
|
|
2531
|
-
|
|
2923
|
+
// src/extraction/pipeline.ts
|
|
2924
|
+
import { randomBytes } from "crypto";
|
|
2925
|
+
var ExtractionPipeline = class {
|
|
2926
|
+
extractor;
|
|
2927
|
+
enricher;
|
|
2928
|
+
storage;
|
|
2929
|
+
workDir;
|
|
2930
|
+
constructor(options) {
|
|
2931
|
+
this.extractor = new SignalExtractor(options.anthropicApiKey);
|
|
2932
|
+
this.enricher = new MetadataEnricher();
|
|
2933
|
+
this.storage = getStorage(options.workingDirectory);
|
|
2934
|
+
this.workDir = options.workingDirectory;
|
|
2935
|
+
}
|
|
2936
|
+
/**
|
|
2937
|
+
* Process raw content through the entire pipeline
|
|
2938
|
+
*/
|
|
2939
|
+
async process(content, context) {
|
|
2940
|
+
console.log("\u{1F50D} Extracting signals from content...");
|
|
2941
|
+
let extractedSignal = await this.extractor.extract(content, context.sourceType, context.sourceId);
|
|
2942
|
+
extractedSignal = this.addIds(extractedSignal, context);
|
|
2943
|
+
console.log(` \u2713 Extracted ${extractedSignal.decisions.length} decisions, ${extractedSignal.facts.length} facts, ${extractedSignal.blockers.length} blockers, ${extractedSignal.questions.length} questions`);
|
|
2944
|
+
console.log("\u{1F3F7}\uFE0F Enriching with metadata...");
|
|
2945
|
+
const { metadata: enrichedMeta } = await this.enricher.enrichSignal(extractedSignal, {
|
|
2946
|
+
workingDirectory: this.workDir
|
|
2947
|
+
});
|
|
2948
|
+
if (enrichedMeta.expandedTags.length > 0) {
|
|
2949
|
+
console.log(` \u2713 Expanded tags: ${enrichedMeta.expandedTags.slice(0, 5).join(", ")}${enrichedMeta.expandedTags.length > 5 ? "..." : ""}`);
|
|
2950
|
+
}
|
|
2951
|
+
if (enrichedMeta.dependencies.length > 0) {
|
|
2952
|
+
console.log(` \u2713 Dependencies: ${enrichedMeta.dependencies.join(", ")}`);
|
|
2953
|
+
}
|
|
2954
|
+
if (enrichedMeta.codebaseArea.length > 0) {
|
|
2955
|
+
console.log(` \u2713 Codebase areas: ${enrichedMeta.codebaseArea.join(", ")}`);
|
|
2956
|
+
}
|
|
2957
|
+
if (enrichedMeta.domain.length > 0) {
|
|
2958
|
+
console.log(` \u2713 Domains: ${enrichedMeta.domain.join(", ")}`);
|
|
2959
|
+
}
|
|
2960
|
+
console.log("\u{1F4BE} Storing in decision ledger...");
|
|
2961
|
+
await this.storage.storeSignal(extractedSignal, {
|
|
2962
|
+
expandedTags: enrichedMeta.expandedTags,
|
|
2963
|
+
dependencies: enrichedMeta.dependencies,
|
|
2964
|
+
codebaseArea: enrichedMeta.codebaseArea,
|
|
2965
|
+
domain: enrichedMeta.domain
|
|
2966
|
+
});
|
|
2967
|
+
console.log("\u2705 Successfully stored in decision ledger");
|
|
2968
|
+
return extractedSignal;
|
|
2969
|
+
}
|
|
2970
|
+
/**
|
|
2971
|
+
* Add IDs and metadata to extracted signal
|
|
2972
|
+
*/
|
|
2973
|
+
addIds(signal, context) {
|
|
2974
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2975
|
+
const metadata = {
|
|
2976
|
+
extractedAt: now,
|
|
2977
|
+
sourceType: context.sourceType,
|
|
2978
|
+
extractionModel: "claude-haiku"
|
|
2979
|
+
};
|
|
2980
|
+
if (context.sourceId !== void 0) {
|
|
2981
|
+
metadata.sourceId = context.sourceId;
|
|
2982
|
+
}
|
|
2983
|
+
return {
|
|
2984
|
+
decisions: signal.decisions.map((d) => {
|
|
2985
|
+
const decision = {
|
|
2986
|
+
...d,
|
|
2987
|
+
id: d.id || this.generateId(),
|
|
2988
|
+
when: d.when || now,
|
|
2989
|
+
status: d.status || "active"
|
|
2990
|
+
};
|
|
2991
|
+
if (context.who !== void 0) {
|
|
2992
|
+
decision.who = d.who || context.who;
|
|
2532
2993
|
}
|
|
2533
|
-
|
|
2994
|
+
return decision;
|
|
2995
|
+
}),
|
|
2996
|
+
facts: signal.facts.map((f) => ({
|
|
2997
|
+
...f,
|
|
2998
|
+
id: f.id || this.generateId(),
|
|
2999
|
+
when: f.when || now,
|
|
3000
|
+
confidence: f.confidence ?? 0.8
|
|
3001
|
+
})),
|
|
3002
|
+
blockers: signal.blockers.map((b) => ({
|
|
3003
|
+
...b,
|
|
3004
|
+
id: b.id || this.generateId(),
|
|
3005
|
+
when: b.when || now
|
|
3006
|
+
})),
|
|
3007
|
+
questions: signal.questions.map((q) => ({
|
|
3008
|
+
...q,
|
|
3009
|
+
id: q.id || this.generateId(),
|
|
3010
|
+
when: q.when || now
|
|
3011
|
+
})),
|
|
3012
|
+
metadata
|
|
2534
3013
|
};
|
|
2535
3014
|
}
|
|
3015
|
+
/**
|
|
3016
|
+
* Generate a unique ID
|
|
3017
|
+
*/
|
|
3018
|
+
generateId() {
|
|
3019
|
+
return randomBytes(8).toString("hex");
|
|
3020
|
+
}
|
|
3021
|
+
/**
|
|
3022
|
+
* Initialize storage
|
|
3023
|
+
*/
|
|
3024
|
+
async initialize() {
|
|
3025
|
+
await this.storage.initialize();
|
|
3026
|
+
}
|
|
3027
|
+
/**
|
|
3028
|
+
* Close storage connections
|
|
3029
|
+
*/
|
|
3030
|
+
close() {
|
|
3031
|
+
this.storage.close();
|
|
3032
|
+
}
|
|
2536
3033
|
};
|
|
3034
|
+
async function processIncident(incidentDescription, options) {
|
|
3035
|
+
const pipeline = new ExtractionPipeline(options);
|
|
3036
|
+
await pipeline.initialize();
|
|
3037
|
+
try {
|
|
3038
|
+
return await pipeline.process(incidentDescription, {
|
|
3039
|
+
sourceType: "incident",
|
|
3040
|
+
sourceId: `incident-${Date.now()}`
|
|
3041
|
+
});
|
|
3042
|
+
} finally {
|
|
3043
|
+
pipeline.close();
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
2537
3046
|
|
|
2538
3047
|
// src/tools/watch.ts
|
|
2539
|
-
import { watch, existsSync as existsSync4, readFileSync } from "fs";
|
|
2540
|
-
import { stat } from "fs/promises";
|
|
2541
|
-
import { join as join2, extname as extname4, basename as basename2 } from "path";
|
|
2542
3048
|
var WATCH_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2543
3049
|
".ts",
|
|
2544
3050
|
".tsx",
|
|
@@ -2565,6 +3071,7 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
2565
3071
|
]);
|
|
2566
3072
|
var TrieWatchTool = class {
|
|
2567
3073
|
scanTool = new TrieScanTool();
|
|
3074
|
+
extractionPipeline = null;
|
|
2568
3075
|
state = {
|
|
2569
3076
|
isRunning: false,
|
|
2570
3077
|
lastScan: /* @__PURE__ */ new Map(),
|
|
@@ -2622,6 +3129,14 @@ var TrieWatchTool = class {
|
|
|
2622
3129
|
}]
|
|
2623
3130
|
};
|
|
2624
3131
|
}
|
|
3132
|
+
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
3133
|
+
if (anthropicApiKey) {
|
|
3134
|
+
this.extractionPipeline = new ExtractionPipeline({
|
|
3135
|
+
workingDirectory: directory,
|
|
3136
|
+
anthropicApiKey
|
|
3137
|
+
});
|
|
3138
|
+
await this.extractionPipeline.initialize();
|
|
3139
|
+
}
|
|
2625
3140
|
this.state.isRunning = true;
|
|
2626
3141
|
this.state.issueCache.clear();
|
|
2627
3142
|
this.state.totalIssuesFound = 0;
|
|
@@ -2633,6 +3148,7 @@ var TrieWatchTool = class {
|
|
|
2633
3148
|
console.error("TRIE AGENT - NOW WATCHING");
|
|
2634
3149
|
console.error("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
|
|
2635
3150
|
console.error("Your Trie agent is now watching over your codebase.");
|
|
3151
|
+
console.error("Signal extraction: ENABLED (building decision ledger)");
|
|
2636
3152
|
console.error(`Watching: ${directory}`);
|
|
2637
3153
|
console.error(`Debounce: ${debounceMs}ms`);
|
|
2638
3154
|
console.error("");
|
|
@@ -2671,23 +3187,30 @@ var TrieWatchTool = class {
|
|
|
2671
3187
|
return {
|
|
2672
3188
|
content: [{
|
|
2673
3189
|
type: "text",
|
|
2674
|
-
text: `**TRIE AGENT ACTIVATED**
|
|
3190
|
+
text: `**TRIE AGENT ACTIVATED**
|
|
2675
3191
|
|
|
2676
|
-
Your Trie agent is now watching
|
|
3192
|
+
Your Trie agent is now autonomously watching and learning from your codebase.
|
|
2677
3193
|
|
|
2678
3194
|
**Watching:** \`${directory}\`
|
|
2679
3195
|
**Debounce:** ${debounceMs}ms (waits for you to stop typing)
|
|
3196
|
+
**Signal Extraction:** ${process.env.ANTHROPIC_API_KEY ? "\u2713 ENABLED" : "\u26A0\uFE0F LIMITED (set ANTHROPIC_API_KEY for full extraction)"}
|
|
2680
3197
|
|
|
2681
|
-
### How
|
|
3198
|
+
### How the agent works:
|
|
2682
3199
|
1. [*] You write/edit code
|
|
2683
|
-
2. [#]
|
|
2684
|
-
3. [
|
|
2685
|
-
4. [
|
|
3200
|
+
2. [#] Agent detects the change
|
|
3201
|
+
3. [\u{1F9E0}] Extracts decisions, facts, blockers \u2192 stores in ledger
|
|
3202
|
+
4. [?] Predicts risks based on historical patterns
|
|
3203
|
+
5. [>] Nudges you in plain English if something looks risky
|
|
3204
|
+
|
|
3205
|
+
### The agent learns:
|
|
3206
|
+
- Every commit builds the decision ledger
|
|
3207
|
+
- \`trie gotcha\` queries the ledger for predictions
|
|
3208
|
+
- \`trie ok\` / \`trie bad\` teach the agent what matters (coming soon)
|
|
2686
3209
|
|
|
2687
3210
|
### Commands:
|
|
2688
|
-
- \`trie_watch status\` - See
|
|
3211
|
+
- \`trie_watch status\` - See agent status
|
|
2689
3212
|
- \`trie_watch issues\` - Get all issues found so far
|
|
2690
|
-
- \`trie_watch stop\` - Stop the
|
|
3213
|
+
- \`trie_watch stop\` - Stop the agent
|
|
2691
3214
|
|
|
2692
3215
|
---
|
|
2693
3216
|
|
|
@@ -2717,8 +3240,8 @@ ${initialResult.content?.[0]?.text || "Initial scan complete."}`
|
|
|
2717
3240
|
}, debounceMs);
|
|
2718
3241
|
});
|
|
2719
3242
|
this.watchers.set(dir, watcher);
|
|
2720
|
-
const { readdir:
|
|
2721
|
-
const entries = await
|
|
3243
|
+
const { readdir: readdir2 } = await import("fs/promises");
|
|
3244
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
2722
3245
|
for (const entry of entries) {
|
|
2723
3246
|
if (entry.isDirectory()) {
|
|
2724
3247
|
await this.watchDirectory(join2(dir, entry.name), debounceMs);
|
|
@@ -2747,6 +3270,52 @@ Detected changes in ${files.length} file(s):`);
|
|
|
2747
3270
|
console.error("");
|
|
2748
3271
|
}
|
|
2749
3272
|
try {
|
|
3273
|
+
if (this.extractionPipeline) {
|
|
3274
|
+
try {
|
|
3275
|
+
const fileContents = await Promise.all(
|
|
3276
|
+
files.map(async (file) => {
|
|
3277
|
+
try {
|
|
3278
|
+
const content = await readFile4(file, "utf-8");
|
|
3279
|
+
return { file, content };
|
|
3280
|
+
} catch {
|
|
3281
|
+
return null;
|
|
3282
|
+
}
|
|
3283
|
+
})
|
|
3284
|
+
);
|
|
3285
|
+
const validFiles = fileContents.filter((f) => f !== null);
|
|
3286
|
+
if (validFiles.length > 0) {
|
|
3287
|
+
const combinedContent = validFiles.map(
|
|
3288
|
+
(f) => `File: ${basename2(f.file)}
|
|
3289
|
+
${f.content.slice(0, 1e3)}`
|
|
3290
|
+
// First 1KB of each file
|
|
3291
|
+
).join("\n\n---\n\n");
|
|
3292
|
+
if (!isInteractiveMode()) {
|
|
3293
|
+
console.error("\u{1F9E0} Extracting signals from changes...");
|
|
3294
|
+
}
|
|
3295
|
+
const signal = await this.extractionPipeline.process(combinedContent, {
|
|
3296
|
+
sourceType: "file",
|
|
3297
|
+
sourceId: `watch-${Date.now()}`
|
|
3298
|
+
});
|
|
3299
|
+
if (signal.decisions.length > 0 || signal.facts.length > 0 || signal.blockers.length > 0) {
|
|
3300
|
+
if (!isInteractiveMode()) {
|
|
3301
|
+
console.error(` \u2713 Extracted: ${signal.decisions.length} decisions, ${signal.facts.length} facts, ${signal.blockers.length} blockers`);
|
|
3302
|
+
}
|
|
3303
|
+
if (this.streamingManager) {
|
|
3304
|
+
this.streamingManager.reportSignalExtraction({
|
|
3305
|
+
decisions: signal.decisions.length,
|
|
3306
|
+
facts: signal.facts.length,
|
|
3307
|
+
blockers: signal.blockers.length,
|
|
3308
|
+
questions: signal.questions.length
|
|
3309
|
+
});
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
} catch (error) {
|
|
3314
|
+
if (!isInteractiveMode()) {
|
|
3315
|
+
console.error(` \u26A0\uFE0F Signal extraction failed: ${error}`);
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
2750
3319
|
if (this.streamingManager) {
|
|
2751
3320
|
for (const file of files) {
|
|
2752
3321
|
this.streamingManager.reportWatchChange(file);
|
|
@@ -2921,6 +3490,10 @@ Found ${newIssues} issues in changed files!`);
|
|
|
2921
3490
|
watcher.close();
|
|
2922
3491
|
}
|
|
2923
3492
|
this.watchers.clear();
|
|
3493
|
+
if (this.extractionPipeline) {
|
|
3494
|
+
this.extractionPipeline.close();
|
|
3495
|
+
this.extractionPipeline = null;
|
|
3496
|
+
}
|
|
2924
3497
|
if (this.state.scanDebounceTimer) {
|
|
2925
3498
|
clearTimeout(this.state.scanDebounceTimer);
|
|
2926
3499
|
}
|
|
@@ -2941,14 +3514,16 @@ Found ${newIssues} issues in changed files!`);
|
|
|
2941
3514
|
return {
|
|
2942
3515
|
content: [{
|
|
2943
3516
|
type: "text",
|
|
2944
|
-
text: `[*] **
|
|
3517
|
+
text: `[*] **TRIE AGENT STOPPED** \u{1F916}
|
|
2945
3518
|
|
|
2946
3519
|
### Session Summary:
|
|
2947
3520
|
- Files scanned: ${this.state.filesScanned}
|
|
2948
3521
|
- Total issues found: ${this.state.totalIssuesFound}
|
|
2949
3522
|
- Directories watched: ${this.watchers.size}
|
|
3523
|
+
- Decision ledger: Updated continuously
|
|
2950
3524
|
|
|
2951
|
-
|
|
3525
|
+
The agent's learning has been stored in the decision ledger.
|
|
3526
|
+
Use \`trie_watch start\` to resume autonomous operation.`
|
|
2952
3527
|
}]
|
|
2953
3528
|
};
|
|
2954
3529
|
}
|
|
@@ -2972,7 +3547,7 @@ Use \`trie_watch start\` to begin autonomous scanning.`
|
|
|
2972
3547
|
).join("\n");
|
|
2973
3548
|
let agencyStatus = "";
|
|
2974
3549
|
try {
|
|
2975
|
-
const { getGuardian } = await import("./guardian-agent-
|
|
3550
|
+
const { getGuardian } = await import("./guardian-agent-M352CBE5.js");
|
|
2976
3551
|
const guardian = getGuardian(getWorkingDirectory(void 0, true));
|
|
2977
3552
|
await guardian.initialize();
|
|
2978
3553
|
const status = await guardian.getAgencyStatus();
|
|
@@ -3018,1226 +3593,66 @@ ${recentNudges || "(none)"}
|
|
|
3018
3593
|
text: `[#] Recent nudges (${this.state.nudges.length} this session)
|
|
3019
3594
|
` + (this.state.nudges.length ? this.state.nudges.map(
|
|
3020
3595
|
(n) => `- ${basename2(n.file)} [${n.severity}] @ ${n.timestamp}
|
|
3021
|
-
${n.message}`
|
|
3022
|
-
).join("\n") : "(none)")
|
|
3023
|
-
},
|
|
3024
|
-
{
|
|
3025
|
-
type: "json",
|
|
3026
|
-
json: this.state.nudges
|
|
3027
|
-
}
|
|
3028
|
-
]
|
|
3029
|
-
};
|
|
3030
|
-
}
|
|
3031
|
-
getCurrentIssues() {
|
|
3032
|
-
return {
|
|
3033
|
-
content: [{
|
|
3034
|
-
type: "text",
|
|
3035
|
-
text: `[L] **Issues Found This Session**
|
|
3036
|
-
|
|
3037
|
-
Total issues: ${this.state.totalIssuesFound}
|
|
3038
|
-
Files scanned: ${this.state.filesScanned}
|
|
3039
|
-
|
|
3040
|
-
To get a full report, run \`trie_scan\` on your codebase.`
|
|
3041
|
-
}]
|
|
3042
|
-
};
|
|
3043
|
-
}
|
|
3044
|
-
};
|
|
3045
|
-
|
|
3046
|
-
// src/tools/agent.ts
|
|
3047
|
-
import { readdir, readFile as readFile4 } from "fs/promises";
|
|
3048
|
-
import { existsSync as existsSync5 } from "fs";
|
|
3049
|
-
import { join as join3, extname as extname5, isAbsolute as isAbsolute4, resolve as resolve4, basename as basename3 } from "path";
|
|
3050
|
-
|
|
3051
|
-
// src/knowledge/index.ts
|
|
3052
|
-
var SECURITY_SOURCES = [
|
|
3053
|
-
{
|
|
3054
|
-
name: "OWASP Top 10",
|
|
3055
|
-
url: "https://owasp.org/Top10/",
|
|
3056
|
-
description: "Most critical web application security risks"
|
|
3057
|
-
},
|
|
3058
|
-
{
|
|
3059
|
-
name: "NIST NVD",
|
|
3060
|
-
url: "https://nvd.nist.gov/",
|
|
3061
|
-
description: "National Vulnerability Database"
|
|
3062
|
-
},
|
|
3063
|
-
{
|
|
3064
|
-
name: "CVE Database",
|
|
3065
|
-
url: "https://cve.mitre.org/",
|
|
3066
|
-
description: "Common Vulnerabilities and Exposures"
|
|
3067
|
-
},
|
|
3068
|
-
{
|
|
3069
|
-
name: "Snyk Vulnerability DB",
|
|
3070
|
-
url: "https://security.snyk.io/",
|
|
3071
|
-
description: "Open source vulnerability database"
|
|
3072
|
-
},
|
|
3073
|
-
{
|
|
3074
|
-
name: "GitHub Advisory Database",
|
|
3075
|
-
url: "https://github.com/advisories",
|
|
3076
|
-
description: "Security advisories from GitHub"
|
|
3077
|
-
}
|
|
3078
|
-
];
|
|
3079
|
-
var DOCS_SOURCES = {
|
|
3080
|
-
react: [
|
|
3081
|
-
{ name: "React Docs", url: "https://react.dev/", description: "Official React documentation" },
|
|
3082
|
-
{ name: "React Security", url: "https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html", description: "React security guidance" }
|
|
3083
|
-
],
|
|
3084
|
-
nextjs: [
|
|
3085
|
-
{ name: "Next.js Docs", url: "https://nextjs.org/docs", description: "Official Next.js documentation" },
|
|
3086
|
-
{ name: "Next.js Security", url: "https://nextjs.org/docs/advanced-features/security-headers", description: "Next.js security headers" }
|
|
3087
|
-
],
|
|
3088
|
-
express: [
|
|
3089
|
-
{ name: "Express Docs", url: "https://expressjs.com/", description: "Official Express.js documentation" },
|
|
3090
|
-
{ name: "Express Security", url: "https://expressjs.com/en/advanced/best-practice-security.html", description: "Express security best practices" }
|
|
3091
|
-
],
|
|
3092
|
-
node: [
|
|
3093
|
-
{ name: "Node.js Docs", url: "https://nodejs.org/docs/", description: "Official Node.js documentation" },
|
|
3094
|
-
{ name: "Node.js Security", url: "https://nodejs.org/en/docs/guides/security/", description: "Node.js security guidance" }
|
|
3095
|
-
],
|
|
3096
|
-
typescript: [
|
|
3097
|
-
{ name: "TypeScript Docs", url: "https://www.typescriptlang.org/docs/", description: "Official TypeScript documentation" }
|
|
3098
|
-
]
|
|
3099
|
-
};
|
|
3100
|
-
var COMPLIANCE_SOURCES = {
|
|
3101
|
-
gdpr: [
|
|
3102
|
-
{ name: "GDPR Official Text", url: "https://gdpr.eu/", description: "Complete GDPR regulation text" },
|
|
3103
|
-
{ name: "GDPR Checklist", url: "https://gdpr.eu/checklist/", description: "GDPR compliance checklist" }
|
|
3104
|
-
],
|
|
3105
|
-
hipaa: [
|
|
3106
|
-
{ name: "HIPAA Guidelines", url: "https://www.hhs.gov/hipaa/", description: "Official HIPAA guidance" }
|
|
3107
|
-
],
|
|
3108
|
-
wcag: [
|
|
3109
|
-
{ name: "WCAG 2.1", url: "https://www.w3.org/WAI/WCAG21/quickref/", description: "WCAG 2.1 quick reference" }
|
|
3110
|
-
],
|
|
3111
|
-
pci: [
|
|
3112
|
-
{ name: "PCI DSS", url: "https://www.pcisecuritystandards.org/", description: "Payment Card Industry standards" }
|
|
3113
|
-
]
|
|
3114
|
-
};
|
|
3115
|
-
function generateCVELookup(library, version) {
|
|
3116
|
-
let prompt = `## \u{1F512} Security Vulnerability Lookup
|
|
3117
|
-
|
|
3118
|
-
`;
|
|
3119
|
-
prompt += `**Library:** ${library}
|
|
3120
|
-
`;
|
|
3121
|
-
if (version) prompt += `**Version:** ${version}
|
|
3122
|
-
`;
|
|
3123
|
-
prompt += `
|
|
3124
|
-
`;
|
|
3125
|
-
prompt += `### Action Required
|
|
3126
|
-
|
|
3127
|
-
`;
|
|
3128
|
-
prompt += `Please check for known vulnerabilities:
|
|
3129
|
-
|
|
3130
|
-
`;
|
|
3131
|
-
prompt += `1. Search the **NIST NVD** (https://nvd.nist.gov/) for CVEs affecting \`${library}\`
|
|
3132
|
-
`;
|
|
3133
|
-
prompt += `2. Check **Snyk** (https://security.snyk.io/) for vulnerability reports
|
|
3134
|
-
`;
|
|
3135
|
-
prompt += `3. Review **GitHub Advisory Database** for any security advisories
|
|
3136
|
-
`;
|
|
3137
|
-
prompt += `4. Check npm audit / yarn audit if it's an npm package
|
|
3138
|
-
|
|
3139
|
-
`;
|
|
3140
|
-
prompt += `### Report Format
|
|
3141
|
-
|
|
3142
|
-
`;
|
|
3143
|
-
prompt += `For each vulnerability found, provide:
|
|
3144
|
-
`;
|
|
3145
|
-
prompt += `- CVE ID (if applicable)
|
|
3146
|
-
`;
|
|
3147
|
-
prompt += `- Severity (Critical/High/Medium/Low)
|
|
3148
|
-
`;
|
|
3149
|
-
prompt += `- Affected versions
|
|
3150
|
-
`;
|
|
3151
|
-
prompt += `- Description of the vulnerability
|
|
3152
|
-
`;
|
|
3153
|
-
prompt += `- Remediation (upgrade version, patches, mitigations)
|
|
3154
|
-
`;
|
|
3155
|
-
return prompt;
|
|
3156
|
-
}
|
|
3157
|
-
function generateDocsLookup(topic, framework) {
|
|
3158
|
-
let prompt = `## \u{1F4DA} Documentation Lookup
|
|
3159
|
-
|
|
3160
|
-
`;
|
|
3161
|
-
prompt += `**Topic:** ${topic}
|
|
3162
|
-
`;
|
|
3163
|
-
if (framework) prompt += `**Framework:** ${framework}
|
|
3164
|
-
`;
|
|
3165
|
-
prompt += `
|
|
3166
|
-
`;
|
|
3167
|
-
const sources = framework ? DOCS_SOURCES[framework.toLowerCase()] : [];
|
|
3168
|
-
if (sources && sources.length > 0) {
|
|
3169
|
-
prompt += `### Recommended Sources
|
|
3170
|
-
|
|
3171
|
-
`;
|
|
3172
|
-
for (const source of sources) {
|
|
3173
|
-
prompt += `- [${source.name}](${source.url}) - ${source.description}
|
|
3174
|
-
`;
|
|
3175
|
-
}
|
|
3176
|
-
prompt += `
|
|
3177
|
-
`;
|
|
3178
|
-
}
|
|
3179
|
-
prompt += `### Information Needed
|
|
3180
|
-
|
|
3181
|
-
`;
|
|
3182
|
-
prompt += `Please look up the latest documentation and provide:
|
|
3183
|
-
|
|
3184
|
-
`;
|
|
3185
|
-
prompt += `1. Current best practices for "${topic}"
|
|
3186
|
-
`;
|
|
3187
|
-
prompt += `2. Common pitfalls to avoid
|
|
3188
|
-
`;
|
|
3189
|
-
prompt += `3. Code examples demonstrating correct usage
|
|
3190
|
-
`;
|
|
3191
|
-
prompt += `4. Any recent changes or deprecations
|
|
3192
|
-
`;
|
|
3193
|
-
return prompt;
|
|
3194
|
-
}
|
|
3195
|
-
function generateSecurityLookup(pattern, context) {
|
|
3196
|
-
let prompt = `## \u{1F6E1}\uFE0F Security Best Practices Lookup
|
|
3197
|
-
|
|
3198
|
-
`;
|
|
3199
|
-
prompt += `**Pattern:** ${pattern}
|
|
3200
|
-
`;
|
|
3201
|
-
if (context) prompt += `**Context:** ${context}
|
|
3202
|
-
`;
|
|
3203
|
-
prompt += `
|
|
3204
|
-
`;
|
|
3205
|
-
prompt += `### Reference Sources
|
|
3206
|
-
|
|
3207
|
-
`;
|
|
3208
|
-
for (const source of SECURITY_SOURCES.slice(0, 3)) {
|
|
3209
|
-
prompt += `- [${source.name}](${source.url})
|
|
3210
|
-
`;
|
|
3211
|
-
}
|
|
3212
|
-
prompt += `
|
|
3213
|
-
`;
|
|
3214
|
-
prompt += `### Analysis Requested
|
|
3215
|
-
|
|
3216
|
-
`;
|
|
3217
|
-
prompt += `Please research and provide:
|
|
3218
|
-
|
|
3219
|
-
`;
|
|
3220
|
-
prompt += `1. **OWASP guidance** for this security pattern
|
|
3221
|
-
`;
|
|
3222
|
-
prompt += `2. **Attack vectors** - how this could be exploited
|
|
3223
|
-
`;
|
|
3224
|
-
prompt += `3. **Defense strategies** - recommended mitigations
|
|
3225
|
-
`;
|
|
3226
|
-
prompt += `4. **Code examples** - secure implementation patterns
|
|
3227
|
-
`;
|
|
3228
|
-
prompt += `5. **Testing approaches** - how to verify security
|
|
3229
|
-
`;
|
|
3230
|
-
return prompt;
|
|
3231
|
-
}
|
|
3232
|
-
function generateComplianceLookup(regulation, requirement) {
|
|
3233
|
-
let prompt = `## \u2696\uFE0F Compliance Requirement Lookup
|
|
3234
|
-
|
|
3235
|
-
`;
|
|
3236
|
-
prompt += `**Regulation:** ${regulation}
|
|
3237
|
-
`;
|
|
3238
|
-
if (requirement) prompt += `**Specific Requirement:** ${requirement}
|
|
3239
|
-
`;
|
|
3240
|
-
prompt += `
|
|
3241
|
-
`;
|
|
3242
|
-
const sources = COMPLIANCE_SOURCES[regulation.toLowerCase()];
|
|
3243
|
-
if (sources && sources.length > 0) {
|
|
3244
|
-
prompt += `### Official Sources
|
|
3245
|
-
|
|
3246
|
-
`;
|
|
3247
|
-
for (const source of sources) {
|
|
3248
|
-
prompt += `- [${source.name}](${source.url})
|
|
3249
|
-
`;
|
|
3250
|
-
}
|
|
3251
|
-
prompt += `
|
|
3252
|
-
`;
|
|
3253
|
-
}
|
|
3254
|
-
prompt += `### Compliance Information Needed
|
|
3255
|
-
|
|
3256
|
-
`;
|
|
3257
|
-
prompt += `Please research and provide:
|
|
3258
|
-
|
|
3259
|
-
`;
|
|
3260
|
-
prompt += `1. **Specific requirement text** from the regulation
|
|
3261
|
-
`;
|
|
3262
|
-
prompt += `2. **Technical requirements** for compliance
|
|
3263
|
-
`;
|
|
3264
|
-
prompt += `3. **Implementation guidance** with code examples
|
|
3265
|
-
`;
|
|
3266
|
-
prompt += `4. **Documentation requirements** - what records to keep
|
|
3267
|
-
`;
|
|
3268
|
-
prompt += `5. **Penalties** for non-compliance
|
|
3269
|
-
`;
|
|
3270
|
-
return prompt;
|
|
3271
|
-
}
|
|
3272
|
-
function generateChangelogLookup(library, fromVersion, toVersion) {
|
|
3273
|
-
let prompt = `## \u{1F4CB} Changelog Lookup
|
|
3274
|
-
|
|
3275
|
-
`;
|
|
3276
|
-
prompt += `**Library:** ${library}
|
|
3277
|
-
`;
|
|
3278
|
-
prompt += `**Current Version:** ${fromVersion}
|
|
3279
|
-
`;
|
|
3280
|
-
if (toVersion) prompt += `**Target Version:** ${toVersion}
|
|
3281
|
-
`;
|
|
3282
|
-
prompt += `
|
|
3283
|
-
`;
|
|
3284
|
-
prompt += `### Information Needed
|
|
3285
|
-
|
|
3286
|
-
`;
|
|
3287
|
-
prompt += `Please find the changelog/release notes and provide:
|
|
3288
|
-
|
|
3289
|
-
`;
|
|
3290
|
-
prompt += `1. **Breaking changes** between versions
|
|
3291
|
-
`;
|
|
3292
|
-
prompt += `2. **New features** added
|
|
3293
|
-
`;
|
|
3294
|
-
prompt += `3. **Deprecations** to be aware of
|
|
3295
|
-
`;
|
|
3296
|
-
prompt += `4. **Security fixes** included
|
|
3297
|
-
`;
|
|
3298
|
-
prompt += `5. **Migration guide** if available
|
|
3299
|
-
`;
|
|
3300
|
-
prompt += `6. **Known issues** with the upgrade
|
|
3301
|
-
`;
|
|
3302
|
-
return prompt;
|
|
3303
|
-
}
|
|
3304
|
-
function lookupKnowledge(request2) {
|
|
3305
|
-
const { type, query, context = {} } = request2;
|
|
3306
|
-
switch (type) {
|
|
3307
|
-
case "cve":
|
|
3308
|
-
return generateCVELookup(query, context.version);
|
|
3309
|
-
case "docs":
|
|
3310
|
-
return generateDocsLookup(query, context.framework);
|
|
3311
|
-
case "security":
|
|
3312
|
-
return generateSecurityLookup(query, context.context);
|
|
3313
|
-
case "best-practices":
|
|
3314
|
-
return generateComplianceLookup(query, context.requirement);
|
|
3315
|
-
case "changelog":
|
|
3316
|
-
return generateChangelogLookup(query, context.fromVersion || "current", context.toVersion);
|
|
3317
|
-
default:
|
|
3318
|
-
return `Unknown knowledge request type: ${type}`;
|
|
3319
|
-
}
|
|
3320
|
-
}
|
|
3321
|
-
|
|
3322
|
-
// src/tools/agent.ts
|
|
3323
|
-
var SCANNABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
3324
|
-
".ts",
|
|
3325
|
-
".tsx",
|
|
3326
|
-
".js",
|
|
3327
|
-
".jsx",
|
|
3328
|
-
".mjs",
|
|
3329
|
-
".cjs",
|
|
3330
|
-
".vue",
|
|
3331
|
-
".svelte",
|
|
3332
|
-
".astro",
|
|
3333
|
-
".py",
|
|
3334
|
-
".go",
|
|
3335
|
-
".rs"
|
|
3336
|
-
]);
|
|
3337
|
-
var SKIP_DIRS2 = /* @__PURE__ */ new Set([
|
|
3338
|
-
"node_modules",
|
|
3339
|
-
".git",
|
|
3340
|
-
"dist",
|
|
3341
|
-
"build",
|
|
3342
|
-
".next",
|
|
3343
|
-
".nuxt",
|
|
3344
|
-
"coverage",
|
|
3345
|
-
".nyc_output",
|
|
3346
|
-
"__pycache__",
|
|
3347
|
-
".pytest_cache",
|
|
3348
|
-
"vendor",
|
|
3349
|
-
".venv",
|
|
3350
|
-
"venv",
|
|
3351
|
-
"target",
|
|
3352
|
-
".turbo",
|
|
3353
|
-
".cache"
|
|
3354
|
-
]);
|
|
3355
|
-
var TrieAgentTool = class {
|
|
3356
|
-
agentRegistry = getSkillRegistry();
|
|
3357
|
-
customSkillsLoaded = false;
|
|
3358
|
-
/**
|
|
3359
|
-
* Ensure custom skills are loaded before using the registry
|
|
3360
|
-
*/
|
|
3361
|
-
async ensureCustomSkillsLoaded() {
|
|
3362
|
-
if (!this.customSkillsLoaded) {
|
|
3363
|
-
await this.agentRegistry.loadCustomSkills();
|
|
3364
|
-
this.customSkillsLoaded = true;
|
|
3365
|
-
}
|
|
3366
|
-
}
|
|
3367
|
-
async execute(args) {
|
|
3368
|
-
const { agent, files, directory, depth: _depth = "standard", lookup, output = "full" } = args;
|
|
3369
|
-
if (lookup) {
|
|
3370
|
-
return this.handleKnowledgeLookup(lookup);
|
|
3371
|
-
}
|
|
3372
|
-
await this.ensureCustomSkillsLoaded();
|
|
3373
|
-
if (!agent) {
|
|
3374
|
-
return this.listSkills();
|
|
3375
|
-
}
|
|
3376
|
-
const agentInstance = this.agentRegistry.getSkill(agent);
|
|
3377
|
-
if (!agentInstance) {
|
|
3378
|
-
return {
|
|
3379
|
-
content: [{
|
|
3380
|
-
type: "text",
|
|
3381
|
-
text: `Skill not found: ${agent}
|
|
3382
|
-
|
|
3383
|
-
Available skills:
|
|
3384
|
-
${this.agentRegistry.getSkillNames().map((n) => `- ${n}`).join("\n")}`
|
|
3385
|
-
}]
|
|
3386
|
-
};
|
|
3387
|
-
}
|
|
3388
|
-
const workDir = getWorkingDirectory(directory);
|
|
3389
|
-
let filesToScan = files || [];
|
|
3390
|
-
if (!filesToScan.length) {
|
|
3391
|
-
console.error(`
|
|
3392
|
-
Discovering files in: ${workDir}`);
|
|
3393
|
-
filesToScan = await this.discoverFiles(workDir);
|
|
3394
|
-
console.error(` Found ${filesToScan.length} files
|
|
3395
|
-
`);
|
|
3396
|
-
} else {
|
|
3397
|
-
filesToScan = filesToScan.map(
|
|
3398
|
-
(f) => isAbsolute4(f) ? f : resolve4(workDir, f)
|
|
3399
|
-
);
|
|
3400
|
-
}
|
|
3401
|
-
const validFiles = filesToScan.filter((f) => existsSync5(f));
|
|
3402
|
-
if (validFiles.length === 0) {
|
|
3403
|
-
return {
|
|
3404
|
-
content: [{
|
|
3405
|
-
type: "text",
|
|
3406
|
-
text: `No valid files found to scan.`
|
|
3407
|
-
}]
|
|
3408
|
-
};
|
|
3409
|
-
}
|
|
3410
|
-
const startTime = Date.now();
|
|
3411
|
-
return this.runSkillScan(agentInstance, validFiles, startTime, output);
|
|
3412
|
-
}
|
|
3413
|
-
/**
|
|
3414
|
-
* Run agent scan using the new hybrid AI system
|
|
3415
|
-
* All agents now use scan() which has pattern detection + optional AI enhancement
|
|
3416
|
-
*/
|
|
3417
|
-
async runSkillScan(agentInstance, files, startTime, _outputMode) {
|
|
3418
|
-
console.error(`
|
|
3419
|
-
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`);
|
|
3420
|
-
console.error(`Running ${agentInstance.name.toUpperCase()} analysis`);
|
|
3421
|
-
console.error(`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
3422
|
-
`);
|
|
3423
|
-
console.error(`${agentInstance.description}`);
|
|
3424
|
-
console.error(`\u{1F4C2} Scanning ${files.length} files...`);
|
|
3425
|
-
console.error(` (Pattern detection + AI enhancement if API key is set)
|
|
3426
|
-
`);
|
|
3427
|
-
try {
|
|
3428
|
-
const result = await agentInstance.scan(files, { workingDir: getWorkingDirectory(void 0, true) });
|
|
3429
|
-
const executionTime = Date.now() - startTime;
|
|
3430
|
-
return {
|
|
3431
|
-
content: [{
|
|
3432
|
-
type: "text",
|
|
3433
|
-
text: await this.formatSkillResult(agentInstance.name, result.issues, files, executionTime)
|
|
3434
|
-
}]
|
|
3435
|
-
};
|
|
3436
|
-
} catch (error) {
|
|
3437
|
-
return {
|
|
3438
|
-
content: [{
|
|
3439
|
-
type: "text",
|
|
3440
|
-
text: `Skill error: ${error instanceof Error ? error.message : String(error)}`
|
|
3441
|
-
}]
|
|
3442
|
-
};
|
|
3443
|
-
}
|
|
3444
|
-
}
|
|
3445
|
-
handleKnowledgeLookup(lookup) {
|
|
3446
|
-
const result = lookupKnowledge({
|
|
3447
|
-
type: lookup.type,
|
|
3448
|
-
query: lookup.query,
|
|
3449
|
-
context: lookup.context ?? {}
|
|
3450
|
-
});
|
|
3451
|
-
return {
|
|
3452
|
-
content: [{
|
|
3453
|
-
type: "text",
|
|
3454
|
-
text: result
|
|
3455
|
-
}]
|
|
3456
|
-
};
|
|
3457
|
-
}
|
|
3458
|
-
listSkills() {
|
|
3459
|
-
const skills = this.agentRegistry.getSkillDescriptions();
|
|
3460
|
-
const skillList = skills.map((a) => {
|
|
3461
|
-
const command = this.getSkillCommand(a.name);
|
|
3462
|
-
return `| \`${command}\` | [PATTERN+AI] ${a.name} | ${a.description} |`;
|
|
3463
|
-
}).join("\n");
|
|
3464
|
-
return {
|
|
3465
|
-
content: [{
|
|
3466
|
-
type: "text",
|
|
3467
|
-
text: `# \u{1F916} Available Skills
|
|
3468
|
-
|
|
3469
|
-
| Command | Skill | Description |
|
|
3470
|
-
|---------|-------|-------------|
|
|
3471
|
-
${skillList}
|
|
3472
|
-
|
|
3473
|
-
**Legend:** [PATTERN+AI] = Pattern detection + AI enhancement (if ANTHROPIC_API_KEY is set)
|
|
3474
|
-
|
|
3475
|
-
## Usage
|
|
3476
|
-
|
|
3477
|
-
### Run a specific skill:
|
|
3478
|
-
\`\`\`
|
|
3479
|
-
trie_security # Security vulnerabilities
|
|
3480
|
-
trie_privacy # Privacy/GDPR compliance
|
|
3481
|
-
trie_accessibility # WCAG accessibility audit
|
|
3482
|
-
trie_bugs # Bug detection
|
|
3483
|
-
trie_ux # User experience testing
|
|
3484
|
-
trie_types # Type safety analysis
|
|
3485
|
-
trie_architecture # Architecture review
|
|
3486
|
-
trie_devops # DevOps readiness
|
|
3487
|
-
trie_legal # Legal compliance
|
|
3488
|
-
\`\`\`
|
|
3489
|
-
|
|
3490
|
-
### With options:
|
|
3491
|
-
\`\`\`
|
|
3492
|
-
trie_security files:["src/auth.ts"] depth:"deep"
|
|
3493
|
-
\`\`\`
|
|
3494
|
-
|
|
3495
|
-
### Knowledge lookup:
|
|
3496
|
-
\`\`\`
|
|
3497
|
-
trie_security lookup:{type:"cve", query:"lodash"}
|
|
3498
|
-
trie_security lookup:{type:"docs", query:"XSS prevention", context:{framework:"react"}}
|
|
3499
|
-
\`\`\`
|
|
3500
|
-
|
|
3501
|
-
### Run all skills:
|
|
3502
|
-
\`\`\`
|
|
3503
|
-
trie_scan # Full scan with smart triaging
|
|
3504
|
-
\`\`\``
|
|
3505
|
-
}]
|
|
3506
|
-
};
|
|
3507
|
-
}
|
|
3508
|
-
getSkillCommand(agentName) {
|
|
3509
|
-
const commandMap = {
|
|
3510
|
-
"security": "trie_security",
|
|
3511
|
-
"privacy": "trie_privacy",
|
|
3512
|
-
"legal": "trie_legal",
|
|
3513
|
-
"accessibility": "trie_accessibility",
|
|
3514
|
-
"design-engineer": "trie_design",
|
|
3515
|
-
"software-architect": "trie_architecture",
|
|
3516
|
-
"bug-finding": "trie_bugs",
|
|
3517
|
-
"user-testing": "trie_ux",
|
|
3518
|
-
"typecheck": "trie_types",
|
|
3519
|
-
"devops": "trie_devops",
|
|
3520
|
-
"comprehension": "trie_explain",
|
|
3521
|
-
"test": "trie_test"
|
|
3522
|
-
};
|
|
3523
|
-
return commandMap[agentName] || `trie_scan --skill ${agentName}`;
|
|
3524
|
-
}
|
|
3525
|
-
async formatSkillResult(agentName, issues, files, executionTime) {
|
|
3526
|
-
const critical = issues.filter((i) => i.severity === "critical").length;
|
|
3527
|
-
const serious = issues.filter((i) => i.severity === "serious").length;
|
|
3528
|
-
const moderate = issues.filter((i) => i.severity === "moderate").length;
|
|
3529
|
-
const low = issues.filter((i) => i.severity === "low").length;
|
|
3530
|
-
const agentEmoji = this.getSkillEmoji(agentName);
|
|
3531
|
-
let output = `
|
|
3532
|
-
`;
|
|
3533
|
-
output += `# ${agentEmoji} ${agentName.toUpperCase()} SCAN
|
|
3534
|
-
|
|
3535
|
-
`;
|
|
3536
|
-
output += `**Files:** ${files.length} | **Time:** ${(executionTime / 1e3).toFixed(2)}s
|
|
3537
|
-
|
|
3538
|
-
`;
|
|
3539
|
-
if (issues.length === 0) {
|
|
3540
|
-
output += `## No Issues Found
|
|
3541
|
-
|
|
3542
|
-
`;
|
|
3543
|
-
output += `Your code passed all ${agentName} checks.
|
|
3544
|
-
|
|
3545
|
-
`;
|
|
3546
|
-
return output;
|
|
3547
|
-
}
|
|
3548
|
-
output += `## ${issues.length} Issues Found
|
|
3549
|
-
|
|
3550
|
-
`;
|
|
3551
|
-
if (critical > 0) output += `[!] ${critical} Critical `;
|
|
3552
|
-
if (serious > 0) output += `[!] ${serious} Serious `;
|
|
3553
|
-
if (moderate > 0) output += `[~] ${moderate} Moderate `;
|
|
3554
|
-
if (low > 0) output += `[-] ${low} Low`;
|
|
3555
|
-
output += `
|
|
3556
|
-
|
|
3557
|
-
`;
|
|
3558
|
-
const sorted = [...issues].sort((a, b) => {
|
|
3559
|
-
const severityOrder = { critical: 0, serious: 1, moderate: 2, low: 3 };
|
|
3560
|
-
if (severityOrder[a.severity] !== severityOrder[b.severity]) {
|
|
3561
|
-
return severityOrder[a.severity] - severityOrder[b.severity];
|
|
3562
|
-
}
|
|
3563
|
-
return (a.line || 0) - (b.line || 0);
|
|
3564
|
-
});
|
|
3565
|
-
for (const issue of sorted) {
|
|
3566
|
-
const icon = { critical: "[!]", serious: "[!]", moderate: "[~]", low: "[-]" }[issue.severity];
|
|
3567
|
-
output += `---
|
|
3568
|
-
|
|
3569
|
-
`;
|
|
3570
|
-
output += `${icon} **${issue.issue}**
|
|
3571
|
-
|
|
3572
|
-
`;
|
|
3573
|
-
output += `\`${issue.file}:${issue.line || "?"}\`
|
|
3574
|
-
|
|
3575
|
-
`;
|
|
3576
|
-
const snippet = await this.getCodeSnippet(issue.file, issue.line);
|
|
3577
|
-
if (snippet) {
|
|
3578
|
-
output += `\`\`\`
|
|
3579
|
-
${snippet}
|
|
3580
|
-
\`\`\`
|
|
3581
|
-
|
|
3582
|
-
`;
|
|
3583
|
-
}
|
|
3584
|
-
output += `**Fix:** ${issue.fix}
|
|
3585
|
-
|
|
3586
|
-
`;
|
|
3587
|
-
if (issue.cwe) output += `CWE: ${issue.cwe}
|
|
3588
|
-
`;
|
|
3589
|
-
if (issue.regulation) output += `Regulation: ${issue.regulation}
|
|
3590
|
-
`;
|
|
3591
|
-
output += `<details>
|
|
3592
|
-
<summary>Prompt to fix this</summary>
|
|
3593
|
-
|
|
3594
|
-
`;
|
|
3595
|
-
output += `\`\`\`
|
|
3596
|
-
Fix the ${issue.issue.toLowerCase()} in ${basename3(issue.file)}${issue.line ? ` at line ${issue.line}` : ""}.
|
|
3597
|
-
|
|
3598
|
-
${issue.fix}
|
|
3599
|
-
\`\`\`
|
|
3600
|
-
|
|
3601
|
-
`;
|
|
3602
|
-
output += `</details>
|
|
3603
|
-
|
|
3604
|
-
`;
|
|
3605
|
-
}
|
|
3606
|
-
output += `---
|
|
3607
|
-
`;
|
|
3608
|
-
output += `*${agentName} scan completed in ${(executionTime / 1e3).toFixed(2)}s*
|
|
3609
|
-
`;
|
|
3610
|
-
return output;
|
|
3611
|
-
}
|
|
3612
|
-
/**
|
|
3613
|
-
* Get a code snippet around a specific line
|
|
3614
|
-
*/
|
|
3615
|
-
async getCodeSnippet(filePath, line) {
|
|
3616
|
-
if (!line || !existsSync5(filePath)) return null;
|
|
3617
|
-
try {
|
|
3618
|
-
const content = await readFile4(filePath, "utf-8");
|
|
3619
|
-
const lines = content.split("\n");
|
|
3620
|
-
const start = Math.max(0, line - 3);
|
|
3621
|
-
const end = Math.min(lines.length, line + 2);
|
|
3622
|
-
return lines.slice(start, end).map((l, idx) => {
|
|
3623
|
-
const lineNum = start + idx + 1;
|
|
3624
|
-
const marker = lineNum === line ? "\u2192" : " ";
|
|
3625
|
-
return `${marker} ${lineNum.toString().padStart(4)} | ${l}`;
|
|
3626
|
-
}).join("\n");
|
|
3627
|
-
} catch {
|
|
3628
|
-
return null;
|
|
3629
|
-
}
|
|
3630
|
-
}
|
|
3631
|
-
getSkillEmoji(agentName) {
|
|
3632
|
-
const emojis = {
|
|
3633
|
-
"security": "[SEC]",
|
|
3634
|
-
"privacy": "[PRIV]",
|
|
3635
|
-
"legal": "[LEGAL]",
|
|
3636
|
-
"accessibility": "[A11Y]",
|
|
3637
|
-
"design-engineer": "[DESIGN]",
|
|
3638
|
-
"software-architect": "[ARCH]",
|
|
3639
|
-
"bug-finding": "[BUG]",
|
|
3640
|
-
"user-testing": "[TEST]",
|
|
3641
|
-
"typecheck": "[TYPE]",
|
|
3642
|
-
"devops": "[OPS]",
|
|
3643
|
-
"comprehension": "[DOC]",
|
|
3644
|
-
"test": "[TEST]"
|
|
3645
|
-
};
|
|
3646
|
-
return emojis[agentName] || "[?]";
|
|
3647
|
-
}
|
|
3648
|
-
async discoverFiles(dir, maxFiles = 200) {
|
|
3649
|
-
const files = [];
|
|
3650
|
-
async function walk(currentDir) {
|
|
3651
|
-
if (files.length >= maxFiles) return;
|
|
3652
|
-
try {
|
|
3653
|
-
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
3654
|
-
for (const entry of entries) {
|
|
3655
|
-
if (files.length >= maxFiles) break;
|
|
3656
|
-
const fullPath = join3(currentDir, entry.name);
|
|
3657
|
-
if (entry.isDirectory()) {
|
|
3658
|
-
if (!SKIP_DIRS2.has(entry.name) && !entry.name.startsWith(".")) {
|
|
3659
|
-
await walk(fullPath);
|
|
3660
|
-
}
|
|
3661
|
-
} else if (entry.isFile()) {
|
|
3662
|
-
const ext = extname5(entry.name).toLowerCase();
|
|
3663
|
-
if (SCANNABLE_EXTENSIONS.has(ext)) {
|
|
3664
|
-
files.push(fullPath);
|
|
3665
|
-
}
|
|
3666
|
-
}
|
|
3667
|
-
}
|
|
3668
|
-
} catch (error) {
|
|
3669
|
-
}
|
|
3670
|
-
}
|
|
3671
|
-
await walk(dir);
|
|
3672
|
-
return files;
|
|
3673
|
-
}
|
|
3674
|
-
};
|
|
3675
|
-
|
|
3676
|
-
// src/tools/create-agent.ts
|
|
3677
|
-
import { existsSync as existsSync6 } from "fs";
|
|
3678
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
3679
|
-
import { join as join4, basename as basename4, extname as extname6 } from "path";
|
|
3680
|
-
var TrieCreateAgentTool = class {
|
|
3681
|
-
async execute(args) {
|
|
3682
|
-
const { filePath, documentContent, agentName, displayName, description, category } = args;
|
|
3683
|
-
if (!agentName) {
|
|
3684
|
-
return this.errorResponse("Missing required parameter: agentName");
|
|
3685
|
-
}
|
|
3686
|
-
if (!filePath && !documentContent) {
|
|
3687
|
-
return this.errorResponse(
|
|
3688
|
-
"Provide either filePath (path to PDF/TXT/MD file) or documentContent (raw text from drag-and-drop)"
|
|
3689
|
-
);
|
|
3690
|
-
}
|
|
3691
|
-
try {
|
|
3692
|
-
let rawText;
|
|
3693
|
-
let title = agentName;
|
|
3694
|
-
let wordCount = 0;
|
|
3695
|
-
if (filePath) {
|
|
3696
|
-
if (!existsSync6(filePath)) {
|
|
3697
|
-
return this.errorResponse(`File not found: ${filePath}`);
|
|
3698
|
-
}
|
|
3699
|
-
const ext = filePath.toLowerCase().split(".").pop();
|
|
3700
|
-
if (!["pdf", "txt", "md", "markdown", "rtf"].includes(ext || "")) {
|
|
3701
|
-
return this.errorResponse(
|
|
3702
|
-
`Unsupported file type: .${ext}
|
|
3703
|
-
Supported types: .pdf, .txt, .md, .rtf`
|
|
3704
|
-
);
|
|
3705
|
-
}
|
|
3706
|
-
const document = await parseDocument(filePath);
|
|
3707
|
-
rawText = document.rawText;
|
|
3708
|
-
title = document.metadata.title || basename4(filePath, extname6(filePath));
|
|
3709
|
-
wordCount = document.metadata.wordCount;
|
|
3710
|
-
} else {
|
|
3711
|
-
rawText = documentContent;
|
|
3712
|
-
wordCount = rawText.split(/\s+/).filter((w) => w.length > 0).length;
|
|
3713
|
-
const firstLine = rawText.split("\n")[0]?.trim();
|
|
3714
|
-
if (firstLine && firstLine.length < 100) {
|
|
3715
|
-
title = firstLine;
|
|
3716
|
-
}
|
|
3717
|
-
}
|
|
3718
|
-
const chunks = this.chunkText(rawText, 6e3);
|
|
3719
|
-
const extractionPrompt = this.buildExtractionPrompt(
|
|
3720
|
-
chunks,
|
|
3721
|
-
title,
|
|
3722
|
-
agentName,
|
|
3723
|
-
category,
|
|
3724
|
-
displayName,
|
|
3725
|
-
description
|
|
3726
|
-
);
|
|
3727
|
-
return {
|
|
3728
|
-
content: [
|
|
3729
|
-
{
|
|
3730
|
-
type: "text",
|
|
3731
|
-
text: this.formatExtractionRequest(
|
|
3732
|
-
agentName,
|
|
3733
|
-
title,
|
|
3734
|
-
wordCount,
|
|
3735
|
-
chunks.length,
|
|
3736
|
-
extractionPrompt
|
|
3737
|
-
)
|
|
3738
|
-
}
|
|
3739
|
-
]
|
|
3740
|
-
};
|
|
3741
|
-
} catch (error) {
|
|
3742
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3743
|
-
return this.errorResponse(`Failed to parse document: ${errorMessage}`);
|
|
3744
|
-
}
|
|
3745
|
-
}
|
|
3746
|
-
/**
|
|
3747
|
-
* Chunk text into manageable pieces
|
|
3748
|
-
*/
|
|
3749
|
-
chunkText(text, maxChunkSize) {
|
|
3750
|
-
if (text.length <= maxChunkSize) {
|
|
3751
|
-
return [text];
|
|
3752
|
-
}
|
|
3753
|
-
const chunks = [];
|
|
3754
|
-
const paragraphs = text.split(/\n\s*\n/);
|
|
3755
|
-
let currentChunk = "";
|
|
3756
|
-
for (const para of paragraphs) {
|
|
3757
|
-
if (currentChunk.length + para.length + 2 > maxChunkSize) {
|
|
3758
|
-
if (currentChunk) chunks.push(currentChunk.trim());
|
|
3759
|
-
currentChunk = para;
|
|
3760
|
-
} else {
|
|
3761
|
-
currentChunk += (currentChunk ? "\n\n" : "") + para;
|
|
3762
|
-
}
|
|
3763
|
-
}
|
|
3764
|
-
if (currentChunk) chunks.push(currentChunk.trim());
|
|
3765
|
-
return chunks;
|
|
3766
|
-
}
|
|
3767
|
-
/**
|
|
3768
|
-
* Build the extraction prompt for Claude
|
|
3769
|
-
*/
|
|
3770
|
-
buildExtractionPrompt(chunks, title, agentName, category, displayName, description) {
|
|
3771
|
-
const prefix = agentName.toUpperCase().replace(/[^A-Z]/g, "").slice(0, 4) || "CUST";
|
|
3772
|
-
const documentContent = chunks.length === 1 ? chunks[0] : chunks.map((c, i) => `--- SECTION ${i + 1}/${chunks.length} ---
|
|
3773
|
-
${c}`).join("\n\n");
|
|
3774
|
-
return `# Create Code Review Agent: "${displayName || this.formatDisplayName(agentName)}"
|
|
3775
|
-
|
|
3776
|
-
## Your Task
|
|
3777
|
-
Analyze the following document and extract structured knowledge to create a code review agent.
|
|
3778
|
-
|
|
3779
|
-
## Document Information
|
|
3780
|
-
- **Title**: ${title}
|
|
3781
|
-
- **Agent Name**: ${agentName}
|
|
3782
|
-
- **Category**: ${category || "auto-detect"}
|
|
3783
|
-
${description ? `- **Description**: ${description}` : ""}
|
|
3784
|
-
|
|
3785
|
-
## Document Content
|
|
3786
|
-
${documentContent}
|
|
3787
|
-
|
|
3788
|
-
---
|
|
3789
|
-
|
|
3790
|
-
## Instructions
|
|
3791
|
-
|
|
3792
|
-
Please analyze this document and produce a **single JSON object** with the following structure. This will be used to create a custom code review agent.
|
|
3793
|
-
|
|
3794
|
-
**IMPORTANT**: Your response should be ONLY the JSON object, no other text.
|
|
3795
|
-
|
|
3796
|
-
\`\`\`json
|
|
3797
|
-
{
|
|
3798
|
-
"agentConfig": {
|
|
3799
|
-
"name": "${this.sanitizeAgentName(agentName)}",
|
|
3800
|
-
"displayName": "${displayName || this.formatDisplayName(agentName)}",
|
|
3801
|
-
"description": "${description || `Code review agent based on ${title}`}",
|
|
3802
|
-
"version": "1.0.0",
|
|
3803
|
-
"category": "string (technical | legal | policy | security | architecture | general)"
|
|
3804
|
-
},
|
|
3805
|
-
"knowledge": {
|
|
3806
|
-
"domain": "string (technical | legal | policy | security | architecture | general)",
|
|
3807
|
-
"summary": "2-3 paragraph summary of the document's key insights for code review",
|
|
3808
|
-
"coreConcepts": [
|
|
3809
|
-
{
|
|
3810
|
-
"name": "string",
|
|
3811
|
-
"description": "string",
|
|
3812
|
-
"importance": "critical | important | supplementary",
|
|
3813
|
-
"keywords": ["string"]
|
|
3814
|
-
}
|
|
3815
|
-
],
|
|
3816
|
-
"bestPractices": [
|
|
3817
|
-
{
|
|
3818
|
-
"name": "string",
|
|
3819
|
-
"description": "string",
|
|
3820
|
-
"rationale": "why this is important",
|
|
3821
|
-
"codeExample": "optional code example or null"
|
|
3822
|
-
}
|
|
3823
|
-
],
|
|
3824
|
-
"antiPatterns": [
|
|
3825
|
-
{
|
|
3826
|
-
"name": "string",
|
|
3827
|
-
"description": "string",
|
|
3828
|
-
"whyBad": "why to avoid",
|
|
3829
|
-
"betterAlternative": "what to do instead"
|
|
3830
|
-
}
|
|
3831
|
-
],
|
|
3832
|
-
"glossary": {
|
|
3833
|
-
"term": "definition"
|
|
3834
|
-
}
|
|
3835
|
-
},
|
|
3836
|
-
"detectionRules": [
|
|
3837
|
-
{
|
|
3838
|
-
"id": "${prefix}-001",
|
|
3839
|
-
"name": "Rule Name",
|
|
3840
|
-
"description": "What this rule detects",
|
|
3841
|
-
"severity": "critical | serious | moderate | low | info",
|
|
3842
|
-
"patterns": {
|
|
3843
|
-
"regex": ["JavaScript regex patterns"],
|
|
3844
|
-
"keywords": ["words that indicate this issue"],
|
|
3845
|
-
"semantic": "Natural language description for AI detection"
|
|
3846
|
-
},
|
|
3847
|
-
"fix": {
|
|
3848
|
-
"description": "How to fix this issue",
|
|
3849
|
-
"example": "Code example or null",
|
|
3850
|
-
"autoFixable": false
|
|
3851
|
-
},
|
|
3852
|
-
"category": "string"
|
|
3853
|
-
}
|
|
3854
|
-
],
|
|
3855
|
-
"prompts": {
|
|
3856
|
-
"systemPrompt": "You are an expert code reviewer specializing in [topic]. Your role is to...",
|
|
3857
|
-
"analysisPrompt": "Review this code for issues related to [topic]. Look for: ...\\n\\nCode:\\n\\\`\\\`\\\`{{language}}\\n{{code}}\\n\\\`\\\`\\\`\\n\\nFile: {{filePath}}",
|
|
3858
|
-
"fixPrompt": "Fix this issue: {{issue}}\\n\\nCode:\\n\\\`\\\`\\\`{{language}}\\n{{code}}\\n\\\`\\\`\\\`"
|
|
3859
|
-
}
|
|
3860
|
-
}
|
|
3861
|
-
\`\`\`
|
|
3862
|
-
|
|
3863
|
-
## Guidelines
|
|
3864
|
-
|
|
3865
|
-
1. **Core Concepts**: Extract 10-20 key concepts that are fundamental to the material
|
|
3866
|
-
2. **Best Practices**: Extract 10-15 recommended approaches with rationale
|
|
3867
|
-
3. **Anti-Patterns**: Extract 10-15 things to avoid with explanations
|
|
3868
|
-
4. **Detection Rules**: Generate 15-30 rules with regex patterns that could detect issues in code
|
|
3869
|
-
5. **Prompts**: Create prompts that embody the expertise from this document
|
|
3870
|
-
|
|
3871
|
-
Focus on extracting actionable, code-reviewable knowledge. The agent should be able to find violations of the principles in this document.
|
|
3872
|
-
|
|
3873
|
-
**Output ONLY the JSON object, starting with \`{\` and ending with \`}\`.**`;
|
|
3874
|
-
}
|
|
3875
|
-
/**
|
|
3876
|
-
* Format the extraction request output
|
|
3877
|
-
*/
|
|
3878
|
-
formatExtractionRequest(agentName, title, wordCount, chunkCount, prompt) {
|
|
3879
|
-
return `
|
|
3880
|
-
**Document Parsed Successfully**
|
|
3881
|
-
|
|
3882
|
-
${"\u2501".repeat(50)}
|
|
3883
|
-
|
|
3884
|
-
**Creating Skill:** \`${agentName}\`
|
|
3885
|
-
**Source Document:** ${title}
|
|
3886
|
-
**Word Count:** ${wordCount.toLocaleString()}
|
|
3887
|
-
**Processing Chunks:** ${chunkCount}
|
|
3888
|
-
|
|
3889
|
-
${"\u2501".repeat(50)}
|
|
3890
|
-
|
|
3891
|
-
## Next Step
|
|
3892
|
-
|
|
3893
|
-
I've prepared the document for analysis. Please process the following prompt to extract the knowledge, then pass the result to \`trie_save_skill\` to save the custom skill.
|
|
3894
|
-
|
|
3895
|
-
${"\u2500".repeat(50)}
|
|
3896
|
-
|
|
3897
|
-
${prompt}
|
|
3898
|
-
`;
|
|
3899
|
-
}
|
|
3900
|
-
sanitizeAgentName(name) {
|
|
3901
|
-
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
3902
|
-
}
|
|
3903
|
-
formatDisplayName(name) {
|
|
3904
|
-
return name.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3905
|
-
}
|
|
3906
|
-
errorResponse(message) {
|
|
3907
|
-
return {
|
|
3908
|
-
content: [
|
|
3909
|
-
{
|
|
3910
|
-
type: "text",
|
|
3911
|
-
text: `\u274C **Error:** ${message}`
|
|
3912
|
-
}
|
|
3913
|
-
],
|
|
3914
|
-
isError: true
|
|
3915
|
-
};
|
|
3916
|
-
}
|
|
3917
|
-
};
|
|
3918
|
-
var TrieSaveAgentTool = class {
|
|
3919
|
-
async execute(args) {
|
|
3920
|
-
const { agentConfig, knowledge, detectionRules, prompts, sourceFile } = args;
|
|
3921
|
-
if (!agentConfig?.name) {
|
|
3922
|
-
return this.errorResponse("Missing agentConfig.name");
|
|
3923
|
-
}
|
|
3924
|
-
if (!knowledge?.summary) {
|
|
3925
|
-
return this.errorResponse("Missing knowledge.summary");
|
|
3926
|
-
}
|
|
3927
|
-
if (!prompts?.systemPrompt) {
|
|
3928
|
-
return this.errorResponse("Missing prompts.systemPrompt");
|
|
3929
|
-
}
|
|
3930
|
-
try {
|
|
3931
|
-
const fullConfig = {
|
|
3932
|
-
name: this.sanitizeAgentName(agentConfig.name),
|
|
3933
|
-
displayName: agentConfig.displayName || this.formatDisplayName(agentConfig.name),
|
|
3934
|
-
description: agentConfig.description,
|
|
3935
|
-
version: agentConfig.version || "1.0.0",
|
|
3936
|
-
category: agentConfig.category || knowledge.domain || "general",
|
|
3937
|
-
source: {
|
|
3938
|
-
type: "document",
|
|
3939
|
-
originalFile: sourceFile || "user-provided",
|
|
3940
|
-
fileType: "txt",
|
|
3941
|
-
compressedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3942
|
-
},
|
|
3943
|
-
systemPrompt: prompts.systemPrompt,
|
|
3944
|
-
analysisPrompt: prompts.analysisPrompt,
|
|
3945
|
-
fixPrompt: prompts.fixPrompt,
|
|
3946
|
-
activationRules: this.buildActivationRules(knowledge, detectionRules),
|
|
3947
|
-
patterns: detectionRules.map((rule, i) => {
|
|
3948
|
-
const fixObj = {
|
|
3949
|
-
description: rule.fix?.description || "Review and fix manually",
|
|
3950
|
-
autoFixable: rule.fix?.autoFixable || false
|
|
3951
|
-
};
|
|
3952
|
-
if (rule.fix?.example) {
|
|
3953
|
-
fixObj.example = rule.fix.example;
|
|
3954
|
-
}
|
|
3955
|
-
return {
|
|
3956
|
-
id: rule.id || `CUST-${String(i + 1).padStart(3, "0")}`,
|
|
3957
|
-
name: rule.name,
|
|
3958
|
-
description: rule.description,
|
|
3959
|
-
severity: rule.severity || "moderate",
|
|
3960
|
-
patterns: {
|
|
3961
|
-
regex: rule.patterns?.regex || [],
|
|
3962
|
-
keywords: rule.patterns?.keywords || [],
|
|
3963
|
-
semantic: rule.patterns?.semantic || ""
|
|
3964
|
-
},
|
|
3965
|
-
fix: fixObj,
|
|
3966
|
-
category: rule.category || agentConfig.category
|
|
3967
|
-
};
|
|
3968
|
-
}),
|
|
3969
|
-
knowledge: {
|
|
3970
|
-
domain: knowledge.domain || "general",
|
|
3971
|
-
summary: knowledge.summary,
|
|
3972
|
-
coreConcepts: knowledge.coreConcepts.map((c) => ({
|
|
3973
|
-
name: c.name,
|
|
3974
|
-
description: c.description,
|
|
3975
|
-
importance: c.importance || "important",
|
|
3976
|
-
relatedPatterns: c.relatedPatterns || [],
|
|
3977
|
-
keywords: c.keywords || []
|
|
3978
|
-
})),
|
|
3979
|
-
bestPractices: knowledge.bestPractices.map((bp) => {
|
|
3980
|
-
const practice = {
|
|
3981
|
-
name: bp.name,
|
|
3982
|
-
description: bp.description,
|
|
3983
|
-
rationale: bp.rationale,
|
|
3984
|
-
category: bp.category || agentConfig.category
|
|
3985
|
-
};
|
|
3986
|
-
if (bp.codeExample) {
|
|
3987
|
-
practice.codeExample = bp.codeExample;
|
|
3988
|
-
}
|
|
3989
|
-
return practice;
|
|
3990
|
-
}),
|
|
3991
|
-
antiPatterns: knowledge.antiPatterns.map((ap) => ({
|
|
3992
|
-
name: ap.name,
|
|
3993
|
-
description: ap.description,
|
|
3994
|
-
whyBad: ap.whyBad,
|
|
3995
|
-
betterAlternative: ap.betterAlternative
|
|
3996
|
-
})),
|
|
3997
|
-
detectionRules: [],
|
|
3998
|
-
glossary: knowledge.glossary || {},
|
|
3999
|
-
sourceDocument: {
|
|
4000
|
-
title: agentConfig.displayName || agentConfig.name,
|
|
4001
|
-
wordCount: 0,
|
|
4002
|
-
compressionRatio: 0
|
|
4003
|
-
}
|
|
4004
|
-
}
|
|
4005
|
-
};
|
|
4006
|
-
const configPath = await this.saveAgentConfig(fullConfig);
|
|
4007
|
-
return {
|
|
4008
|
-
content: [
|
|
4009
|
-
{
|
|
4010
|
-
type: "text",
|
|
4011
|
-
text: this.formatSuccessResponse(fullConfig, configPath)
|
|
4012
|
-
}
|
|
4013
|
-
]
|
|
4014
|
-
};
|
|
4015
|
-
} catch (error) {
|
|
4016
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4017
|
-
return this.errorResponse(`Failed to save skill: ${errorMessage}`);
|
|
4018
|
-
}
|
|
4019
|
-
}
|
|
4020
|
-
buildActivationRules(knowledge, detectionRules) {
|
|
4021
|
-
const domainRules = {
|
|
4022
|
-
technical: {
|
|
4023
|
-
filePatterns: ["*.ts", "*.tsx", "*.js", "*.jsx", "*.py", "*.go", "*.rs"],
|
|
4024
|
-
contextSignals: ["touchesUI", "touchesAPI"],
|
|
4025
|
-
priority: 2
|
|
4026
|
-
},
|
|
4027
|
-
legal: {
|
|
4028
|
-
filePatterns: ["*"],
|
|
4029
|
-
contextSignals: ["touchesUserData", "touchesAuth", "touchesPayments"],
|
|
4030
|
-
priority: 2
|
|
4031
|
-
},
|
|
4032
|
-
policy: {
|
|
4033
|
-
filePatterns: ["*"],
|
|
4034
|
-
contextSignals: ["touchesAuth", "touchesAPI", "touchesDatabase"],
|
|
4035
|
-
priority: 3
|
|
4036
|
-
},
|
|
4037
|
-
security: {
|
|
4038
|
-
filePatterns: ["*"],
|
|
4039
|
-
contextSignals: ["touchesAuth", "touchesCrypto", "touchesAPI", "touchesDatabase"],
|
|
4040
|
-
priority: 1
|
|
4041
|
-
},
|
|
4042
|
-
architecture: {
|
|
4043
|
-
filePatterns: ["*.ts", "*.tsx", "*.js", "*.jsx", "*.py", "*.go"],
|
|
4044
|
-
contextSignals: ["touchesAPI", "touchesDatabase"],
|
|
4045
|
-
priority: 2
|
|
4046
|
-
},
|
|
4047
|
-
general: {
|
|
4048
|
-
filePatterns: ["*"],
|
|
4049
|
-
contextSignals: [],
|
|
4050
|
-
priority: 3
|
|
4051
|
-
}
|
|
4052
|
-
};
|
|
4053
|
-
const defaults = domainRules[knowledge.domain] || domainRules.general;
|
|
4054
|
-
const contentPatterns = [];
|
|
4055
|
-
for (const rule of detectionRules) {
|
|
4056
|
-
if (rule.patterns?.keywords) {
|
|
4057
|
-
contentPatterns.push(...rule.patterns.keywords.slice(0, 3));
|
|
4058
|
-
}
|
|
4059
|
-
}
|
|
4060
|
-
for (const concept of knowledge.coreConcepts.slice(0, 5)) {
|
|
4061
|
-
if (concept.keywords) {
|
|
4062
|
-
contentPatterns.push(...concept.keywords.slice(0, 2));
|
|
4063
|
-
}
|
|
4064
|
-
}
|
|
4065
|
-
return {
|
|
4066
|
-
filePatterns: defaults.filePatterns || ["*"],
|
|
4067
|
-
contentPatterns: [...new Set(contentPatterns)].slice(0, 20),
|
|
4068
|
-
contextSignals: defaults.contextSignals || [],
|
|
4069
|
-
minConfidence: 0.3,
|
|
4070
|
-
priority: defaults.priority || 2
|
|
4071
|
-
};
|
|
4072
|
-
}
|
|
4073
|
-
async saveAgentConfig(config) {
|
|
4074
|
-
const trieDir = join4(getTrieDirectory(getWorkingDirectory(void 0, true)), "agents");
|
|
4075
|
-
await mkdir(trieDir, { recursive: true });
|
|
4076
|
-
const configPath = join4(trieDir, `${config.name}.json`);
|
|
4077
|
-
await writeFile(configPath, JSON.stringify(config, null, 2));
|
|
4078
|
-
return configPath;
|
|
4079
|
-
}
|
|
4080
|
-
formatSuccessResponse(config, configPath) {
|
|
4081
|
-
return `
|
|
4082
|
-
**Custom Skill Created Successfully**
|
|
4083
|
-
|
|
4084
|
-
${"\u2501".repeat(50)}
|
|
4085
|
-
|
|
4086
|
-
**Skill Name:** \`${config.name}\`
|
|
4087
|
-
**Display Name:** ${config.displayName}
|
|
4088
|
-
**Category:** ${config.category}
|
|
4089
|
-
**Config Saved To:** \`${configPath}\`
|
|
4090
|
-
|
|
4091
|
-
**Statistics:**
|
|
4092
|
-
- Core concepts: ${config.knowledge.coreConcepts.length}
|
|
4093
|
-
- Best practices: ${config.knowledge.bestPractices.length}
|
|
4094
|
-
- Anti-patterns: ${config.knowledge.antiPatterns.length}
|
|
4095
|
-
- Detection rules: ${config.patterns.length}
|
|
4096
|
-
|
|
4097
|
-
**Next Steps:**
|
|
4098
|
-
1. The skill is now registered and will activate during scans
|
|
4099
|
-
2. Run \`trie_scan\` to test the new skill
|
|
4100
|
-
3. Edit \`${configPath}\` to customize detection rules
|
|
4101
|
-
|
|
4102
|
-
**Usage:**
|
|
4103
|
-
The skill will automatically activate when scanning code that matches its patterns.
|
|
4104
|
-
Use \`trie_list_skills\` to see all registered skills.
|
|
4105
|
-
`.trim();
|
|
4106
|
-
}
|
|
4107
|
-
sanitizeAgentName(name) {
|
|
4108
|
-
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
4109
|
-
}
|
|
4110
|
-
formatDisplayName(name) {
|
|
4111
|
-
return name.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
4112
|
-
}
|
|
4113
|
-
errorResponse(message) {
|
|
4114
|
-
return {
|
|
4115
|
-
content: [
|
|
3596
|
+
${n.message}`
|
|
3597
|
+
).join("\n") : "(none)")
|
|
3598
|
+
},
|
|
4116
3599
|
{
|
|
4117
|
-
type: "
|
|
4118
|
-
|
|
3600
|
+
type: "json",
|
|
3601
|
+
json: this.state.nudges
|
|
4119
3602
|
}
|
|
4120
|
-
]
|
|
4121
|
-
isError: true
|
|
3603
|
+
]
|
|
4122
3604
|
};
|
|
4123
3605
|
}
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
const customAgentNames = await listCustomAgents();
|
|
4130
|
-
const customAgents = await Promise.all(
|
|
4131
|
-
customAgentNames.map(async (name) => {
|
|
4132
|
-
const config = await loadAgentConfig(name);
|
|
4133
|
-
return config ? {
|
|
4134
|
-
name: config.name,
|
|
4135
|
-
displayName: config.displayName,
|
|
4136
|
-
category: config.category,
|
|
4137
|
-
source: config.source.originalFile,
|
|
4138
|
-
patterns: config.patterns.length,
|
|
4139
|
-
isCustom: true
|
|
4140
|
-
} : null;
|
|
4141
|
-
})
|
|
4142
|
-
);
|
|
4143
|
-
const validCustomAgents = customAgents.filter(Boolean);
|
|
4144
|
-
const builtinAgents = includeBuiltin ? [
|
|
4145
|
-
// Security & Compliance
|
|
4146
|
-
{ name: "security", displayName: "Security Agent", category: "security", isCustom: false },
|
|
4147
|
-
{ name: "privacy", displayName: "Privacy Agent", category: "privacy", isCustom: false },
|
|
4148
|
-
{ name: "soc2", displayName: "SOC 2 Agent", category: "compliance", isCustom: false },
|
|
4149
|
-
{ name: "legal", displayName: "Legal Agent", category: "compliance", isCustom: false },
|
|
4150
|
-
// Code Quality
|
|
4151
|
-
{ name: "software-architect", displayName: "Architecture Agent", category: "architecture", isCustom: false },
|
|
4152
|
-
{ name: "bug-finding", displayName: "Bug Finding Agent", category: "quality", isCustom: false },
|
|
4153
|
-
{ name: "typecheck", displayName: "TypeCheck Agent", category: "quality", isCustom: false },
|
|
4154
|
-
{ name: "trie-clean", displayName: "Clean Agent", category: "ai-code", isCustom: false },
|
|
4155
|
-
{ name: "data-flow", displayName: "Data Flow Agent", category: "quality", isCustom: false },
|
|
4156
|
-
// Design & UX
|
|
4157
|
-
{ name: "design-engineer", displayName: "Design Engineer Agent", category: "design", isCustom: false },
|
|
4158
|
-
{ name: "accessibility", displayName: "Accessibility Agent", category: "accessibility", isCustom: false },
|
|
4159
|
-
{ name: "user-testing", displayName: "UX Agent", category: "ux", isCustom: false },
|
|
4160
|
-
{ name: "visual-qa", displayName: "Visual QA Agent", category: "visual", isCustom: false },
|
|
4161
|
-
// DevOps & Testing
|
|
4162
|
-
{ name: "devops", displayName: "DevOps Agent", category: "devops", isCustom: false },
|
|
4163
|
-
{ name: "test", displayName: "Test Agent", category: "testing", isCustom: false },
|
|
4164
|
-
{ name: "e2e", displayName: "E2E Agent", category: "testing", isCustom: false },
|
|
4165
|
-
{ name: "performance", displayName: "Performance Agent", category: "performance", isCustom: false },
|
|
4166
|
-
// Review & Explanation
|
|
4167
|
-
{ name: "super-reviewer", displayName: "Super Reviewer", category: "review", isCustom: false },
|
|
4168
|
-
{ name: "agent-smith", displayName: "Agent Smith", category: "review", isCustom: false },
|
|
4169
|
-
{ name: "comprehension", displayName: "Comprehension Agent", category: "communication", isCustom: false }
|
|
4170
|
-
] : [];
|
|
4171
|
-
let response = `# Registered Agents & Skills
|
|
4172
|
-
|
|
4173
|
-
`;
|
|
4174
|
-
if (builtinAgents.length > 0) {
|
|
4175
|
-
response += `## Built-in Agents (${builtinAgents.length})
|
|
4176
|
-
|
|
4177
|
-
`;
|
|
4178
|
-
for (const agent of builtinAgents) {
|
|
4179
|
-
response += `- **${agent.displayName}** (\`${agent.name}\`) - ${agent.category}
|
|
4180
|
-
`;
|
|
4181
|
-
}
|
|
4182
|
-
response += "\n";
|
|
4183
|
-
}
|
|
4184
|
-
response += `## Custom Skills (${validCustomAgents.length})
|
|
4185
|
-
|
|
4186
|
-
`;
|
|
4187
|
-
if (validCustomAgents.length === 0) {
|
|
4188
|
-
response += `_No custom skills created yet._
|
|
3606
|
+
getCurrentIssues() {
|
|
3607
|
+
return {
|
|
3608
|
+
content: [{
|
|
3609
|
+
type: "text",
|
|
3610
|
+
text: `[L] **Issues Found This Session**
|
|
4189
3611
|
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
`;
|
|
4193
|
-
response += ` - Provide a PDF, TXT, or MD file path
|
|
4194
|
-
`;
|
|
4195
|
-
response += ` - Or paste/drag document content directly
|
|
4196
|
-
`;
|
|
4197
|
-
} else {
|
|
4198
|
-
for (const agent of validCustomAgents) {
|
|
4199
|
-
if (agent) {
|
|
4200
|
-
response += `- **${agent.displayName}** (\`${agent.name}\`)
|
|
4201
|
-
`;
|
|
4202
|
-
response += ` - Category: ${agent.category}
|
|
4203
|
-
`;
|
|
4204
|
-
response += ` - Patterns: ${agent.patterns}
|
|
4205
|
-
`;
|
|
4206
|
-
response += ` - Source: ${agent.source}
|
|
3612
|
+
Total issues: ${this.state.totalIssuesFound}
|
|
3613
|
+
Files scanned: ${this.state.filesScanned}
|
|
4207
3614
|
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
}
|
|
4212
|
-
return {
|
|
4213
|
-
content: [
|
|
4214
|
-
{
|
|
4215
|
-
type: "text",
|
|
4216
|
-
text: response
|
|
4217
|
-
}
|
|
4218
|
-
]
|
|
4219
|
-
};
|
|
4220
|
-
} catch (error) {
|
|
4221
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4222
|
-
return {
|
|
4223
|
-
content: [
|
|
4224
|
-
{
|
|
4225
|
-
type: "text",
|
|
4226
|
-
text: `\u274C Error listing agents: ${errorMessage}`
|
|
4227
|
-
}
|
|
4228
|
-
],
|
|
4229
|
-
isError: true
|
|
4230
|
-
};
|
|
4231
|
-
}
|
|
3615
|
+
To get a full report, run \`trie_scan\` on your codebase.`
|
|
3616
|
+
}]
|
|
3617
|
+
};
|
|
4232
3618
|
}
|
|
4233
3619
|
};
|
|
4234
3620
|
|
|
4235
3621
|
// src/tools/pr-review.ts
|
|
4236
3622
|
import { readFile as readFile5 } from "fs/promises";
|
|
4237
|
-
import { existsSync as
|
|
4238
|
-
import { join as
|
|
3623
|
+
import { existsSync as existsSync5 } from "fs";
|
|
3624
|
+
import { join as join3, basename as basename3, resolve as resolve4, isAbsolute as isAbsolute4 } from "path";
|
|
3625
|
+
|
|
3626
|
+
// src/skills/built-in/super-reviewer.ts
|
|
3627
|
+
var CRITICAL_REVIEW_CHECKLIST = {
|
|
3628
|
+
stateAndLifecycle: [
|
|
3629
|
+
"Uninitialized state accessed before setup",
|
|
3630
|
+
"Missing cleanup on unmount/dispose",
|
|
3631
|
+
"State mutations in wrong lifecycle phase"
|
|
3632
|
+
],
|
|
3633
|
+
edgeCasesAndRaces: [
|
|
3634
|
+
"Race conditions in async operations",
|
|
3635
|
+
"Missing error handling for edge cases",
|
|
3636
|
+
"Unhandled promise rejections"
|
|
3637
|
+
],
|
|
3638
|
+
missingPieces: [
|
|
3639
|
+
"Missing input validation",
|
|
3640
|
+
"Missing error handling",
|
|
3641
|
+
"Missing logging/monitoring"
|
|
3642
|
+
]
|
|
3643
|
+
};
|
|
3644
|
+
var SuperReviewerAgent = class {
|
|
3645
|
+
async review(_files) {
|
|
3646
|
+
return { issues: [] };
|
|
3647
|
+
}
|
|
3648
|
+
async buildReviewWorkflow(files, context) {
|
|
3649
|
+
return { files, context };
|
|
3650
|
+
}
|
|
3651
|
+
};
|
|
3652
|
+
|
|
3653
|
+
// src/tools/pr-review.ts
|
|
4239
3654
|
var TriePRReviewTool = class {
|
|
4240
|
-
agent = new
|
|
3655
|
+
agent = new SuperReviewerAgent();
|
|
4241
3656
|
exec(command, cwd, maxBuffer) {
|
|
4242
3657
|
const opts = {
|
|
4243
3658
|
captureOutput: false,
|
|
@@ -4319,15 +3734,15 @@ Usage:
|
|
|
4319
3734
|
*/
|
|
4320
3735
|
async getPRInfo(pr, worktree) {
|
|
4321
3736
|
if (worktree) {
|
|
4322
|
-
const worktreePath =
|
|
4323
|
-
if (!
|
|
3737
|
+
const worktreePath = isAbsolute4(worktree) ? worktree : resolve4(getWorkingDirectory(void 0, true), worktree);
|
|
3738
|
+
if (!existsSync5(worktreePath)) {
|
|
4324
3739
|
return { success: false, error: `Worktree not found: ${worktreePath}` };
|
|
4325
3740
|
}
|
|
4326
3741
|
return {
|
|
4327
3742
|
success: true,
|
|
4328
3743
|
type: "worktree",
|
|
4329
3744
|
path: worktreePath,
|
|
4330
|
-
title: `Local changes in ${
|
|
3745
|
+
title: `Local changes in ${basename3(worktreePath)}`,
|
|
4331
3746
|
author: this.getGitUser(),
|
|
4332
3747
|
baseBranch: "HEAD~1",
|
|
4333
3748
|
headBranch: "HEAD"
|
|
@@ -4431,7 +3846,7 @@ Usage:
|
|
|
4431
3846
|
deletions++;
|
|
4432
3847
|
}
|
|
4433
3848
|
}
|
|
4434
|
-
files.push({ path: path3, diff, additions, deletions });
|
|
3849
|
+
files.push({ path: path3, diff, additions, deletions, status: "modified" });
|
|
4435
3850
|
}
|
|
4436
3851
|
return files;
|
|
4437
3852
|
}
|
|
@@ -4453,8 +3868,8 @@ Usage:
|
|
|
4453
3868
|
"rfcs"
|
|
4454
3869
|
];
|
|
4455
3870
|
for (const docPath of designDocPaths) {
|
|
4456
|
-
const fullPath =
|
|
4457
|
-
if (
|
|
3871
|
+
const fullPath = join3(cwd, docPath);
|
|
3872
|
+
if (existsSync5(fullPath)) {
|
|
4458
3873
|
}
|
|
4459
3874
|
}
|
|
4460
3875
|
return designDocs;
|
|
@@ -4467,8 +3882,8 @@ Usage:
|
|
|
4467
3882
|
const cwd = getWorkingDirectory(void 0, true);
|
|
4468
3883
|
await Promise.all(filePaths.map(async (filePath) => {
|
|
4469
3884
|
try {
|
|
4470
|
-
const fullPath =
|
|
4471
|
-
if (
|
|
3885
|
+
const fullPath = isAbsolute4(filePath) ? filePath : join3(cwd, filePath);
|
|
3886
|
+
if (existsSync5(fullPath)) {
|
|
4472
3887
|
const content = await readFile5(fullPath, "utf-8");
|
|
4473
3888
|
contents.set(filePath, content);
|
|
4474
3889
|
}
|
|
@@ -5379,6 +4794,20 @@ var TrieTellTool = class {
|
|
|
5379
4794
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5380
4795
|
const change = (await graph.getRecentChanges(1))[0];
|
|
5381
4796
|
const linkedFiles = /* @__PURE__ */ new Set();
|
|
4797
|
+
console.log("\n\u{1F9E0} Processing incident with signal extraction...");
|
|
4798
|
+
let extractedSignal = null;
|
|
4799
|
+
try {
|
|
4800
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
4801
|
+
const options = {
|
|
4802
|
+
workingDirectory: projectPath
|
|
4803
|
+
};
|
|
4804
|
+
if (apiKey) {
|
|
4805
|
+
options.anthropicApiKey = apiKey;
|
|
4806
|
+
}
|
|
4807
|
+
extractedSignal = await processIncident(description, options);
|
|
4808
|
+
} catch (error) {
|
|
4809
|
+
console.warn("\u26A0\uFE0F Signal extraction failed, continuing with basic incident tracking:", error);
|
|
4810
|
+
}
|
|
5382
4811
|
const incident = await graph.addNode("incident", {
|
|
5383
4812
|
description,
|
|
5384
4813
|
severity: "major",
|
|
@@ -5407,13 +4836,32 @@ var TrieTellTool = class {
|
|
|
5407
4836
|
}
|
|
5408
4837
|
const mentionedFiles = extractFilePathsFromDescription(description);
|
|
5409
4838
|
mentionedFiles.forEach((f) => linkedFiles.add(f));
|
|
4839
|
+
if (extractedSignal) {
|
|
4840
|
+
for (const decision of extractedSignal.decisions) {
|
|
4841
|
+
decision.files.forEach((f) => linkedFiles.add(f));
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
5410
4844
|
const incidentIndex = new IncidentIndex(graph, projectPath);
|
|
5411
4845
|
incidentIndex.addIncidentToTrie(incident, Array.from(linkedFiles));
|
|
5412
4846
|
await exportToJson(graph);
|
|
4847
|
+
let responseText = `Incident recorded${change ? ` and linked to change ${change.id}` : ""}.`;
|
|
4848
|
+
if (extractedSignal) {
|
|
4849
|
+
const counts = [
|
|
4850
|
+
extractedSignal.decisions.length > 0 ? `${extractedSignal.decisions.length} decision(s)` : null,
|
|
4851
|
+
extractedSignal.facts.length > 0 ? `${extractedSignal.facts.length} fact(s)` : null,
|
|
4852
|
+
extractedSignal.blockers.length > 0 ? `${extractedSignal.blockers.length} blocker(s)` : null,
|
|
4853
|
+
extractedSignal.questions.length > 0 ? `${extractedSignal.questions.length} question(s)` : null
|
|
4854
|
+
].filter(Boolean).join(", ");
|
|
4855
|
+
if (counts) {
|
|
4856
|
+
responseText += `
|
|
4857
|
+
|
|
4858
|
+
\u{1F4CA} Extracted and stored: ${counts}`;
|
|
4859
|
+
}
|
|
4860
|
+
}
|
|
5413
4861
|
return {
|
|
5414
4862
|
content: [{
|
|
5415
4863
|
type: "text",
|
|
5416
|
-
text:
|
|
4864
|
+
text: responseText
|
|
5417
4865
|
}]
|
|
5418
4866
|
};
|
|
5419
4867
|
} catch (error) {
|
|
@@ -5535,6 +4983,178 @@ var LinearSyncTool = class {
|
|
|
5535
4983
|
}
|
|
5536
4984
|
};
|
|
5537
4985
|
|
|
4986
|
+
// src/tools/query-tools.ts
|
|
4987
|
+
var TrieGetDecisionsTool = class {
|
|
4988
|
+
async execute(input) {
|
|
4989
|
+
const workDir = input.directory || getWorkingDirectory(void 0, true);
|
|
4990
|
+
const storage = getStorage(workDir);
|
|
4991
|
+
await storage.initialize();
|
|
4992
|
+
let timeWindow;
|
|
4993
|
+
if (input.since) {
|
|
4994
|
+
const now = /* @__PURE__ */ new Date();
|
|
4995
|
+
if (input.since.endsWith("d")) {
|
|
4996
|
+
const days = parseInt(input.since);
|
|
4997
|
+
const start = new Date(now);
|
|
4998
|
+
start.setDate(start.getDate() - days);
|
|
4999
|
+
timeWindow = { start: start.toISOString() };
|
|
5000
|
+
} else {
|
|
5001
|
+
timeWindow = { start: input.since };
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
5004
|
+
const query = {
|
|
5005
|
+
limit: input.limit || 10
|
|
5006
|
+
};
|
|
5007
|
+
if (input.relatedTo) query.relatedTo = input.relatedTo;
|
|
5008
|
+
if (input.tags) query.tags = input.tags;
|
|
5009
|
+
if (timeWindow) query.timeWindow = timeWindow;
|
|
5010
|
+
const decisions = await storage.queryDecisions(query);
|
|
5011
|
+
return {
|
|
5012
|
+
content: [{
|
|
5013
|
+
type: "text",
|
|
5014
|
+
text: this.formatDecisions(decisions)
|
|
5015
|
+
}]
|
|
5016
|
+
};
|
|
5017
|
+
}
|
|
5018
|
+
formatDecisions(decisions) {
|
|
5019
|
+
if (decisions.length === 0) {
|
|
5020
|
+
return "No decisions found matching query.";
|
|
5021
|
+
}
|
|
5022
|
+
let output = `Found ${decisions.length} decision(s):
|
|
5023
|
+
|
|
5024
|
+
`;
|
|
5025
|
+
for (const dec of decisions) {
|
|
5026
|
+
const when = new Date(dec.when).toLocaleDateString();
|
|
5027
|
+
output += `\u{1F4CB} ${dec.decision}
|
|
5028
|
+
`;
|
|
5029
|
+
output += ` Context: ${dec.context}
|
|
5030
|
+
`;
|
|
5031
|
+
if (dec.reasoning) {
|
|
5032
|
+
output += ` Reasoning: ${dec.reasoning}
|
|
5033
|
+
`;
|
|
5034
|
+
}
|
|
5035
|
+
if (dec.tradeoffs && dec.tradeoffs.length > 0) {
|
|
5036
|
+
output += ` Tradeoffs considered: ${dec.tradeoffs.join(", ")}
|
|
5037
|
+
`;
|
|
5038
|
+
}
|
|
5039
|
+
output += ` When: ${when}
|
|
5040
|
+
`;
|
|
5041
|
+
if (dec.files.length > 0) {
|
|
5042
|
+
output += ` Files: ${dec.files.join(", ")}
|
|
5043
|
+
`;
|
|
5044
|
+
}
|
|
5045
|
+
output += ` Tags: ${dec.tags.join(", ")}
|
|
5046
|
+
`;
|
|
5047
|
+
output += `
|
|
5048
|
+
`;
|
|
5049
|
+
}
|
|
5050
|
+
return output;
|
|
5051
|
+
}
|
|
5052
|
+
};
|
|
5053
|
+
var TrieGetBlockersTool = class {
|
|
5054
|
+
async execute(input) {
|
|
5055
|
+
const workDir = input.directory || getWorkingDirectory(void 0, true);
|
|
5056
|
+
const storage = getStorage(workDir);
|
|
5057
|
+
await storage.initialize();
|
|
5058
|
+
const query = {
|
|
5059
|
+
limit: input.limit || 5
|
|
5060
|
+
};
|
|
5061
|
+
if (input.tags) query.tags = input.tags;
|
|
5062
|
+
const blockers = await storage.queryBlockers(query);
|
|
5063
|
+
return {
|
|
5064
|
+
content: [{
|
|
5065
|
+
type: "text",
|
|
5066
|
+
text: this.formatBlockers(blockers)
|
|
5067
|
+
}]
|
|
5068
|
+
};
|
|
5069
|
+
}
|
|
5070
|
+
formatBlockers(blockers) {
|
|
5071
|
+
if (blockers.length === 0) {
|
|
5072
|
+
return "\u2705 No active blockers found.";
|
|
5073
|
+
}
|
|
5074
|
+
let output = `\u26A0\uFE0F Found ${blockers.length} active blocker(s):
|
|
5075
|
+
|
|
5076
|
+
`;
|
|
5077
|
+
for (const blocker of blockers) {
|
|
5078
|
+
const impact = blocker.impact.toUpperCase();
|
|
5079
|
+
const emoji = blocker.impact === "critical" ? "\u{1F534}" : blocker.impact === "high" ? "\u{1F7E0}" : blocker.impact === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
|
|
5080
|
+
output += `${emoji} [${impact}] ${blocker.blocker}
|
|
5081
|
+
`;
|
|
5082
|
+
if (blocker.affectedAreas.length > 0) {
|
|
5083
|
+
output += ` Affects: ${blocker.affectedAreas.join(", ")}
|
|
5084
|
+
`;
|
|
5085
|
+
}
|
|
5086
|
+
output += ` Since: ${new Date(blocker.when).toLocaleDateString()}
|
|
5087
|
+
`;
|
|
5088
|
+
output += `
|
|
5089
|
+
`;
|
|
5090
|
+
}
|
|
5091
|
+
return output;
|
|
5092
|
+
}
|
|
5093
|
+
};
|
|
5094
|
+
var TrieGetRelatedDecisionsTool = class {
|
|
5095
|
+
async execute(input) {
|
|
5096
|
+
const workDir = input.directory || getWorkingDirectory(void 0, true);
|
|
5097
|
+
const storage = getStorage(workDir);
|
|
5098
|
+
await storage.initialize();
|
|
5099
|
+
const query = {
|
|
5100
|
+
limit: input.limit || 5
|
|
5101
|
+
};
|
|
5102
|
+
const relatedTo = input.file || input.topic;
|
|
5103
|
+
if (relatedTo) query.relatedTo = relatedTo;
|
|
5104
|
+
const decisions = await storage.queryDecisions(query);
|
|
5105
|
+
return {
|
|
5106
|
+
content: [{
|
|
5107
|
+
type: "text",
|
|
5108
|
+
text: new TrieGetDecisionsTool().formatDecisions(decisions)
|
|
5109
|
+
}]
|
|
5110
|
+
};
|
|
5111
|
+
}
|
|
5112
|
+
};
|
|
5113
|
+
var TrieQueryContextTool = class {
|
|
5114
|
+
async execute(input) {
|
|
5115
|
+
const workDir = input.directory || getWorkingDirectory(void 0, true);
|
|
5116
|
+
const storage = getStorage(workDir);
|
|
5117
|
+
await storage.initialize();
|
|
5118
|
+
const keywords = input.query.toLowerCase().split(/\s+/);
|
|
5119
|
+
let output = `Query: "${input.query}"
|
|
5120
|
+
|
|
5121
|
+
`;
|
|
5122
|
+
if (!input.type || input.type === "decisions" || input.type === "all") {
|
|
5123
|
+
const decisions = await storage.queryDecisions({ limit: input.limit || 5 });
|
|
5124
|
+
const matches = decisions.filter(
|
|
5125
|
+
(d) => keywords.some(
|
|
5126
|
+
(kw) => d.decision.toLowerCase().includes(kw) || d.context.toLowerCase().includes(kw) || d.tags.some((t) => t.toLowerCase().includes(kw))
|
|
5127
|
+
)
|
|
5128
|
+
);
|
|
5129
|
+
if (matches.length > 0) {
|
|
5130
|
+
output += `\u{1F4CB} DECISIONS (${matches.length}):
|
|
5131
|
+
`;
|
|
5132
|
+
output += new TrieGetDecisionsTool().formatDecisions(matches);
|
|
5133
|
+
output += "\n";
|
|
5134
|
+
}
|
|
5135
|
+
}
|
|
5136
|
+
if (!input.type || input.type === "blockers" || input.type === "all") {
|
|
5137
|
+
const blockers = await storage.queryBlockers({ limit: input.limit || 5 });
|
|
5138
|
+
const matches = blockers.filter(
|
|
5139
|
+
(b) => keywords.some(
|
|
5140
|
+
(kw) => b.blocker.toLowerCase().includes(kw) || b.tags.some((t) => t.toLowerCase().includes(kw))
|
|
5141
|
+
)
|
|
5142
|
+
);
|
|
5143
|
+
if (matches.length > 0) {
|
|
5144
|
+
output += `\u26A0\uFE0F BLOCKERS (${matches.length}):
|
|
5145
|
+
`;
|
|
5146
|
+
output += new TrieGetBlockersTool().formatBlockers(matches);
|
|
5147
|
+
}
|
|
5148
|
+
}
|
|
5149
|
+
return {
|
|
5150
|
+
content: [{
|
|
5151
|
+
type: "text",
|
|
5152
|
+
text: output.trim() || "No matches found."
|
|
5153
|
+
}]
|
|
5154
|
+
};
|
|
5155
|
+
}
|
|
5156
|
+
};
|
|
5157
|
+
|
|
5538
5158
|
// src/server/tool-registry.ts
|
|
5539
5159
|
var TrieCheckpointTool = class {
|
|
5540
5160
|
async execute(input) {
|
|
@@ -5559,15 +5179,7 @@ var ToolRegistry = class {
|
|
|
5559
5179
|
this.tools.set("fix", new TrieFixTool());
|
|
5560
5180
|
this.tools.set("explain", new TrieExplainTool());
|
|
5561
5181
|
this.tools.set("test", new TrieTestTool());
|
|
5562
|
-
this.tools.set("register_agent", new TrieRegisterAgentTool());
|
|
5563
5182
|
this.tools.set("watch", new TrieWatchTool());
|
|
5564
|
-
this.tools.set("agent", new TrieAgentTool());
|
|
5565
|
-
this.tools.set("create_skill", new TrieCreateAgentTool());
|
|
5566
|
-
this.tools.set("create_agent", new TrieCreateAgentTool());
|
|
5567
|
-
this.tools.set("save_skill", new TrieSaveAgentTool());
|
|
5568
|
-
this.tools.set("save_agent", new TrieSaveAgentTool());
|
|
5569
|
-
this.tools.set("list_skills", new TrieListAgentsTool());
|
|
5570
|
-
this.tools.set("list_agents", new TrieListAgentsTool());
|
|
5571
5183
|
this.tools.set("pr_review", new TriePRReviewTool());
|
|
5572
5184
|
this.tools.set("project", new TrieProjectInfoTool());
|
|
5573
5185
|
this.tools.set("init", new TrieInitTool());
|
|
@@ -5581,6 +5193,10 @@ var ToolRegistry = class {
|
|
|
5581
5193
|
this.tools.set("ok", new TrieFeedbackTool());
|
|
5582
5194
|
this.tools.set("bad", new TrieFeedbackTool());
|
|
5583
5195
|
this.tools.set("linear_sync", new LinearSyncTool());
|
|
5196
|
+
this.tools.set("get_decisions", new TrieGetDecisionsTool());
|
|
5197
|
+
this.tools.set("get_blockers", new TrieGetBlockersTool());
|
|
5198
|
+
this.tools.set("get_related_decisions", new TrieGetRelatedDecisionsTool());
|
|
5199
|
+
this.tools.set("query_context", new TrieQueryContextTool());
|
|
5584
5200
|
}
|
|
5585
5201
|
defineToolSchemas() {
|
|
5586
5202
|
this.definitions = [
|
|
@@ -5667,7 +5283,7 @@ var ToolRegistry = class {
|
|
|
5667
5283
|
properties: {
|
|
5668
5284
|
action: {
|
|
5669
5285
|
type: "string",
|
|
5670
|
-
description: "Optional quick action: scan, security,
|
|
5286
|
+
description: "Optional quick action: scan, security, legal, bugs, types, devops, architecture, ux, clean, soc2, performance, e2e, visual_qa, data_flow, agent_smith, pr_review, watch, fix, explain"
|
|
5671
5287
|
},
|
|
5672
5288
|
agent: {
|
|
5673
5289
|
type: "string",
|
|
@@ -5847,31 +5463,6 @@ var ToolRegistry = class {
|
|
|
5847
5463
|
required: ["action"]
|
|
5848
5464
|
}
|
|
5849
5465
|
},
|
|
5850
|
-
{
|
|
5851
|
-
name: "trie_register_agent",
|
|
5852
|
-
description: "Register an agent by name and path. Alias: register_agent",
|
|
5853
|
-
inputSchema: {
|
|
5854
|
-
type: "object",
|
|
5855
|
-
properties: {
|
|
5856
|
-
name: { type: "string", description: "Name of the agent" },
|
|
5857
|
-
path: { type: "string", description: "Path to the agent implementation" }
|
|
5858
|
-
},
|
|
5859
|
-
required: ["name", "path"]
|
|
5860
|
-
}
|
|
5861
|
-
},
|
|
5862
|
-
{
|
|
5863
|
-
name: "trie_list_skills",
|
|
5864
|
-
description: "List all skills (external and custom). Alias: list_skills, list_agents",
|
|
5865
|
-
inputSchema: {
|
|
5866
|
-
type: "object",
|
|
5867
|
-
properties: {
|
|
5868
|
-
includeBuiltin: {
|
|
5869
|
-
type: "boolean",
|
|
5870
|
-
description: "Include built-in agents (default true)"
|
|
5871
|
-
}
|
|
5872
|
-
}
|
|
5873
|
-
}
|
|
5874
|
-
},
|
|
5875
5466
|
{
|
|
5876
5467
|
name: "trie_project",
|
|
5877
5468
|
description: "View and manage project information (.trie/PROJECT.md). Store project context for AI assistants. Alias: project",
|
|
@@ -6009,105 +5600,9 @@ var ToolRegistry = class {
|
|
|
6009
5600
|
}
|
|
6010
5601
|
},
|
|
6011
5602
|
// Add remaining tool definitions...
|
|
6012
|
-
this.createAgentToolDefinitions(),
|
|
6013
|
-
this.createCustomSkillDefinitions(),
|
|
6014
5603
|
this.createSpecialAgentDefinitions()
|
|
6015
5604
|
].flat();
|
|
6016
5605
|
}
|
|
6017
|
-
createAgentToolDefinitions() {
|
|
6018
|
-
const agentTypes = [
|
|
6019
|
-
{ name: "security", desc: "detect vulnerabilities, injection risks, auth issues, hardcoded secrets" },
|
|
6020
|
-
{ name: "privacy", desc: "PII handling, GDPR/HIPAA compliance, data encryption" },
|
|
6021
|
-
{ name: "legal", desc: "GDPR, CCPA, consent patterns, data retention compliance" },
|
|
6022
|
-
{ name: "accessibility", desc: "WCAG 2.1 compliance, keyboard nav, screen readers, color contrast" },
|
|
6023
|
-
{ name: "design", desc: "Awwwards-level polish, design systems, motion design, creative CSS" },
|
|
6024
|
-
{ name: "architecture", desc: "code organization, SOLID principles, N+1 queries, scalability" },
|
|
6025
|
-
{ name: "bugs", desc: "null safety, edge cases, common bugs, async issues" },
|
|
6026
|
-
{ name: "ux", desc: "simulate happy path, security tester, confused user, impatient user" },
|
|
6027
|
-
{ name: "types", desc: "type errors, missing annotations, null checks" },
|
|
6028
|
-
{ name: "devops", desc: "config issues, logging, environment variables, deployment patterns" },
|
|
6029
|
-
{ name: "clean", desc: "\u{1F9F9} Clean up AI-generated code: find common mistakes, bad patterns, and quick fixes" },
|
|
6030
|
-
{ name: "soc2", desc: "SOC 2 compliance: access controls, secrets management, encryption, logging, change management" }
|
|
6031
|
-
];
|
|
6032
|
-
return agentTypes.map((agent) => ({
|
|
6033
|
-
name: `trie_${agent.name}`,
|
|
6034
|
-
description: `Run ${agent.name} agent: ${agent.desc}. Alias: ${agent.name}`,
|
|
6035
|
-
inputSchema: {
|
|
6036
|
-
type: "object",
|
|
6037
|
-
properties: {
|
|
6038
|
-
files: { type: "array", items: { type: "string" }, description: "Files to scan" },
|
|
6039
|
-
directory: { type: "string", description: "Directory to scan" },
|
|
6040
|
-
output: {
|
|
6041
|
-
type: "string",
|
|
6042
|
-
enum: ["summary", "full"],
|
|
6043
|
-
description: "summary = concise (default), full = includes AI prompt/code (large output)"
|
|
6044
|
-
}
|
|
6045
|
-
}
|
|
6046
|
-
}
|
|
6047
|
-
}));
|
|
6048
|
-
}
|
|
6049
|
-
createCustomSkillDefinitions() {
|
|
6050
|
-
return [
|
|
6051
|
-
{
|
|
6052
|
-
name: "trie_create_skill",
|
|
6053
|
-
description: "Create a custom skill from a document. Returns extraction prompt for Claude to process. Alias: create_skill, create_agent",
|
|
6054
|
-
inputSchema: {
|
|
6055
|
-
type: "object",
|
|
6056
|
-
properties: {
|
|
6057
|
-
filePath: {
|
|
6058
|
-
type: "string",
|
|
6059
|
-
description: "Path to the document file (PDF, TXT, MD, or RTF)"
|
|
6060
|
-
},
|
|
6061
|
-
documentContent: {
|
|
6062
|
-
type: "string",
|
|
6063
|
-
description: "Raw document text (for drag-and-drop content). Use this OR filePath."
|
|
6064
|
-
},
|
|
6065
|
-
skillName: {
|
|
6066
|
-
type: "string",
|
|
6067
|
-
description: 'Name for the new skill (e.g., "react-fundamentals")'
|
|
6068
|
-
},
|
|
6069
|
-
displayName: { type: "string", description: "Optional display name" },
|
|
6070
|
-
description: { type: "string", description: "Optional description" },
|
|
6071
|
-
category: { type: "string", description: 'Optional category (e.g., "security", "react")' }
|
|
6072
|
-
},
|
|
6073
|
-
required: ["skillName"]
|
|
6074
|
-
}
|
|
6075
|
-
},
|
|
6076
|
-
{
|
|
6077
|
-
name: "trie_save_skill",
|
|
6078
|
-
description: "Save a custom skill config after Claude extracts knowledge. Alias: save_skill, save_agent",
|
|
6079
|
-
inputSchema: {
|
|
6080
|
-
type: "object",
|
|
6081
|
-
properties: {
|
|
6082
|
-
skillConfig: {
|
|
6083
|
-
type: "object",
|
|
6084
|
-
description: "Skill configuration",
|
|
6085
|
-
properties: {
|
|
6086
|
-
name: { type: "string" },
|
|
6087
|
-
displayName: { type: "string" },
|
|
6088
|
-
description: { type: "string" },
|
|
6089
|
-
version: { type: "string" },
|
|
6090
|
-
category: { type: "string" }
|
|
6091
|
-
},
|
|
6092
|
-
required: ["name", "category"]
|
|
6093
|
-
},
|
|
6094
|
-
knowledge: { type: "object", description: "Extracted knowledge" },
|
|
6095
|
-
detectionRules: { type: "array", description: "Detection rules array" },
|
|
6096
|
-
prompts: {
|
|
6097
|
-
type: "object",
|
|
6098
|
-
properties: {
|
|
6099
|
-
systemPrompt: { type: "string" },
|
|
6100
|
-
analysisPrompt: { type: "string" },
|
|
6101
|
-
fixPrompt: { type: "string" }
|
|
6102
|
-
},
|
|
6103
|
-
required: ["systemPrompt", "analysisPrompt", "fixPrompt"]
|
|
6104
|
-
}
|
|
6105
|
-
},
|
|
6106
|
-
required: ["skillConfig", "knowledge", "detectionRules", "prompts"]
|
|
6107
|
-
}
|
|
6108
|
-
}
|
|
6109
|
-
];
|
|
6110
|
-
}
|
|
6111
5606
|
createSpecialAgentDefinitions() {
|
|
6112
5607
|
return [
|
|
6113
5608
|
{
|
|
@@ -6153,76 +5648,72 @@ var ToolRegistry = class {
|
|
|
6153
5648
|
}
|
|
6154
5649
|
},
|
|
6155
5650
|
{
|
|
6156
|
-
name: "
|
|
6157
|
-
description:
|
|
5651
|
+
name: "trie_linear_sync",
|
|
5652
|
+
description: "Sync active Linear tickets to build context for JIT defect prediction. Alias: linear_sync",
|
|
6158
5653
|
inputSchema: {
|
|
6159
5654
|
type: "object",
|
|
6160
5655
|
properties: {
|
|
6161
|
-
|
|
6162
|
-
type: "array",
|
|
6163
|
-
items: { type: "string" },
|
|
6164
|
-
description: "Files to scan (defaults to entire codebase)"
|
|
6165
|
-
},
|
|
6166
|
-
directory: {
|
|
6167
|
-
type: "string",
|
|
6168
|
-
description: "Directory to scan. Pass the workspace/project root path for accurate results."
|
|
6169
|
-
},
|
|
6170
|
-
clear_memory: {
|
|
6171
|
-
type: "boolean",
|
|
6172
|
-
description: "Clear Agent Smith's memory bank"
|
|
6173
|
-
},
|
|
6174
|
-
show_stats: {
|
|
6175
|
-
type: "boolean",
|
|
6176
|
-
description: "Show memory statistics"
|
|
6177
|
-
}
|
|
5656
|
+
directory: { type: "string", description: "Project directory" }
|
|
6178
5657
|
}
|
|
6179
5658
|
}
|
|
6180
5659
|
},
|
|
6181
5660
|
{
|
|
6182
|
-
name: "
|
|
6183
|
-
description: "
|
|
5661
|
+
name: "trie_get_decisions",
|
|
5662
|
+
description: "Query decisions from decision ledger with targeted retrieval. Prevents context pollution by returning only relevant decisions.",
|
|
6184
5663
|
inputSchema: {
|
|
6185
5664
|
type: "object",
|
|
6186
5665
|
properties: {
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
}
|
|
6192
|
-
directory: {
|
|
6193
|
-
type: "string",
|
|
6194
|
-
description: "Directory to scan. Pass the workspace/project root path for accurate results."
|
|
6195
|
-
}
|
|
5666
|
+
relatedTo: { type: "string", description: "File path or topic to find related decisions" },
|
|
5667
|
+
tags: { type: "array", items: { type: "string" }, description: "Filter by tags" },
|
|
5668
|
+
since: { type: "string", description: 'Time filter: ISO date or "7d", "30d", "90d"' },
|
|
5669
|
+
limit: { type: "number", description: "Max results (default 10)" },
|
|
5670
|
+
directory: { type: "string", description: "Working directory" }
|
|
6196
5671
|
}
|
|
6197
5672
|
}
|
|
6198
5673
|
},
|
|
6199
5674
|
{
|
|
6200
|
-
name: "
|
|
6201
|
-
description: "
|
|
5675
|
+
name: "trie_get_blockers",
|
|
5676
|
+
description: "Get active blockers from decision ledger. Returns only unresolved blockers to avoid noise.",
|
|
6202
5677
|
inputSchema: {
|
|
6203
5678
|
type: "object",
|
|
6204
5679
|
properties: {
|
|
6205
|
-
|
|
5680
|
+
tags: { type: "array", items: { type: "string" }, description: "Filter by tags" },
|
|
5681
|
+
limit: { type: "number", description: "Max results (default 5)" },
|
|
5682
|
+
directory: { type: "string", description: "Working directory" }
|
|
6206
5683
|
}
|
|
6207
5684
|
}
|
|
6208
5685
|
},
|
|
6209
5686
|
{
|
|
6210
|
-
name: "
|
|
6211
|
-
description: "
|
|
5687
|
+
name: "trie_get_related_decisions",
|
|
5688
|
+
description: "Find decisions related to a specific decision, file, or topic. Targeted context retrieval.",
|
|
6212
5689
|
inputSchema: {
|
|
6213
5690
|
type: "object",
|
|
6214
5691
|
properties: {
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
}
|
|
6220
|
-
directory: {
|
|
6221
|
-
type: "string",
|
|
6222
|
-
description: "Directory to review. Pass the workspace/project root path."
|
|
6223
|
-
}
|
|
5692
|
+
decisionId: { type: "string", description: "Decision ID to find related decisions" },
|
|
5693
|
+
file: { type: "string", description: "File path to find related decisions" },
|
|
5694
|
+
topic: { type: "string", description: "Topic to find related decisions" },
|
|
5695
|
+
limit: { type: "number", description: "Max results (default 5)" },
|
|
5696
|
+
directory: { type: "string", description: "Working directory" }
|
|
6224
5697
|
}
|
|
6225
5698
|
}
|
|
5699
|
+
},
|
|
5700
|
+
{
|
|
5701
|
+
name: "trie_query_context",
|
|
5702
|
+
description: "Query decision ledger with natural language. Returns targeted signal, not full dump.",
|
|
5703
|
+
inputSchema: {
|
|
5704
|
+
type: "object",
|
|
5705
|
+
properties: {
|
|
5706
|
+
query: { type: "string", description: "Natural language query" },
|
|
5707
|
+
type: {
|
|
5708
|
+
type: "string",
|
|
5709
|
+
enum: ["decisions", "blockers", "facts", "questions", "all"],
|
|
5710
|
+
description: "Type of context to query (default: all)"
|
|
5711
|
+
},
|
|
5712
|
+
limit: { type: "number", description: "Max results per type (default 5)" },
|
|
5713
|
+
directory: { type: "string", description: "Working directory" }
|
|
5714
|
+
},
|
|
5715
|
+
required: ["query"]
|
|
5716
|
+
}
|
|
6226
5717
|
}
|
|
6227
5718
|
];
|
|
6228
5719
|
}
|
|
@@ -6241,9 +5732,9 @@ var ToolRegistry = class {
|
|
|
6241
5732
|
};
|
|
6242
5733
|
|
|
6243
5734
|
// src/server/resource-manager.ts
|
|
6244
|
-
import { readdir
|
|
6245
|
-
import { existsSync as
|
|
6246
|
-
import { join as
|
|
5735
|
+
import { readdir, readFile as readFile6 } from "fs/promises";
|
|
5736
|
+
import { existsSync as existsSync6 } from "fs";
|
|
5737
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
6247
5738
|
import { fileURLToPath } from "url";
|
|
6248
5739
|
var UI_APPS = {
|
|
6249
5740
|
"scan-dashboard": {
|
|
@@ -6357,8 +5848,8 @@ var ResourceManager = class {
|
|
|
6357
5848
|
}
|
|
6358
5849
|
async getScanReportResources() {
|
|
6359
5850
|
try {
|
|
6360
|
-
const reportsDir =
|
|
6361
|
-
const files = await
|
|
5851
|
+
const reportsDir = join4(getWorkingDirectory(void 0, true), "trie-reports");
|
|
5852
|
+
const files = await readdir(reportsDir);
|
|
6362
5853
|
const reportFiles = files.filter((f) => f.endsWith(".txt") || f.endsWith(".json"));
|
|
6363
5854
|
return reportFiles.slice(0, 10).map((file) => ({
|
|
6364
5855
|
uri: `trie://reports/${file}`,
|
|
@@ -6457,10 +5948,10 @@ var ResourceManager = class {
|
|
|
6457
5948
|
async getUIAppResource(uri, appId) {
|
|
6458
5949
|
const currentFile = fileURLToPath(import.meta.url);
|
|
6459
5950
|
const distDir = dirname2(dirname2(currentFile));
|
|
6460
|
-
const uiDir =
|
|
6461
|
-
const htmlPath =
|
|
5951
|
+
const uiDir = join4(distDir, "ui");
|
|
5952
|
+
const htmlPath = join4(uiDir, `${appId}.html`);
|
|
6462
5953
|
try {
|
|
6463
|
-
if (!
|
|
5954
|
+
if (!existsSync6(htmlPath)) {
|
|
6464
5955
|
return {
|
|
6465
5956
|
contents: [{
|
|
6466
5957
|
uri,
|
|
@@ -6650,9 +6141,9 @@ var ResourceManager = class {
|
|
|
6650
6141
|
} catch {
|
|
6651
6142
|
}
|
|
6652
6143
|
summary.push("---", "", "# Detailed Context", "");
|
|
6653
|
-
const agentsMdPath =
|
|
6144
|
+
const agentsMdPath = join4(getTrieDirectory(workDir), "AGENTS.md");
|
|
6654
6145
|
try {
|
|
6655
|
-
if (
|
|
6146
|
+
if (existsSync6(agentsMdPath)) {
|
|
6656
6147
|
const agentsContent = await readFile6(agentsMdPath, "utf-8");
|
|
6657
6148
|
summary.push(agentsContent);
|
|
6658
6149
|
} else {
|
|
@@ -6778,7 +6269,7 @@ This information is automatically available to Claude Code, Cursor, and other AI
|
|
|
6778
6269
|
}
|
|
6779
6270
|
async getCacheStatsResource(uri) {
|
|
6780
6271
|
try {
|
|
6781
|
-
const cachePath =
|
|
6272
|
+
const cachePath = join4(getTrieDirectory(getWorkingDirectory(void 0, true)), ".trie-cache.json");
|
|
6782
6273
|
const cacheContent = await readFile6(cachePath, "utf-8");
|
|
6783
6274
|
const cache = JSON.parse(cacheContent);
|
|
6784
6275
|
const fileCount = Object.keys(cache.files || {}).length;
|
|
@@ -6813,8 +6304,8 @@ This information is automatically available to Claude Code, Cursor, and other AI
|
|
|
6813
6304
|
}
|
|
6814
6305
|
}
|
|
6815
6306
|
async getSignaturesResource(uri) {
|
|
6816
|
-
const { getVulnerabilityStats } = await import("./vulnerability-signatures-
|
|
6817
|
-
const { getVibeCodeStats } = await import("./vibe-code-signatures-
|
|
6307
|
+
const { getVulnerabilityStats } = await import("./vulnerability-signatures-EIJQX2TS.js");
|
|
6308
|
+
const { getVibeCodeStats } = await import("./vibe-code-signatures-ELEWJFGZ.js");
|
|
6818
6309
|
const vulnStats = getVulnerabilityStats();
|
|
6819
6310
|
const vibeStats = getVibeCodeStats();
|
|
6820
6311
|
return {
|
|
@@ -6858,7 +6349,7 @@ This information is automatically available to Claude Code, Cursor, and other AI
|
|
|
6858
6349
|
}
|
|
6859
6350
|
async getScanReportResource(uri, parsedUri) {
|
|
6860
6351
|
const fileName = parsedUri.replace("reports/", "");
|
|
6861
|
-
const reportPath =
|
|
6352
|
+
const reportPath = join4(getWorkingDirectory(void 0, true), "trie-reports", fileName);
|
|
6862
6353
|
try {
|
|
6863
6354
|
const content = await readFile6(reportPath, "utf-8");
|
|
6864
6355
|
return {
|
|
@@ -7007,32 +6498,32 @@ async function findOpenPort() {
|
|
|
7007
6498
|
return portChecks.find((port) => port !== null) || null;
|
|
7008
6499
|
}
|
|
7009
6500
|
async function checkPort(port) {
|
|
7010
|
-
return new Promise((
|
|
6501
|
+
return new Promise((resolve5) => {
|
|
7011
6502
|
const testServer = createServer();
|
|
7012
6503
|
let portInUse = false;
|
|
7013
6504
|
testServer.once("error", (err) => {
|
|
7014
6505
|
if (err.code === "EADDRINUSE") {
|
|
7015
6506
|
portInUse = true;
|
|
7016
|
-
testHttpPort(port).then(
|
|
6507
|
+
testHttpPort(port).then(resolve5).catch(() => resolve5(false));
|
|
7017
6508
|
} else {
|
|
7018
|
-
|
|
6509
|
+
resolve5(false);
|
|
7019
6510
|
}
|
|
7020
6511
|
});
|
|
7021
6512
|
testServer.once("listening", () => {
|
|
7022
6513
|
testServer.close();
|
|
7023
|
-
|
|
6514
|
+
resolve5(false);
|
|
7024
6515
|
});
|
|
7025
6516
|
setTimeout(() => {
|
|
7026
6517
|
if (!portInUse) {
|
|
7027
6518
|
testServer.close();
|
|
7028
|
-
|
|
6519
|
+
resolve5(false);
|
|
7029
6520
|
}
|
|
7030
6521
|
}, 1e3);
|
|
7031
6522
|
testServer.listen(port, "127.0.0.1");
|
|
7032
6523
|
});
|
|
7033
6524
|
}
|
|
7034
6525
|
async function testHttpPort(port) {
|
|
7035
|
-
return new Promise((
|
|
6526
|
+
return new Promise((resolve5) => {
|
|
7036
6527
|
const req = request({
|
|
7037
6528
|
hostname: "localhost",
|
|
7038
6529
|
port,
|
|
@@ -7040,18 +6531,18 @@ async function testHttpPort(port) {
|
|
|
7040
6531
|
method: "GET",
|
|
7041
6532
|
timeout: 2e3
|
|
7042
6533
|
}, (res) => {
|
|
7043
|
-
|
|
6534
|
+
resolve5(res.statusCode !== void 0);
|
|
7044
6535
|
res.on("data", () => {
|
|
7045
6536
|
});
|
|
7046
6537
|
res.on("end", () => {
|
|
7047
6538
|
});
|
|
7048
6539
|
});
|
|
7049
6540
|
req.on("error", () => {
|
|
7050
|
-
|
|
6541
|
+
resolve5(false);
|
|
7051
6542
|
});
|
|
7052
6543
|
req.on("timeout", () => {
|
|
7053
6544
|
req.destroy();
|
|
7054
|
-
|
|
6545
|
+
resolve5(false);
|
|
7055
6546
|
});
|
|
7056
6547
|
req.end();
|
|
7057
6548
|
});
|
|
@@ -7339,8 +6830,6 @@ var RequestHandlers = class {
|
|
|
7339
6830
|
// Individual agent commands
|
|
7340
6831
|
case "security":
|
|
7341
6832
|
return await this.toolRegistry.getTool("agent").execute({ ...args, agent: "security" });
|
|
7342
|
-
case "privacy":
|
|
7343
|
-
return await this.toolRegistry.getTool("agent").execute({ ...args, agent: "privacy" });
|
|
7344
6833
|
case "legal":
|
|
7345
6834
|
return await this.toolRegistry.getTool("agent").execute({ ...args, agent: "legal" });
|
|
7346
6835
|
case "accessibility":
|
|
@@ -7535,7 +7024,7 @@ npx playwright install chromium
|
|
|
7535
7024
|
'- `action: "visual_qa_browser"` \u2014 screenshots for visual QA',
|
|
7536
7025
|
"",
|
|
7537
7026
|
"**Built-in skills:**",
|
|
7538
|
-
"`security`, `
|
|
7027
|
+
"`security`, `legal`, `accessibility`, `design`, `architecture`, `bugs`, `ux`, `types`, `devops`, `clean`, `soc2`, `performance`, `e2e`, `visual_qa`, `data_flow`",
|
|
7539
7028
|
"",
|
|
7540
7029
|
"**Special skills:**",
|
|
7541
7030
|
"`agent_smith` \u2014 35 vibe code hunters with cross-file detection",
|
|
@@ -7546,37 +7035,23 @@ npx playwright install chromium
|
|
|
7546
7035
|
}]
|
|
7547
7036
|
};
|
|
7548
7037
|
}
|
|
7549
|
-
async handleAgentSmith(
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
"\u2550".repeat(40),
|
|
7567
|
-
`Tracked issues: ${stats.issueCount}`,
|
|
7568
|
-
`Dismissed issues: ${stats.dismissedCount}`,
|
|
7569
|
-
`Resurrected issues: ${stats.resurrectedCount}`,
|
|
7570
|
-
`Oldest issue: ${stats.oldestIssue ? new Date(stats.oldestIssue).toLocaleDateString() : "N/A"}`,
|
|
7571
|
-
`Memory file size: ${stats.fileSizeKB} KB`,
|
|
7572
|
-
"",
|
|
7573
|
-
"To clear memory: trie_agent_smith with clear_memory:true"
|
|
7574
|
-
].join("\n")
|
|
7575
|
-
}]
|
|
7576
|
-
};
|
|
7577
|
-
}
|
|
7578
|
-
const agentSmithRunner = await import("./agent-smith-runner-4TBONXCP.js");
|
|
7579
|
-
return await agentSmithRunner.runAgentSmith(smithArgs);
|
|
7038
|
+
async handleAgentSmith(_smithArgs) {
|
|
7039
|
+
return {
|
|
7040
|
+
content: [{
|
|
7041
|
+
type: "text",
|
|
7042
|
+
text: [
|
|
7043
|
+
"\u{1F916} Agent Smith functionality has been integrated into the decision ledger.",
|
|
7044
|
+
"",
|
|
7045
|
+
"The autonomous agent now:",
|
|
7046
|
+
"- Extracts patterns automatically via `trie watch`",
|
|
7047
|
+
"- Builds decision ledger from every change",
|
|
7048
|
+
"- Predicts problems via `trie gotcha`",
|
|
7049
|
+
"",
|
|
7050
|
+
"Start the agent: `trie_watch start`",
|
|
7051
|
+
"Query the ledger: `trie_gotcha`"
|
|
7052
|
+
].join("\n")
|
|
7053
|
+
}]
|
|
7054
|
+
};
|
|
7580
7055
|
}
|
|
7581
7056
|
};
|
|
7582
7057
|
|