diffprism 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,97 +2,102 @@
2
2
 
3
3
  Local-first code review tool for agent-generated code changes. Opens a browser-based diff viewer from the CLI or Claude Code (via MCP).
4
4
 
5
- DiffPrism gives you a visual review step for AI-written code — stage your changes, run the tool, and a browser window opens with a syntax-highlighted diff viewer. Approve or request changes, and the result is returned as structured JSON.
5
+ DiffPrism gives you a visual review step for AI-written code — stage your changes, run the tool, and a browser window opens with a full-featured diff viewer. Review inline, leave comments, and your decision is returned as structured JSON.
6
+
7
+ ## Features
8
+
9
+ - **Syntax-highlighted diffs** — unified or split (side-by-side) view with toggle
10
+ - **Inline line-level commenting** — click any line to add comments typed as `must_fix`, `suggestion`, `question`, or `nitpick`
11
+ - **File-level review status** — mark each file as reviewed, approved, or needs changes
12
+ - **Review briefing bar** — summary stats, complexity scoring, test coverage gaps, pattern flags, and dependency tracking
13
+ - **Agent reasoning panel** — see why the AI made each change
14
+ - **Dark/light mode** — toggle with theme persistence
15
+ - **Keyboard shortcuts** — `j`/`k` navigate files, `Space`/`Enter` cycle file status
16
+ - **Three-way decisions** — approve, request changes, or approve with comments
17
+ - **Branch display** — current git branch shown in the review header
6
18
 
7
19
  ## Quick Start
8
20
 
9
- ```bash
10
- # Clone and install
11
- git clone <repo-url> && cd diffprism
12
- pnpm install
21
+ ### Use with Claude Code (recommended)
13
22
 
14
- # Review staged changes
15
- pnpm cli review --staged
23
+ Run this from your project root:
24
+
25
+ ```bash
26
+ npx diffprism setup
16
27
  ```
17
28
 
18
- A browser window opens with the diff viewer. Click **Approve** or **Request Changes**, and the result prints to stdout as JSON.
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
33
+
34
+ After running, restart Claude Code. The first time you use `/review`, Claude will ask your preferences and save them to `diffprism.config.json`.
19
35
 
20
- ## Usage
36
+ See the [full setup guide](docs/claude-setup.md) for manual configuration, Claude Desktop config, troubleshooting, and advanced options.
21
37
 
22
- ### CLI
38
+ ### Use from the CLI
23
39
 
24
40
  ```bash
25
- # Review staged changes (default)
26
- pnpm cli review
27
- pnpm cli review --staged
41
+ # Install globally (or use npx)
42
+ npm install -g diffprism
28
43
 
29
- # Review unstaged changes
30
- pnpm cli review --unstaged
44
+ # Review all changes (staged + unstaged, default)
45
+ diffprism review
46
+
47
+ # Review staged changes only
48
+ diffprism review --staged
49
+
50
+ # Review unstaged changes only
51
+ diffprism review --unstaged
31
52
 
32
53
  # Review a specific ref range
33
- pnpm cli review HEAD~3
34
- pnpm cli review main..feature-branch
54
+ diffprism review HEAD~3
55
+ diffprism review main..feature-branch
35
56
 
36
57
  # Add a title to the review
37
- pnpm cli review --staged --title "Add auth middleware"
58
+ diffprism review --staged --title "Add auth middleware"
38
59
  ```
39
60
 
40
- **Output:** A `ReviewResult` JSON object:
61
+ A browser window opens with the diff viewer. Review the changes and click **Approve**, **Request Changes**, or **Approve with Comments**.
41
62
 
42
- ```json
43
- {
44
- "decision": "approved",
45
- "comments": [],
46
- "summary": ""
47
- }
48
- ```
63
+ ## MCP Tool Reference
49
64
 
50
- Decisions are one of: `approved`, `changes_requested`, or `approved_with_comments`.
65
+ The MCP server exposes one tool: **`open_review`**
51
66
 
52
- ### Claude Code (MCP)
67
+ | Parameter | Required | Description |
68
+ |---------------|----------|-------------------------------------------------------------------|
69
+ | `diff_ref` | Yes | `"staged"`, `"unstaged"`, or a git ref range (e.g. `"HEAD~3..HEAD"`, `"main..feature"`) |
70
+ | `title` | No | Title displayed in the review UI |
71
+ | `description` | No | Description of the changes |
72
+ | `reasoning` | No | Agent reasoning about why the changes were made (shown in the reasoning panel) |
53
73
 
54
- DiffPrism ships an MCP server so Claude Code can open reviews during a coding session.
55
-
56
- **Setup:** Add to your Claude Code MCP config (`.mcp.json` or project settings). See the [full setup guide](docs/claude-setup.md) for detailed instructions covering Claude Code, Claude Desktop, auto-approval, and troubleshooting.
74
+ **Returns:** A `ReviewResult` JSON object:
57
75
 
58
76
  ```json
59
77
  {
60
- "mcpServers": {
61
- "diffprism": {
62
- "command": "npx",
63
- "args": ["diffprism", "serve"]
78
+ "decision": "approved",
79
+ "comments": [
80
+ {
81
+ "file": "src/index.ts",
82
+ "line": 42,
83
+ "body": "Consider adding a null check here",
84
+ "type": "suggestion"
64
85
  }
65
- }
86
+ ],
87
+ "summary": "Looks good, one minor suggestion."
66
88
  }
67
89
  ```
68
90
 
69
- **Tool:** `open_review`
70
-
71
- | Parameter | Required | Description |
72
- |---------------|----------|--------------------------------------|
73
- | `diff_ref` | yes | Git diff reference: `"staged"`, `"unstaged"`, or a ref range |
74
- | `title` | no | Title shown in the review UI |
75
- | `description` | no | Description of the changes |
76
- | `reasoning` | no | Agent reasoning about why changes were made |
77
-
78
- The tool opens a browser, blocks until you submit a review, and returns the `ReviewResult` to Claude Code.
79
-
80
- **Auto-approve the tool:** By default Claude Code prompts for confirmation each time. To skip that, add `mcp__diffprism__open_review` to the `permissions.allow` array in your project's `.claude/settings.json` or your user-level `~/.claude/settings.json`:
81
-
82
- ```json
83
- {
84
- "permissions": {
85
- "allow": [
86
- "mcp__diffprism__open_review"
87
- ]
88
- }
89
- }
90
- ```
91
+ | Field | Description |
92
+ |-------|-------------|
93
+ | `decision` | `approved`, `changes_requested`, or `approved_with_comments` |
94
+ | `comments` | Array of inline comments with file, line, body, and type (`must_fix`, `suggestion`, `question`, `nitpick`) |
95
+ | `summary` | Optional reviewer summary |
91
96
 
92
97
  ## How It Works
93
98
 
94
99
  1. **Extract** — runs `git diff` and parses the output into a structured `DiffSet`
95
- 2. **Analyze** — generates a `ReviewBriefing` with file stats, impact detection, and triage
100
+ 2. **Analyze** — generates a `ReviewBriefing`: file stats, complexity scores, test gap detection, pattern flags, dependency changes
96
101
  3. **Serve** — starts a Vite dev server (React UI) and WebSocket bridge on random ports
97
102
  4. **Review** — opens a browser to the diff viewer, waits for your decision
98
103
  5. **Return** — cleans up servers and returns the `ReviewResult`
@@ -100,8 +105,12 @@ The tool opens a browser, blocks until you submit a review, and returns the `Rev
100
105
  ## Development
101
106
 
102
107
  ```bash
103
- pnpm install # Install all deps
108
+ git clone https://github.com/CodeJonesW/diffprism.git
109
+ cd diffprism
110
+ pnpm install
104
111
  pnpm test # Run all tests (Vitest)
112
+ pnpm run build # Build all packages
113
+ pnpm cli review --staged # Run CLI from source
105
114
  npx tsc --noEmit -p packages/core/tsconfig.json # Type-check a package
106
115
  ```
107
116
 
@@ -110,15 +119,19 @@ npx tsc --noEmit -p packages/core/tsconfig.json # Type-check a package
110
119
  ```
111
120
  packages/core — Shared types, pipeline orchestrator, WebSocket bridge
112
121
  packages/git — Git diff extraction + unified diff parser
113
- packages/analysis — Deterministic review briefing generation
114
- packages/ui — React 19 + Vite + Tailwind diff viewer
122
+ packages/analysis — Deterministic review briefing (complexity, test gaps, patterns)
123
+ packages/ui — React 19 + Vite 6 + Tailwind + Zustand diff viewer
115
124
  packages/mcp-server — MCP tool server (open_review)
116
- packages/github — Placeholder (future GitHub integration)
117
125
  cli/ — Commander CLI entry point
118
126
  ```
119
127
 
120
128
  ### Requirements
121
129
 
122
130
  - Node.js >= 20
123
- - pnpm
131
+ - pnpm (for development)
124
132
  - Git
133
+
134
+ ## Documentation
135
+
136
+ - [Claude Code / Claude Desktop Setup Guide](docs/claude-setup.md) — detailed MCP configuration, auto-approval, and troubleshooting
137
+ - [UX Design Notes](docs/ux-design-notes.md) — design decisions, CLI defaults rationale, and multi-agent workflow thinking
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.10.1" : "0.0.0-dev");
257
+ program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(true ? "0.11.0" : "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();
@@ -11,7 +11,7 @@ import { z } from "zod";
11
11
  async function startMcpServer() {
12
12
  const server = new McpServer({
13
13
  name: "diffprism",
14
- version: true ? "0.10.1" : "0.0.0-dev"
14
+ version: true ? "0.11.0" : "0.0.0-dev"
15
15
  });
16
16
  server.tool(
17
17
  "open_review",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diffprism",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "description": "Local-first code review tool for agent-generated code changes",
6
6
  "bin": {