@triedotdev/mcp 1.0.7 → 1.0.8
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/QUICK_START.md +1 -1
- package/README.md +60 -17
- package/dist/{chunk-EDWYG3KK.js → chunk-Z3GM6UVW.js} +758 -11
- package/dist/chunk-Z3GM6UVW.js.map +1 -0
- package/dist/cli/main.js +1 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +1 -1
- package/dist/index.js +470 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-EDWYG3KK.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -5,12 +5,14 @@ import {
|
|
|
5
5
|
parseDocument
|
|
6
6
|
} from "./chunk-EYNAGEQK.js";
|
|
7
7
|
import {
|
|
8
|
+
CRITICAL_REVIEW_CHECKLIST,
|
|
9
|
+
SuperReviewerAgent,
|
|
8
10
|
TrieFixTool,
|
|
9
11
|
TrieScanTool,
|
|
10
12
|
getAgentRegistry,
|
|
11
13
|
getPrompt,
|
|
12
14
|
getSystemPrompt
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-Z3GM6UVW.js";
|
|
14
16
|
import "./chunk-3CS6Z2SL.js";
|
|
15
17
|
import "./chunk-MR755QGT.js";
|
|
16
18
|
import "./chunk-6NLHFIYA.js";
|
|
@@ -25,8 +27,8 @@ import {
|
|
|
25
27
|
ListResourcesRequestSchema,
|
|
26
28
|
ReadResourceRequestSchema
|
|
27
29
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
28
|
-
import { readdir as readdir2, readFile as
|
|
29
|
-
import { join as
|
|
30
|
+
import { readdir as readdir2, readFile as readFile7 } from "fs/promises";
|
|
31
|
+
import { join as join7 } from "path";
|
|
30
32
|
|
|
31
33
|
// src/tools/explain.ts
|
|
32
34
|
import { readFile } from "fs/promises";
|
|
@@ -2066,7 +2068,8 @@ var AGENT_TO_AI_TYPE = {
|
|
|
2066
2068
|
"security": "security",
|
|
2067
2069
|
"privacy": "privacy",
|
|
2068
2070
|
"legal": "legal",
|
|
2069
|
-
"
|
|
2071
|
+
"accessibility": "accessibility",
|
|
2072
|
+
"design-engineer": "design-engineer",
|
|
2070
2073
|
"software-architect": "architecture",
|
|
2071
2074
|
"bug-finding": "bugs",
|
|
2072
2075
|
"user-testing": "ux",
|
|
@@ -2074,7 +2077,8 @@ var AGENT_TO_AI_TYPE = {
|
|
|
2074
2077
|
"devops": "devops",
|
|
2075
2078
|
"comprehension": "explain",
|
|
2076
2079
|
"test": "test",
|
|
2077
|
-
"trie_clean": "vibe"
|
|
2080
|
+
"trie_clean": "vibe",
|
|
2081
|
+
"super-reviewer": "pr_review"
|
|
2078
2082
|
};
|
|
2079
2083
|
var TrieAgentTool = class {
|
|
2080
2084
|
agentRegistry = getAgentRegistry();
|
|
@@ -2300,7 +2304,8 @@ trie_scan # Full scan with smart triaging
|
|
|
2300
2304
|
"security": "trie_security",
|
|
2301
2305
|
"privacy": "trie_privacy",
|
|
2302
2306
|
"legal": "trie_legal",
|
|
2303
|
-
"
|
|
2307
|
+
"accessibility": "trie_accessibility",
|
|
2308
|
+
"design-engineer": "trie_design",
|
|
2304
2309
|
"software-architect": "trie_architecture",
|
|
2305
2310
|
"bug-finding": "trie_bugs",
|
|
2306
2311
|
"user-testing": "trie_ux",
|
|
@@ -2422,7 +2427,8 @@ ${issue.fix}
|
|
|
2422
2427
|
"security": "\u{1F512}",
|
|
2423
2428
|
"privacy": "\u{1F464}",
|
|
2424
2429
|
"legal": "\u2696\uFE0F",
|
|
2425
|
-
"
|
|
2430
|
+
"accessibility": "\u267F",
|
|
2431
|
+
"design-engineer": "\u{1F3A8}",
|
|
2426
2432
|
"software-architect": "\u{1F3D7}\uFE0F",
|
|
2427
2433
|
"bug-finding": "\u{1F41B}",
|
|
2428
2434
|
"user-testing": "\u{1F3AF}",
|
|
@@ -2935,7 +2941,7 @@ var TrieListAgentsTool = class {
|
|
|
2935
2941
|
{ name: "legal", displayName: "Legal Agent", category: "compliance", isCustom: false },
|
|
2936
2942
|
{ name: "typecheck", displayName: "TypeCheck Agent", category: "quality", isCustom: false },
|
|
2937
2943
|
{ name: "comprehension", displayName: "Comprehension Agent", category: "communication", isCustom: false },
|
|
2938
|
-
{ name: "
|
|
2944
|
+
{ name: "accessibility", displayName: "Accessibility Agent", category: "accessibility", isCustom: false },
|
|
2939
2945
|
{ name: "test", displayName: "Test Agent", category: "testing", isCustom: false },
|
|
2940
2946
|
{ name: "software-architect", displayName: "Software Architect Agent", category: "architecture", isCustom: false },
|
|
2941
2947
|
{ name: "devops", displayName: "DevOps Agent", category: "devops", isCustom: false },
|
|
@@ -3007,6 +3013,402 @@ var TrieListAgentsTool = class {
|
|
|
3007
3013
|
}
|
|
3008
3014
|
};
|
|
3009
3015
|
|
|
3016
|
+
// src/tools/pr-review.ts
|
|
3017
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
3018
|
+
import { existsSync as existsSync6 } from "fs";
|
|
3019
|
+
import { join as join5, basename as basename6, resolve as resolve4, isAbsolute as isAbsolute4 } from "path";
|
|
3020
|
+
import { execSync } from "child_process";
|
|
3021
|
+
var TriePRReviewTool = class {
|
|
3022
|
+
agent = new SuperReviewerAgent();
|
|
3023
|
+
async execute(args) {
|
|
3024
|
+
const {
|
|
3025
|
+
pr,
|
|
3026
|
+
worktree,
|
|
3027
|
+
mode,
|
|
3028
|
+
files: specificFiles
|
|
3029
|
+
} = args;
|
|
3030
|
+
try {
|
|
3031
|
+
const prInfo = await this.getPRInfo(pr, worktree);
|
|
3032
|
+
if (!prInfo.success) {
|
|
3033
|
+
return {
|
|
3034
|
+
content: [{
|
|
3035
|
+
type: "text",
|
|
3036
|
+
text: `\u274C ${prInfo.error}
|
|
3037
|
+
|
|
3038
|
+
Usage:
|
|
3039
|
+
- \`pr_review 12345\` \u2014 review specific PR
|
|
3040
|
+
- \`pr_review\` \u2014 review PR for current branch
|
|
3041
|
+
- \`pr_review ../worktree\` \u2014 review worktree changes`
|
|
3042
|
+
}]
|
|
3043
|
+
};
|
|
3044
|
+
}
|
|
3045
|
+
const changes = await this.getChanges(prInfo);
|
|
3046
|
+
if (changes.files.length === 0) {
|
|
3047
|
+
return {
|
|
3048
|
+
content: [{
|
|
3049
|
+
type: "text",
|
|
3050
|
+
text: `\u2139\uFE0F No changes found to review.`
|
|
3051
|
+
}]
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
const designDocs = await this.findDesignDocs(changes.files, prInfo);
|
|
3055
|
+
const workflow = await this.agent.buildReviewWorkflow(
|
|
3056
|
+
changes.files,
|
|
3057
|
+
{
|
|
3058
|
+
prNumber: prInfo.number,
|
|
3059
|
+
prTitle: prInfo.title,
|
|
3060
|
+
prAuthor: prInfo.author,
|
|
3061
|
+
baseBranch: prInfo.baseBranch,
|
|
3062
|
+
headBranch: prInfo.headBranch,
|
|
3063
|
+
mode: mode || "own",
|
|
3064
|
+
designDocs
|
|
3065
|
+
}
|
|
3066
|
+
);
|
|
3067
|
+
const fileContents = await this.preloadFiles(changes.files.map((f) => f.path));
|
|
3068
|
+
const reviewPrompt = this.generateReviewPrompt(workflow, changes, fileContents);
|
|
3069
|
+
return {
|
|
3070
|
+
content: [{
|
|
3071
|
+
type: "text",
|
|
3072
|
+
text: reviewPrompt
|
|
3073
|
+
}]
|
|
3074
|
+
};
|
|
3075
|
+
} catch (error) {
|
|
3076
|
+
return {
|
|
3077
|
+
content: [{
|
|
3078
|
+
type: "text",
|
|
3079
|
+
text: `\u274C Error: ${error instanceof Error ? error.message : String(error)}`
|
|
3080
|
+
}]
|
|
3081
|
+
};
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
/**
|
|
3085
|
+
* Get PR information from GitHub or local worktree
|
|
3086
|
+
*/
|
|
3087
|
+
async getPRInfo(pr, worktree) {
|
|
3088
|
+
if (worktree) {
|
|
3089
|
+
const worktreePath = isAbsolute4(worktree) ? worktree : resolve4(process.cwd(), worktree);
|
|
3090
|
+
if (!existsSync6(worktreePath)) {
|
|
3091
|
+
return { success: false, error: `Worktree not found: ${worktreePath}` };
|
|
3092
|
+
}
|
|
3093
|
+
return {
|
|
3094
|
+
success: true,
|
|
3095
|
+
type: "worktree",
|
|
3096
|
+
path: worktreePath,
|
|
3097
|
+
title: `Local changes in ${basename6(worktreePath)}`,
|
|
3098
|
+
author: this.getGitUser(),
|
|
3099
|
+
baseBranch: "HEAD~1",
|
|
3100
|
+
headBranch: "HEAD"
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
if (pr) {
|
|
3104
|
+
return this.getPRFromGitHub(pr);
|
|
3105
|
+
}
|
|
3106
|
+
try {
|
|
3107
|
+
const branch = execSync("git branch --show-current", { encoding: "utf-8" }).trim();
|
|
3108
|
+
const prJson = execSync(`gh pr view --json number,title,author,headRefName,baseRefName`, {
|
|
3109
|
+
encoding: "utf-8",
|
|
3110
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
3111
|
+
}).trim();
|
|
3112
|
+
const prData = JSON.parse(prJson);
|
|
3113
|
+
return {
|
|
3114
|
+
success: true,
|
|
3115
|
+
type: "github",
|
|
3116
|
+
number: String(prData.number),
|
|
3117
|
+
title: prData.title,
|
|
3118
|
+
author: prData.author?.login || "unknown",
|
|
3119
|
+
baseBranch: prData.baseRefName,
|
|
3120
|
+
headBranch: prData.headRefName
|
|
3121
|
+
};
|
|
3122
|
+
} catch {
|
|
3123
|
+
return {
|
|
3124
|
+
success: true,
|
|
3125
|
+
type: "local",
|
|
3126
|
+
title: "Local uncommitted changes",
|
|
3127
|
+
author: this.getGitUser(),
|
|
3128
|
+
baseBranch: "HEAD",
|
|
3129
|
+
headBranch: "working tree"
|
|
3130
|
+
};
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
/**
|
|
3134
|
+
* Get PR info from GitHub CLI
|
|
3135
|
+
*/
|
|
3136
|
+
async getPRFromGitHub(prNumber) {
|
|
3137
|
+
try {
|
|
3138
|
+
const prJson = execSync(`gh pr view ${prNumber} --json number,title,author,headRefName,baseRefName`, {
|
|
3139
|
+
encoding: "utf-8",
|
|
3140
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
3141
|
+
}).trim();
|
|
3142
|
+
const prData = JSON.parse(prJson);
|
|
3143
|
+
return {
|
|
3144
|
+
success: true,
|
|
3145
|
+
type: "github",
|
|
3146
|
+
number: String(prData.number),
|
|
3147
|
+
title: prData.title,
|
|
3148
|
+
author: prData.author?.login || "unknown",
|
|
3149
|
+
baseBranch: prData.baseRefName,
|
|
3150
|
+
headBranch: prData.headRefName
|
|
3151
|
+
};
|
|
3152
|
+
} catch (error) {
|
|
3153
|
+
return {
|
|
3154
|
+
success: false,
|
|
3155
|
+
error: `Failed to get PR #${prNumber}. Is \`gh\` CLI installed and authenticated?`
|
|
3156
|
+
};
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
/**
|
|
3160
|
+
* Get changes (diff) for the PR or local changes
|
|
3161
|
+
*/
|
|
3162
|
+
async getChanges(prInfo) {
|
|
3163
|
+
let diffOutput;
|
|
3164
|
+
try {
|
|
3165
|
+
if (prInfo.type === "github" && prInfo.number) {
|
|
3166
|
+
diffOutput = execSync(`gh pr diff ${prInfo.number}`, {
|
|
3167
|
+
encoding: "utf-8",
|
|
3168
|
+
maxBuffer: 50 * 1024 * 1024
|
|
3169
|
+
// 50MB buffer for large PRs
|
|
3170
|
+
});
|
|
3171
|
+
} else if (prInfo.type === "worktree" && prInfo.path) {
|
|
3172
|
+
diffOutput = execSync(`git diff HEAD`, {
|
|
3173
|
+
encoding: "utf-8",
|
|
3174
|
+
cwd: prInfo.path,
|
|
3175
|
+
maxBuffer: 50 * 1024 * 1024
|
|
3176
|
+
});
|
|
3177
|
+
} else {
|
|
3178
|
+
diffOutput = execSync(`git diff HEAD`, {
|
|
3179
|
+
encoding: "utf-8",
|
|
3180
|
+
maxBuffer: 50 * 1024 * 1024
|
|
3181
|
+
});
|
|
3182
|
+
if (!diffOutput.trim()) {
|
|
3183
|
+
diffOutput = execSync(`git diff --cached`, {
|
|
3184
|
+
encoding: "utf-8",
|
|
3185
|
+
maxBuffer: 50 * 1024 * 1024
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
} catch {
|
|
3190
|
+
diffOutput = "";
|
|
3191
|
+
}
|
|
3192
|
+
const files = this.parseDiff(diffOutput);
|
|
3193
|
+
return { files, fullDiff: diffOutput };
|
|
3194
|
+
}
|
|
3195
|
+
/**
|
|
3196
|
+
* Parse git diff output into structured file changes
|
|
3197
|
+
*/
|
|
3198
|
+
parseDiff(diffOutput) {
|
|
3199
|
+
const files = [];
|
|
3200
|
+
const fileDiffs = diffOutput.split(/^diff --git /m).slice(1);
|
|
3201
|
+
for (const fileDiff of fileDiffs) {
|
|
3202
|
+
const lines = fileDiff.split("\n");
|
|
3203
|
+
const headerLine = lines[0] || "";
|
|
3204
|
+
const pathMatch = headerLine.match(/a\/(.+?) b\/(.+)/);
|
|
3205
|
+
if (!pathMatch) continue;
|
|
3206
|
+
const path = pathMatch[2];
|
|
3207
|
+
const diff = `diff --git ${fileDiff}`;
|
|
3208
|
+
let additions = 0;
|
|
3209
|
+
let deletions = 0;
|
|
3210
|
+
for (const line of lines) {
|
|
3211
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
3212
|
+
additions++;
|
|
3213
|
+
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
3214
|
+
deletions++;
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
files.push({ path, diff, additions, deletions });
|
|
3218
|
+
}
|
|
3219
|
+
return files;
|
|
3220
|
+
}
|
|
3221
|
+
/**
|
|
3222
|
+
* Find related design docs
|
|
3223
|
+
*/
|
|
3224
|
+
async findDesignDocs(files, prInfo) {
|
|
3225
|
+
const designDocs = [];
|
|
3226
|
+
const cwd = prInfo.path || process.cwd();
|
|
3227
|
+
for (const file of files) {
|
|
3228
|
+
if (file.path.includes("design_docs/") || file.path.includes("docs/design/") || file.path.includes("rfcs/")) {
|
|
3229
|
+
designDocs.push(file.path);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
const designDocPaths = [
|
|
3233
|
+
"design_docs",
|
|
3234
|
+
"docs/design",
|
|
3235
|
+
"docs/rfcs",
|
|
3236
|
+
"rfcs"
|
|
3237
|
+
];
|
|
3238
|
+
for (const docPath of designDocPaths) {
|
|
3239
|
+
const fullPath = join5(cwd, docPath);
|
|
3240
|
+
if (existsSync6(fullPath)) {
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
return designDocs;
|
|
3244
|
+
}
|
|
3245
|
+
/**
|
|
3246
|
+
* Pre-load all changed files for instant responses during review
|
|
3247
|
+
*/
|
|
3248
|
+
async preloadFiles(filePaths) {
|
|
3249
|
+
const contents = /* @__PURE__ */ new Map();
|
|
3250
|
+
const cwd = process.cwd();
|
|
3251
|
+
await Promise.all(filePaths.map(async (filePath) => {
|
|
3252
|
+
try {
|
|
3253
|
+
const fullPath = isAbsolute4(filePath) ? filePath : join5(cwd, filePath);
|
|
3254
|
+
if (existsSync6(fullPath)) {
|
|
3255
|
+
const content = await readFile5(fullPath, "utf-8");
|
|
3256
|
+
contents.set(filePath, content);
|
|
3257
|
+
}
|
|
3258
|
+
} catch {
|
|
3259
|
+
}
|
|
3260
|
+
}));
|
|
3261
|
+
return contents;
|
|
3262
|
+
}
|
|
3263
|
+
/**
|
|
3264
|
+
* Get git user name
|
|
3265
|
+
*/
|
|
3266
|
+
getGitUser() {
|
|
3267
|
+
try {
|
|
3268
|
+
return execSync("git config user.name", { encoding: "utf-8" }).trim();
|
|
3269
|
+
} catch {
|
|
3270
|
+
return "unknown";
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
3273
|
+
/**
|
|
3274
|
+
* Generate the full review prompt for Claude to execute
|
|
3275
|
+
*/
|
|
3276
|
+
generateReviewPrompt(workflow, changes, fileContents) {
|
|
3277
|
+
const { metadata, fileOrder, reviewInstructions } = workflow;
|
|
3278
|
+
let prompt = `# \u{1F50D} Super Reviewer \u2014 Interactive PR Review
|
|
3279
|
+
|
|
3280
|
+
`;
|
|
3281
|
+
if (metadata.prNumber) {
|
|
3282
|
+
prompt += `## PR #${metadata.prNumber}: ${metadata.prTitle}
|
|
3283
|
+
|
|
3284
|
+
`;
|
|
3285
|
+
} else {
|
|
3286
|
+
prompt += `## ${metadata.prTitle}
|
|
3287
|
+
|
|
3288
|
+
`;
|
|
3289
|
+
}
|
|
3290
|
+
prompt += `**Author:** ${metadata.prAuthor}
|
|
3291
|
+
`;
|
|
3292
|
+
prompt += `**Branch:** \`${metadata.headBranch}\` \u2192 \`${metadata.baseBranch}\`
|
|
3293
|
+
`;
|
|
3294
|
+
prompt += `**Scope:** ${metadata.totalFiles} files, +${metadata.totalAdditions}/-${metadata.totalDeletions} lines
|
|
3295
|
+
|
|
3296
|
+
`;
|
|
3297
|
+
prompt += `---
|
|
3298
|
+
|
|
3299
|
+
`;
|
|
3300
|
+
prompt += `## Review Mode
|
|
3301
|
+
|
|
3302
|
+
`;
|
|
3303
|
+
prompt += `**Current Mode:** ${reviewInstructions.mode === "own" ? "1" : "2"}. ${reviewInstructions.description}
|
|
3304
|
+
|
|
3305
|
+
`;
|
|
3306
|
+
prompt += `> To switch modes, say "mode 1" for your own PR or "mode 2" for someone else's
|
|
3307
|
+
|
|
3308
|
+
`;
|
|
3309
|
+
prompt += `---
|
|
3310
|
+
|
|
3311
|
+
`;
|
|
3312
|
+
prompt += `## Files to Review (ordered for understanding)
|
|
3313
|
+
|
|
3314
|
+
`;
|
|
3315
|
+
prompt += `| # | File | Why this order |
|
|
3316
|
+
`;
|
|
3317
|
+
prompt += `|---|------|----------------|
|
|
3318
|
+
`;
|
|
3319
|
+
for (const file of fileOrder) {
|
|
3320
|
+
const stats = `+${changes.files.find((f) => f.path === file.path)?.additions || 0}/-${changes.files.find((f) => f.path === file.path)?.deletions || 0}`;
|
|
3321
|
+
prompt += `| ${file.index} | \`${file.path}\` (${stats}) | ${file.reason} |
|
|
3322
|
+
`;
|
|
3323
|
+
}
|
|
3324
|
+
prompt += `
|
|
3325
|
+
---
|
|
3326
|
+
|
|
3327
|
+
`;
|
|
3328
|
+
prompt += `## \u{1F3AF} Critical Review Mindset
|
|
3329
|
+
|
|
3330
|
+
`;
|
|
3331
|
+
prompt += `As we go through each file, I'll actively look for:
|
|
3332
|
+
|
|
3333
|
+
`;
|
|
3334
|
+
prompt += `**State & Lifecycle:**
|
|
3335
|
+
`;
|
|
3336
|
+
for (const check of CRITICAL_REVIEW_CHECKLIST.stateAndLifecycle) {
|
|
3337
|
+
prompt += `- ${check}
|
|
3338
|
+
`;
|
|
3339
|
+
}
|
|
3340
|
+
prompt += `
|
|
3341
|
+
**Edge Cases & Races:**
|
|
3342
|
+
`;
|
|
3343
|
+
for (const check of CRITICAL_REVIEW_CHECKLIST.edgeCasesAndRaces) {
|
|
3344
|
+
prompt += `- ${check}
|
|
3345
|
+
`;
|
|
3346
|
+
}
|
|
3347
|
+
prompt += `
|
|
3348
|
+
**Missing Pieces:**
|
|
3349
|
+
`;
|
|
3350
|
+
for (const check of CRITICAL_REVIEW_CHECKLIST.missingPieces) {
|
|
3351
|
+
prompt += `- ${check}
|
|
3352
|
+
`;
|
|
3353
|
+
}
|
|
3354
|
+
prompt += `
|
|
3355
|
+
---
|
|
3356
|
+
|
|
3357
|
+
`;
|
|
3358
|
+
prompt += `## File Diffs (pre-loaded for instant review)
|
|
3359
|
+
|
|
3360
|
+
`;
|
|
3361
|
+
prompt += `<details>
|
|
3362
|
+
<summary>\u{1F4C1} All file diffs (click to expand)</summary>
|
|
3363
|
+
|
|
3364
|
+
`;
|
|
3365
|
+
for (const file of fileOrder) {
|
|
3366
|
+
const fileChange = changes.files.find((f) => f.path === file.path);
|
|
3367
|
+
if (fileChange) {
|
|
3368
|
+
prompt += `### ${file.path}
|
|
3369
|
+
|
|
3370
|
+
`;
|
|
3371
|
+
prompt += `\`\`\`diff
|
|
3372
|
+
${fileChange.diff}
|
|
3373
|
+
\`\`\`
|
|
3374
|
+
|
|
3375
|
+
`;
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
prompt += `</details>
|
|
3379
|
+
|
|
3380
|
+
`;
|
|
3381
|
+
prompt += `---
|
|
3382
|
+
|
|
3383
|
+
`;
|
|
3384
|
+
prompt += `## Ready to Begin
|
|
3385
|
+
|
|
3386
|
+
`;
|
|
3387
|
+
prompt += `I'll walk you through each file, explaining what changed and why. After each file, I'll pause for your questions.
|
|
3388
|
+
|
|
3389
|
+
`;
|
|
3390
|
+
prompt += `**Commands during review:**
|
|
3391
|
+
`;
|
|
3392
|
+
prompt += `- \`yes\` or \`y\` \u2014 continue to next file
|
|
3393
|
+
`;
|
|
3394
|
+
prompt += `- \`skip to [filename]\` \u2014 jump to specific file
|
|
3395
|
+
`;
|
|
3396
|
+
prompt += `- \`questions?\` \u2014 ask about current file
|
|
3397
|
+
`;
|
|
3398
|
+
prompt += `- \`reorder\` \u2014 change the file order
|
|
3399
|
+
`;
|
|
3400
|
+
prompt += `- \`done\` \u2014 end review and show summary
|
|
3401
|
+
|
|
3402
|
+
`;
|
|
3403
|
+
prompt += `**Ready for File 1?** (\`${fileOrder[0]?.path || "no files"}\`)
|
|
3404
|
+
|
|
3405
|
+
`;
|
|
3406
|
+
prompt += `*(say "yes" to start, or ask me anything)*
|
|
3407
|
+
`;
|
|
3408
|
+
return prompt;
|
|
3409
|
+
}
|
|
3410
|
+
};
|
|
3411
|
+
|
|
3010
3412
|
// src/utils/ai-tool-detector.ts
|
|
3011
3413
|
function detectAITool() {
|
|
3012
3414
|
if (process.env.CLAUDE_CODE_VERSION || process.env.CLAUDE_CODE) {
|
|
@@ -3075,8 +3477,8 @@ function detectAITool() {
|
|
|
3075
3477
|
}
|
|
3076
3478
|
|
|
3077
3479
|
// src/config/loader.ts
|
|
3078
|
-
import { readFile as
|
|
3079
|
-
import { join as
|
|
3480
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
3481
|
+
import { join as join6 } from "path";
|
|
3080
3482
|
|
|
3081
3483
|
// src/config/defaults.ts
|
|
3082
3484
|
var DEFAULT_CONFIG = {
|
|
@@ -3095,7 +3497,7 @@ var DEFAULT_CONFIG = {
|
|
|
3095
3497
|
security: { enabled: true },
|
|
3096
3498
|
privacy: { enabled: true },
|
|
3097
3499
|
legal: { enabled: true },
|
|
3098
|
-
"
|
|
3500
|
+
"accessibility": { enabled: true },
|
|
3099
3501
|
"software-architect": { enabled: true },
|
|
3100
3502
|
comprehension: { enabled: true },
|
|
3101
3503
|
devops: { enabled: true },
|
|
@@ -3131,8 +3533,8 @@ var DEFAULT_CONFIG = {
|
|
|
3131
3533
|
// src/config/loader.ts
|
|
3132
3534
|
async function loadConfig() {
|
|
3133
3535
|
try {
|
|
3134
|
-
const configPath =
|
|
3135
|
-
const configFile = await
|
|
3536
|
+
const configPath = join6(process.cwd(), ".trie", "config.json");
|
|
3537
|
+
const configFile = await readFile6(configPath, "utf-8");
|
|
3136
3538
|
const userConfig = JSON.parse(configFile);
|
|
3137
3539
|
return mergeConfig(DEFAULT_CONFIG, userConfig);
|
|
3138
3540
|
} catch (error) {
|
|
@@ -3179,6 +3581,7 @@ var agentTool = new TrieAgentTool();
|
|
|
3179
3581
|
var createAgentTool = new TrieCreateAgentTool();
|
|
3180
3582
|
var saveAgentTool = new TrieSaveAgentTool();
|
|
3181
3583
|
var listAgentsTool = new TrieListAgentsTool();
|
|
3584
|
+
var prReviewTool = new TriePRReviewTool();
|
|
3182
3585
|
var tools = [
|
|
3183
3586
|
{
|
|
3184
3587
|
name: "scan",
|
|
@@ -3422,6 +3825,22 @@ var tools = [
|
|
|
3422
3825
|
}
|
|
3423
3826
|
}
|
|
3424
3827
|
},
|
|
3828
|
+
{
|
|
3829
|
+
name: "design",
|
|
3830
|
+
description: "\u{1F3A8} Run design engineer agent: Awwwards-level polish, design systems, motion design, creative CSS",
|
|
3831
|
+
inputSchema: {
|
|
3832
|
+
type: "object",
|
|
3833
|
+
properties: {
|
|
3834
|
+
files: { type: "array", items: { type: "string" }, description: "Files to scan" },
|
|
3835
|
+
directory: { type: "string", description: "Directory to scan" },
|
|
3836
|
+
output: {
|
|
3837
|
+
type: "string",
|
|
3838
|
+
enum: ["summary", "full"],
|
|
3839
|
+
description: "summary = concise (default), full = includes AI prompt/code (large output)"
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
},
|
|
3425
3844
|
{
|
|
3426
3845
|
name: "architecture",
|
|
3427
3846
|
description: "Run architecture agent: code organization, SOLID principles, N+1 queries, scalability",
|
|
@@ -3625,6 +4044,34 @@ var tools = [
|
|
|
3625
4044
|
}
|
|
3626
4045
|
}
|
|
3627
4046
|
}
|
|
4047
|
+
},
|
|
4048
|
+
// PR Review — Interactive AI-guided code review
|
|
4049
|
+
{
|
|
4050
|
+
name: "pr_review",
|
|
4051
|
+
description: "\u{1F50D} Interactive PR review: walks through changes file-by-file, explains each chunk, pauses for cross-examination. Makes large PR reviews a delight.",
|
|
4052
|
+
inputSchema: {
|
|
4053
|
+
type: "object",
|
|
4054
|
+
properties: {
|
|
4055
|
+
pr: {
|
|
4056
|
+
type: "string",
|
|
4057
|
+
description: 'PR number to review (e.g., "12345"). If omitted, reviews current branch PR or local changes.'
|
|
4058
|
+
},
|
|
4059
|
+
worktree: {
|
|
4060
|
+
type: "string",
|
|
4061
|
+
description: "Path to worktree directory to review local changes"
|
|
4062
|
+
},
|
|
4063
|
+
mode: {
|
|
4064
|
+
type: "string",
|
|
4065
|
+
enum: ["own", "others"],
|
|
4066
|
+
description: `Review mode: "own" = your PR (I explain, you verify), "others" = someone else's PR (I flag issues, you comment)`
|
|
4067
|
+
},
|
|
4068
|
+
files: {
|
|
4069
|
+
type: "array",
|
|
4070
|
+
items: { type: "string" },
|
|
4071
|
+
description: "Specific files to review (optional, defaults to all changed files)"
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
3628
4075
|
}
|
|
3629
4076
|
];
|
|
3630
4077
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
@@ -3653,6 +4100,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3653
4100
|
"## Trie Menu",
|
|
3654
4101
|
"",
|
|
3655
4102
|
"- `trie_scan` or `scan`: Full intelligent scan (auto triage agents)",
|
|
4103
|
+
"- `pr_review`: \u{1F50D} Interactive PR review \u2014 walks through changes file-by-file",
|
|
3656
4104
|
"- `fix`: Apply high-confidence fixes",
|
|
3657
4105
|
"- `explain`: Explain code/issues/risks",
|
|
3658
4106
|
"- `watch`: Watch mode (scan on change)",
|
|
@@ -3685,6 +4133,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3685
4133
|
case "legal":
|
|
3686
4134
|
return await agentTool.execute({ ...args, agent: "legal" });
|
|
3687
4135
|
case "accessibility":
|
|
4136
|
+
return await agentTool.execute({ ...args, agent: "accessibility" });
|
|
4137
|
+
case "design":
|
|
3688
4138
|
return await agentTool.execute({ ...args, agent: "design-engineer" });
|
|
3689
4139
|
case "architecture":
|
|
3690
4140
|
return await agentTool.execute({ ...args, agent: "software-architect" });
|
|
@@ -3707,6 +4157,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3707
4157
|
return await saveAgentTool.execute(args);
|
|
3708
4158
|
case "list_agents":
|
|
3709
4159
|
return await listAgentsTool.execute(args);
|
|
4160
|
+
case "pr_review":
|
|
4161
|
+
return await prReviewTool.execute(args);
|
|
3710
4162
|
default:
|
|
3711
4163
|
throw new Error(`Unknown tool: ${name}`);
|
|
3712
4164
|
}
|
|
@@ -3749,7 +4201,7 @@ async function getAvailableResources() {
|
|
|
3749
4201
|
mimeType: "application/json"
|
|
3750
4202
|
});
|
|
3751
4203
|
try {
|
|
3752
|
-
const reportsDir =
|
|
4204
|
+
const reportsDir = join7(process.cwd(), "trie-reports");
|
|
3753
4205
|
const files = await readdir2(reportsDir);
|
|
3754
4206
|
const reportFiles = files.filter((f) => f.endsWith(".txt") || f.endsWith(".json"));
|
|
3755
4207
|
for (const file of reportFiles.slice(0, 10)) {
|
|
@@ -3826,8 +4278,8 @@ async function readResourceContent(uri) {
|
|
|
3826
4278
|
}
|
|
3827
4279
|
if (parsedUri === "cache/stats") {
|
|
3828
4280
|
try {
|
|
3829
|
-
const cachePath =
|
|
3830
|
-
const cacheContent = await
|
|
4281
|
+
const cachePath = join7(process.cwd(), ".trie", ".trie-cache.json");
|
|
4282
|
+
const cacheContent = await readFile7(cachePath, "utf-8");
|
|
3831
4283
|
const cache = JSON.parse(cacheContent);
|
|
3832
4284
|
const fileCount = Object.keys(cache.files || {}).length;
|
|
3833
4285
|
const totalVulns = Object.values(cache.files || {}).reduce((acc, file) => {
|
|
@@ -3879,9 +4331,9 @@ async function readResourceContent(uri) {
|
|
|
3879
4331
|
}
|
|
3880
4332
|
if (parsedUri.startsWith("reports/")) {
|
|
3881
4333
|
const fileName = parsedUri.replace("reports/", "");
|
|
3882
|
-
const reportPath =
|
|
4334
|
+
const reportPath = join7(process.cwd(), "trie-reports", fileName);
|
|
3883
4335
|
try {
|
|
3884
|
-
const content = await
|
|
4336
|
+
const content = await readFile7(reportPath, "utf-8");
|
|
3885
4337
|
return {
|
|
3886
4338
|
contents: [{
|
|
3887
4339
|
uri,
|