diffprism 0.10.2 → 0.11.1
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 +9 -34
- package/dist/bin.js +214 -1
- package/dist/mcp-server.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,45 +20,20 @@ DiffPrism gives you a visual review step for AI-written code — stage your chan
|
|
|
20
20
|
|
|
21
21
|
### Use with Claude Code (recommended)
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Run this from your project root:
|
|
24
24
|
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
"mcpServers": {
|
|
28
|
-
"diffprism": {
|
|
29
|
-
"command": "npx",
|
|
30
|
-
"args": ["diffprism", "serve"]
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
**2. Auto-approve the tool** (optional) — add to `.claude/settings.json` so Claude can open reviews without prompting:
|
|
37
|
-
|
|
38
|
-
```json
|
|
39
|
-
{
|
|
40
|
-
"permissions": {
|
|
41
|
-
"allow": [
|
|
42
|
-
"mcp__diffprism__open_review"
|
|
43
|
-
]
|
|
44
|
-
}
|
|
45
|
-
}
|
|
25
|
+
```bash
|
|
26
|
+
npx diffprism setup
|
|
46
27
|
```
|
|
47
28
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
Before committing changes, use the diffprism MCP tool to open a review:
|
|
54
|
-
- Call `open_review` with the appropriate `diff_ref` (e.g. `"staged"`, `"HEAD~1..HEAD"`)
|
|
55
|
-
- Include a `title` and `description` summarizing the changes
|
|
56
|
-
- Wait for the user's review decision before proceeding
|
|
57
|
-
```
|
|
29
|
+
This single command configures everything:
|
|
30
|
+
- Creates `.mcp.json` with the DiffPrism MCP server
|
|
31
|
+
- Creates `.claude/settings.json` with auto-approve permissions
|
|
32
|
+
- Installs a `/review` skill so you can type `/review` in Claude Code at any time
|
|
58
33
|
|
|
59
|
-
|
|
34
|
+
After running, restart Claude Code. The first time you use `/review`, Claude will ask your preferences and save them to `diffprism.config.json`.
|
|
60
35
|
|
|
61
|
-
See the [full setup guide](docs/claude-setup.md) for Claude Desktop config, troubleshooting, and advanced options.
|
|
36
|
+
See the [full setup guide](docs/claude-setup.md) for manual configuration, Claude Desktop config, troubleshooting, and advanced options.
|
|
62
37
|
|
|
63
38
|
### Use from the CLI
|
|
64
39
|
|
package/dist/bin.js
CHANGED
|
@@ -40,9 +40,222 @@ async function serve() {
|
|
|
40
40
|
await startMcpServer();
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// cli/src/commands/setup.ts
|
|
44
|
+
import fs from "fs";
|
|
45
|
+
import path from "path";
|
|
46
|
+
import os from "os";
|
|
47
|
+
|
|
48
|
+
// cli/src/templates/skill.ts
|
|
49
|
+
var skillContent = `---
|
|
50
|
+
name: review
|
|
51
|
+
description: Open current code changes in DiffPrism's browser-based review UI for human review.
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
# DiffPrism Review Skill
|
|
55
|
+
|
|
56
|
+
When the user invokes \`/review\`, open the current code changes in DiffPrism for browser-based human review.
|
|
57
|
+
|
|
58
|
+
## Steps
|
|
59
|
+
|
|
60
|
+
### 1. Check for Configuration
|
|
61
|
+
|
|
62
|
+
Look for \`diffprism.config.json\` at the project root. If it exists, read it for preferences:
|
|
63
|
+
|
|
64
|
+
\`\`\`json
|
|
65
|
+
{
|
|
66
|
+
"reviewTrigger": "ask | before_commit | always",
|
|
67
|
+
"defaultDiffScope": "staged | unstaged | all",
|
|
68
|
+
"includeReasoning": true | false
|
|
69
|
+
}
|
|
70
|
+
\`\`\`
|
|
71
|
+
|
|
72
|
+
**Defaults** (when fields are missing or file doesn't exist):
|
|
73
|
+
- \`reviewTrigger\`: \`"ask"\`
|
|
74
|
+
- \`defaultDiffScope\`: \`"all"\`
|
|
75
|
+
- \`includeReasoning\`: \`true\`
|
|
76
|
+
|
|
77
|
+
### 2. First-Run Onboarding
|
|
78
|
+
|
|
79
|
+
If \`diffprism.config.json\` does **not** exist, ask the user these questions before proceeding:
|
|
80
|
+
|
|
81
|
+
1. **"When should I open DiffPrism reviews?"**
|
|
82
|
+
- \`"ask"\` \u2014 Only when you explicitly ask (default)
|
|
83
|
+
- \`"before_commit"\` \u2014 Automatically before every commit
|
|
84
|
+
- \`"always"\` \u2014 After every code change
|
|
85
|
+
|
|
86
|
+
2. **"What should the default diff scope be?"**
|
|
87
|
+
- \`"all"\` \u2014 All changes, staged and unstaged (default)
|
|
88
|
+
- \`"staged"\` \u2014 Only staged changes
|
|
89
|
+
- \`"unstaged"\` \u2014 Only unstaged changes
|
|
90
|
+
|
|
91
|
+
3. **"Should I include my reasoning about the changes in reviews?"**
|
|
92
|
+
- Yes (default)
|
|
93
|
+
- No
|
|
94
|
+
|
|
95
|
+
After collecting answers, create \`diffprism.config.json\` at the project root with the user's choices. Then proceed to open the review.
|
|
96
|
+
|
|
97
|
+
### 3. Open the Review
|
|
98
|
+
|
|
99
|
+
Call \`mcp__diffprism__open_review\` with:
|
|
100
|
+
|
|
101
|
+
- \`diff_ref\`: Use the \`defaultDiffScope\` from config. If the user specified a scope in their message (e.g., "/review staged"), use that instead.
|
|
102
|
+
- \`title\`: A short summary of the changes (generate from git status or the user's message).
|
|
103
|
+
- \`description\`: A brief description of what changed and why.
|
|
104
|
+
- \`reasoning\`: If \`includeReasoning\` is \`true\`, include your reasoning about the implementation decisions.
|
|
105
|
+
|
|
106
|
+
### 4. Handle the Result
|
|
107
|
+
|
|
108
|
+
The tool blocks until the user submits their review in the browser. When it returns:
|
|
109
|
+
|
|
110
|
+
- **\`approved\`** \u2014 Acknowledge and proceed with whatever task was in progress.
|
|
111
|
+
- **\`approved_with_comments\`** \u2014 Note the comments, address any actionable feedback.
|
|
112
|
+
- **\`changes_requested\`** \u2014 Read the comments carefully, make the requested changes, and offer to open another review.
|
|
113
|
+
|
|
114
|
+
### 5. Error Handling
|
|
115
|
+
|
|
116
|
+
If the \`mcp__diffprism__open_review\` tool is not available:
|
|
117
|
+
- Tell the user: "The DiffPrism MCP server isn't configured. Run \`npx diffprism setup\` to set it up, then restart Claude Code."
|
|
118
|
+
|
|
119
|
+
## Behavior Rules
|
|
120
|
+
|
|
121
|
+
- When invoked via \`/review\`, always open a review regardless of the \`reviewTrigger\` setting.
|
|
122
|
+
- The \`reviewTrigger\` setting only applies to automatic review behavior during other workflows:
|
|
123
|
+
- \`"ask"\` \u2014 Never auto-review; only review when the user asks.
|
|
124
|
+
- \`"before_commit"\` \u2014 Open a review before creating any git commit.
|
|
125
|
+
- \`"always"\` \u2014 Open a review after any code change.
|
|
126
|
+
- To re-run onboarding, the user can delete \`diffprism.config.json\` and invoke \`/review\` again.
|
|
127
|
+
`;
|
|
128
|
+
|
|
129
|
+
// cli/src/commands/setup.ts
|
|
130
|
+
function findGitRoot(from) {
|
|
131
|
+
let dir = path.resolve(from);
|
|
132
|
+
while (true) {
|
|
133
|
+
if (fs.existsSync(path.join(dir, ".git"))) {
|
|
134
|
+
return dir;
|
|
135
|
+
}
|
|
136
|
+
const parent = path.dirname(dir);
|
|
137
|
+
if (parent === dir) return null;
|
|
138
|
+
dir = parent;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function readJsonFile(filePath) {
|
|
142
|
+
try {
|
|
143
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
144
|
+
return JSON.parse(raw);
|
|
145
|
+
} catch {
|
|
146
|
+
return {};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function writeJsonFile(filePath, data) {
|
|
150
|
+
const dir = path.dirname(filePath);
|
|
151
|
+
if (!fs.existsSync(dir)) {
|
|
152
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
153
|
+
}
|
|
154
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
|
|
155
|
+
}
|
|
156
|
+
function setupMcpJson(gitRoot, force) {
|
|
157
|
+
const filePath = path.join(gitRoot, ".mcp.json");
|
|
158
|
+
const existing = readJsonFile(filePath);
|
|
159
|
+
const servers = existing.mcpServers ?? {};
|
|
160
|
+
if (servers.diffprism && !force) {
|
|
161
|
+
return { action: "skipped", filePath };
|
|
162
|
+
}
|
|
163
|
+
servers.diffprism = {
|
|
164
|
+
command: "npx",
|
|
165
|
+
args: ["diffprism@latest", "serve"]
|
|
166
|
+
};
|
|
167
|
+
const action = fs.existsSync(filePath) ? "updated" : "created";
|
|
168
|
+
writeJsonFile(filePath, { ...existing, mcpServers: servers });
|
|
169
|
+
return { action, filePath };
|
|
170
|
+
}
|
|
171
|
+
function setupClaudeSettings(gitRoot, force) {
|
|
172
|
+
const filePath = path.join(gitRoot, ".claude", "settings.json");
|
|
173
|
+
const existing = readJsonFile(filePath);
|
|
174
|
+
const permissions = existing.permissions ?? {};
|
|
175
|
+
const allow = permissions.allow ?? [];
|
|
176
|
+
const toolName = "mcp__diffprism__open_review";
|
|
177
|
+
if (allow.includes(toolName) && !force) {
|
|
178
|
+
return { action: "skipped", filePath };
|
|
179
|
+
}
|
|
180
|
+
if (!allow.includes(toolName)) {
|
|
181
|
+
allow.push(toolName);
|
|
182
|
+
}
|
|
183
|
+
permissions.allow = allow;
|
|
184
|
+
const action = fs.existsSync(filePath) ? "updated" : "created";
|
|
185
|
+
writeJsonFile(filePath, { ...existing, permissions });
|
|
186
|
+
return { action, filePath };
|
|
187
|
+
}
|
|
188
|
+
function setupSkill(gitRoot, global, force) {
|
|
189
|
+
const skillDir = global ? path.join(os.homedir(), ".claude", "skills", "review") : path.join(gitRoot, ".claude", "skills", "review");
|
|
190
|
+
const filePath = path.join(skillDir, "SKILL.md");
|
|
191
|
+
if (fs.existsSync(filePath)) {
|
|
192
|
+
const existingContent = fs.readFileSync(filePath, "utf-8");
|
|
193
|
+
if (existingContent === skillContent) {
|
|
194
|
+
return { action: "skipped", filePath };
|
|
195
|
+
}
|
|
196
|
+
if (!force) {
|
|
197
|
+
console.log(
|
|
198
|
+
` Warning: ${filePath} exists with different content. Use --force to overwrite.`
|
|
199
|
+
);
|
|
200
|
+
return { action: "skipped", filePath };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (!fs.existsSync(skillDir)) {
|
|
204
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
205
|
+
}
|
|
206
|
+
const action = fs.existsSync(filePath) ? "updated" : "created";
|
|
207
|
+
fs.writeFileSync(filePath, skillContent);
|
|
208
|
+
return { action, filePath };
|
|
209
|
+
}
|
|
210
|
+
async function setup(flags) {
|
|
211
|
+
const gitRoot = findGitRoot(process.cwd());
|
|
212
|
+
if (!gitRoot) {
|
|
213
|
+
console.error(
|
|
214
|
+
"Error: Not in a git repository. Run this command from inside a git project."
|
|
215
|
+
);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const force = flags.force ?? false;
|
|
220
|
+
const global = flags.global ?? false;
|
|
221
|
+
console.log("Setting up DiffPrism for Claude Code...\n");
|
|
222
|
+
const result = { created: [], updated: [], skipped: [] };
|
|
223
|
+
const mcp = setupMcpJson(gitRoot, force);
|
|
224
|
+
result[mcp.action === "skipped" ? "skipped" : mcp.action === "created" ? "created" : "updated"].push(mcp.filePath);
|
|
225
|
+
const settings = setupClaudeSettings(gitRoot, force);
|
|
226
|
+
result[settings.action === "skipped" ? "skipped" : settings.action === "created" ? "created" : "updated"].push(settings.filePath);
|
|
227
|
+
const skill = setupSkill(gitRoot, global, force);
|
|
228
|
+
result[skill.action === "skipped" ? "skipped" : skill.action === "created" ? "created" : "updated"].push(skill.filePath);
|
|
229
|
+
if (result.created.length > 0) {
|
|
230
|
+
console.log("Created:");
|
|
231
|
+
for (const f of result.created) {
|
|
232
|
+
console.log(` + ${path.relative(gitRoot, f)}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (result.updated.length > 0) {
|
|
236
|
+
console.log("Updated:");
|
|
237
|
+
for (const f of result.updated) {
|
|
238
|
+
console.log(` ~ ${path.relative(gitRoot, f)}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (result.skipped.length > 0) {
|
|
242
|
+
console.log("Skipped (already configured):");
|
|
243
|
+
for (const f of result.skipped) {
|
|
244
|
+
console.log(` - ${path.relative(gitRoot, f)}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
console.log(
|
|
248
|
+
"\nYou can now use /review in Claude Code to open a DiffPrism review."
|
|
249
|
+
);
|
|
250
|
+
console.log(
|
|
251
|
+
"If Claude Code is running, restart it to pick up the new configuration."
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
43
255
|
// cli/src/index.ts
|
|
44
256
|
var program = new Command();
|
|
45
|
-
program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(true ? "0.
|
|
257
|
+
program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(true ? "0.11.1" : "0.0.0-dev");
|
|
46
258
|
program.command("review [ref]").description("Open a browser-based diff review").option("--staged", "Review staged changes").option("--unstaged", "Review unstaged changes").option("-t, --title <title>", "Review title").option("--dev", "Use Vite dev server with HMR instead of static files").action(review);
|
|
47
259
|
program.command("serve").description("Start the MCP server for Claude Code integration").action(serve);
|
|
260
|
+
program.command("setup").description("Configure DiffPrism for Claude Code integration").option("--global", "Install skill globally (~/.claude/skills/)").option("--force", "Overwrite existing configuration files").action(setup);
|
|
48
261
|
program.parse();
|
package/dist/mcp-server.js
CHANGED